I'm trying to convert an embedded project from CMake (via a brief detour to meson) to Bazel. We are using the llvm-embedded toolchain which uses picolibc. I manually setup the toolchain more or less based on bazel-embedded (which doesn't support llvm-embedded directly).
So far, everything seems to work, except that the link fails with undefined symbol: stdout
, which gets referenced from tinystdio/puts.c
, part of picolibc
. Indeed, "Picolibc and Operating Systems" explains that we have to provide that symbol. We do that as part of our startup C-file, basically exactly copying that documentation.
With both CMake and meson, that links perfectly, but I can't get it to link with bazel. Some of the differences I did notice are that bazel uses the C driver (clang
) instead of the C++ driver (clang++
), see bazel issue 11122. The assumption is that the difference is mostly unimportant, the C++ linking issues can be resolved by either linking directly to libc++
and libc++abi
, or by passing --driver-mode=g++
.
Also, it does link correctly without -flto=thin
.
While for this blinky
test we don't really need LTO, we do rely on LTO in our larger builds, and we need it to get working.
Here is the full linker command line created by bazel in one of the failed attempts:
/path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/clang
-o bazel-out/.../blinky
bazel-out/.../blinky.o
...some-dependency-libs.a...
bazel-out/.../libapollo4-fam-picolibc-startup.a
-nodefaultlibs -nostdlib
-T mcus/apollo4l/llvm-picolibc.ld
-Wl,--start-group
-lc -lc++ -lc++abi -lunwind -lclang_rt.builtins -lm -lcrt0
bazel-out/.../libapollo4-fam-picolibc-startup.a
-Wl,--end-group
-Wl,--as-needed -Wl,--no-undefined
-Wl,-v -v -Wl,-S -Wl,--gc-sections
'-march=armv7em' '-mfloat-abi=hard' '-mfpu=fpv4-sp-d16' -mlittle-endian
-Os '-flto=thin' '-fuse-ld=lld' '--driver-mode=g++'
-fno-exceptions -fno-rtti
'-mabi=aapcs' -mthumb '--target=armv7em-none-eabi'
-static
The stdout
symbol is provided in libapollo4-fam-picolibc-startup.a
. The -nodefaultlibs -nostdlib
, and then packing all stdlibs between -Wl,--start-group
, -Wl,--end-group
is my heaviest gun I have been able to muster, to no effect.
For comparison, here is the successful meson command line:
/path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/clang++
-o blinky
blinky.afx.p/blinky.cpp.o
-flto=thin -Wl,--as-needed -Wl,--no-undefined
-fuse-ld=/path/zo/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64/bin/ld.lld
-ffunction-sections
-fdata-sections
-fomit-frame-pointer
--target=armv7em-none-eabi
-mfpu=fpv4-sp-d16
-Wl,--start-group
libstartup.a
...dependency-libs.a...
-T/path/to/llvm-picolibc.ld
-Wl,-Map,/path/to/blinky.map
/path/to/LLVMEmbeddedToolchainForArm-17.0.1-Darwin-AArch64//lib/clang-runtimes/arm-none-eabi/armv7m_soft_fpv4_sp_d16/lib/libcrt0.a
-Wl,--end-group
Here, the stdout
is found in libstartup.a
.
I don't know what else to try.