Skip to content

Commit 4291cb6

Browse files
committed
Add target_toolchain_roots and make sysroot more hermetic
It is useful when cross compiling to have 1 LLVM build used as the compiler, and multiple others used for their libc++/target libraries. This concept forces us to be much more robust about what comes from the target toolchain, and what comes from the compiler. Leave toolchain_roots for the compiler roots, but add a new flag, target_toolchain_roots with the same semantics for target toolchains. This necesitates being much more clear internally about what comes from what. This isn't fully enough to make everything hermetic, clang still has some autodetection logic left over when using sysroots. We want to very explicity specify the resource directory it should use, as well as where the standard C/C++ libraries come from so it finds only what we want it to find. When pulling from a sysroot, we need to know the version of stdc++ to find includes. Use the stdlib variable for that by supporting "stdc++-12" for example, and parsing the number out.
1 parent de26c39 commit 4291cb6

File tree

5 files changed

+245
-58
lines changed

5 files changed

+245
-58
lines changed

toolchain/BUILD.llvm_repo

+4-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ filegroup(
4848
filegroup(
4949
name = "include",
5050
srcs = glob([
51-
"include/**/c++/**",
51+
"include/**",
5252
"lib/clang/*/include/**",
5353
]),
5454
)
@@ -70,8 +70,11 @@ filegroup(
7070
name = "lib",
7171
srcs = glob(
7272
[
73+
"lib/lib*.a",
7374
"lib/**/lib*.a",
75+
"lib/**/lib*.a.syms",
7476
"lib/clang/*/lib/**/*.a",
77+
"lib/clang/*/lib/**/*.a.syms",
7578
"lib/clang/*/lib/**/*.dylib",
7679
# clang_rt.*.o supply crtbegin and crtend sections.
7780
"lib/**/clang_rt.*.o",

toolchain/cc_toolchain_config.bzl

+156-35
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,12 @@ def cc_toolchain_config(
3737
target_os,
3838
target_system_name,
3939
toolchain_path_prefix,
40+
target_toolchain_path_prefix,
4041
tools_path_prefix,
4142
wrapper_bin_prefix,
4243
compiler_configuration,
4344
cxx_builtin_include_directories,
44-
major_llvm_version):
45+
llvm_version):
4546
exec_os_arch_key = _os_arch_pair(exec_os, exec_arch)
4647
target_os_arch_key = _os_arch_pair(target_os, target_arch)
4748
_check_os_arch_keys([exec_os_arch_key, target_os_arch_key])
@@ -56,6 +57,7 @@ def cc_toolchain_config(
5657
compiler,
5758
abi_version,
5859
abi_libc_version,
60+
multiarch,
5961
) = {
6062
"darwin-x86_64": (
6163
"clang-x86_64-darwin",
@@ -64,6 +66,7 @@ def cc_toolchain_config(
6466
"clang",
6567
"darwin_x86_64",
6668
"darwin_x86_64",
69+
None,
6770
),
6871
"darwin-aarch64": (
6972
"clang-aarch64-darwin",
@@ -72,6 +75,7 @@ def cc_toolchain_config(
7275
"clang",
7376
"darwin_aarch64",
7477
"darwin_aarch64",
78+
None,
7579
),
7680
"linux-aarch64": (
7781
"clang-aarch64-linux",
@@ -80,6 +84,7 @@ def cc_toolchain_config(
8084
"clang",
8185
"clang",
8286
"glibc_unknown",
87+
"aarch64-linux-gnu",
8388
),
8489
"linux-x86_64": (
8590
"clang-x86_64-linux",
@@ -88,6 +93,7 @@ def cc_toolchain_config(
8893
"clang",
8994
"clang",
9095
"glibc_unknown",
96+
"x86_64-linux-gnu",
9197
),
9298
"wasm32": (
9399
"clang-wasm32",
@@ -96,6 +102,7 @@ def cc_toolchain_config(
96102
"clang",
97103
"unknown",
98104
"unknown",
105+
None,
99106
),
100107
"wasm64": (
101108
"clang-wasm64",
@@ -104,6 +111,7 @@ def cc_toolchain_config(
104111
"clang",
105112
"unknown",
106113
"unknown",
114+
None,
107115
),
108116
}[target_os_arch_key]
109117

@@ -120,12 +128,30 @@ def cc_toolchain_config(
120128
"-D__TIME__=\"redacted\"",
121129
"-fdebug-prefix-map={}=__bazel_toolchain_llvm_repo__/".format(toolchain_path_prefix),
122130
]
131+
if target_toolchain_path_prefix != toolchain_path_prefix:
132+
unfiltered_compile_flags.extend([
133+
"-fdebug-prefix-map={}=__bazel_toolchain_llvm_repo__/".format(target_toolchain_path_prefix),
134+
])
123135

124136
is_xcompile = not (exec_os == target_os and exec_arch == target_arch)
125137

126-
# Default compiler flags:
127-
compile_flags = [
138+
major_llvm_version = int(llvm_version.split(".")[0])
139+
140+
external_include_paths = None
141+
142+
resource_dir_version = llvm_version if major_llvm_version < 16 else major_llvm_version
143+
144+
resource_dir = [
145+
"-resource-dir",
146+
"{}lib/clang/{}".format(target_toolchain_path_prefix, resource_dir_version),
147+
]
148+
149+
target_flags = [
128150
"--target=" + target_system_name,
151+
]
152+
153+
# Default compiler flags:
154+
compile_flags = target_flags + [
129155
# Security
130156
"-U_FORTIFY_SOURCE", # https://github.com/google/sanitizers/issues/247
131157
"-fstack-protector",
@@ -135,22 +161,36 @@ def cc_toolchain_config(
135161
"-Wall",
136162
"-Wthread-safety",
137163
"-Wself-assign",
138-
]
164+
"-B{}bin/".format(toolchain_path_prefix),
165+
] + resource_dir
139166

140167
dbg_compile_flags = ["-g", "-fstandalone-debug"]
141168

142169
opt_compile_flags = [
143-
"-g0",
170+
# Disable debug info
171+
"-ggdb0",
144172
"-O2",
145173
"-D_FORTIFY_SOURCE=1",
146174
"-DNDEBUG",
147175
"-ffunction-sections",
148176
"-fdata-sections",
149177
]
150178

151-
link_flags = [
152-
"--target=" + target_system_name,
179+
link_flags = target_flags + [
153180
"-no-canonical-prefixes",
181+
] + resource_dir
182+
183+
# Use the standard libc++ location when not using msan
184+
non_msan_compile_flags = [
185+
"-isystem",
186+
target_toolchain_path_prefix + "include/c++/v1/",
187+
"-isystem",
188+
target_toolchain_path_prefix + "include/" + target_system_name + "/c++/v1/",
189+
]
190+
191+
non_msan_link_flags = [
192+
"-L{}lib".format(target_toolchain_path_prefix),
193+
"-L{}lib/{}".format(target_toolchain_path_prefix, target_system_name),
154194
]
155195

156196
stdlib = compiler_configuration["stdlib"]
@@ -210,13 +250,30 @@ def cc_toolchain_config(
210250
cxx_standard = compiler_configuration["cxx_standard"]
211251
conly_flags = compiler_configuration["conly_flags"]
212252
sysroot_path = compiler_configuration["sysroot_path"]
253+
254+
# Flags related to C++ standard.
255+
cxx_flags = [
256+
"-std=" + cxx_standard,
257+
]
258+
compile_flags_post_language = []
259+
260+
# We only support getting libc++ from the toolchain for now. Is it worth
261+
# supporting libc++ from the sysroot? Or maybe just part of a LLVM distribution
262+
# that's built for the target?
263+
if not stdlib and is_xcompile:
264+
print("WARNING: Using libc++ for host architecture while cross compiling, this is " +
265+
"probably not what you want. Explicitly set standard_libraries to libc++ to silence.")
266+
213267
if stdlib == "builtin-libc++" and is_xcompile:
214268
stdlib = "stdc++"
215269
if stdlib == "builtin-libc++":
216-
cxx_flags = [
217-
"-std=" + cxx_standard,
270+
cxx_flags.extend([
218271
"-stdlib=libc++",
219-
]
272+
])
273+
compile_flags_post_language.extend([
274+
"-isystem",
275+
target_toolchain_path_prefix + "lib/clang/{}/include".format(resource_dir_version),
276+
])
220277
if major_llvm_version >= 14:
221278
# With C++20, Clang defaults to using C++ rather than Clang modules,
222279
# which breaks Bazel's `use_module_maps` feature, which is used by
@@ -260,37 +317,80 @@ def cc_toolchain_config(
260317
]
261318

262319
elif stdlib == "libc++":
263-
cxx_flags = [
264-
"-std=" + cxx_standard,
320+
cxx_flags.extend([
265321
"-stdlib=libc++",
266-
]
322+
])
267323

268324
link_flags.extend([
269325
"-l:c++.a",
270326
"-l:c++abi.a",
271327
])
272328
elif stdlib == "dynamic-stdc++":
273-
cxx_flags = [
329+
cxx_flags.extend([
274330
"-std=" + cxx_standard,
275331
"-stdlib=libstdc++",
276-
]
332+
])
277333

278334
link_flags.extend([
279335
"-lstdc++",
280336
])
281-
elif stdlib == "stdc++":
282-
cxx_flags = [
283-
"-std=" + cxx_standard,
284-
"-stdlib=libstdc++",
285-
]
337+
elif stdlib.startswith("stdc++"):
338+
if not use_lld:
339+
fail("libstdc++ only supported with lld")
286340

341+
# We use libgcc when using libstdc++ from a sysroot. Most libstdc++
342+
# builds link to libgcc, which means we need to use libgcc's exception
343+
# handling implementation, not the separate one in compiler-rt.
344+
# Unfortunately, clang sometimes emits code incompatible with libgcc,
345+
# see <https://bugs.llvm.org/show_bug.cgi?id=27455> and
346+
# <https://lists.llvm.org/pipermail/cfe-dev/2016-April/048466.html> for
347+
# example. This seems to be a commonly-used configuration with clang
348+
# though, so it's probably good enough for most people.
349+
link_flags.extend([
350+
"-L{}lib".format(target_toolchain_path_prefix),
351+
"-L{}lib/{}".format(target_toolchain_path_prefix, target_system_name),
352+
])
353+
354+
# We expect to pick up these libraries from the sysroot.
287355
link_flags.extend([
288356
"-l:libstdc++.a",
289357
])
358+
if stdlib == "stdc++":
359+
cxx_flags.extend([
360+
"-stdlib=libstdc++",
361+
])
362+
elif stdlib.startswith("stdc++-"):
363+
if sysroot_path == None:
364+
fail("Need a sysroot to link against stdc++")
365+
366+
# -stdlib does nothing when using -nostdinc besides produce a warning
367+
# that it's unused, so don't use it here.
368+
libstdcxx_version = stdlib[len("stdc++-"):]
369+
370+
cxx_flags.extend([
371+
"-nostdinc++",
372+
"-isystem",
373+
sysroot_path + "/usr/include/c++/" + libstdcxx_version,
374+
"-isystem",
375+
sysroot_path + "/usr/include/" + multiarch + "/c++/" + libstdcxx_version,
376+
"-isystem",
377+
sysroot_path + "/usr/include/c++/" + libstdcxx_version + "/backward",
378+
])
379+
380+
# Clang really wants C system header includes after C++ ones.
381+
compile_flags_post_language.extend([
382+
"-nostdinc",
383+
"-isystem",
384+
target_toolchain_path_prefix + "lib/clang/{}/include".format(resource_dir_version),
385+
])
386+
387+
link_flags.extend([
388+
"-L" + sysroot_path + "/usr/lib/gcc/" + multiarch + "/" + libstdcxx_version,
389+
])
390+
else:
391+
fail("Invalid stdlib: " + stdlib)
290392
elif stdlib == "libc":
291-
cxx_flags = [
292-
"-std=" + cxx_standard,
293-
]
393+
pass
294394
elif stdlib == "none":
295395
cxx_flags = [
296396
"-nostdlib",
@@ -343,27 +443,46 @@ def cc_toolchain_config(
343443

344444
# Replace flags with any user-provided overrides.
345445
if compiler_configuration["compile_flags"] != None:
346-
compile_flags = _fmt_flags(compiler_configuration["compile_flags"], toolchain_path_prefix)
446+
compile_flags.extend(_fmt_flags(compiler_configuration["compile_flags"], toolchain_path_prefix))
347447
if compiler_configuration["cxx_flags"] != None:
348-
cxx_flags = _fmt_flags(compiler_configuration["cxx_flags"], toolchain_path_prefix)
448+
cxx_flags.extend(_fmt_flags(compiler_configuration["cxx_flags"], toolchain_path_prefix))
349449
if compiler_configuration["link_flags"] != None:
350-
link_flags = _fmt_flags(compiler_configuration["link_flags"], toolchain_path_prefix)
450+
link_flags.extend(_fmt_flags(compiler_configuration["link_flags"], toolchain_path_prefix))
351451
if compiler_configuration["archive_flags"] != None:
352-
archive_flags = _fmt_flags(compiler_configuration["archive_flags"], toolchain_path_prefix)
452+
archive_flags.extend(_fmt_flags(compiler_configuration["archive_flags"], toolchain_path_prefix))
353453
if compiler_configuration["link_libs"] != None:
354-
link_libs = _fmt_flags(compiler_configuration["link_libs"], toolchain_path_prefix)
454+
link_libs.extend(_fmt_flags(compiler_configuration["link_libs"], toolchain_path_prefix))
355455
if compiler_configuration["opt_compile_flags"] != None:
356-
opt_compile_flags = _fmt_flags(compiler_configuration["opt_compile_flags"], toolchain_path_prefix)
456+
opt_compile_flags.extend(_fmt_flags(compiler_configuration["opt_compile_flags"], toolchain_path_prefix))
357457
if compiler_configuration["opt_link_flags"] != None:
358-
opt_link_flags = _fmt_flags(compiler_configuration["opt_link_flags"], toolchain_path_prefix)
458+
opt_link_flags.extend(_fmt_flags(compiler_configuration["opt_link_flags"], toolchain_path_prefix))
359459
if compiler_configuration["dbg_compile_flags"] != None:
360-
dbg_compile_flags = _fmt_flags(compiler_configuration["dbg_compile_flags"], toolchain_path_prefix)
460+
dbg_compile_flags.extend(_fmt_flags(compiler_configuration["dbg_compile_flags"], toolchain_path_prefix))
361461
if compiler_configuration["coverage_compile_flags"] != None:
362-
coverage_compile_flags = _fmt_flags(compiler_configuration["coverage_compile_flags"], toolchain_path_prefix)
462+
coverage_compile_flags.extend(_fmt_flags(compiler_configuration["coverage_compile_flags"], toolchain_path_prefix))
363463
if compiler_configuration["coverage_link_flags"] != None:
364-
coverage_link_flags = _fmt_flags(compiler_configuration["coverage_link_flags"], toolchain_path_prefix)
464+
coverage_link_flags.extend(_fmt_flags(compiler_configuration["coverage_link_flags"], toolchain_path_prefix))
365465
if compiler_configuration["unfiltered_compile_flags"] != None:
366-
unfiltered_compile_flags = _fmt_flags(compiler_configuration["unfiltered_compile_flags"], toolchain_path_prefix)
466+
unfiltered_compile_flags.extend(_fmt_flags(compiler_configuration["unfiltered_compile_flags"], toolchain_path_prefix))
467+
468+
# TODO(AustinSchuh): Add msan support and make this conditional.
469+
cxx_flags = non_msan_compile_flags + cxx_flags
470+
471+
# Add the sysroot flags here, as we want to check these last
472+
if sysroot_path != None:
473+
external_include_paths = [
474+
sysroot_path + "usr/local/include",
475+
]
476+
if multiarch != None:
477+
external_include_paths.extend([
478+
sysroot_path + "usr/" + multiarch + "/include",
479+
sysroot_path + "usr/include/" + multiarch,
480+
])
481+
482+
external_include_paths.extend([
483+
sysroot_path + "usr/include",
484+
sysroot_path + "include",
485+
])
367486

368487
# Source: https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/unix_cc_toolchain_config.bzl
369488
unix_cc_toolchain_config(
@@ -383,8 +502,10 @@ def cc_toolchain_config(
383502
opt_compile_flags = opt_compile_flags,
384503
conly_flags = conly_flags,
385504
cxx_flags = cxx_flags,
505+
compile_flags_post_language = compile_flags_post_language,
386506
link_flags = link_flags + select({str(Label("@toolchains_llvm//toolchain/config:use_libunwind")): libunwind_link_flags, "//conditions:default": []}) +
387-
select({str(Label("@toolchains_llvm//toolchain/config:use_compiler_rt")): compiler_rt_link_flags, "//conditions:default": []}),
507+
select({str(Label("@toolchains_llvm//toolchain/config:use_compiler_rt")): compiler_rt_link_flags, "//conditions:default": []}) +
508+
non_msan_link_flags,
388509
archive_flags = archive_flags,
389510
link_libs = link_libs,
390511
opt_link_flags = opt_link_flags,

0 commit comments

Comments
 (0)