Add support for clang's libc++ to Unix toolchain
Due to two separate issues, it is currently not possible to compile and link against clang's libc++ with Bazel's auto-configured Unix toolchain, e.g. via adding `-stdlib=libc++` as a `cxxopt` and `linkopt` on a `cc_binary`:
1. Since Bazel uses `-no-canonical-prefixes`, clang is not able to find the libc++ headers if it is invoked through a symlink in a different directory. This is fixed by fully resolving the path to the clang binary in the toolchain.
2. The list of built-in include paths does not contain the base directory of the libc++ headers, which makes Bazel's implicit dependency checker fail on targets with the `cxxopt` `-stdlib=lib++`. This is fixed by adding the search paths obtained from `clang -v` with that option to the list of built-in include paths in the toolchain.
Both 1. and 2. can be partially worked around by passing in `-stdlib=libc++` and a fully resolved `CC` via `--repo_env`. However, the former means that the choice of standard library has to be fixed for the entire workspace and the latter cannot be accomplished with a system-independent entry in `.bazelrc`. Proper fixes in Bazel thus seem vastly superior.
Fixes #13071
Closes #13666.
PiperOrigin-RevId: 389877696
diff --git a/tools/cpp/unix_cc_configure.bzl b/tools/cpp/unix_cc_configure.bzl
index 14a0ed5..371b66f 100644
--- a/tools/cpp/unix_cc_configure.bzl
+++ b/tools/cpp/unix_cc_configure.bzl
@@ -307,7 +307,15 @@
return result
def find_cc(repository_ctx, overriden_tools):
- return _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
+ cc = _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
+ if _is_clang(repository_ctx, cc):
+ # If clang is run through a symlink with -no-canonical-prefixes, it does
+ # not find its own include directory, which includes the headers for
+ # libc++. Resolving the potential symlink here prevents this.
+ result = repository_ctx.execute(["readlink", "-f", cc])
+ if result.return_code == 0:
+ return result.stdout.strip()
+ return cc
def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
"""Configure C++ toolchain on Unix platforms."""
@@ -333,7 +341,7 @@
repository_ctx.file("tools/cpp/empty.cc", "int main() {}")
darwin = cpu_value.startswith("darwin")
- cc = _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
+ cc = find_cc(repository_ctx, overriden_tools)
is_clang = _is_clang(repository_ctx, cc)
overriden_tools = dict(overriden_tools)
overriden_tools["gcc"] = cc
@@ -428,6 +436,12 @@
_get_cxx_include_directories(
repository_ctx,
cc,
+ "-xc++",
+ cxx_opts + ["-stdlib=libc++"],
+ ) +
+ _get_cxx_include_directories(
+ repository_ctx,
+ cc,
"-xc",
_get_no_canonical_prefixes_opt(repository_ctx, cc),
) +
@@ -436,6 +450,12 @@
cc,
"-xc++",
cxx_opts + _get_no_canonical_prefixes_opt(repository_ctx, cc),
+ ) +
+ _get_cxx_include_directories(
+ repository_ctx,
+ cc,
+ "-xc++",
+ cxx_opts + _get_no_canonical_prefixes_opt(repository_ctx, cc) + ["-stdlib=libc++"],
),
)