Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion cc/common/cc_helper.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions cc/private/cc_common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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)

Expand All @@ -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 = []

Expand All @@ -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,
Expand Down
132 changes: 107 additions & 25 deletions cc/private/compile/compile.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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(
*,
Expand Down Expand Up @@ -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 = {}
Expand Down Expand Up @@ -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,
Expand All @@ -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():
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
15 changes: 15 additions & 0 deletions cc/private/rules_impl/attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@ C++ Standard has no restriction about module interface file extension
<code>--experimental_cpp_modules</code>.</p>
""",
),
"module_header_maps": attr.string_keyed_label_dict(
allow_files = [".modulemap"],
doc = """
Maps C++20 named module names to Clang module map files that redirect legacy
<code>#include</code> to <code>import</code> for the same module.

<p>Keys are logical module names (for example <code>a</code> for
<code>export module a;</code>). Values are <code>.modulemap</code> files.</p>
<p>All C++ sources on this target compiled with <code>cpp_modules</code> enabled
receive every module listed here via a generated modmap, without per-source
dependency scanning.</p>
<p>Requires <code>--experimental_cpp_modules</code> and the
<code>cpp_modules</code> toolchain feature.</p>
""",
),
"data": attr.label_list(
allow_files = True,
flags = ["SKIP_CONSTRAINTS_OVERRIDE"],
Expand Down
1 change: 1 addition & 0 deletions cc/private/rules_impl/cc_binary_impl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ def cc_binary_impl(ctx, additional_linkopts, force_linkstatic = False):
public_hdrs = cc_helper.get_public_hdrs(ctx),
srcs = cc_helper.get_srcs(ctx),
module_interfaces = cc_helper.get_cpp_module_interfaces(ctx),
module_header_map_entries = cc_helper.get_module_header_map_entries(ctx),
compilation_contexts = compilation_context_deps,
code_coverage_enabled = cc_helper.is_code_coverage_enabled(ctx = ctx),
additional_inputs = ctx.files.additional_compiler_inputs,
Expand Down
1 change: 1 addition & 0 deletions cc/private/rules_impl/cc_library_impl.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def _cc_library_impl(ctx):
purpose = "cc_library-compile",
srcs = cc_helper.get_srcs(ctx),
module_interfaces = cc_helper.get_cpp_module_interfaces(ctx),
module_header_map_entries = cc_helper.get_module_header_map_entries(ctx),
private_hdrs = cc_helper.get_private_hdrs(ctx),
public_hdrs = cc_helper.get_public_hdrs(ctx),
code_coverage_enabled = cc_helper.is_code_coverage_enabled(ctx),
Expand Down
19 changes: 19 additions & 0 deletions cc/private/toolchain/unix_cc_toolchain_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1865,6 +1865,24 @@ def _impl(ctx):
enabled = True,
)

cpp_module_header_map_files_feature = feature(
name = "cpp_module_header_map_files",
flag_sets = [
flag_set(
actions = [
ACTION_NAMES.cpp_compile,
],
flag_groups = [
flag_group(
iterate_over = "cpp_module_header_map_files",
flags = ["-fmodule-map-file=%{cpp_module_header_map_files}"],
),
],
),
],
enabled = True,
)

no_dotd_file_feature = feature(name = "no_dotd_file")

skip_virtual_includes_feature = feature(name = "skip_virtual_includes")
Expand All @@ -1883,6 +1901,7 @@ def _impl(ctx):
cpp_modules_feature,
cpp_module_modmap_file_feature,
cpp20_module_compile_flags_feature,
cpp_module_header_map_files_feature,
dependency_file_feature,
serialized_diagnostics_file_feature,
random_seed_feature,
Expand Down