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++"], ), )