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

Put toolchain default library flags in LDFLAGS broke many projects on Darwin #1227

Open
ashi009 opened this issue Jul 16, 2024 · 1 comment

Comments

@ashi009
Copy link

ashi009 commented Jul 16, 2024

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.

phlax pushed a commit to envoyproxy/envoy that referenced this issue Dec 12, 2024
…ke (#37632)

When upstream `rules_foreign_cc` builds its own GNUMake, it injects
bazel's default libraries into `LDFLAGS`, which causes trouble on Darwin
in newer versions of Bazel that added `-lm` to the list of default
libraries.

As explained nicely in
bazel-contrib/rules_foreign_cc#1227, Apple's
libm re-exports a bunch of symbols and, due to linker argument order,
clobbers some symbols from make itself. We don't need any of the default
libraries in GNUMake, so disable the feature to link them.

Risk Level: low
Testing: CI

---------

Signed-off-by: Alejandro R Sedeño <[email protected]>
Signed-off-by: Alejandro R. Sedeño <[email protected]>
@asedeno
Copy link

asedeno commented Dec 12, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants