Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rules_go does not respect CC #1320

Closed
snowp opened this issue Feb 12, 2018 · 5 comments
Closed

rules_go does not respect CC #1320

snowp opened this issue Feb 12, 2018 · 5 comments

Comments

@snowp
Copy link

snowp commented Feb 12, 2018

Compiling the standard library requires both a C and a C++ compiler. Normally this is fine, as rules_go grabs the compilers from the path (I think? or well known location?), but if you try to override the compilers with CXX and CC rules_go will use the location specified by CXX for both the C and C++ compiler, resulting in this:

ERROR: /root/.cache/bazel/_bazel_root/2ca1f4ebdc59348ffdc31d97a51a98d5/external/go_stdlib_linux_amd64_cgo/BUILD.bazel:4:1: error executing shell command: 'export GOROOT="$(pwd)/bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo" GOROOT_FINAL="GOROOT" GOOS="linux" GOARCH="amd64" CGO_ENABLED="1" CC="/opt/rh/devtoolset-4/root/usr/bin/g++" CXX="/opt/r...' failed (Exit 2)
# runtime/cgo
gcc_libinit.c: In function 'int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)':
gcc_libinit.c:106:21: error: invalid conversion from 'void*' to 'timespec*' [-fpermissive]
   nanosleep(&ts, nil);
                     ^
In file included from /usr/include/pthread.h:24:0,
                 from gcc_libinit.c:8:
/usr/include/time.h:334:12: note:   initializing argument 2 of 'int nanosleep(const timespec*, timespec*)'
 extern int nanosleep (const struct timespec *__requested_time,
            ^

That is: it's trying to compile C code with a C++ compiler, which forbids this kind of implicit casting.

The offending code in rules_go is here:
https://github.com/bazelbuild/rules_go/blob/cdaa8e35cf53ba539ebe5bf6a4a407f91a284594/go/tools/builders/env.go#L98-L104

It's reading the cc value from the C++ fragment in Bazel which respects CXX. Since it sets the same value for both CC and CXX here, it's not possible to override a specific C compiler (not even a C++ one unless it can also be used as a C compiler).

I realize this might be due to a lack of a specific C toolchain in bazel, but I figured I should file the issue regardless.

@jayconrod
Copy link
Contributor

Thanks for reporting. I don't know if it's possible to resolve this with the old cpp fragment. There might be something in the new C++ toolchain API that lets us distinguish between C and C++. This option comes from the location below, and there's just one compiler_executable. Without setting either CC or CXX for that, I get /usr/bin/gcc out of that.

https://github.com/bazelbuild/rules_go/blob/1c41d106559cbfa6fffe75481eeb492ae77471c0/go/private/context.bzl#L274

Are you able to build cc_library rules using these settings?

cc @ianthehat Is this something that would require a custom CROSSTOOL?

@snowp
Copy link
Author

snowp commented Feb 15, 2018

Some more details: Seeing this when updating from 4374be38e9a75ff5957c3922adb155d32086fe14 to 0.9.0, see envoyproxy/envoy#2617:

From one of the failing tests:
> clang: error: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Werror,-Wdeprecated]

In different test:

  (cd /build/tmp/_bazel_bazel/436badd4919a15958fa3800a4e21074a/execroot/ci && \
  exec env - \
  /bin/bash -c 'export GOROOT="$(pwd)/bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo" GOROOT_FINAL="GOROOT" GOOS="linux" GOARCH="amd64" CGO_ENABLED="1" CC="/usr/bin/g++" CXX="/usr/bin/g++" COMPILER_PATH="/usr/bin" CGO_CPPFLAGS="-U_FORTIFY_SOURCE -fstack-protector -B/usr/bin -B/usr/bin -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer -g0 -O2 -D_FORTIFY_SOURCE=1 -DNDEBUG -ffunction-sections -fdata-sections -g0" CGO_LDFLAGS="-lm -fuse-ld=gold -Wl,-no-as-needed -Wl,-z,relro,-z,now -B/usr/bin -B/usr/bin -pass-exit-codes" && export PATH=$PATH:$(cd "$COMPILER_PATH" && pwd) && mkdir -p bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo/src && mkdir -p bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo/pkg && cp -rf external/go_sdk/src/* bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo/src/ && cp -rf external/go_sdk/pkg/tool bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo/pkg/ && cp -rf external/go_sdk/pkg/include bazel-out/host/bin/external/go_stdlib_linux_amd64_cgo/pkg/ && external/go_sdk/bin/go install -asmflags "-trimpath $(pwd)"  std && external/go_sdk/bin/go install -asmflags "-trimpath $(pwd)"  runtime/cgo')

# runtime/cgo
gcc_libinit.c: In function 'int _cgo_try_pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)':
gcc_libinit.c:106:21: error: invalid conversion from 'void*' to 'timespec*' [-fpermissive]
   nanosleep(&ts, nil);
                     ^
In file included from /usr/include/pthread.h:24:0,
                 from gcc_libinit.c:8:
/usr/include/time.h:334:12: note:   initializing argument 2 of 'int nanosleep(const timespec*, timespec*)'
 extern int nanosleep (const struct timespec *__requested_time,

Different output due to different C++ compiler used.

@snowp
Copy link
Author

snowp commented Feb 15, 2018

Running this fixed the build, so it's really just an issue of plumbing through the C compiler:

sed -i bazel-project/external/io_bazel_rules_go/go/private/rules/stdlib.bzl -e "s;CC.*$;CC\": \"$(which gcc)\",;g"

@jayconrod
Copy link
Contributor

Ok, I've done some research into this, and I think I have a better understanding of what's happening.

Bazel will configure a C / C++ toolchain using something that's nominally a C compiler (like gcc or clang, not g++ or clang++). When it wants to build C++ code, it will do so by explicitly passing a flag like -std=c++0x. You can set the compiler by defining a CROSSTOOL file, or by setting the CC environment variable (which will cause a CROSSTOOL to be generated at @local_config_cc//:CROSSTOOL). The CXX environment variable is ignored.

The name of the C compiler is exposed to Skylark rules (i.e., rules_go). We get this from ctx.fragments.cpp.compiler_executable. We pass it to our builders with the -cc flag. As you pointed out, we're also setting the CXX flag. That probably isn't necessary, but I can't think of a case where we would be building C++ code with a Go builder.

From the error message you posted earlier, I think this is the problem:

CC="/opt/rh/devtoolset-4/root/usr/bin/g++"

That looks like a custom value coming from your environment. I think if you pass in CC=/opt/rh/devtoolset-4/root/usr/bin/gcc instead, it will work.

@snowp
Copy link
Author

snowp commented Feb 15, 2018

Yup, that seems to be the issue. I was kinda surprised that Bazel doesn't let you differentiate between C++/C compiler (like cmake et al) does, but I guess this is okay. Turns out the specific project I was running into uses a custom cc toolchain that looks for g++ instead of gcc for the cpp fragment. Gonna close this out because I don't think this is a rules_go issue

Thanks a lot for providing the additional context, sorry about the noise.

@snowp snowp closed this as completed Feb 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants