Problem: While trying to setup and run a C++ project with Clang + Bazel + VSCode on Mac, I noticed that the compiler/linker errors that I am getting from bazel run :main
are not descriptive enough and do not help me debug or find the actual errors themselves. The project used hedron_compile_commands for linting, but the problem occurs without it. When compared to a regular clang++ main.cc
, I find the errors are much, much better (or using gcc, g++, clang for that matter).
At a glance: here is a side-by-side between bazel run :main
and clang++ main.cc
runs, where the clang++
version actually tells me the missing symbol and where the problem is:
$ bazel clean --expunge # Just in case
$ bazel run :main
...
INFO: Running command line: bazel-bin/main
dyld[21237]: missing symbol called
[1] 21237 abort bazel run :main
vs.
$ clang++ main.cc
Undefined symbols for architecture arm64:
"hello()", referenced from:
_main in main-1ad55b.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Minimal Reproducible Example: To help debug, I removed all project specifics and started a minimum working example (below) that intentionally causes an error. How can I make the error more informative like clang++
does?
File: WORKSPACE
(empty)
File: BUILD
cc_binary(
name = "main",
srcs = ["main.cc"],
)
File: main.cc
#include <iostream>
// Intentionally not defining function hello() to cause symbol not found error.
void hello();
int main() {
hello();
return 0;
}
Other details, if they are helpful:
$ xcode-select -p
/Library/Developer/CommandLineTools
$ clang -v
Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.5.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
$ bazel --version
bazel 6.2.0-homebrew
Subcommand-level printout for bazel (no extra args):
$ bazel run --subcommands :main
INFO: Analyzed target //:main (4 packages loaded, 36 targets configured).
INFO: Found 1 target...
SUBCOMMAND: # //:main [action 'Compiling main.cc', configuration: 0909373ec580d3e2e8ec40b71c3e423e7c33b13b4c974f9aae5bd5b5697a6d2f, execution platform: @local_config_platform//:host]
(cd /private/var/tmp/_bazel_tshur/a61ba18154c69c2d95531d3e0a4c3e62/execroot/__main__ && \
exec env - \
PATH=/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/git/current/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:...(other_PATH_locations_of_mine) \
PWD=/proc/self/cwd \
external/local_config_cc/cc_wrapper.sh -U_FORTIFY_SOURCE -fstack-protector -Wall -Wthread-safety -Wself-assign -Wunused-but-set-parameter -Wno-free-nonheap-object -fcolor-diagnostics -fno-omit-frame-pointer '-std=c++0x' -MD -MF bazel-out/darwin_arm64-fastbuild/bin/_objs/main/main.pic.d '-frandom-seed=bazel-out/darwin_arm64-fastbuild/bin/_objs/main/main.pic.o' -fPIC '-DBAZEL_CURRENT_REPOSITORY=""' -iquote . -iquote bazel-out/darwin_arm64-fastbuild/bin -iquote external/bazel_tools -iquote bazel-out/darwin_arm64-fastbuild/bin/external/bazel_tools -no-canonical-prefixes -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -c main.cc -o bazel-out/darwin_arm64-fastbuild/bin/_objs/main/main.pic.o)
# Configuration: 0909373ec580d3e2e8ec40b71c3e423e7c33b13b4c974f9aae5bd5b5697a6d2f
# Execution platform: @local_config_platform//:host
SUBCOMMAND: # //:main [action 'Linking main', configuration: 0909373ec580d3e2e8ec40b71c3e423e7c33b13b4c974f9aae5bd5b5697a6d2f, execution platform: @local_config_platform//:host]
(cd /private/var/tmp/_bazel_tshur/a61ba18154c69c2d95531d3e0a4c3e62/execroot/__main__ && \
exec env - \
PATH=/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/git/current/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:...(other_PATH_locations_of_mine) \
PWD=/proc/self/cwd \
external/local_config_cc/cc_wrapper.sh @bazel-out/darwin_arm64-fastbuild/bin/main-2.params)
# Configuration: 0909373ec580d3e2e8ec40b71c3e423e7c33b13b4c974f9aae5bd5b5697a6d2f
# Execution platform: @local_config_platform//:host
Target //:main up-to-date:
bazel-bin/main
INFO: Elapsed time: 5.609s, Critical Path: 0.52s
INFO: 8 processes: 6 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 8 total actions
INFO: Running command line: bazel-bin/main
dyld[23482]: missing symbol called
[1] 23482 abort bazel run --subcommands :main
Some things I have tried / looked into:
A lot of command-line options found across bazel github / stack exchange such as
--action_env CC=clang++
--subcommands
-c dbg
--incompatible_enable_cc_toolchain_resolution
CC=/opt/homebrew/opt/llvm/bin/clang++
--spawn_strategy=local
--sandbox_debug
--strip=never
--apple_generate_dsym
--strategy_regexp=^Linking=local
--features=oso_prefix_is_pwd
BAZEL_USE_CPP_ONLY_TOOLCHAIN=1
I have briefly tried playing with C++ toolchain setting in Bazel, but I would ideally like to find a way to have Bazel automatically detect the correct C++ toolchain
Tried searching for this issue many, many times. The most similar issues I have seen are where some #include'd library is showing
dydl
errors, but no posts about how to improve this error logging for a regular project. Other similar issues involved getting symbols inlldb
debugging, but I want the solution to output errors regardless of debugger.
Where I am now: My best understanding to date is that the issue I am having is related to the Linker and Mac/OSX. It seems to me that the Linker is finding the error that the symbol is not found (I know this is because the function hello()
is not defined/implemented). clang++
is doing a great job of describing the linker error. However, bazel
seems to be hiding or truncating the error.
From other posts, I have seen that Mac/OSX may be hiding or not storing all of the symbols for bazel
to use during error reporting? I feel like I am looking for some verbosity or dbg flag, but the ones that I have found and tried (above) do not seem to work. Are there some kind of linkopts that are needed?
Also, I am not certain which compiler bazel
is using. My best understanding is that it comes from xcode command line tools. I also tried brew install llvm
, but I am not sure how to point to that.
Please help! Thanks so much in advance for any help ~~
Edit 1: As @AlanBirtles pointed out, I can pass bazel run --linkopt="-Wl,-undefined,error" :main
to create a descriptive build-time error (rather than a non-descriptive run-time error).
However, I cannot add build --linkopt="-Wl,-undefined,error"
to my workspace .bazelrc
. Otherwise, my other dependencies (e.g., absl) are built with this flag, and they have failures.
Undefined symbols for architecture arm64:
"absl::random_internal::kRandenRoundKeys", referenced from:
absl::random_internal::RandenHwAes::GetKeys() in randen_hwaes.pic.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)