From 4291cb69234ffb0ca38aa44e4fafd82fd758ef07 Mon Sep 17 00:00:00 2001 From: Austin Schuh Date: Mon, 13 Jan 2025 22:32:29 -0800 Subject: [PATCH] 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. --- toolchain/BUILD.llvm_repo | 5 +- toolchain/cc_toolchain_config.bzl | 191 ++++++++++++++++++++++++------ toolchain/internal/configure.bzl | 84 +++++++++---- toolchain/internal/repo.bzl | 15 ++- toolchain/rules.bzl | 8 +- 5 files changed, 245 insertions(+), 58 deletions(-) diff --git a/toolchain/BUILD.llvm_repo b/toolchain/BUILD.llvm_repo index f2bbc76e..fd1ed71e 100644 --- a/toolchain/BUILD.llvm_repo +++ b/toolchain/BUILD.llvm_repo @@ -48,7 +48,7 @@ filegroup( filegroup( name = "include", srcs = glob([ - "include/**/c++/**", + "include/**", "lib/clang/*/include/**", ]), ) @@ -70,8 +70,11 @@ filegroup( name = "lib", srcs = glob( [ + "lib/lib*.a", "lib/**/lib*.a", + "lib/**/lib*.a.syms", "lib/clang/*/lib/**/*.a", + "lib/clang/*/lib/**/*.a.syms", "lib/clang/*/lib/**/*.dylib", # clang_rt.*.o supply crtbegin and crtend sections. "lib/**/clang_rt.*.o", diff --git a/toolchain/cc_toolchain_config.bzl b/toolchain/cc_toolchain_config.bzl index 6349a979..75544000 100644 --- a/toolchain/cc_toolchain_config.bzl +++ b/toolchain/cc_toolchain_config.bzl @@ -37,11 +37,12 @@ def cc_toolchain_config( target_os, target_system_name, toolchain_path_prefix, + target_toolchain_path_prefix, tools_path_prefix, wrapper_bin_prefix, compiler_configuration, cxx_builtin_include_directories, - major_llvm_version): + llvm_version): exec_os_arch_key = _os_arch_pair(exec_os, exec_arch) target_os_arch_key = _os_arch_pair(target_os, target_arch) _check_os_arch_keys([exec_os_arch_key, target_os_arch_key]) @@ -56,6 +57,7 @@ def cc_toolchain_config( compiler, abi_version, abi_libc_version, + multiarch, ) = { "darwin-x86_64": ( "clang-x86_64-darwin", @@ -64,6 +66,7 @@ def cc_toolchain_config( "clang", "darwin_x86_64", "darwin_x86_64", + None, ), "darwin-aarch64": ( "clang-aarch64-darwin", @@ -72,6 +75,7 @@ def cc_toolchain_config( "clang", "darwin_aarch64", "darwin_aarch64", + None, ), "linux-aarch64": ( "clang-aarch64-linux", @@ -80,6 +84,7 @@ def cc_toolchain_config( "clang", "clang", "glibc_unknown", + "aarch64-linux-gnu", ), "linux-x86_64": ( "clang-x86_64-linux", @@ -88,6 +93,7 @@ def cc_toolchain_config( "clang", "clang", "glibc_unknown", + "x86_64-linux-gnu", ), "wasm32": ( "clang-wasm32", @@ -96,6 +102,7 @@ def cc_toolchain_config( "clang", "unknown", "unknown", + None, ), "wasm64": ( "clang-wasm64", @@ -104,6 +111,7 @@ def cc_toolchain_config( "clang", "unknown", "unknown", + None, ), }[target_os_arch_key] @@ -120,12 +128,30 @@ def cc_toolchain_config( "-D__TIME__=\"redacted\"", "-fdebug-prefix-map={}=__bazel_toolchain_llvm_repo__/".format(toolchain_path_prefix), ] + if target_toolchain_path_prefix != toolchain_path_prefix: + unfiltered_compile_flags.extend([ + "-fdebug-prefix-map={}=__bazel_toolchain_llvm_repo__/".format(target_toolchain_path_prefix), + ]) is_xcompile = not (exec_os == target_os and exec_arch == target_arch) - # Default compiler flags: - compile_flags = [ + major_llvm_version = int(llvm_version.split(".")[0]) + + external_include_paths = None + + resource_dir_version = llvm_version if major_llvm_version < 16 else major_llvm_version + + resource_dir = [ + "-resource-dir", + "{}lib/clang/{}".format(target_toolchain_path_prefix, resource_dir_version), + ] + + target_flags = [ "--target=" + target_system_name, + ] + + # Default compiler flags: + compile_flags = target_flags + [ # Security "-U_FORTIFY_SOURCE", # https://github.com/google/sanitizers/issues/247 "-fstack-protector", @@ -135,12 +161,14 @@ def cc_toolchain_config( "-Wall", "-Wthread-safety", "-Wself-assign", - ] + "-B{}bin/".format(toolchain_path_prefix), + ] + resource_dir dbg_compile_flags = ["-g", "-fstandalone-debug"] opt_compile_flags = [ - "-g0", + # Disable debug info + "-ggdb0", "-O2", "-D_FORTIFY_SOURCE=1", "-DNDEBUG", @@ -148,9 +176,21 @@ def cc_toolchain_config( "-fdata-sections", ] - link_flags = [ - "--target=" + target_system_name, + link_flags = target_flags + [ "-no-canonical-prefixes", + ] + resource_dir + + # Use the standard libc++ location when not using msan + non_msan_compile_flags = [ + "-isystem", + target_toolchain_path_prefix + "include/c++/v1/", + "-isystem", + target_toolchain_path_prefix + "include/" + target_system_name + "/c++/v1/", + ] + + non_msan_link_flags = [ + "-L{}lib".format(target_toolchain_path_prefix), + "-L{}lib/{}".format(target_toolchain_path_prefix, target_system_name), ] stdlib = compiler_configuration["stdlib"] @@ -210,13 +250,30 @@ def cc_toolchain_config( cxx_standard = compiler_configuration["cxx_standard"] conly_flags = compiler_configuration["conly_flags"] sysroot_path = compiler_configuration["sysroot_path"] + + # Flags related to C++ standard. + cxx_flags = [ + "-std=" + cxx_standard, + ] + compile_flags_post_language = [] + + # We only support getting libc++ from the toolchain for now. Is it worth + # supporting libc++ from the sysroot? Or maybe just part of a LLVM distribution + # that's built for the target? + if not stdlib and is_xcompile: + print("WARNING: Using libc++ for host architecture while cross compiling, this is " + + "probably not what you want. Explicitly set standard_libraries to libc++ to silence.") + if stdlib == "builtin-libc++" and is_xcompile: stdlib = "stdc++" if stdlib == "builtin-libc++": - cxx_flags = [ - "-std=" + cxx_standard, + cxx_flags.extend([ "-stdlib=libc++", - ] + ]) + compile_flags_post_language.extend([ + "-isystem", + target_toolchain_path_prefix + "lib/clang/{}/include".format(resource_dir_version), + ]) if major_llvm_version >= 14: # With C++20, Clang defaults to using C++ rather than Clang modules, # which breaks Bazel's `use_module_maps` feature, which is used by @@ -260,37 +317,80 @@ def cc_toolchain_config( ] elif stdlib == "libc++": - cxx_flags = [ - "-std=" + cxx_standard, + cxx_flags.extend([ "-stdlib=libc++", - ] + ]) link_flags.extend([ "-l:c++.a", "-l:c++abi.a", ]) elif stdlib == "dynamic-stdc++": - cxx_flags = [ + cxx_flags.extend([ "-std=" + cxx_standard, "-stdlib=libstdc++", - ] + ]) link_flags.extend([ "-lstdc++", ]) - elif stdlib == "stdc++": - cxx_flags = [ - "-std=" + cxx_standard, - "-stdlib=libstdc++", - ] + elif stdlib.startswith("stdc++"): + if not use_lld: + fail("libstdc++ only supported with lld") + # We use libgcc when using libstdc++ from a sysroot. Most libstdc++ + # builds link to libgcc, which means we need to use libgcc's exception + # handling implementation, not the separate one in compiler-rt. + # Unfortunately, clang sometimes emits code incompatible with libgcc, + # see and + # for + # example. This seems to be a commonly-used configuration with clang + # though, so it's probably good enough for most people. + link_flags.extend([ + "-L{}lib".format(target_toolchain_path_prefix), + "-L{}lib/{}".format(target_toolchain_path_prefix, target_system_name), + ]) + + # We expect to pick up these libraries from the sysroot. link_flags.extend([ "-l:libstdc++.a", ]) + if stdlib == "stdc++": + cxx_flags.extend([ + "-stdlib=libstdc++", + ]) + elif stdlib.startswith("stdc++-"): + if sysroot_path == None: + fail("Need a sysroot to link against stdc++") + + # -stdlib does nothing when using -nostdinc besides produce a warning + # that it's unused, so don't use it here. + libstdcxx_version = stdlib[len("stdc++-"):] + + cxx_flags.extend([ + "-nostdinc++", + "-isystem", + sysroot_path + "/usr/include/c++/" + libstdcxx_version, + "-isystem", + sysroot_path + "/usr/include/" + multiarch + "/c++/" + libstdcxx_version, + "-isystem", + sysroot_path + "/usr/include/c++/" + libstdcxx_version + "/backward", + ]) + + # Clang really wants C system header includes after C++ ones. + compile_flags_post_language.extend([ + "-nostdinc", + "-isystem", + target_toolchain_path_prefix + "lib/clang/{}/include".format(resource_dir_version), + ]) + + link_flags.extend([ + "-L" + sysroot_path + "/usr/lib/gcc/" + multiarch + "/" + libstdcxx_version, + ]) + else: + fail("Invalid stdlib: " + stdlib) elif stdlib == "libc": - cxx_flags = [ - "-std=" + cxx_standard, - ] + pass elif stdlib == "none": cxx_flags = [ "-nostdlib", @@ -343,27 +443,46 @@ def cc_toolchain_config( # Replace flags with any user-provided overrides. if compiler_configuration["compile_flags"] != None: - compile_flags = _fmt_flags(compiler_configuration["compile_flags"], toolchain_path_prefix) + compile_flags.extend(_fmt_flags(compiler_configuration["compile_flags"], toolchain_path_prefix)) if compiler_configuration["cxx_flags"] != None: - cxx_flags = _fmt_flags(compiler_configuration["cxx_flags"], toolchain_path_prefix) + cxx_flags.extend(_fmt_flags(compiler_configuration["cxx_flags"], toolchain_path_prefix)) if compiler_configuration["link_flags"] != None: - link_flags = _fmt_flags(compiler_configuration["link_flags"], toolchain_path_prefix) + link_flags.extend(_fmt_flags(compiler_configuration["link_flags"], toolchain_path_prefix)) if compiler_configuration["archive_flags"] != None: - archive_flags = _fmt_flags(compiler_configuration["archive_flags"], toolchain_path_prefix) + archive_flags.extend(_fmt_flags(compiler_configuration["archive_flags"], toolchain_path_prefix)) if compiler_configuration["link_libs"] != None: - link_libs = _fmt_flags(compiler_configuration["link_libs"], toolchain_path_prefix) + link_libs.extend(_fmt_flags(compiler_configuration["link_libs"], toolchain_path_prefix)) if compiler_configuration["opt_compile_flags"] != None: - opt_compile_flags = _fmt_flags(compiler_configuration["opt_compile_flags"], toolchain_path_prefix) + opt_compile_flags.extend(_fmt_flags(compiler_configuration["opt_compile_flags"], toolchain_path_prefix)) if compiler_configuration["opt_link_flags"] != None: - opt_link_flags = _fmt_flags(compiler_configuration["opt_link_flags"], toolchain_path_prefix) + opt_link_flags.extend(_fmt_flags(compiler_configuration["opt_link_flags"], toolchain_path_prefix)) if compiler_configuration["dbg_compile_flags"] != None: - dbg_compile_flags = _fmt_flags(compiler_configuration["dbg_compile_flags"], toolchain_path_prefix) + dbg_compile_flags.extend(_fmt_flags(compiler_configuration["dbg_compile_flags"], toolchain_path_prefix)) if compiler_configuration["coverage_compile_flags"] != None: - coverage_compile_flags = _fmt_flags(compiler_configuration["coverage_compile_flags"], toolchain_path_prefix) + coverage_compile_flags.extend(_fmt_flags(compiler_configuration["coverage_compile_flags"], toolchain_path_prefix)) if compiler_configuration["coverage_link_flags"] != None: - coverage_link_flags = _fmt_flags(compiler_configuration["coverage_link_flags"], toolchain_path_prefix) + coverage_link_flags.extend(_fmt_flags(compiler_configuration["coverage_link_flags"], toolchain_path_prefix)) if compiler_configuration["unfiltered_compile_flags"] != None: - unfiltered_compile_flags = _fmt_flags(compiler_configuration["unfiltered_compile_flags"], toolchain_path_prefix) + unfiltered_compile_flags.extend(_fmt_flags(compiler_configuration["unfiltered_compile_flags"], toolchain_path_prefix)) + + # TODO(AustinSchuh): Add msan support and make this conditional. + cxx_flags = non_msan_compile_flags + cxx_flags + + # Add the sysroot flags here, as we want to check these last + if sysroot_path != None: + external_include_paths = [ + sysroot_path + "usr/local/include", + ] + if multiarch != None: + external_include_paths.extend([ + sysroot_path + "usr/" + multiarch + "/include", + sysroot_path + "usr/include/" + multiarch, + ]) + + external_include_paths.extend([ + sysroot_path + "usr/include", + sysroot_path + "include", + ]) # Source: https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/unix_cc_toolchain_config.bzl unix_cc_toolchain_config( @@ -383,8 +502,10 @@ def cc_toolchain_config( opt_compile_flags = opt_compile_flags, conly_flags = conly_flags, cxx_flags = cxx_flags, + compile_flags_post_language = compile_flags_post_language, link_flags = link_flags + select({str(Label("@toolchains_llvm//toolchain/config:use_libunwind")): libunwind_link_flags, "//conditions:default": []}) + - select({str(Label("@toolchains_llvm//toolchain/config:use_compiler_rt")): compiler_rt_link_flags, "//conditions:default": []}), + select({str(Label("@toolchains_llvm//toolchain/config:use_compiler_rt")): compiler_rt_link_flags, "//conditions:default": []}) + + non_msan_link_flags, archive_flags = archive_flags, link_libs = link_libs, opt_link_flags = opt_link_flags, diff --git a/toolchain/internal/configure.bzl b/toolchain/internal/configure.bzl index acc5135e..03cd2d3c 100644 --- a/toolchain/internal/configure.bzl +++ b/toolchain/internal/configure.bzl @@ -59,11 +59,17 @@ def _join(path1, path2): else: return path2 +def _is_absolute(path): + return path[0] == "/" and (len(path) == 1 or path[1] != "/") + def llvm_config_impl(rctx): + _check_os_arch_keys(rctx.attr.toolchain_roots) + _check_os_arch_keys(rctx.attr.target_toolchain_roots) _check_os_arch_keys(rctx.attr.sysroot) _check_os_arch_keys(rctx.attr.cxx_builtin_include_directories) _check_os_arch_keys(rctx.attr.extra_exec_compatible_with) _check_os_arch_keys(rctx.attr.extra_target_compatible_with) + _check_os_arch_keys(rctx.attr.stdlib) os = _os(rctx) if os == "windows": @@ -86,6 +92,25 @@ def llvm_config_impl(rctx): use_absolute_paths_llvm = rctx.attr.absolute_paths use_absolute_paths_sysroot = use_absolute_paths_llvm + # Make sure the toolchain root and target toolchain roots either are both absolute or both not. + for target_toolchain_root in rctx.attr.target_toolchain_roots.values(): + if _is_absolute(toolchain_root) != _is_absolute(target_toolchain_root): + fail("Host and target toolchain roots must both be absolute or not") + + # Compute the repo paths for each of the target toolchains. + target_llvm_repo_paths = {} + toolchain_path_prefix = None + if use_absolute_paths_llvm: + llvm_repo_label = Label(toolchain_root + ":BUILD.bazel") # Exact target does not matter. + toolchain_path_prefix = _canonical_dir_path(str(rctx.path(llvm_repo_label).dirname)) + for a_key in rctx.attr.target_toolchain_roots: + target_llvm_repo_label = Label(rctx.attr.target_toolchain_roots[a_key] + ":BUILD.bazel") + target_llvm_repo_paths[a_key] = _canonical_dir_path(str(rctx.path(target_llvm_repo_label).dirname)) + else: + for a_key in rctx.attr.target_toolchain_roots: + target_llvm_repo_label = Label(rctx.attr.target_toolchain_roots[a_key] + ":BUILD.bazel") + target_llvm_repo_paths[a_key] = _pkg_path_from_label(target_llvm_repo_label) + # Check if the toolchain root is a system path. system_llvm = False if _is_absolute_path(toolchain_root): @@ -169,6 +194,10 @@ def llvm_config_impl(rctx): dbg_compile_flags_dict = rctx.attr.dbg_compile_flags, coverage_compile_flags_dict = rctx.attr.coverage_compile_flags, coverage_link_flags_dict = rctx.attr.coverage_link_flags, + target_toolchain_path_prefixes_dict = target_llvm_repo_paths, + target_toolchain_roots_dict = rctx.attr.target_toolchain_roots, + toolchain_path_prefix = toolchain_path_prefix, + toolchain_root = toolchain_root, unfiltered_compile_flags_dict = rctx.attr.unfiltered_compile_flags, llvm_version = llvm_version, extra_compiler_files = rctx.attr.extra_compiler_files, @@ -325,20 +354,29 @@ def _cc_toolchain_str( "wasm32": "wasm32-unknown-unknown", "wasm64": "wasm64-unknown-unknown", }[target_pair] + + target_toolchain_root = toolchain_info.toolchain_root + if target_pair in toolchain_info.target_toolchain_roots_dict: + target_toolchain_root = toolchain_info.target_toolchain_roots_dict[target_pair] + elif "" in toolchain_info.target_toolchain_roots_dict: + target_toolchain_root = toolchain_info.target_toolchain_roots_dict[""] + target_toolchain_path_prefix = toolchain_info.toolchain_path_prefix + if target_pair in toolchain_info.target_toolchain_path_prefixes_dict: + target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[target_pair] + elif "" in toolchain_info.target_toolchain_roots_dict: + target_toolchain_path_prefix = toolchain_info.target_toolchain_path_prefixes_dict[""] + + # C++ built-in include directories: + resource_dir_version = llvm_version if major_llvm_version < 16 else major_llvm_version cxx_builtin_include_directories = [ - toolchain_path_prefix + "include/c++/v1", - toolchain_path_prefix + "include/{}/c++/v1".format(target_system_name), - toolchain_path_prefix + "lib/clang/{}/include".format(llvm_version), - toolchain_path_prefix + "lib/clang/{}/share".format(llvm_version), - toolchain_path_prefix + "lib64/clang/{}/include".format(llvm_version), - toolchain_path_prefix + "lib/clang/{}/include".format(major_llvm_version), - toolchain_path_prefix + "lib/clang/{}/share".format(major_llvm_version), - toolchain_path_prefix + "lib64/clang/{}/include".format(major_llvm_version), + target_toolchain_path_prefix + "include/c++/v1", + target_toolchain_path_prefix + "include/{}/c++/v1".format(target_system_name), + target_toolchain_path_prefix + "lib/clang/{}/include".format(resource_dir_version), + target_toolchain_path_prefix + "lib/clang/{}/share".format(resource_dir_version), + target_toolchain_path_prefix + "lib64/clang/{}/include".format(resource_dir_version), ] - sysroot_prefix = "" - if sysroot_path: - sysroot_prefix = "%sysroot%" + sysroot_prefix = "%sysroot%" if sysroot_path else "" if target_os == "linux": cxx_builtin_include_directories.extend([ _join(sysroot_prefix, "/include"), @@ -371,6 +409,7 @@ cc_toolchain_config( target_os = "{target_os}", target_system_name = "{target_system_name}", toolchain_path_prefix = "{llvm_dist_path_prefix}", + target_toolchain_path_prefix = "{target_toolchain_path_prefix}", tools_path_prefix = "{tools_path_prefix}", wrapper_bin_prefix = "{wrapper_bin_prefix}", compiler_configuration = {{ @@ -391,7 +430,7 @@ cc_toolchain_config( "unfiltered_compile_flags": {unfiltered_compile_flags}, }}, cxx_builtin_include_directories = {cxx_builtin_include_directories}, - major_llvm_version = {major_llvm_version}, + llvm_version = "{llvm_version}", ) toolchain( @@ -454,8 +493,8 @@ filegroup(name = "strip-files-{suffix}", srcs = [{extra_files_str}]) filegroup( name = "compiler-components-{suffix}", srcs = [ - "{llvm_dist_label_prefix}clang", - "{llvm_dist_label_prefix}include", + "{toolchain_root}:clang", + "{target_toolchain_root}:include", ":sysroot-components-{suffix}", {extra_compiler_files} ], @@ -464,18 +503,18 @@ filegroup( filegroup( name = "linker-components-{suffix}", srcs = [ - "{llvm_dist_label_prefix}clang", - "{llvm_dist_label_prefix}ld", - "{llvm_dist_label_prefix}ar", - "{llvm_dist_label_prefix}lib", ":sysroot-components-{suffix}", + "{toolchain_root}:clang", + "{toolchain_root}:ld", + "{toolchain_root}:ar", + "{target_toolchain_root}:lib", ], ) filegroup( name = "all-components-{suffix}", srcs = [ - "{llvm_dist_label_prefix}bin", + "{toolchain_root}:bin", ":compiler-components-{suffix}", ":linker-components-{suffix}", ], @@ -544,6 +583,9 @@ cc_toolchain( exec_os_bzl = exec_os_bzl, llvm_dist_label_prefix = toolchain_info.llvm_dist_label_prefix, llvm_dist_path_prefix = toolchain_info.llvm_dist_path_prefix, + toolchain_root = toolchain_info.toolchain_root, + target_toolchain_root = target_toolchain_root, + target_toolchain_path_prefix = target_toolchain_path_prefix, tools_path_prefix = toolchain_info.tools_path_prefix, wrapper_bin_prefix = toolchain_info.wrapper_bin_prefix, sysroot_label_str = sysroot_label_str, @@ -565,7 +607,7 @@ cc_toolchain( extra_files_str = extra_files_str, cxx_builtin_include_directories = _list_to_string(filtered_cxx_builtin_include_directories), extra_compiler_files = ("\"%s\"," % str(toolchain_info.extra_compiler_files)) if toolchain_info.extra_compiler_files else "", - major_llvm_version = major_llvm_version, + llvm_version = llvm_version, extra_exec_compatible_with_specific = toolchain_info.extra_exec_compatible_with.get(target_pair, []), extra_target_compatible_with_specific = toolchain_info.extra_target_compatible_with.get(target_pair, []), extra_exec_compatible_with_all_targets = toolchain_info.extra_exec_compatible_with.get("", []), @@ -576,6 +618,8 @@ def _is_remote(rctx, exec_os, exec_arch): return not (_os_from_rctx(rctx) == exec_os and _arch_from_rctx(rctx) == exec_arch) def _convenience_targets_str(rctx, use_absolute_paths, llvm_dist_rel_path, llvm_dist_label_prefix, exec_dl_ext): + # TODO: This doesn't really deal with cross compilation very well. There can be multiple + # targets for 1 toolchain, and the target platform matters, not the exec platform. if use_absolute_paths: llvm_dist_label_prefix = ":" filenames = [] diff --git a/toolchain/internal/repo.bzl b/toolchain/internal/repo.bzl index 0f17cb56..30a94ed1 100644 --- a/toolchain/internal/repo.bzl +++ b/toolchain/internal/repo.bzl @@ -265,7 +265,7 @@ llvm_config_attrs = dict(common_attrs) llvm_config_attrs.update(_compiler_configuration_attrs) llvm_config_attrs.update({ "toolchain_roots": attr.string_dict( - mandatory = False, + mandatory = True, # TODO: Ideally, we should be taking a filegroup label here instead of a package path, but # we ultimately need to subset the files to be more selective in what we include in the # sandbox for which operations, and it is not straightforward to subset a filegroup. @@ -279,6 +279,19 @@ llvm_config_attrs.update({ "paths. Else, the value will be assumed to be a bazel package containing the " + "filegroup targets as in BUILD.llvm_repo."), ), + "target_toolchain_roots": attr.string_dict( + mandatory = True, + # TODO: Ideally, we should be taking a filegroup label here instead of a package path, but + # we ultimately need to subset the files to be more selective in what we include in the + # sandbox for which operations, and it is not straightforward to subset a filegroup. + doc = ("System or package path, keyed by target OS release name and architecture, e.g. " + + "darwin-x86_64, darwin-aarch64, ubuntu-20.04-x86_64, etc., or a less specific " + + "OS and arch pair ({}), to be used as the LLVM toolchain ".format(_target_pairs) + + "distributions. If the value begins with exactly one forward slash '/', then " + + "the value is assumed to be a system path and the toolchain is configured to use " + + "absolute paths. Else, the value will be assumed to be a bazel package " + + "containing the filegroup targets as in BUILD.llvm_repo."), + ), "absolute_paths": attr.bool( default = False, doc = "Use absolute paths in the toolchain. Avoids sandbox overhead.", diff --git a/toolchain/rules.bzl b/toolchain/rules.bzl index 237d965f..5008b0ec 100644 --- a/toolchain/rules.bzl +++ b/toolchain/rules.bzl @@ -47,11 +47,17 @@ def llvm_toolchain(name, **kwargs): for k, v in kwargs.items() if (k not in _llvm_config_attrs.keys()) or (k in _common_attrs.keys()) } - llvm(name = name + "_llvm", **llvm_args) + llvm_name = name + "_llvm" + llvm(name = llvm_name, **llvm_args) + toolchain_roots = {"": "@" + llvm_name + "//"} + kwargs["toolchain_roots"] = toolchain_roots if not kwargs.get("llvm_versions"): kwargs.update(llvm_versions = {"": kwargs.get("llvm_version")}) + if not kwargs.get("target_toolchain_roots"): + kwargs["target_toolchain_roots"] = kwargs["toolchain_roots"] + toolchain_args = { k: v for k, v in kwargs.items()