Skip to content

Commit 66f870a

Browse files
committed
toolchain: Add cxx_lib attribute to inject libc++ in x-compile
Signed-off-by: Ryan Northey <ryan@synca.io>
1 parent 7914ad1 commit 66f870a

File tree

3 files changed

+97
-5
lines changed

3 files changed

+97
-5
lines changed

toolchain/extensions/llvm.bzl

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,30 @@ def _llvm_impl_(module_ctx):
7373
name,
7474
)
7575

76+
cxx_lib = {}
77+
for cl in mod.tags.cxx_lib:
78+
if cl.name != name:
79+
continue
80+
for target in cl.targets:
81+
if cxx_lib.get(target):
82+
fail("duplicate target '%s' for cxx_lib with name '%s'" % (target, name))
83+
cxx_lib[target] = str(cl.label)
84+
attrs["cxx_lib"] = cxx_lib
85+
7686
llvm_toolchain(
7787
**attrs
7888
)
7989

80-
# Check that every defined toolchain_root or sysroot has a corresponding toolchain.
90+
# Check that every defined toolchain_root, sysroot, or cxx_lib has a corresponding toolchain.
8191
for root in mod.tags.toolchain_root:
8292
if root.name not in toolchain_names:
8393
fail("toolchain_root '%s' does not have a corresponding toolchain" % root.name)
8494
for root in mod.tags.sysroot:
8595
if root.name not in toolchain_names:
8696
fail("sysroot '%s' does not have a corresponding toolchain" % root.name)
97+
for cl in mod.tags.cxx_lib:
98+
if cl.name not in toolchain_names:
99+
fail("cxx_lib '%s' does not have a corresponding toolchain" % cl.name)
87100

88101
if bazel_features.external_deps.extension_metadata_has_reproducible:
89102
return module_ctx.extension_metadata(reproducible = True)
@@ -100,6 +113,7 @@ _attrs.update(_llvm_repo_attrs)
100113

101114
_attrs.pop("toolchain_roots", None)
102115
_attrs.pop("sysroot", None)
116+
_attrs.pop("cxx_lib", None)
103117

104118
llvm = module_extension(
105119
implementation = _llvm_impl_,
@@ -137,5 +151,12 @@ llvm = module_extension(
137151
"constraints": attr.label_list(doc = "List of extra constraints to add to target_compatible_with for the generated toolchains."),
138152
},
139153
),
154+
"cxx_lib": tag_class(
155+
attrs = {
156+
"name": attr.string(doc = "Name of the toolchain this cxx_lib applies to; must match a toolchain tag name.", default = "llvm_toolchain"),
157+
"targets": attr.string_list(doc = "Target pairs, e.g. linux-aarch64, linux-x86_64."),
158+
"label": attr.label(doc = "Label of a repo containing include/ and lib/ for the C++ standard library."),
159+
},
160+
),
140161
},
141162
)

toolchain/internal/configure.bzl

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,57 @@ def llvm_config_impl(rctx):
150150
use_absolute_paths_sysroot,
151151
)
152152

