bazel-contrib / bazel-contrib/rules_foreign_cc

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

Open
#1,227 1 comment 1 reaction 0 assignees View on GitHub
Dominant language
Starlark
Stars
737
Forks
270
PR merge metrics
No merged PRs in 30d

Description

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`](https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/unix_cc_configure.bzl;l=465;drc=9e913fbfa2e3930742fc30dfb60ac5e2694c70cf) 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:

```make
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:

```autoconf
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:

```paramfile
-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.

Contributor guide

Open the contributing guide

Research direction

Start by tracing how the C++ toolchain's default libraries become LDFLAGS for foreign_cc actions, then reproduce the configure or GNU Make link failure on Darwin. Done means library flags such as -lXX are no longer passed through LDFLAGS and affected Darwin builds no longer fail or segfault.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.