Skip to content

Commit af903f5

Browse files
srikantharunSrikanth Arunachalam
authored andcommitted
Auto-detect GCC C++ headers in sysroot for libstdc++ cross-compilation
Fixes #533 When cross-compiling with a sysroot and using libstdc++ (stdlib = "stdc++" or "dynamic-stdc++"), clang needs the GCC C++ headers to be explicitly listed in cxx_builtin_include_directories. Previously, users had to manually specify these paths. This change adds automatic detection of GCC C++ headers in the sysroot by: 1. Scanning /usr/include/c++/<version> for modern distros (Debian 10+) 2. Scanning /usr/lib/gcc/<triple>/<version>/... for traditional layouts The detection adds paths for: - Main C++ headers: /usr/include/c++/<version> - Target-specific headers: /usr/include/<triple>/c++/<version> - Backward compatibility: /usr/include/c++/<version>/backward This enables cross-compiling from Darwin to Linux with custom Debian sysroots without manual configuration of include directories.
1 parent 53170fe commit af903f5

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

toolchain/internal/configure.bzl

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,72 @@ load(
5252
# workspace builds, there is never a @@ in labels.
5353
BZLMOD_ENABLED = "@@" in str(Label("//:unused"))
5454

55+
def _detect_gcc_cxx_headers(rctx, sysroot_path, target_system_name):
56+
"""Detect GCC C++ header directories in a sysroot.
57+
58+
When using libstdc++ with a sysroot, clang needs to know where the GCC C++
59+
headers are located. This function auto-detects these paths by scanning
60+
the sysroot for installed GCC versions.
61+
62+
Args:
63+
rctx: Repository context.
64+
sysroot_path: Path to the sysroot (absolute or relative).
65+
target_system_name: Target triple (e.g., x86_64-unknown-linux-gnu).
66+
67+
Returns:
68+
List of C++ include directory paths relative to the sysroot root.
69+
"""
70+
include_dirs = []
71+
72+
# For non-absolute paths (Bazel labels), we can't inspect the filesystem
73+
# during repository rule execution. Return empty and let users specify
74+
# additional include dirs manually via cxx_builtin_include_directories.
75+
if not _is_absolute_path(sysroot_path):
76+
return include_dirs
77+
78+
# Extract the GNU target triple from target_system_name
79+
# e.g., "x86_64-unknown-linux-gnu" -> "x86_64-linux-gnu"
80+
parts = target_system_name.split("-")
81+
if len(parts) >= 3:
82+
# Common GNU triple format: arch-linux-gnu or arch-linux-gnueabihf
83+
gnu_triple = parts[0] + "-linux-" + parts[-1]
84+
else:
85+
gnu_triple = target_system_name
86+
87+
# Check for GCC C++ headers in common locations
88+
# Modern distros (Debian 10+, Ubuntu 18.04+): /usr/include/c++/<version>
89+
cxx_include_base = sysroot_path + "/usr/include/c++"
90+
if rctx.path(cxx_include_base).exists:
91+
# Find GCC version directories (e.g., "14", "13", "12")
92+
result = rctx.execute(["ls", cxx_include_base])
93+
if result.return_code == 0:
94+
versions = [v.strip() for v in result.stdout.strip().split("\n") if v.strip()]
95+
for version in versions:
96+
# Add main C++ headers
97+
include_dirs.append("/usr/include/c++/" + version)
98+
# Add target-specific headers (for multi-arch)
99+
include_dirs.append("/usr/include/" + gnu_triple + "/c++/" + version)
100+
# Add backward compatibility headers
101+
include_dirs.append("/usr/include/c++/" + version + "/backward")
102+
103+
# Also check traditional GCC installation path: /usr/lib/gcc/<triple>/<version>/...
104+
# This is the layout used by older distros and Chromium sysroots
105+
gcc_lib_base = sysroot_path + "/usr/lib/gcc/" + gnu_triple
106+
if rctx.path(gcc_lib_base).exists:
107+
result = rctx.execute(["ls", gcc_lib_base])
108+
if result.return_code == 0:
109+
versions = [v.strip() for v in result.stdout.strip().split("\n") if v.strip()]
110+
for version in versions:
111+
# Traditional GCC include path structure uses relative paths from gcc lib dir
112+
# e.g., /usr/lib/gcc/x86_64-linux-gnu/6/../../../../include/c++/6
113+
# which resolves to /usr/include/c++/6
114+
base = "/usr/lib/gcc/" + gnu_triple + "/" + version
115+
include_dirs.append(base + "/../../../../include/c++/" + version)
116+
include_dirs.append(base + "/../../../../include/" + gnu_triple + "/c++/" + version)
117+
include_dirs.append(base + "/../../../../include/c++/" + version + "/backward")
118+
119+
return include_dirs
120+
55121
def _empty_repository(rctx):
56122
rctx.file("BUILD.bazel")
57123
rctx.file("toolchains.bzl", """\
@@ -382,6 +448,17 @@ def _cc_toolchain_str(
382448
_join(sysroot_prefix, "/usr/include"),
383449
_join(sysroot_prefix, "/usr/local/include"),
384450
])
451+
# Add GCC C++ headers from sysroot when using libstdc++.
452+
# These paths are needed because clang doesn't automatically add them
453+
# to the include search path when cross-compiling with a sysroot.
454+
# See https://github.com/bazel-contrib/toolchains_llvm/issues/533
455+
stdlib = _dict_value(toolchain_info.stdlib_dict, target_pair, "builtin-libc++")
456+
if stdlib in ["stdc++", "dynamic-stdc++"] and sysroot_path:
457+
# Common GCC C++ header locations in modern distros (Debian/Ubuntu)
458+
# Pattern: /usr/include/c++/<version> and /usr/include/<triple>/c++/<version>
459+
gcc_cxx_include_dirs = _detect_gcc_cxx_headers(rctx, sysroot_path, target_system_name)
460+
for dir in gcc_cxx_include_dirs:
461+
cxx_builtin_include_directories.append(_join(sysroot_prefix, dir))
385462
elif target_os == "darwin":
386463
cxx_builtin_include_directories.extend([
387464
_join(sysroot_prefix, "/usr/include"),

0 commit comments

Comments
 (0)