|
| 1 | +"""Tests for C++20 module compilation in cc_library. |
| 2 | +
|
| 3 | +The C++20 modules pipeline (dependency scanning -> aggregate ddi -> generate |
| 4 | +modmap -> module interface compile) is implemented in rules_cc's compile.bzl and |
| 5 | +is not exercised by Bazel's own analysis tests (which only check the |
| 6 | +`--experimental_cpp_modules` / `cpp_modules` gating). These analysis tests cover |
| 7 | +the action-creation paths so that regressions in e.g. forwarding the module |
| 8 | +output/modmap arguments or the dependency-scanning action's outputs are caught |
| 9 | +without needing a real compiler. |
| 10 | +""" |
| 11 | + |
| 12 | +load("@bazel_features//:features.bzl", "bazel_features") |
| 13 | +load("@rules_testing//lib:analysis_test.bzl", "test_suite") |
| 14 | +load("@rules_testing//lib:truth.bzl", "matching") |
| 15 | +load("@rules_testing//lib:util.bzl", "TestingAspectInfo", "util") |
| 16 | +load("//cc:cc_library.bzl", "cc_library") |
| 17 | +load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test") |
| 18 | + |
| 19 | +# Action names of the C++20 module actions. Passing these to the mock toolchain's |
| 20 | +# with_action_configs makes it provide (dummy) tools for them so the actions can |
| 21 | +# be created during analysis. |
| 22 | +_CPP20_MODULE_ACTION_CONFIGS = [ |
| 23 | + "c++-module-deps-scanning", |
| 24 | + "c++20-module-compile", |
| 25 | + "c++20-module-codegen", |
| 26 | +] |
| 27 | + |
| 28 | +def _test_cpp20_module_interface_actions(name, **kwargs): |
| 29 | + util.helper_target( |
| 30 | + cc_library, |
| 31 | + name = name + "_subject", |
| 32 | + module_interfaces = ["mod.cppm"], |
| 33 | + ) |
| 34 | + cc_analysis_test( |
| 35 | + name = name, |
| 36 | + impl = _test_cpp20_module_interface_actions_impl, |
| 37 | + target = name + "_subject", |
| 38 | + # Enables rules_cc's C++20 modules pipeline. |
| 39 | + test_features = ["cpp_modules"], |
| 40 | + # Provide (dummy) tools for the module actions so they can be created. |
| 41 | + with_action_configs = _CPP20_MODULE_ACTION_CONFIGS, |
| 42 | + # The module_interfaces attribute is gated behind this flag. |
| 43 | + config_settings = { |
| 44 | + "//command_line_option:experimental_cpp_modules": True, |
| 45 | + }, |
| 46 | + **kwargs |
| 47 | + ) |
| 48 | + |
| 49 | +def _test_cpp20_module_interface_actions_impl(env, target): |
| 50 | + actions = target[TestingAspectInfo].actions |
| 51 | + |
| 52 | + # Reaching the assertions at all means the dependency-scanning action and the |
| 53 | + # module interface compile action were created without error. That covers |
| 54 | + # regressions where the scanning action does not pass needs_include_validation |
| 55 | + # or where the module output / modmap arguments are not forwarded to the |
| 56 | + # compile action, both of which fail analysis. |
| 57 | + scan_actions = [a for a in actions if a.mnemonic == "CppDepsScanning"] |
| 58 | + env.expect.that_collection(scan_actions).has_size(1) |
| 59 | + |
| 60 | + for scan in scan_actions: |
| 61 | + basenames = [f.basename for f in scan.outputs.to_list()] |
| 62 | + |
| 63 | + # The scanner writes a P1689 .ddi file ... |
| 64 | + env.expect.that_collection(basenames).contains_predicate( |
| 65 | + matching.str_endswith(".ddi"), |
| 66 | + ) |
| 67 | + |
| 68 | + # ... and must not declare a Make-style .d dependency file, which the |
| 69 | + # scanner never produces. |
| 70 | + env.expect.that_collection(basenames).not_contains_predicate( |
| 71 | + matching.str_endswith(".d"), |
| 72 | + ) |
| 73 | + |
| 74 | + # The .ddi files are aggregated into the modules info before the modmap is |
| 75 | + # generated; assert the rest of the pipeline is wired up too. |
| 76 | + aggregate_actions = [a for a in actions if a.mnemonic == "CppAggregateDdi"] |
| 77 | + env.expect.that_collection(aggregate_actions).has_size(1) |
| 78 | + |
| 79 | +def cc_module_compile_configured_target_tests(name): |
| 80 | + test_suite( |
| 81 | + name = name, |
| 82 | + tests = [ |
| 83 | + _test_cpp20_module_interface_actions, |
| 84 | + ] if bazel_features.cc.cc_common_is_in_rules_cc else [], |
| 85 | + ) |
0 commit comments