Put toolchain default library flags in LDFLAGS broke many projects on Darwin
I started this quest as @rules_foreign_cc//toolchains/private:make_tool segfaults when wildcard is used. It turned out that make was not linking against the glob() function from the source tree, but a version from some system libraries. The version from the system library is not compatible with gnulib's glob() and caused segfault.
TLDR
We need to strip -lXX flags from LDFLAGS to make autoconfig and linker sane on Darwin.
Root cause
Standard cpp toolchain includes defaults libs -lc++ (or -lstdc++) and -lm for linking flags. Which also uses -as-needed around those flags. However, Darwin's ld doesn't support the --as-needed feature, which means, all these libraries are loaded even if it's not required.
And here comes the interesting part. Those libs are presented as LDFLAGS to foreign cc build actions, and LDFLAGS almost always come before the actual object files from the target project. Take GNUMake's makefile as an example:
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
make$(EXEEXT): $(make_OBJECTS) $(make_DEPENDENCIES) $(EXTRA_make_DEPENDENCIES)
@rm -f make$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(make_OBJECTS) $(make_LDADD) $(LIBS)
As well as the gettext's auto-configure script:
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
This means, ld will try to link against the libs defined by the cpp toolchain and then with the object files from the project. On contrast, the cc_binary will put those flags after the object files:
-o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/zstd_cli
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/benchfn.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/benchzstd.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/dibio.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/fileio.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/fileio_asyncio.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/lorem.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/timefn.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/util.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/zstdcli.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/_objs/zstd_cli/zstdcli_trace.o
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/libdatagen.a
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/libutil.a
bazel-out/darwin_arm64-fastbuild/bin/external/zstd/libzstd.a
-Wl,-S
-mmacosx-version-min=14.5
-no-canonical-prefixes
-fobjc-link-runtime
--target=aarch64-apple-macosx
-lm
-no-canonical-prefixes
-headerpad_max_install_names
-fobjc-link-runtime
-L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
-lc++
-lc++abi
-Bstatic
-lunwind
-Bdynamic
-Lexternal/llvm_toolchain_llvm/lib
-pthread
--sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
Those standard libraries won't be a big deal in a perfect world. However, Darwin is weird, especially the math lib (try open /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/libm.tbd) re-exports a lot of symbols from other libs, including libsystem_c.dylib, which is not fully POSIX-compliant. Linking against it broke auto-config and caused segfault.
As a result, foreign_cc cannot build many projects on Darwin, while homebrew can.
The patch in the Envoy commit that referenced this issue fixes GNUMake on Darwin (and everywhere else) to not link in the default bazel libraries. If applied upstream (read: here) it should fix the example described here, but that doesn't mean the same problem won't crop up building other things. At least fixing the segfault in the GNUMake that rules_foreign_cc builds for itself should help concentrate user efforts on debugging their builds and not their tools.