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 · 0 comments
Open

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.

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

1 participant