diff --git a/cc/common/cc_helper.bzl b/cc/common/cc_helper.bzl
index 92483ac6d..6d52c01cf 100644
--- a/cc/common/cc_helper.bzl
+++ b/cc/common/cc_helper.bzl
@@ -901,7 +901,9 @@ def _report_invalid_options(cc_toolchain, cpp_config):
fail("The selected toolchain does not support setting --grte_top (it doesn't specify builtin_sysroot).")
def _check_cpp_modules(ctx, feature_configuration):
- if len(ctx.files.module_interfaces) == 0:
+ has_module_interfaces = len(ctx.files.module_interfaces) > 0
+ has_module_header_maps = hasattr(ctx.attr, "module_header_maps") and len(ctx.attr.module_header_maps) > 0
+ if not has_module_interfaces and not has_module_header_maps:
return
if not ctx.fragments.cpp.experimental_cpp_modules():
fail("requires --experimental_cpp_modules", attr = "module_interfaces")
@@ -1016,6 +1018,28 @@ def _get_cpp_module_interfaces(ctx):
artifact_label_map = _calculate_artifact_label_map(ctx.attr.module_interfaces, "module_interfaces")
return _map_to_list(artifact_label_map)
+def _get_module_header_map_entries(ctx):
+ """Returns (module_name, map_file) tuples from module_header_maps."""
+ if not hasattr(ctx.attr, "module_header_maps"):
+ return []
+ entries = []
+ for name, map_label in ctx.attr.module_header_maps.items():
+ map_files = map_label.files.to_list()
+ if len(map_files) != 1:
+ fail(
+ "module_header_maps[%r]: label %s must provide exactly one .modulemap file, got %d" %
+ (name, map_label, len(map_files)),
+ attr = "module_header_maps",
+ )
+ map_file = map_files[0]
+ if not map_file.basename.endswith(".modulemap"):
+ fail(
+ "module_header_maps[%r]: expected a .modulemap file, got %s" % (name, map_file.basename),
+ attr = "module_header_maps",
+ )
+ entries.append((name, map_file))
+ return entries
+
# Returns a list of (Artifact, Label) tuples. Each tuple represents an input source
# file and the label of the rule that generates it (or the label of the source file itself if it
# is an input file).
@@ -1155,6 +1179,7 @@ cc_helper = struct(
local_defines = _local_defines,
get_srcs = _get_srcs,
get_cpp_module_interfaces = _get_cpp_module_interfaces,
+ get_module_header_map_entries = _get_module_header_map_entries,
get_private_hdrs = _get_private_hdrs,
get_public_hdrs = _get_public_hdrs,
is_code_coverage_enabled = _is_code_coverage_enabled,
diff --git a/cc/private/cc_common.bzl b/cc/private/cc_common.bzl
index 8db674306..1d0cd9eda 100644
--- a/cc/private/cc_common.bzl
+++ b/cc/private/cc_common.bzl
@@ -489,6 +489,7 @@ def _compile(
purpose = _UNBOUND,
separate_module_headers = _UNBOUND,
module_interfaces = _UNBOUND,
+ module_header_map_entries = _UNBOUND,
non_compilation_additional_inputs = _UNBOUND):
if module_map != _UNBOUND or \
additional_module_maps != _UNBOUND or \
@@ -501,6 +502,7 @@ def _compile(
implementation_compilation_contexts != _UNBOUND or \
separate_module_headers != _UNBOUND or \
module_interfaces != _UNBOUND or \
+ module_header_map_entries != _UNBOUND or \
non_compilation_additional_inputs != _UNBOUND:
_cc_internal.check_private_api(allowlist = _PRIVATE_STARLARKIFICATION_ALLOWLIST)
@@ -524,6 +526,8 @@ def _compile(
separate_module_headers = []
if module_interfaces == _UNBOUND:
module_interfaces = []
+ if module_header_map_entries == _UNBOUND:
+ module_header_map_entries = []
if non_compilation_additional_inputs == _UNBOUND:
non_compilation_additional_inputs = []
@@ -538,6 +542,7 @@ def _compile(
name = name,
srcs = srcs,
module_interfaces = module_interfaces,
+ module_header_map_entries = module_header_map_entries,
public_hdrs = public_hdrs,
private_hdrs = private_hdrs,
textual_hdrs = textual_hdrs,
diff --git a/cc/private/compile/compile.bzl b/cc/private/compile/compile.bzl
index d7272e1d2..8b0b21fdd 100644
--- a/cc/private/compile/compile.bzl
+++ b/cc/private/compile/compile.bzl
@@ -135,6 +135,7 @@ def compile(
purpose = None,
separate_module_headers = [],
module_interfaces = [],
+ module_header_map_entries = [],
non_compilation_additional_inputs = [],
progress_message_prefix = None):
"""Should be used for C++ compilation.
@@ -385,6 +386,7 @@ def compile(
auxiliary_fdo_inputs = auxiliary_fdo_inputs,
fdo_build_variables = fdo_build_variables,
progress_message_prefix = progress_message_prefix,
+ module_header_map_entries = module_header_map_entries,
)
compilation_outputs_dict["lto_compilation_context"] = create_lto_compilation_context(
@@ -637,6 +639,77 @@ def _create_gen_modmap_action(
toolchain = None,
)
+def _create_header_map_modmap_actions(
+ *,
+ actions,
+ action_construction_context,
+ cc_toolchain,
+ configuration,
+ label,
+ use_pic,
+ module_header_map_entries,
+ modules_info_file):
+ """Creates a shared modmap for all module_header_maps on this target."""
+ if use_pic:
+ output_name_base_for_modmap = _cc_internal.get_artifact_name_for_category(
+ cc_toolchain = cc_toolchain,
+ category = artifact_category.PIC_FILE,
+ output_name = label.name,
+ )
+ else:
+ output_name_base_for_modmap = label.name
+ modmap_output_name = output_name_base_for_modmap + "_header_maps"
+ modmap_file = _get_compile_output_file(
+ action_construction_context,
+ label,
+ configuration = configuration,
+ output_name = _cc_internal.get_artifact_name_for_category(
+ cc_toolchain = cc_toolchain,
+ category = artifact_category.CPP_MODULES_MODMAP,
+ output_name = modmap_output_name,
+ ),
+ )
+ modmap_input_file = _get_compile_output_file(
+ action_construction_context,
+ label,
+ configuration = configuration,
+ output_name = _cc_internal.get_artifact_name_for_category(
+ cc_toolchain = cc_toolchain,
+ category = artifact_category.CPP_MODULES_MODMAP_INPUT,
+ output_name = modmap_output_name,
+ ),
+ )
+ ddi_file = _get_compile_output_file(
+ action_construction_context,
+ label,
+ configuration = configuration,
+ output_name = _cc_internal.get_artifact_name_for_category(
+ cc_toolchain = cc_toolchain,
+ category = artifact_category.CPP_MODULES_DDI,
+ output_name = modmap_output_name,
+ ),
+ )
+ actions.write(
+ ddi_file,
+ json.encode({
+ "rules": [{
+ "requires": [
+ {"logical-name": name}
+ for name, _ in module_header_map_entries
+ ],
+ }],
+ }),
+ )
+ _create_gen_modmap_action(
+ actions = actions,
+ cc_toolchain = cc_toolchain,
+ ddi_file = ddi_file,
+ modules_info_file = modules_info_file,
+ modmap_file = modmap_file,
+ modmap_input_file = modmap_input_file,
+ )
+ return modmap_file, modmap_input_file
+
# buildifier: disable=unused-variable
def _create_cc_compile_actions_with_cpp20_module_helper(
*,
@@ -668,7 +741,8 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
use_pic,
enable_dotd_files,
output_name_map,
- progress_message_prefix):
+ progress_message_prefix,
+ module_header_map_entries = []):
direct_module_files = []
source_to_module_file_map = {}
source_to_ddi_file_map = {}
@@ -752,6 +826,10 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
)
source_to_ddi_file_map[source_artifact] = ddi_file
+ shared_header_map_modmap_file = None
+ shared_header_map_modmap_input_file = None
+ header_map_input_files = []
+
_create_aggregate_ddi_action(
actions = actions,
cc_toolchain = cc_toolchain,
@@ -760,6 +838,18 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
transitive_modules_info_files = cc_compilation_context._pic_modules_info_files if use_pic else cc_compilation_context._modules_info_files,
modules_info_file = modules_info_file,
)
+ if module_header_map_entries:
+ header_map_input_files = [map_file for _, map_file in module_header_map_entries]
+ shared_header_map_modmap_file, shared_header_map_modmap_input_file = _create_header_map_modmap_actions(
+ actions = actions,
+ action_construction_context = action_construction_context,
+ cc_toolchain = cc_toolchain,
+ configuration = configuration,
+ label = label,
+ use_pic = use_pic,
+ module_header_map_entries = module_header_map_entries,
+ modules_info_file = modules_info_file,
+ )
compiled_basenames = set()
transitive_module_files = cc_compilation_context._pic_module_files if use_pic else cc_compilation_context._module_files
for cpp_source in module_interfaces_sources.values():
@@ -876,9 +966,17 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
additional_build_variables = {}
modmap_file = None
modmap_input_file = None
+ source_additional_compilation_inputs = additional_compilation_inputs
+ is_cc_source = "." + source_artifact.extension in extensions.CC_SOURCE
# Only C++ compilation unit will be compiled with C++20 Modules.
- if "." + source_artifact.extension in extensions.CC_SOURCE:
+ if is_cc_source and shared_header_map_modmap_file != None:
+ modmap_file = shared_header_map_modmap_file
+ modmap_input_file = shared_header_map_modmap_input_file
+ additional_build_variables["cpp_module_modmap_file"] = modmap_file
+ additional_build_variables["cpp_module_header_map_files"] = header_map_input_files
+ source_additional_compilation_inputs = additional_compilation_inputs + header_map_input_files
+ elif is_cc_source:
modmap_file = _get_compile_output_file(
action_construction_context,
label,
@@ -933,26 +1031,6 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
ddi_output_name = ddi_output_name,
progress_message_prefix = progress_message_prefix,
)
- modmap_file = _get_compile_output_file(
- action_construction_context,
- label,
- configuration = configuration,
- output_name = _cc_internal.get_artifact_name_for_category(
- cc_toolchain = cc_toolchain,
- category = artifact_category.CPP_MODULES_MODMAP,
- output_name = output_name_base,
- ),
- )
- modmap_input_file = _get_compile_output_file(
- action_construction_context,
- label,
- configuration = configuration,
- output_name = _cc_internal.get_artifact_name_for_category(
- cc_toolchain = cc_toolchain,
- category = artifact_category.CPP_MODULES_MODMAP_INPUT,
- output_name = output_name_base,
- ),
- )
additional_build_variables["cpp_module_modmap_file"] = modmap_file
_create_gen_modmap_action(
actions = actions,
@@ -989,7 +1067,7 @@ def _create_cc_compile_actions_with_cpp20_module_helper(
bitcode_output = bitcode_output,
fdo_context = fdo_context,
auxiliary_fdo_inputs = auxiliary_fdo_inputs,
- additional_compilation_inputs = additional_compilation_inputs,
+ additional_compilation_inputs = source_additional_compilation_inputs,
additional_include_scanning_roots = additional_include_scanning_roots,
use_pic = use_pic,
enable_dotd_files = enable_dotd_files,
@@ -1030,7 +1108,8 @@ def _create_cc_compile_actions_with_cpp20_module(
auxiliary_fdo_inputs,
fdo_build_variables,
enable_dotd_files,
- progress_message_prefix):
+ progress_message_prefix,
+ module_header_map_entries = []):
"""Constructs the C++ compiler actions with C++20 modules support.
"""
output_name_prefix_dir = _cc_internal.compute_output_name_prefix_dir(configuration = configuration, purpose = purpose)
@@ -1071,6 +1150,7 @@ def _create_cc_compile_actions_with_cpp20_module(
enable_dotd_files = enable_dotd_files,
output_name_map = output_name_map,
progress_message_prefix = progress_message_prefix,
+ module_header_map_entries = module_header_map_entries,
)
def _create_cc_compile_actions(
@@ -1103,7 +1183,8 @@ def _create_cc_compile_actions(
common_compile_build_variables,
auxiliary_fdo_inputs,
fdo_build_variables,
- progress_message_prefix):
+ progress_message_prefix,
+ module_header_map_entries = []):
"""Constructs the C++ compiler actions.
It generally creates one action for every specified source
@@ -1148,6 +1229,7 @@ def _create_cc_compile_actions(
fdo_build_variables = fdo_build_variables,
enable_dotd_files = enable_dotd_files,
progress_message_prefix = progress_message_prefix,
+ module_header_map_entries = module_header_map_entries,
)
return
diff --git a/cc/private/rules_impl/attrs.bzl b/cc/private/rules_impl/attrs.bzl
index 9ca8fae9e..3621355e1 100644
--- a/cc/private/rules_impl/attrs.bzl
+++ b/cc/private/rules_impl/attrs.bzl
@@ -102,6 +102,21 @@ C++ Standard has no restriction about module interface file extension
--experimental_cpp_modules.
#include to import for the same module.
+
+Keys are logical module names (for example a for
+export module a;). Values are .modulemap files.
All C++ sources on this target compiled with cpp_modules enabled
+receive every module listed here via a generated modmap, without per-source
+dependency scanning.
Requires --experimental_cpp_modules and the
+cpp_modules toolchain feature.