153+
# Resolve cross-compile C++ standard library paths.
154+
cxx_lib_include_dirs = {}
155+
cxx_lib_link_flags = {}
156+
cxx_lib_cxx_flags = {}
157+
for target_pair, cxx_lib_label_str in rctx.attr.cxx_lib.items():
158+
cxx_lib_label = Label(cxx_lib_label_str)
159+
cxx_lib_path = _pkg_path_from_label(cxx_lib_label)
160+
cxx_lib_rel_path = _canonical_dir_path("../../" + cxx_lib_path)
161+
162+
# Symlink the cxx_lib include/ and lib/ into the config repo
163+
# so they are accessible without ../ paths.
164+
local_include = "libcxx_libs_{}/include".format(target_pair.split("-")[1])
165+
local_lib = "libcxx_libs_{}/lib".format(target_pair.split("-")[1])
166+
rctx.symlink(cxx_lib_rel_path + "include", local_include)
167+
rctx.symlink(cxx_lib_rel_path + "lib", local_lib)
168+
cxx_lib_include_dirs[target_pair] = [
169+
"%workspace%/" + cxx_lib_path + "/include",
170+
]
171+
cxx_lib_link_flags[target_pair] = [
172+
"-L" + cxx_lib_path + "/lib",
173+
]
174+
cxx_lib_cxx_flags[target_pair] = [
175+
"-nostdinc++",
176+
"-isystem",
177+
llvm_dist_path_prefix + "include/c++/v1",
178+
"-isystem",
179+
cxx_lib_path + "/include",
180+
]
181+
182+
# Merge cxx_lib paths into include dirs, link flags, and cxx flags.
183+
merged_include_dirs = dict(rctx.attr.cxx_builtin_include_directories)
184+
for k, v in cxx_lib_include_dirs.items():
185+
merged_include_dirs[k] = merged_include_dirs.get(k, []) + v
186+
187+
merged_extra_link_flags = dict(rctx.attr.extra_link_flags)
188+
for k, v in cxx_lib_link_flags.items():
189+
merged_extra_link_flags[k] = merged_extra_link_flags.get(k, []) + v
190+
191+
merged_extra_cxx_flags = dict(rctx.attr.extra_cxx_flags)
192+
for k, v in cxx_lib_cxx_flags.items():
193+
merged_extra_cxx_flags[k] = merged_extra_cxx_flags.get(k, []) + v
194+
195+
# Auto-set stdlib to "libc++" for target pairs that have cxx_lib configured
196+
# but no explicit stdlib override. This prevents the builtin-libc++ ->
197+
# stdc++ cross-compile fallback in cc_toolchain_config.bzl from kicking in,
198+
# since the user has provided the actual libc++ libraries via cxx_lib.
199+
merged_stdlib = dict(rctx.attr.stdlib)
200+
for target_pair in rctx.attr.cxx_lib.keys():
201+
if target_pair not in merged_stdlib:
202+
merged_stdlib[target_pair] = "libc++"
203+
153204
workspace_name = rctx.name
154205
toolchain_info = struct(
155206
os = os,
@@ -161,8 +212,8 @@ def llvm_config_impl(rctx):
161212
sysroot_paths_dict = sysroot_paths_dict,
162213
sysroot_labels_dict = sysroot_labels_dict,
163214
target_settings_dict = rctx.attr.target_settings,
164-
additional_include_dirs_dict = rctx.attr.cxx_builtin_include_directories,
165-
stdlib_dict = rctx.attr.stdlib,
215+
additional_include_dirs_dict = merged_include_dirs,
216+
stdlib_dict = merged_stdlib,
166217
cxx_standard_dict = rctx.attr.cxx_standard,
167218
compile_flags_dict = rctx.attr.compile_flags,
168219
conly_flags_dict = rctx.attr.conly_flags,
@@ -178,12 +229,13 @@ def llvm_config_impl(rctx):
178229
coverage_link_flags_dict = rctx.attr.coverage_link_flags,
179230
unfiltered_compile_flags_dict = rctx.attr.unfiltered_compile_flags,
180231
llvm_version = llvm_version,
232+
cxx_lib_dict = rctx.attr.cxx_lib,
181233
extra_compiler_files = rctx.attr.extra_compiler_files,
182234
extra_exec_compatible_with = rctx.attr.extra_exec_compatible_with,
183235
extra_target_compatible_with = rctx.attr.extra_target_compatible_with,
184236
extra_compile_flags_dict = rctx.attr.extra_compile_flags,
185-
extra_cxx_flags_dict = rctx.attr.extra_cxx_flags,
186-
extra_link_flags_dict = rctx.attr.extra_link_flags,
237+
extra_cxx_flags_dict = merged_extra_cxx_flags,
238+
extra_link_flags_dict = merged_extra_link_flags,
187239
extra_archive_flags_dict = rctx.attr.extra_archive_flags,
188240
extra_link_libs_dict = rctx.attr.extra_link_libs,
189241
extra_opt_compile_flags_dict = rctx.attr.extra_opt_compile_flags,
@@ -359,6 +411,12 @@ def _cc_toolchain_str(
359411
"wasip1-wasm64": "wasm64-wasip1",
360412
}[target_pair]
361413

414+
cxx_lib_label = toolchain_info.cxx_lib_dict.get(target_pair)
415+
if cxx_lib_label:
416+
cxx_lib_label_str = "\"%s\"," % cxx_lib_label
417+
else:
418+
cxx_lib_label_str = ""
419+
362420
cxx_builtin_include_directories = [
363421
toolchain_path_prefix + "include/c++/v1",
364422
toolchain_path_prefix + "lib/clang/{}/include".format(
@@ -482,6 +540,7 @@ filegroup(
482540
name = "compiler-components-{suffix}",
483541
srcs = [
484542
":sysroot-components-{suffix}",
543+
{cxx_lib_label_str}
485544
{extra_compiler_files}
486545
],
487546
)
@@ -522,6 +581,7 @@ filegroup(
522581
":sysroot-components-{suffix}",
523582
"{llvm_dist_label_prefix}extra_config_site",
524583
"{llvm_dist_label_prefix}clang",
584+
{cxx_lib_label_str}
525585
{extra_compiler_files}
526586
],
527587
)
@@ -534,6 +594,7 @@ filegroup(
534594
"{llvm_dist_label_prefix}ar",
535595
"{llvm_dist_label_prefix}{lib_label}",
536596
":sysroot-components-{suffix}",
597+
{cxx_lib_label_str}
537598
],
538599
)
539600
@@ -608,6 +669,7 @@ cc_toolchain(
608669
sysroot_label_str = sysroot_label_str,
609670
sysroot_path = sysroot_path,
610671
stdlib = _dict_value(toolchain_info.stdlib_dict, target_pair, "builtin-libc++"),
672+
cxx_lib_label_str = cxx_lib_label_str,
611673
cxx_standard = _dict_value(toolchain_info.cxx_standard_dict, target_pair, "c++17"),
612674
compile_flags = _list_to_string(_dict_value(toolchain_info.compile_flags_dict, target_pair)),
613675
conly_flags = _list_to_string(toolchain_info.conly_flags_dict.get(target_pair, [])),

toolchain/internal/repo.bzl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,15 @@ _compiler_configuration_attrs = {
141141
"containing the files and the sysroot path will be taken as the path to the " +
142142
"package of this label."),
143143
),
144+
"cxx_lib": attr.string_dict(
145+
mandatory = False,
146+
doc = ("Cross-compile C++ standard library paths, keyed by target pair " +
147+
"({}). ".format(_target_pairs) +
148+
"Value is a label pointing to a repo containing prebuilt C++ standard " +
149+
"library headers in include/ and libraries in lib/. The include/ directory " +
150+
"will be added to cxx_builtin_include_directories and lib/ will be added to " +
151+
"the linker search path via extra_link_flags for the specified target."),
152+
),
144153
"cxx_builtin_include_directories": attr.string_list_dict(
145154
mandatory = False,
146155
doc = ("Additional builtin include directories to be added to the default system " +

0 commit comments

Comments
 (0)