2

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 in lldb 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)
Tim
  • 21
  • 2
  • 1
    https://groups.google.com/g/bazel-discuss/c/YGVWGnhFEXc?pli=1 – Alan Birtles Jun 23 '23 at 05:59
  • Hi, thank you for this link: the suggestion to add `bazel run --linkopts="-Wl,-undefined,error" :main` does what I want! However, I can't add this to my workspace `.bazelrc`, otherwise my external dependencies (absl, gtest, etc.) generate linker errors from using this linkopt. Any advice @AlanBirtles? – Tim Jun 23 '23 at 22:01
  • I've never used bazel,i just googled your error message – Alan Birtles Jun 24 '23 at 05:03
  • You can use https://bazel.build/reference/be/c-cpp#cc_binary.linkopts for the `cc_binary()` – lummax Jul 06 '23 at 06:56

0 Answers0