diff --git a/MODULE.bazel b/MODULE.bazel index 8c2d556a5..63b4bc463 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -20,7 +20,7 @@ module( ) bazel_dep(name = "bazel_skylib", version = "1.5.0") -bazel_dep(name = "rules_cc", version = "0.0.17") +bazel_dep(name = "rules_cc", version = "0.1.1") bazel_dep(name = "platforms", version = "0.0.8") # TODO: Remove when protobuf is released with a version of rules_python that supports 8.x diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 1c953b212..abf3cdae9 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -22,6 +22,11 @@ cc_library( hdrs = ["stdlib.h"], ) +cc_binary( + name = "hello", + srcs = ["main.c"] +) + # We want to emulate the behavior of cc_binary but be able to run the target as # a test, so we use a cc_test target with linkstatic. cc_test( diff --git a/tests/MODULE.bazel b/tests/MODULE.bazel index 40fea7a4e..dc2d0a6d9 100644 --- a/tests/MODULE.bazel +++ b/tests/MODULE.bazel @@ -22,7 +22,11 @@ local_path_override( bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "platforms", version = "0.0.11") -bazel_dep(name = "rules_cc", version = "0.0.9") +bazel_dep(name = "rules_cc", version = "0.1.1") +local_path_override( + module_name = "rules_cc", + path = "../../rules_cc" +) bazel_dep(name = "rules_go", version = "0.50.1", repo_name = "io_bazel_rules_go") bazel_dep(name = "rules_rust", version = "0.54.1") bazel_dep(name = "rules_foreign_cc", version = "0.13.0") diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..fd0391f17 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,4 @@ +main: + gcc main.c -lmagic -o main \ + -L $(shell brew --prefix)/lib -I $(shell brew --prefix)/include + \ No newline at end of file diff --git a/tests/main b/tests/main new file mode 100755 index 000000000..30940d28c Binary files /dev/null and b/tests/main differ diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 000000000..1e5c34124 --- /dev/null +++ b/tests/main.c @@ -0,0 +1,40 @@ +#include +#include +#include + +int main(int argc, char *argv[]) { + // Check if filename is provided + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + // Initialize magic handle + magic_t magic = magic_open(MAGIC_MIME_TYPE); + if (magic == NULL) { + fprintf(stderr, "Failed to initialize libmagic\n"); + return 1; + } + + // Load magic database + if (magic_load(magic, NULL) != 0) { + fprintf(stderr, "Cannot load magic database: %s\n", magic_error(magic)); + magic_close(magic); + return 1; + } + + // Get MIME type + const char *mime_type = magic_file(magic, argv[1]); + if (mime_type == NULL) { + fprintf(stderr, "Error determining MIME type: %s\n", magic_error(magic)); + magic_close(magic); + return 1; + } + + // Print result + printf("MIME type: %s\n", mime_type); + + // Cleanup + magic_close(magic); + return 0; +} \ No newline at end of file diff --git a/toolchain/BUILD.llvm_repo b/toolchain/BUILD.llvm_repo index f2bbc76e0..cdb3aa11d 100644 --- a/toolchain/BUILD.llvm_repo +++ b/toolchain/BUILD.llvm_repo @@ -14,6 +14,54 @@ package(default_visibility = ["//visibility:public"]) +load("@bazel_skylib//rules/directory:directory.bzl", "directory") +load("@bazel_skylib//rules/directory:subdirectory.bzl", "subdirectory") + +# Directory-based rules in this toolchain only referece things in +# lib/ or include/ subdirectories. +directory( + name = "toolchain_root", + srcs = glob([ + "lib/**", + "lib64/**", + "include/**", + ], allow_empty = True), +) + +subdirectory( + name = "include-c++-v1", + parent = ":toolchain_root", + path = "include/c++/v1", +) + +# subdirectory( +# name = "include-c++-v1-arch", +# parent = ":toolchain_root", +# # TODO: fix this. +# path = "include/aarch64-apple-macosx/c++/v1", +# visibility = ["//visibility:public"] +# ) + +subdirectory( + name = "lib-clang-include", + parent = ":toolchain_root", + # TODO + # "lib/clang/{llvm_version}/include", + # "lib64/clang/{major_llvm_version}/include", + # "lib64/clang/{llvm_version}/include" + path = "lib/clang/{major_llvm_version}/include", + visibility = ["//visibility:public"] +) + +subdirectory( + name = "lib-clang-share", + parent = ":toolchain_root", + # TODO: + # "lib/clang/{llvm_version}/share" + path = "lib/clang/{major_llvm_version}/share", + visibility = ["//visibility:public"] +) + # Some targets may need to directly depend on these files. exports_files(glob( [ diff --git a/toolchain/BUILD.toolchain.tpl b/toolchain/BUILD.toolchain.tpl index 9a7a75b0b..8b3769077 100644 --- a/toolchain/BUILD.toolchain.tpl +++ b/toolchain/BUILD.toolchain.tpl @@ -15,9 +15,49 @@ package(default_visibility = ["//visibility:public"]) load("@bazel_skylib//rules:native_binary.bzl", "native_binary") -load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") load("@toolchains_llvm//toolchain/internal:system_module_map.bzl", "system_module_map") -load("%{cc_toolchain_config_bzl}", "cc_toolchain_config") +load("@toolchains_llvm//toolchain/internal:host_sysroot_directory.bzl", "host_sysroot_directory") +load("@rules_cc//cc/toolchains:args.bzl", "cc_args") +load("@rules_cc//cc/toolchains:tool.bzl", "cc_tool") +load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map") +load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature") +load("@rules_cc//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint") +load("@rules_cc//cc/toolchains:toolchain.bzl", "cc_toolchain") +load("@rules_cc//cc/toolchains/args:sysroot.bzl", "cc_sysroot") + + +cc_feature_constraint( + name = "constraint_opt", + all_of = ["@rules_cc//cc/toolchains/features:opt"], +) + +cc_feature_constraint( + name = "constraint_dbg", + all_of = ["@rules_cc//cc/toolchains/features:dbg"], +) + +cc_feature_constraint( + name = "constraint_fastbuild", + all_of = ["@rules_cc//cc/toolchains/features:fastbuild"], +) + +# TODO: what's the non-legacy way of this doing this? +cc_feature_constraint( + name = "constraint_unfiltered_compile_flags", + all_of = ["@rules_cc//cc/toolchains/features/legacy:unfiltered_compile_flags"] +) + + +# Do not resolve our symlinked resource prefixes to real paths. +cc_args( + name = "no_absolute_paths_for_builtins", + actions = [ + "@rules_cc//cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:ar_actions", + ], + args = ["-no-canonical-prefixes"], + visibility = ["//visibility:public"], +) # Following filegroup targets are used when not using absolute paths and shared # between different toolchains. diff --git a/toolchain/deps.bzl b/toolchain/deps.bzl index 04903a5a8..6508b83c8 100644 --- a/toolchain/deps.bzl +++ b/toolchain/deps.bzl @@ -19,9 +19,9 @@ def bazel_toolchain_dependencies(): if not native.existing_rule("rules_cc"): http_archive( name = "rules_cc", - urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.17/rules_cc-0.0.17.tar.gz"], - sha256 = "abc605dd850f813bb37004b77db20106a19311a96b2da1c92b789da529d28fe1", - strip_prefix = "rules_cc-0.0.17", + urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.1/rules_cc-0.1.1.tar.gz"], + sha256 = "712d77868b3152dd618c4d64faaddefcc5965f90f5de6e6dd1d5ddcd0be82d42", + strip_prefix = "rules_cc-0.1.1", ) # Load bazel_skylib if the user has not defined them. diff --git a/toolchain/extensions/llvm.bzl b/toolchain/extensions/llvm.bzl index 28148719c..569a71bfb 100644 --- a/toolchain/extensions/llvm.bzl +++ b/toolchain/extensions/llvm.bzl @@ -1,8 +1,10 @@ """LLVM extension for use with bzlmod""" -load("@toolchains_llvm//toolchain:rules.bzl", "llvm_toolchain") +load("//toolchain:toolchain.bzl", _toolchain = "toolchain") +load("//toolchain:llvm.bzl", _llvm = "llvm") load( - "@toolchains_llvm//toolchain/internal:repo.bzl", + "//toolchain/internal:repo.bzl", + _common_attrs = "common_attrs", _llvm_config_attrs = "llvm_config_attrs", _llvm_repo_attrs = "llvm_repo_attrs", ) @@ -72,9 +74,25 @@ def _llvm_impl_(module_ctx): name, ) - llvm_toolchain( - **attrs - ) + if not attrs.get("toolchain_roots"): + llvm_args = { + k: v + for k, v in attrs.items() + if (k not in _llvm_config_attrs.keys()) or (k in _common_attrs.keys()) + } + llvm_args["name"] = name + "_llvm" + _llvm(**llvm_args) + + if not attrs.get("llvm_versions"): + attrs.update(llvm_versions = {"": attrs.get("llvm_version")}) + + toolchain_args = { + k: v + for k, v in attrs.items() + if (k not in _llvm_repo_attrs.keys()) or (k in _common_attrs.keys()) + } + _toolchain(**toolchain_args) + # Check that every defined toolchain_root or sysroot has a corresponding toolchain. for root in mod.tags.toolchain_root: diff --git a/toolchain/internal/configure.bzl b/toolchain/internal/configure.bzl index 1f02e9ffc..9424aa740 100644 --- a/toolchain/internal/configure.bzl +++ b/toolchain/internal/configure.bzl @@ -205,7 +205,6 @@ def llvm_config_impl(rctx): "BUILD.bazel", rctx.attr._build_toolchain_tpl, { - "%{cc_toolchain_config_bzl}": str(rctx.attr._cc_toolchain_config_bzl), "%{cc_toolchains}": cc_toolchains_str, "%{symlinked_tools}": symlinked_tools_str, "%{wrapper_bin_prefix}": wrapper_bin_prefix, @@ -289,6 +288,31 @@ def _cc_toolchain_str( target_pair = _os_arch_pair(target_os, target_arch) + target_system_name = { + "darwin-x86_64": "x86_64-apple-macosx", + "darwin-aarch64": "aarch64-apple-macosx", + "linux-aarch64": "aarch64-unknown-linux-gnu", + "linux-armv7": "armv7-unknown-linux-gnueabihf", + "linux-x86_64": "x86_64-unknown-linux-gnu", + "wasm32": "wasm32-unknown-unknown", + "wasm64": "wasm64-unknown-unknown", + "wasip1-wasm32": "wasm32-wasip1", + "wasip1-wasm64": "wasm64-wasip1", + }[target_pair] + + # C++ built-in include directories. + # This contains both the includes shipped with the compiler as well as the sysroot (or host) + # include directories. While Bazel's default undeclared inclusions check does not seem to be + # triggered by header files under the execroot, we still include those paths here as they are + # visible via the "built_in_include_directories" attribute of CcToolchainInfo as well as to keep + # them in sync with the directories included in the system module map generated for the stricter + # "layering_check" feature. + allowlist_include_directories = [ + toolchain_info.llvm_dist_label_prefix + "include-c++-v1", + # toolchain_info.llvm_dist_label_prefix + "include-c++-v1-arch", + toolchain_info.llvm_dist_label_prefix + "lib-clang-include", + ] + sysroot_path = toolchain_info.sysroot_paths_dict.get(target_pair) sysroot_label = toolchain_info.sysroot_labels_dict.get(target_pair) if sysroot_label: @@ -296,107 +320,306 @@ def _cc_toolchain_str( else: sysroot_label_str = "" + + sysroot_targets = [] + if not sysroot_path: if exec_os == target_os and exec_arch == target_arch: # For darwin -> darwin, we can use the macOS SDK path. sysroot_path = _default_sysroot_path(rctx, exec_os) + sysroot_targets.append(""" +host_sysroot_directory( + name = "host_sysroot_path_{suffix}", + path = "{sysroot_path}" +) + +cc_sysroot( + name = "sysroot-{suffix}", + sysroot = ":host_sysroot_path_{suffix}", + visibility = ["//visibility:public"], +) +""".format(sysroot_path = sysroot_path, suffix = suffix)) + allowlist_include_directories.append(":host_sysroot_path_" + suffix) else: # We are trying to cross-compile without a sysroot, let's bail. # TODO: Are there situations where we can continue? return "" + # sysroot_prefix = "" + # if sysroot_path: + # sysroot_prefix = "%sysroot%" + # if target_os == "linux": + # cxx_builtin_include_directories.extend([ + # _join(sysroot_prefix, "/include"), + # _join(sysroot_prefix, "/usr/include"), + # _join(sysroot_prefix, "/usr/local/include"), + # ]) + # elif target_os == "darwin": + # cxx_builtin_include_directories.extend([ + # _join(sysroot_prefix, "/usr/include"), + # _join(sysroot_prefix, "/System/Library/Frameworks"), + # ]) + # elif target_os == "none" or target_os == "wasip1": + # if sysroot_prefix: + # cxx_builtin_include_directories.extend([ + # _join(sysroot_prefix, "/include"), + # ]) + # else: + # fail("Unreachable") + + # cxx_builtin_include_directories.extend(toolchain_info.additional_include_dirs_dict.get(target_pair, [])) + extra_files_str = "\":internal-use-files\"" - # C++ built-in include directories. - # This contains both the includes shipped with the compiler as well as the sysroot (or host) - # include directories. While Bazel's default undeclared inclusions check does not seem to be - # triggered by header files under the execroot, we still include those paths here as they are - # visible via the "built_in_include_directories" attribute of CcToolchainInfo as well as to keep - # them in sync with the directories included in the system module map generated for the stricter - # "layering_check" feature. - toolchain_path_prefix = "%workspace%/" + toolchain_info.llvm_dist_path_prefix - llvm_version = toolchain_info.llvm_version - major_llvm_version = int(llvm_version.split(".")[0]) - target_system_name = { - "darwin-x86_64": "x86_64-apple-macosx", - "darwin-aarch64": "aarch64-apple-macosx", - "linux-aarch64": "aarch64-unknown-linux-gnu", - "linux-armv7": "armv7-unknown-linux-gnueabihf", - "linux-x86_64": "x86_64-unknown-linux-gnu", - "wasm32": "wasm32-unknown-unknown", - "wasm64": "wasm64-unknown-unknown", - "wasip1-wasm32": "wasm32-wasip1", - "wasip1-wasm64": "wasm64-wasip1", - }[target_pair] - 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), + template = """ +# CC toolchain for cc-clang-{suffix}. + + +# TOOLS:START +COMMON_TOOLS_{suffix_var_safe} = {{ + "@rules_cc//cc/toolchains/actions:c_compile": ":clang-{suffix}", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang++-{suffix}", + "@rules_cc//cc/toolchains/actions:link_actions": ":lld-{suffix}", + "@rules_cc//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy-{suffix}", + "@rules_cc//cc/toolchains/actions:assembly_actions": ":llvm-as-{suffix}", + "@rules_cc//cc/toolchains/actions:strip": ":llvm-strip-{suffix}", + "@rules_cc//cc/toolchains/actions:llvm_cov": ":llvm-cov-{suffix}", + "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-ar-{suffix}", + + # Equivalent? + # "@rules_cc//cc/toolchains/actions:objdump": ":llvm-objdump-{suffix}", + # "@rules_cc//cc/toolchains/actions:dwp": ":llvm-dwp-{suffix}", + # "@rules_cc//cc/toolchains/actions:nm": ":llvm-nm-{suffix}", +}} + +cc_tool_map( + name = "default_tools-{suffix}", + tools = COMMON_TOOLS_{suffix_var_safe}, + visibility = ["//visibility:private"], +) + +cc_tool_map( + name = "libtool_tools-{suffix}", + tools = COMMON_TOOLS_{suffix_var_safe} | {{ + # This `select` happens under the target configuration. For macOS, + # llvm-libtool-darwin should be used when creating static libraries even if the + # exec platform is linux. + # TODO: https://github.com/bazelbuild/rules_cc/commit/9da1d5ca89e47f0f6b7d020d4e9f3a9e31ba17c7 + # Use the bundled libtool (llvm-libtool-darwin). + "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-libtool-darwin-{suffix}", + }}, + visibility = ["//visibility:private"], +) + +alias( + name = "all_tools-{suffix}", + actual = select({{ + "@rules_cc//cc/toolchains/args/archiver_flags:use_libtool_on_macos_setting": "libtool_tools-{suffix}", + "//conditions:default": "default_tools-{suffix}", + }}) +) + +cc_tool( + name = "clang-{suffix}", + src = "{llvm_dist_label_prefix}bin/clang", + data = [":compiler-components-{suffix}", {extra_files_str}], + allowlist_include_directories = {allowlist_include_directories} +) + +cc_tool( + name = "clang++-{suffix}", + src = "{llvm_dist_label_prefix}bin/clang-cpp", + data = [":compiler-components-{suffix}", {extra_files_str}], + allowlist_include_directories = {allowlist_include_directories} +) + + +cc_tool( + name = "lld-{suffix}", + src = "{llvm_dist_label_prefix}bin/ld.lld", + data = [":linker-components-{suffix}", {extra_files_str}], + allowlist_include_directories = {allowlist_include_directories} +) + +cc_tool( + name = "llvm-objcopy-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-objcopy", + data = ["{llvm_dist_label_prefix}objcopy", {extra_files_str}], +) + +cc_tool( + name = "llvm-objdump-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-objdump", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-cov-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-cov", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-ar-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-ar", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-as-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-as", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-dwp-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-dwp", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-strip-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-strip", + data = [{extra_files_str}], +) + +cc_tool( + name = "llvm-libtool-darwin-{suffix}", + src = "{llvm_dist_label_prefix}bin/llvm-libtool-darwin", + data = [{extra_files_str}], +) + +# TOOLS:END + + +# ARGS:START +cc_args( + name = "unfiltered_compile_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:c_compile", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions", + ], + args = {unfiltered_compile_flags}, + requires_any_of = [":constraint_unfiltered_compile_flags"] +) + +cc_args( + name = "target_args", + actions = [ + "@rules_cc//cc/toolchains/actions:compile_actions", + "@rules_cc//cc/toolchains/actions:link_actions" ] +) - sysroot_prefix = "" - if sysroot_path: - sysroot_prefix = "%sysroot%" - if target_os == "linux": - cxx_builtin_include_directories.extend([ - _join(sysroot_prefix, "/include"), - _join(sysroot_prefix, "/usr/include"), - _join(sysroot_prefix, "/usr/local/include"), - ]) - elif target_os == "darwin": - cxx_builtin_include_directories.extend([ - _join(sysroot_prefix, "/usr/include"), - _join(sysroot_prefix, "/System/Library/Frameworks"), - ]) - elif target_os == "none" or target_os == "wasip1": - if sysroot_prefix: - cxx_builtin_include_directories.extend([ - _join(sysroot_prefix, "/include"), - ]) - else: - fail("Unreachable") +cc_args( + name = "conly_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:c_compile", + ], + args = {conly_flags}, +) - cxx_builtin_include_directories.extend(toolchain_info.additional_include_dirs_dict.get(target_pair, [])) - template = """ -# CC toolchain for cc-clang-{suffix}. +cc_args( + name = "cxx_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:cpp_compile_actions", + ], + args = {cxx_flags}, +) -cc_toolchain_config( - name = "local-{suffix}", - exec_arch = "{exec_arch}", - exec_os = "{exec_os}", - target_arch = "{target_arch}", - target_os = "{target_os}", - target_system_name = "{target_system_name}", - toolchain_path_prefix = "{llvm_dist_path_prefix}", - tools_path_prefix = "{tools_path_prefix}", - wrapper_bin_prefix = "{wrapper_bin_prefix}", - compiler_configuration = {{ - "sysroot_path": "{sysroot_path}", - "stdlib": "{stdlib}", - "cxx_standard": "{cxx_standard}", - "compile_flags": {compile_flags}, - "conly_flags": {conly_flags}, - "cxx_flags": {cxx_flags}, - "link_flags": {link_flags}, - "archive_flags": {archive_flags}, - "link_libs": {link_libs}, - "opt_compile_flags": {opt_compile_flags}, - "opt_link_flags": {opt_link_flags}, - "dbg_compile_flags": {dbg_compile_flags}, - "coverage_compile_flags": {coverage_compile_flags}, - "coverage_link_flags": {coverage_link_flags}, - "unfiltered_compile_flags": {unfiltered_compile_flags}, - }}, - cxx_builtin_include_directories = {cxx_builtin_include_directories}, - major_llvm_version = {major_llvm_version}, + + + +# Compile args +cc_args( + name = "compile_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:c_compile", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions", + ], + args = {compile_flags}, +) + +cc_args( + name = "opt_compile_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:c_compile", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions", + ], + args = {opt_compile_flags}, + requires_any_of = [":constraint_opt"] +) + +cc_args( + name = "dbg_compile_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:c_compile", + "@rules_cc//cc/toolchains/actions:cpp_compile_actions", + ], + args = {dbg_compile_flags}, + requires_any_of = [":constraint_dbg"] +) + + +# LINKER ARGS +cc_args( + name = "link_flags-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = {link_flags}, +) + +cc_args( + name = "opt_link_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:link_actions", + ], + args = {opt_link_flags}, + requires_any_of = [":constraint_opt"] +) + +print({link_flags}) +# ARCHIVE ARGS +cc_args( + name = "archive_args-{suffix}", + actions = [ + "@rules_cc//cc/toolchains/actions:ar_actions", + ], + args = {archive_flags}, ) +# ARGS:END + +# Sysroot from the host +{sysroot_targets} + + +cc_toolchain( + name = "cc-clang-{suffix}", + tool_map = ":all_tools-{suffix}", + module_map = ":module-{suffix}", + compiler = "clang", + args = [ + ":no_absolute_paths_for_builtins", + ":unfiltered_compile_args-{suffix}", + ":compile_args-{suffix}", + ":link_flags-{suffix}", + ":archive_args-{suffix}", + ":conly_args-{suffix}", + ":cxx_args-{suffix}", + ":sysroot-{suffix}", + ], + known_features = [ + "@rules_cc//cc/toolchains/args:experimental_replace_legacy_action_config_features" + ], + enabled_features = [ + "@rules_cc//cc/toolchains/args:experimental_replace_legacy_action_config_features" + ], +) + + toolchain( name = "cc-toolchain-{suffix}", exec_compatible_with = [ @@ -411,49 +634,14 @@ toolchain( toolchain = ":cc-clang-{suffix}", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) -""" - template = template + """ -filegroup( - name = "sysroot-components-{suffix}", - srcs = [{sysroot_label_str}], -) -""" - if use_absolute_paths_llvm: - template = template + """ -filegroup( - name = "compiler-components-{suffix}", - srcs = [ - ":sysroot-components-{suffix}", - {extra_compiler_files} - ], -) - -filegroup( - name = "linker-components-{suffix}", - srcs = [":sysroot-components-{suffix}"], -) filegroup( - name = "all-components-{suffix}", - srcs = [ - ":compiler-components-{suffix}", - ":linker-components-{suffix}", - ], + name = "sysroot-components-{suffix}", + srcs = [{sysroot_label_str}], ) -filegroup(name = "all-files-{suffix}", srcs = [":all-components-{suffix}", {extra_files_str}]) -filegroup(name = "archiver-files-{suffix}", srcs = [{extra_files_str}]) -filegroup(name = "assembler-files-{suffix}", srcs = [{extra_files_str}]) -filegroup(name = "compiler-files-{suffix}", srcs = [":compiler-components-{suffix}", {extra_files_str}]) -filegroup(name = "dwp-files-{suffix}", srcs = [{extra_files_str}]) -filegroup(name = "linker-files-{suffix}", srcs = [":linker-components-{suffix}", {extra_files_str}]) -filegroup(name = "objcopy-files-{suffix}", srcs = [{extra_files_str}]) -filegroup(name = "strip-files-{suffix}", srcs = [{extra_files_str}]) -""" - else: - template = template + """ filegroup( name = "compiler-components-{suffix}", srcs = [ @@ -475,6 +663,7 @@ filegroup( ], ) + filegroup( name = "all-components-{suffix}", srcs = [ @@ -484,17 +673,6 @@ filegroup( ], ) -filegroup(name = "all-files-{suffix}", srcs = [":all-components-{suffix}", {extra_files_str}]) -filegroup(name = "archiver-files-{suffix}", srcs = ["{llvm_dist_label_prefix}ar", {extra_files_str}]) -filegroup(name = "assembler-files-{suffix}", srcs = ["{llvm_dist_label_prefix}as", {extra_files_str}]) -filegroup(name = "compiler-files-{suffix}", srcs = [":compiler-components-{suffix}", {extra_files_str}]) -filegroup(name = "dwp-files-{suffix}", srcs = ["{llvm_dist_label_prefix}dwp", {extra_files_str}]) -filegroup(name = "linker-files-{suffix}", srcs = [":linker-components-{suffix}", {extra_files_str}]) -filegroup(name = "objcopy-files-{suffix}", srcs = ["{llvm_dist_label_prefix}objcopy", {extra_files_str}]) -filegroup(name = "strip-files-{suffix}", srcs = ["{llvm_dist_label_prefix}strip", {extra_files_str}]) -""" - - template = template + """ filegroup( name = "include-components-{suffix}", srcs = [ @@ -509,34 +687,69 @@ system_module_map( cxx_builtin_include_directories = {cxx_builtin_include_directories}, sysroot_path = "{sysroot_path}", ) - -cc_toolchain( - name = "cc-clang-{suffix}", - all_files = "all-files-{suffix}", - ar_files = "archiver-files-{suffix}", - as_files = "assembler-files-{suffix}", - compiler_files = "compiler-files-{suffix}", - dwp_files = "dwp-files-{suffix}", - linker_files = "linker-files-{suffix}", - objcopy_files = "objcopy-files-{suffix}", - strip_files = "strip-files-{suffix}", - toolchain_config = "local-{suffix}", - module_map = "module-{suffix}", -) """ # Filter out non-existing directories with absolute paths as they # result in a -Wincomplete-umbrella warning when mentioned in the # system module map. Note that this filtering is skipped for remote # execution because it is not possible to check directory existence. - filtered_cxx_builtin_include_directories = cxx_builtin_include_directories if _is_remote(rctx, exec_os, exec_arch) else [ - dir - for dir in cxx_builtin_include_directories - if _is_hermetic_or_exists(rctx, dir, sysroot_path) + # filtered_cxx_builtin_include_directories = cxx_builtin_include_directories if _is_remote(rctx, exec_os, exec_arch) else [ + # dir + # for dir in cxx_builtin_include_directories + # if _is_hermetic_or_exists(rctx, dir, sysroot_path) + # ] + filtered_cxx_builtin_include_directories = [] + + # Unfiltered compiler flags; these are placed at the end of the command + # line, so take precendence over any user supplied flags through --copts or + # such. + # TODO: use flags defined here. + # https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args + unfiltered_compile_flags = [ + # Reproducibility + "-Wno-builtin-macro-redefined", + "-D__DATE__=\\\"redacted\\\"", + "-D__TIMESTAMP__=\\\"redacted\\\"", + "-D__TIME__=\\\"redacted\\\"", + ] + + # Default compiler flags: + compile_flags = [ + "--target=" + target_system_name, + # Security + "-U_FORTIFY_SOURCE", # https://github.com/google/sanitizers/issues/247 + "-fstack-protector", + "-fno-omit-frame-pointer", + # Diagnostics + "-fcolor-diagnostics", + "-Wall", + "-Wthread-safety", + "-Wself-assign", + ] + + dbg_compile_flags = ["-g", "-fstandalone-debug"] + + opt_compile_flags = [ + "-g0", + "-O2", + "-D_FORTIFY_SOURCE=1", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections", + ] + + link_flags = [ + "--target=" + target_system_name, ] + opt_link_flags = ["-Wl,--gc-sections"] if target_os == "linux" else [] + + + coverage_compile_flags = ["-fprofile-instr-generate", "-fcoverage-mapping"] + coverage_link_flags = ["-fprofile-instr-generate"] - return template.format( + x = template.format( suffix = suffix, + suffix_var_safe = suffix.replace("-", "_"), target_os = target_os, target_arch = target_arch, exec_os = exec_os, @@ -551,29 +764,37 @@ cc_toolchain( wrapper_bin_prefix = toolchain_info.wrapper_bin_prefix, sysroot_label_str = sysroot_label_str, sysroot_path = sysroot_path, + sysroot_targets = "\n".join(sysroot_targets), stdlib = _dict_value(toolchain_info.stdlib_dict, target_pair, "builtin-libc++"), cxx_standard = _dict_value(toolchain_info.cxx_standard_dict, target_pair, "c++17"), - compile_flags = _list_to_string(_dict_value(toolchain_info.compile_flags_dict, target_pair)), - conly_flags = _list_to_string(toolchain_info.conly_flags_dict.get(target_pair, [])), - cxx_flags = _list_to_string(_dict_value(toolchain_info.cxx_flags_dict, target_pair)), - link_flags = _list_to_string(_dict_value(toolchain_info.link_flags_dict, target_pair)), - archive_flags = _list_to_string(_dict_value(toolchain_info.archive_flags_dict, target_pair)), - link_libs = _list_to_string(_dict_value(toolchain_info.link_libs_dict, target_pair)), - opt_compile_flags = _list_to_string(_dict_value(toolchain_info.opt_compile_flags_dict, target_pair)), - opt_link_flags = _list_to_string(_dict_value(toolchain_info.opt_link_flags_dict, target_pair)), - dbg_compile_flags = _list_to_string(_dict_value(toolchain_info.dbg_compile_flags_dict, target_pair)), - coverage_compile_flags = _list_to_string(_dict_value(toolchain_info.coverage_compile_flags_dict, target_pair)), - coverage_link_flags = _list_to_string(_dict_value(toolchain_info.coverage_link_flags_dict, target_pair)), - unfiltered_compile_flags = _list_to_string(_dict_value(toolchain_info.unfiltered_compile_flags_dict, target_pair)), + # standard compile flags per c++ and conly + unfiltered_compile_flags = _list_to_string(_dict_value(toolchain_info.coverage_link_flags_dict, target_pair, unfiltered_compile_flags)), + conly_flags = _list_to_string(_dict_value(toolchain_info.conly_flags_dict, target_pair, [])), + cxx_flags = _list_to_string(_dict_value(toolchain_info.cxx_flags_dict, target_pair, [])), + # compile flags + compile_flags = _list_to_string(_dict_value(toolchain_info.compile_flags_dict, target_pair, compile_flags)), + opt_compile_flags = _list_to_string(_dict_value(toolchain_info.opt_compile_flags_dict, target_pair, opt_compile_flags)), + dbg_compile_flags = _list_to_string(_dict_value(toolchain_info.dbg_compile_flags_dict, target_pair, dbg_compile_flags)), + coverage_compile_flags = _list_to_string(_dict_value(toolchain_info.coverage_compile_flags_dict, target_pair, coverage_compile_flags)), + # link flags + link_flags = _list_to_string(_dict_value(toolchain_info.link_flags_dict, target_pair, link_flags)), + opt_link_flags = _list_to_string(_dict_value(toolchain_info.opt_link_flags_dict, target_pair, opt_link_flags)), + coverage_link_flags = _list_to_string(_dict_value(toolchain_info.coverage_link_flags_dict, target_pair, coverage_link_flags)), + # archive flags + archive_flags = _list_to_string(_dict_value(toolchain_info.archive_flags_dict, target_pair, [])), + # others + link_libs = _list_to_string(_dict_value(toolchain_info.link_libs_dict, target_pair, [])), extra_files_str = extra_files_str, cxx_builtin_include_directories = _list_to_string(filtered_cxx_builtin_include_directories), + allowlist_include_directories = _list_to_string(allowlist_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, 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("", []), extra_target_compatible_with_all_targets = toolchain_info.extra_target_compatible_with.get("", []), ) + # print(x) + return x def _is_remote(rctx, exec_os, exec_arch): return not (_os_from_rctx(rctx) == exec_os and _arch_from_rctx(rctx) == exec_arch) diff --git a/toolchain/internal/host_sysroot_directory.bzl b/toolchain/internal/host_sysroot_directory.bzl new file mode 100644 index 000000000..85ffe55ce --- /dev/null +++ b/toolchain/internal/host_sysroot_directory.bzl @@ -0,0 +1,12 @@ +load("@bazel_skylib//rules/directory:providers.bzl", "create_directory_info") + +# Workaround https://github.com/bazelbuild/rules_cc/issues/277 + +host_sysroot_directory = rule( + implementation = lambda ctx : create_directory_info( + path = ctx.attr.path + ), + attrs = { + "path": attr.string(mandatory = True) + } +) \ No newline at end of file diff --git a/toolchain/internal/llvm_distributions.bzl b/toolchain/internal/llvm_distributions.bzl index cd5a2cd1b..eb36616d7 100644 --- a/toolchain/internal/llvm_distributions.bzl +++ b/toolchain/internal/llvm_distributions.bzl @@ -683,12 +683,16 @@ def download_llvm(rctx): strip_prefix = None key = None update_sha256 = False + version = None if rctx.attr.urls: urls, sha256, strip_prefix, key = _urls(rctx) if not sha256: update_sha256 = True + version = rctx.attr.llvm_versions[key] if not urls: - urls, sha256, strip_prefix = _distribution_urls(rctx) + urls, sha256, strip_prefix, version = _distribution_urls(rctx) + + res = rctx.download_and_extract( urls, @@ -708,7 +712,7 @@ def download_llvm(rctx): updated_attrs = _attr_dict(rctx.attr) if update_sha256: updated_attrs["sha256"].update([(key, res.sha256)]) - return updated_attrs + return updated_attrs, version def _urls(rctx): (key, urls) = _exec_os_arch_dict_value(rctx, "urls", debug = False) @@ -761,4 +765,4 @@ def _distribution_urls(rctx): strip_prefix = strip_prefix.rstrip("-rhel86") - return urls, sha256, strip_prefix + return urls, sha256, strip_prefix, llvm_version diff --git a/toolchain/internal/repo.bzl b/toolchain/internal/repo.bzl index 0f17cb569..a1cb42c77 100644 --- a/toolchain/internal/repo.bzl +++ b/toolchain/internal/repo.bzl @@ -291,9 +291,6 @@ llvm_config_attrs.update({ mandatory = False, doc = "Extra constraints to be added to target_compatible_with for each target", ), - "_cc_toolchain_config_bzl": attr.label( - default = "//toolchain:cc_toolchain_config.bzl", - ), "_toolchains_bzl_tpl": attr.label( default = "//toolchain:toolchains.bzl.tpl", ), @@ -313,15 +310,20 @@ def llvm_repo_impl(rctx): if os == "windows": rctx.file("BUILD.bazel", executable = False) return None + + llvm_build_file_label = Label("//toolchain:BUILD.llvm_repo") + + updated_attrs, version = _download_llvm(rctx) rctx.file( "BUILD.bazel", - content = rctx.read(Label("//toolchain:BUILD.llvm_repo")), + content = rctx.read(llvm_build_file_label).format( + major_llvm_version = version.split(".")[0], # TODO: this is horrible + llvm_version = version + ), executable = False, ) - updated_attrs = _download_llvm(rctx) - # We try to avoid patches to the downloaded repo so that it is easier for # users to bring their own LLVM distribution through `http_archive`. If we # do want to make changes, then we should do it through a patch file, and diff --git a/toolchain/llvm.bzl b/toolchain/llvm.bzl new file mode 100644 index 000000000..dfc21b6da --- /dev/null +++ b/toolchain/llvm.bzl @@ -0,0 +1,14 @@ +load( + "//toolchain/internal:repo.bzl", + _common_attrs = "common_attrs", + _llvm_config_attrs = "llvm_config_attrs", + _llvm_repo_attrs = "llvm_repo_attrs", + _llvm_repo_impl = "llvm_repo_impl", +) + + +llvm = repository_rule( + attrs = _llvm_repo_attrs, + local = False, + implementation = _llvm_repo_impl, +) \ No newline at end of file diff --git a/toolchain/rules.bzl b/toolchain/rules.bzl index 237d965f2..c5ea5ba55 100644 --- a/toolchain/rules.bzl +++ b/toolchain/rules.bzl @@ -11,31 +11,15 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -load( - "//toolchain/internal:configure.bzl", - _llvm_config_impl = "llvm_config_impl", -) +load(":toolchain.bzl", "toolchain") +load(":llvm.bzl", "llvm") load( "//toolchain/internal:repo.bzl", _common_attrs = "common_attrs", _llvm_config_attrs = "llvm_config_attrs", _llvm_repo_attrs = "llvm_repo_attrs", - _llvm_repo_impl = "llvm_repo_impl", ) -llvm = repository_rule( - attrs = _llvm_repo_attrs, - local = False, - implementation = _llvm_repo_impl, -) - -toolchain = repository_rule( - attrs = _llvm_config_attrs, - local = True, - configure = True, - implementation = _llvm_config_impl, -) def llvm_toolchain(name, **kwargs): if kwargs.get("llvm_version") == kwargs.get("llvm_versions"): diff --git a/toolchain/toolchain.bzl b/toolchain/toolchain.bzl new file mode 100644 index 000000000..8f38e7fad --- /dev/null +++ b/toolchain/toolchain.bzl @@ -0,0 +1,314 @@ +# Copyright 2025 The Bazel Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load( + "//toolchain/internal:configure.bzl", + _llvm_config_impl = "llvm_config_impl", +) + +load( + "//toolchain/internal:common.bzl", + _supported_os_arch_keys = "supported_os_arch_keys", +) + +_target_pairs = ", ".join(_supported_os_arch_keys()) + + +# Atributes common to both `llvm` and `toolchain` repository rules. +common_attrs = { + "llvm_versions": attr.string_dict( + mandatory = False, + doc = ("LLVM version strings, keyed by host 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 ({}). ".format(_target_pairs) + + "An empty key is used to specify a fallback default for all hosts. " + + "If no `toolchain_roots` is given, then the toolchain will be looked up " + + "in the list of known llvm_distributions using the provided version. " + + "If unset, a default value is set from the `llvm_version` attribute."), + ), + "exec_os": attr.string( + mandatory = False, + doc = "Execution platform OS, if different from host OS.", + ), + "exec_arch": attr.string( + mandatory = False, + doc = "Execution platform architecture, if different from host arch.", + ), +} + +llvm_repo_attrs = dict(common_attrs) +llvm_repo_attrs.update({ + "llvm_version": attr.string( + doc = ("One of the supported versions of LLVM, e.g. 12.0.0; used with the " + + "`auto` value for the `distribution` attribute, and as a default value " + + "for the `llvm_versions` attribute."), + ), + "urls": attr.string_list_dict( + mandatory = False, + doc = ("URLs to LLVM pre-built binary distribution archives, keyed by host 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 " + + "({}). ".format(_target_pairs) + + "May also need the `strip_prefix` attribute. " + + "Consider also setting the `sha256` attribute. An empty key is " + + "used to specify a fallback default for all hosts. This attribute " + + "overrides `distribution`, `llvm_version`, `llvm_mirror` and " + + "`alternative_llvm_sources` attributes if the host OS key is present."), + ), + "sha256": attr.string_dict( + mandatory = False, + doc = "The expected SHA-256 of the file downloaded as per the `urls` attribute.", + ), + "strip_prefix": attr.string_dict( + mandatory = False, + doc = "The prefix to strip from the extracted file from the `urls` attribute.", + ), + "distribution": attr.string( + default = "auto", + doc = ("LLVM pre-built binary distribution filename, must be one " + + "listed on http://releases.llvm.org/download.html for the version " + + "specified in the `llvm_version` attribute. A special value of " + + "'auto' tries to detect the version based on host OS."), + ), + "llvm_mirror": attr.string( + doc = "Base URL for an LLVM release mirror." + + "\n\n" + + "This mirror must follow the same structure as the official LLVM release " + + "sources (`releases.llvm.org` for versions <= 9, `llvm/llvm-project` GitHub " + + "releases for newer versions)." + + "\n\n" + + "If provided, this mirror will be given precedence over the official LLVM release " + + "sources (see: " + + "https://github.com/bazel-contrib/toolchains_llvm/toolchain/internal/llvm_distributions.bzl).", + ), + "alternative_llvm_sources": attr.string_list( + doc = "Patterns for alternative LLVM release sources. Unlike URLs specified for `llvm_mirror` " + + "these do not have to follow the same structure as the official LLVM release sources." + + "\n\n" + + "Patterns may include `{llvm_version}` (which will be substituted for the full LLVM " + + "version, i.e. 13.0.0) and `{basename}` (which will be replaced with the filename " + + "used by the official LLVM release sources for a particular distribution; i.e. " + + "`llvm-13.0.0-x86_64-linux-gnu-ubuntu-20.04.tar.xz`)." + + "\n\n" + + "As with `llvm_mirror`, these sources will take precedence over the official LLVM " + + "release sources.", + ), + "libclang_rt": attr.label_keyed_string_dict( + mandatory = False, + doc = ("Additional libclang_rt libraries to overlay into the downloaded LLVM " + + "distribution. The key is the label of a libclang_rt library, " + + "and the value is `\"{llvm_target_name}/{library_name}.a\"`."), + ), + "netrc": attr.string( + mandatory = False, + doc = "Path to the netrc file for authenticated LLVM URL downloads.", + ), + "auth_patterns": attr.string_dict( + mandatory = False, + doc = "An optional dict mapping host names to custom authorization patterns.", + ), +}) + +_compiler_configuration_attrs = { + "sysroot": attr.string_dict( + mandatory = False, + doc = ("System path or fileset, for each target OS and arch pair you want to support " + + "({}), ".format(_target_pairs) + + "used to indicate the set of files that form the sysroot for the compiler. " + + "If the value begins with exactly one forward slash '/', then the value is " + + "assumed to be a system path. Else, the value will be assumed to be a label " + + "containing the files and the sysroot path will be taken as the path to the " + + "package of this label."), + ), + "cxx_builtin_include_directories": attr.string_list_dict( + mandatory = False, + doc = ("Additional builtin include directories to be added to the default system " + + "directories, for each target OS and arch pair you want to support " + + "({}); ".format(_target_pairs) + + "see documentation for bazel's create_cc_toolchain_config_info."), + ), + "stdlib": attr.string_dict( + mandatory = False, + doc = ("stdlib implementation, for each target OS and arch pair you want to support " + + "({}), ".format(_target_pairs) + + "linked to the compiled binaries. An empty key can be used to specify a " + + "value for all target pairs. Possible values are `builtin-libc++` (default) " + + "which uses the libc++ shipped with clang, `libc++` which uses libc++ available on " + + "the host or sysroot, `stdc++` which uses libstdc++ available on the host or " + + "sysroot, and `none` which uses `-nostdlib` with the compiler."), + ), + "cxx_standard": attr.string_dict( + mandatory = False, + doc = ("C++ standard, for each target OS and arch pair you want to support " + + "({}), ".format(_target_pairs) + + "passed as `-std` flag to the compiler. An empty key can be used to specify a " + + "value for all target pairs. Default value is c++17."), + ), + # For default values of all the below flags overrides, consult + # cc_toolchain_config.bzl in this directory. + "compile_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for compile_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "conly_flags": attr.string_list_dict( + mandatory = False, + doc = ("Extra flags for compiling C (not C++) files, " + + "for each target OS and arch pair you want to support " + + "({}), ".format(", ".join(_supported_os_arch_keys())) + "."), + ), + "cxx_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for cxx_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "link_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for link_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "archive_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for archive_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "link_libs": attr.string_list_dict( + mandatory = False, + doc = ("Override for link_libs, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "opt_compile_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for opt_compile_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "opt_link_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for opt_link_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "dbg_compile_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for dbg_compile_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "coverage_compile_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for coverage_compile_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "coverage_link_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for coverage_link_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "unfiltered_compile_flags": attr.string_list_dict( + mandatory = False, + doc = ("Override for unfiltered_compile_flags, replacing the default values. " + + "`{toolchain_path_prefix}` in the flags will be substituted by the path " + + "to the root LLVM distribution directory. Provide one list for each " + + "target OS and arch pair you want to override " + + "({}); empty key overrides all.".format(_target_pairs)), + ), + "target_settings": attr.string_list_dict( + mandatory = False, + doc = ("Override the toolchain's `target_settings` attribute."), + ), + "extra_compiler_files": attr.label( + mandatory = False, + doc = ("Files to be made available in the sandbox for compile actions. " + + "Mostly useful for providing files containing lists of flags, e.g. " + + "sanitizer ignorelists."), + ), +} + +llvm_config_attrs = dict(common_attrs) +llvm_config_attrs.update(_compiler_configuration_attrs) +llvm_config_attrs.update({ + "toolchain_roots": attr.string_dict( + mandatory = False, + # 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 host 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. An empty key can be used to specify a fallback default for " + + "all hosts, e.g. with the llvm_toolchain_repo rule. " + + "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.", + ), + "extra_exec_compatible_with": attr.string_list_dict( + mandatory = False, + doc = "Extra constraints to be added to exec_compatible_with for each target", + ), + "extra_target_compatible_with": attr.string_list_dict( + mandatory = False, + doc = "Extra constraints to be added to target_compatible_with for each target", + ), + "_toolchains_bzl_tpl": attr.label( + default = "//toolchain:toolchains.bzl.tpl", + ), + "_build_toolchain_tpl": attr.label( + default = "//toolchain:BUILD.toolchain.tpl", + ), + "_darwin_cc_wrapper_sh_tpl": attr.label( + default = "//toolchain:osx_cc_wrapper.sh.tpl", + ), + "_cc_wrapper_sh_tpl": attr.label( + default = "//toolchain:cc_wrapper.sh.tpl", + ), +}) + +toolchain = repository_rule( + attrs = llvm_config_attrs, + implementation = _llvm_config_impl, +) +