diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 940c9577..02ab2032 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -14,7 +14,7 @@ load("@bazel_skylib//rules:build_test.bzl", "build_test") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") -load(":transitions.bzl", "dwp_file") +load(":transitions.bzl", "dwp_file", "transition_library_to_platform") cc_library( name = "stdlib", @@ -139,3 +139,64 @@ toolchain( toolchain = "@@rules_foreign_cc~~tools~ninja_1.11.1_mac//:ninja_tool", toolchain_type = "@rules_foreign_cc//toolchains:ninja_toolchain", ) + +# Testing extra_target_compatible_with +constraint_setting( + name = "cxx_standard", + default_constraint_value = ":cxx17", + visibility = ["//visibility:public"], +) + +constraint_value( + name = "cxx20", + constraint_setting = ":cxx_standard", + visibility = ["//visibility:public"], +) + +constraint_value( + name = "cxx17", + constraint_setting = ":cxx_standard", + visibility = ["//visibility:public"], +) + +platform( + name = "cxx20_platform", + constraint_values = [ + ":cxx20", + ], + parents = ["@platforms//host"], + visibility = ["//visibility:public"], +) + +cc_library( + name = "test_cxx_standard_lib", + srcs = ["test_cxx_standard.cc"], +) + +cc_test( + name = "test_cxx_standard_is_17", + size = "small", + srcs = ["test_cxx_standard_main.cc"], + args = ["201703"], + deps = [":test_cxx_standard_lib"], +) + +transition_library_to_platform( + name = "test_cxx_standard_lib_transitioned", + lib = ":test_cxx_standard_lib", + platform = ":cxx20_platform", +) + +cc_test( + name = "test_cxx_standard_is_20", + size = "small", + srcs = ["test_cxx_standard_main.cc"], + args = ["202002"], + + # Since some platforms require special toolchains (e.g. llvm 13.0.0) this + # target won't build on those platforms unless we create a new toolchain per + # platform with c++20. So instead just only run this test on platforms that + # can use the default toolchain + tags = ["manual"], + deps = [":test_cxx_standard_lib_transitioned"], +) diff --git a/tests/MODULE.bazel b/tests/MODULE.bazel index 126b4dd3..1145b32c 100644 --- a/tests/MODULE.bazel +++ b/tests/MODULE.bazel @@ -65,11 +65,28 @@ LLVM_VERSIONS = { llvm.toolchain( name = "llvm_toolchain", llvm_versions = LLVM_VERSIONS, + cxx_standard = {"": "c++17"}, +) +llvm.extra_target_compatible_with( + name = "llvm_toolchain", + constraints = ["@//:cxx17"], ) use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm") - register_toolchains("@llvm_toolchain//:all") +llvm.toolchain( + name = "llvm_toolchain_cxx20", + llvm_versions = LLVM_VERSIONS, + cxx_standard = {"": "c++20"}, +) +llvm.extra_target_compatible_with( + name = "llvm_toolchain_cxx20", + constraints = ["//:cxx20"], +) +use_repo(llvm, "llvm_toolchain_cxx20") +register_toolchains("@llvm_toolchain_cxx20//:all") + + # Example toolchain with user provided URLs. # TODO(siddharthab): Add test. llvm.toolchain( diff --git a/tests/WORKSPACE b/tests/WORKSPACE index 04129246..65c8ee52 100644 --- a/tests/WORKSPACE +++ b/tests/WORKSPACE @@ -37,6 +37,19 @@ LLVM_VERSIONS = { llvm_toolchain( name = "llvm_toolchain", + cxx_standard = {"": "c++17"}, + extra_target_compatible_with = { + "": ["@//:cxx17"], + }, + llvm_versions = LLVM_VERSIONS, +) + +llvm_toolchain( + name = "llvm_toolchain_cxx20", + cxx_standard = {"": "c++20"}, + extra_target_compatible_with = { + "": ["@//:cxx20"], + }, llvm_versions = LLVM_VERSIONS, ) @@ -75,6 +88,10 @@ load("@llvm_toolchain//:toolchains.bzl", "llvm_register_toolchains") llvm_register_toolchains() +load("@llvm_toolchain_cxx20//:toolchains.bzl", llvm_register_toolchains_cxx20 = "llvm_register_toolchains") + +llvm_register_toolchains_cxx20() + ## Toolchain example with absolute paths; tested in GitHub CI. llvm_toolchain( name = "llvm_toolchain_with_absolute_paths", @@ -230,3 +247,16 @@ http_archive( "https://ftp.pcre.org/pub/pcre/pcre-8.43.tar.gz", ], ) + +http_archive( + name = "platforms", + sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", + ], +) + +load("@platforms//host:extension.bzl", "host_platform_repo") + +host_platform_repo(name = "host_platform") diff --git a/tests/scripts/run_tests.sh b/tests/scripts/run_tests.sh index 694e5533..c50a346a 100755 --- a/tests/scripts/run_tests.sh +++ b/tests/scripts/run_tests.sh @@ -46,8 +46,18 @@ test_args=( "--linkopt=-Wl,-t" ) +targets=( + "//:all" +) +# :test_cxx_standard_is_20 builds with a version of the default toolchain, if +# we're trying to build with a different toolchain then it's likely the default +# toolchain won't work so :test_cxx_standard_is_20 won't build. +if [[ -z ${toolchain_name} ]]; then + targets+=("//:test_cxx_standard_is_20") +fi + "${bazel}" ${TEST_MIGRATION:+"--strict"} --bazelrc=/dev/null test \ - "${common_test_args[@]}" "${test_args[@]}" //:all + "${common_test_args[@]}" "${test_args[@]}" "${targets[@]}" # Note that the following flags are currently known to cause issues in migration tests: # --incompatible_disallow_struct_provider_syntax # https://github.com/bazelbuild/bazel/issues/7347 diff --git a/tests/test_cxx_standard.cc b/tests/test_cxx_standard.cc new file mode 100644 index 00000000..26892880 --- /dev/null +++ b/tests/test_cxx_standard.cc @@ -0,0 +1,22 @@ +#include +#include + +int run_test(int argc, char** argv) { + if (argc != 2) { + std::cout << "Not enough arguments" << std::endl; + return 1; + } + + long expected_version = std::atol(argv[1]); + + if (expected_version == 0) { + std::cout << "Invalid version argument, must be an integer" << std::endl; + return 1; + } + + if (expected_version != __cplusplus) { + std::cout << "Expected version to be " << argv[1] << " but got " << __cplusplus << std::endl; + return 1; + } + return 0; +} diff --git a/tests/test_cxx_standard_main.cc b/tests/test_cxx_standard_main.cc new file mode 100644 index 00000000..9a388226 --- /dev/null +++ b/tests/test_cxx_standard_main.cc @@ -0,0 +1,5 @@ +int run_test(int argc, char** argv); + +int main(int argc, char** argv) { + return run_test(argc, argv); +} \ No newline at end of file diff --git a/tests/transitions.bzl b/tests/transitions.bzl index 23db8d31..ac7316ed 100644 --- a/tests/transitions.bzl +++ b/tests/transitions.bzl @@ -96,3 +96,28 @@ dwp_file = rule( ), }, ) + +def _transition_library_to_platform_transition_impl(_, attr): + return {"//command_line_option:platforms": str(attr.platform)} + +_transition_library_to_platform_transition = transition( + implementation = _transition_library_to_platform_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def _transition_library_to_platform_impl(ctx): + return [ + ctx.attr.lib[0][CcInfo], + ] + +transition_library_to_platform = rule( + implementation = _transition_library_to_platform_impl, + attrs = { + "lib": attr.label(mandatory = True, cfg = _transition_library_to_platform_transition), + "platform": attr.label(mandatory = True), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, +) diff --git a/toolchain/extensions/llvm.bzl b/toolchain/extensions/llvm.bzl index e38b783a..28148719 100644 --- a/toolchain/extensions/llvm.bzl +++ b/toolchain/extensions/llvm.bzl @@ -34,6 +34,20 @@ def _root_dict(roots, cls, name, strip_target): return res +def _constraint_dict(tags, name): + constraints = {} + + # Gather all the additional constraints for each target + for tag in tags: + targets = list(tag.targets) + if not targets: + targets = [""] + for target in targets: + constraints_for_target = constraints.setdefault(target, []) + constraints_for_target.extend([str(c) for c in tag.constraints]) + + return constraints + def _llvm_impl_(module_ctx): for mod in module_ctx.modules: if not mod.is_root: @@ -49,6 +63,14 @@ def _llvm_impl_(module_ctx): } attrs["toolchain_roots"] = _root_dict([root for root in mod.tags.toolchain_root if root.name == name], "toolchain_root", name, True) attrs["sysroot"] = _root_dict([sysroot for sysroot in mod.tags.sysroot if sysroot.name == name], "sysroot", name, False) + attrs["extra_exec_compatible_with"] = _constraint_dict( + [tag for tag in mod.tags.extra_exec_compatible_with if tag.name == name], + name, + ) + attrs["extra_target_compatible_with"] = _constraint_dict( + [tag for tag in mod.tags.extra_target_compatible_with if tag.name == name], + name, + ) llvm_toolchain( **attrs @@ -95,5 +117,19 @@ llvm = module_extension( "path": attr.string(doc = "Absolute path to the sysroot."), }, ), + "extra_exec_compatible_with": tag_class( + attrs = { + "name": attr.string(doc = "Same name as the toolchain tag.", default = "llvm_toolchain"), + "targets": attr.string_list(doc = "Specific targets, if any; empty list means this applies to all."), + "constraints": attr.label_list(doc = "List of extra constraints to add to exec_compatible_with for the generated toolchains."), + }, + ), + "extra_target_compatible_with": tag_class( + attrs = { + "name": attr.string(doc = "Same name as the toolchain tag.", default = "llvm_toolchain"), + "targets": attr.string_list(doc = "Specific targets, if any; empty list means this applies to all."), + "constraints": attr.label_list(doc = "List of extra constraints to add to target_compatible_with for the generated toolchains."), + }, + ), }, ) diff --git a/toolchain/internal/configure.bzl b/toolchain/internal/configure.bzl index 6e40059c..8731af75 100644 --- a/toolchain/internal/configure.bzl +++ b/toolchain/internal/configure.bzl @@ -59,6 +59,8 @@ def _join(path1, path2): def llvm_config_impl(rctx): _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) os = _os(rctx) if os == "windows": @@ -166,6 +168,8 @@ def llvm_config_impl(rctx): unfiltered_compile_flags_dict = rctx.attr.unfiltered_compile_flags, llvm_version = llvm_version, extra_compiler_files = rctx.attr.extra_compiler_files, + extra_exec_compatible_with = rctx.attr.extra_exec_compatible_with, + extra_target_compatible_with = rctx.attr.extra_target_compatible_with, ) exec_dl_ext = "dylib" if os == "darwin" else "so" cc_toolchains_str, toolchain_labels_str = _cc_toolchains_str( @@ -380,11 +384,11 @@ toolchain( exec_compatible_with = [ "@platforms//cpu:{exec_arch}", "@platforms//os:{exec_os_bzl}", - ], + ] + {extra_exec_compatible_with_specific} + {extra_exec_compatible_with_all_targets}, target_compatible_with = [ "@platforms//cpu:{target_arch}", "@platforms//os:{target_os_bzl}", - ], + ] + {extra_target_compatible_with_specific} + {extra_target_compatible_with_all_targets}, target_settings = {target_settings}, toolchain = ":cc-clang-{suffix}", toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", @@ -543,6 +547,10 @@ cc_toolchain( ]), 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("", []), ) def _convenience_targets_str(rctx, use_absolute_paths, llvm_dist_rel_path, llvm_dist_label_prefix, exec_dl_ext): diff --git a/toolchain/internal/repo.bzl b/toolchain/internal/repo.bzl index 27012db6..df89c4c1 100644 --- a/toolchain/internal/repo.bzl +++ b/toolchain/internal/repo.bzl @@ -271,6 +271,14 @@ llvm_config_attrs.update({ 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", + ), "_cc_toolchain_config_bzl": attr.label( default = "//toolchain:cc_toolchain_config.bzl", ),