Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1/5] support C++20 Modules, add module_interfaces attr #22425

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cac4929
support C++20 Modules, add module_interfaces attr
PikachuHyA May 17, 2024
ba28f7c
remove tag DIRECT_COMPILE_TIME_INPUT
PikachuHyA May 24, 2024
829c581
set module_interfaces default value to _UNBOUND and check it
PikachuHyA May 24, 2024
65c8973
remove feature cpp20_module in getLegacyFeatures
PikachuHyA May 24, 2024
c92a23e
add JavaDoc for cpp20_module features
PikachuHyA May 24, 2024
a849792
use plural, cpp20_modules
PikachuHyA May 24, 2024
354a993
move moduleInterfacesUnchecked next to separateModuleHeadersObject
PikachuHyA May 24, 2024
dabccb4
rename get_module_interfaces to get_cpp20module_interfaces
PikachuHyA May 24, 2024
d997c6e
add cpp20_modules feature to toolchains
PikachuHyA May 24, 2024
3beb4c8
introduce a new flag --experimental_cpp20_modules
PikachuHyA May 24, 2024
f82951d
add test
PikachuHyA May 27, 2024
b729f86
add note to module_interfaces attr
PikachuHyA May 27, 2024
4cc08d9
remove duplicate check on module_interfaces
PikachuHyA May 27, 2024
0144b35
update doc to experimental_cpp20_modules option
PikachuHyA Jun 3, 2024
b5dbeb9
move semantics.check_can_module_interfaces into cc_helper.check_cpp20…
PikachuHyA Jun 3, 2024
c4953f9
update doc: change `For now usage` to `The use`
PikachuHyA Jun 3, 2024
93e772a
refactor _calculate_artifact_label_map
PikachuHyA Jun 3, 2024
8955664
remove createRuleClassProvider
PikachuHyA Jun 3, 2024
4db47fb
add setupBasicRulesWithModules
PikachuHyA Jun 3, 2024
41586ee
fix weird indentation, make cc_library line up with opening
PikachuHyA Jun 3, 2024
94cc23e
unroll assert loop
PikachuHyA Jun 3, 2024
b1be8ee
change test pattern
PikachuHyA Jun 3, 2024
defa8c6
add more assert
PikachuHyA Jun 3, 2024
244e980
special handle for module_interfaces due to file extension
PikachuHyA Jun 3, 2024
ec14d57
add testSameModuleInterfacesFileTwice
PikachuHyA Jun 3, 2024
4d80f99
split testcase in Cpp20ModulesConfiguredTargetTest
PikachuHyA Jun 4, 2024
2cebc32
add copyright
PikachuHyA Jun 4, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public CcCompilationContext getCcCompilationContext() {
private final List<PathFragment> additionalExportedHeaders = new ArrayList<>();
private final List<CppModuleMap> additionalCppModuleMaps = new ArrayList<>();
private final LinkedHashMap<Artifact, CppSource> compilationUnitSources = new LinkedHashMap<>();
private final LinkedHashMap<Artifact, CppSource> moduleInterfaceSources = new LinkedHashMap<>();
private ImmutableList<String> copts = ImmutableList.of();
private CoptsFilter coptsFilter = CoptsFilter.alwaysPasses();
private final Set<String> defines = new LinkedHashSet<>();
Expand Down Expand Up @@ -518,6 +519,27 @@ public CcCompilationHelper addSources(Artifact... sources) {
return addSources(Arrays.asList(sources));
}

@CanIgnoreReturnValue
public CcCompilationHelper addModuleInterfaceSources(Collection<Artifact> sources) {
for (Artifact source : sources) {
addModuleInterfaceSource(source, label);
}
return this;
}

@CanIgnoreReturnValue
public CcCompilationHelper addModuleInterfaceSources(Iterable<Pair<Artifact, Label>> sources) {
for (Pair<Artifact, Label> source : sources) {
addModuleInterfaceSource(source.first, source.second);
}
return this;
}

private void addModuleInterfaceSource(Artifact source, Label label) {
Preconditions.checkNotNull(featureConfiguration);
moduleInterfaceSources.put(source, CppSource.create(source, label, CppSource.Type.SOURCE));
}

/** Add the corresponding files as non-header, non-source input files. */
@CanIgnoreReturnValue
public CcCompilationHelper addAdditionalInputs(Collection<Artifact> inputs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,7 @@ public Tuple compile(
Object purposeObject,
Object coptsFilterObject,
Object separateModuleHeadersObject,
Sequence<?> moduleInterfacesUnchecked, // <Artifact> expected
Object nonCompilationAdditionalInputsObject,
StarlarkThread thread)
throws EvalException, InterruptedException {
Expand Down Expand Up @@ -2143,23 +2144,28 @@ public Tuple compile(
configuration.getFragment(CppConfiguration.class)));
boolean tuple =
(!sourcesUnchecked.isEmpty() && sourcesUnchecked.get(0) instanceof Tuple)
|| (!moduleInterfacesUnchecked.isEmpty() && moduleInterfacesUnchecked.get(0) instanceof Tuple)
|| (!publicHeadersUnchecked.isEmpty() && publicHeadersUnchecked.get(0) instanceof Tuple)
|| (!privateHeadersUnchecked.isEmpty()
&& privateHeadersUnchecked.get(0) instanceof Tuple);
if (tuple) {
ImmutableList<Pair<Artifact, Label>> sources = convertSequenceTupleToPair(sourcesUnchecked);
ImmutableList<Pair<Artifact, Label>> moduleInterfaces = convertSequenceTupleToPair(moduleInterfacesUnchecked);
ImmutableList<Pair<Artifact, Label>> publicHeaders =
convertSequenceTupleToPair(publicHeadersUnchecked);
ImmutableList<Pair<Artifact, Label>> privateHeaders =
convertSequenceTupleToPair(privateHeadersUnchecked);
helper.addPublicHeaders(publicHeaders).addPrivateHeaders(privateHeaders).addSources(sources);
helper.addPublicHeaders(publicHeaders).addPrivateHeaders(privateHeaders).addSources(sources)
.addModuleInterfaceSources(moduleInterfaces);
} else {
List<Artifact> sources = Sequence.cast(sourcesUnchecked, Artifact.class, "srcs");
List<Artifact> moduleInterfaces = Sequence.cast(moduleInterfacesUnchecked, Artifact.class, "module_interfaces");
List<Artifact> publicHeaders =
Sequence.cast(publicHeadersUnchecked, Artifact.class, "public_hdrs");
List<Artifact> privateHeaders =
Sequence.cast(privateHeadersUnchecked, Artifact.class, "private_hdrs");
helper.addPublicHeaders(publicHeaders).addPrivateHeaders(privateHeaders).addSources(sources);
helper.addPublicHeaders(publicHeaders).addPrivateHeaders(privateHeaders).addSources(sources)
.addModuleInterfaceSources(moduleInterfaces);
}

List<String> includes =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -886,10 +886,24 @@ public boolean experimentalCcImplementationDepsForStarlark(StarlarkThread thread
return experimentalCcImplementationDeps();
}

@StarlarkMethod(
name = "experimental_cpp20_modules",
documented = false,
useStarlarkThread = true)
public boolean experimentalCpp20ModulesForStarlark(StarlarkThread thread)
throws EvalException {
CcModule.checkPrivateStarlarkificationAllowlist(thread);
return experimentalCpp20Modules();
}

public boolean experimentalCcImplementationDeps() {
return cppOptions.experimentalCcImplementationDeps;
}

public boolean experimentalCpp20Modules() {
return cppOptions.experimentalCpp20Modules;
}

public boolean getExperimentalCppCompileResourcesEstimation() {
return cppOptions.experimentalCppCompileResourcesEstimation;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,24 @@ public Label getMemProfProfileLabel() {
help = "If enabled, cc_library targets can use attribute `implementation_deps`.")
public boolean experimentalCcImplementationDeps;

@Option(
name = "experimental_cpp20_modules",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
effectTags = {
OptionEffectTag.LOADING_AND_ANALYSIS,
OptionEffectTag.EXECUTION,
OptionEffectTag.CHANGES_INPUTS
},
metadataTags = {OptionMetadataTag.EXPERIMENTAL},
help =
"Enables experimental C++20 modules support. "
+ "Use it with `module_interfaces` attribute on `cc_binary` and `cc_library`."
+ "While the support is behind the experimental flag, "
+ "there are no guarantees about incompatible changes to it or even keeping the support in the future. "
+ "Consider those risks when using it.")
public boolean experimentalCpp20Modules;

@Option(
name = "experimental_link_static_libraries_once",
defaultValue = "true",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ public static ToolchainTypeRequirement ccToolchainTypeRequirement(RuleDefinition
*/
public static final String MODULE_MAPS = "module_maps";

/**
* A string constant for the cpp20_modules feature.
*/
public static final String CPP20_MODULES = "cpp20_modules";

/**
* A string constant for the random_seed feature. This is used by gcc and Clangfor the
* randomization of symbol names that are in the anonymous namespace but have external linkage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,14 @@ default void compilerFlagExists() {}
named = true,
allowedTypes = {@ParamType(type = Sequence.class)},
defaultValue = "unbound"),
@Param(
name = "module_interfaces",
doc =
"The list of module interfaces source files to be compiled."
+ "Note: this is an experimental feature, only enabled with --experimental_cpp20_modules",
positional = false,
named = true,
defaultValue = "unbound"),
@Param(
name = "non_compilation_additional_inputs",
positional = false,
Expand Down Expand Up @@ -405,6 +413,7 @@ Tuple compile(
Object purposeObject,
Object coptsFilterObject,
Object separateModuleHeadersObject,
Sequence<?> moduleInterfacesUnchecked, // <Artifact> expected
Object nonCompilationAdditionalInputsObject,
StarlarkThread thread)
throws EvalException, InterruptedException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ bazel_fragments["CppOptions"] = fragment(
"//command_line_option:target libcTop label",
"//command_line_option:experimental_link_static_libraries_once",
"//command_line_option:experimental_cc_implementation_deps",
"//command_line_option:experimental_cpp20_modules",
"//command_line_option:start_end_lib",
"//command_line_option:experimental_inmemory_dotd_files",
"//command_line_option:incompatible_disable_legacy_cc_provider",
Expand Down
17 changes: 17 additions & 0 deletions src/main/starlark/builtins_bzl/common/cc/attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,23 @@ using the C/C++ compiler.
</p>
""",
),
"module_interfaces": attr.label_list(
allow_files = True,
comius marked this conversation as resolved.
Show resolved Hide resolved
doc = """
The list of files are regarded as C++20 Modules Interface.

<p>
C++ Standard has no restriction about module interface file extension
<ul>
<li>Clang use cppm </li>
<li>GCC can use any source file extension </li>
<li>MSVC use ixx </li>
</ul>
</p>
<p>The use is guarded by the flag
<code>--experimental_cpp20_modules</code>.</p>
""",
),
"data": attr.label_list(
allow_files = True,
flags = ["SKIP_CONSTRAINTS_OVERRIDE"],
Expand Down
4 changes: 4 additions & 0 deletions src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,9 @@ def cc_binary_impl(ctx, additional_linkopts, force_linkstatic = False):
requested_features = features,
unsupported_features = disabled_features,
)

cc_helper.check_cpp20_modules(ctx, feature_configuration)

all_deps = ctx.attr.deps + semantics.get_cc_runtimes(ctx, _is_link_shared(ctx))
compilation_context_deps = [dep[CcInfo].compilation_context for dep in all_deps if CcInfo in dep]

Expand All @@ -507,6 +510,7 @@ def cc_binary_impl(ctx, additional_linkopts, force_linkstatic = False):
public_hdrs = cc_helper.get_public_hdrs(ctx),
copts_filter = cc_helper.copts_filter(ctx, additional_make_variable_substitutions),
srcs = cc_helper.get_srcs(ctx),
module_interfaces = cc_helper.get_cpp20module_interfaces(ctx),
compilation_contexts = compilation_context_deps,
code_coverage_enabled = cc_helper.is_code_coverage_enabled(ctx = ctx),
)
Expand Down
7 changes: 6 additions & 1 deletion src/main/starlark/builtins_bzl/common/cc/cc_common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ def _compile(
purpose = _UNBOUND,
copts_filter = _UNBOUND,
separate_module_headers = _UNBOUND,
module_interfaces = _UNBOUND,
non_compilation_additional_inputs = _UNBOUND):
if module_map != _UNBOUND or \
additional_module_maps != _UNBOUND or \
Expand All @@ -699,6 +700,7 @@ def _compile(
implementation_compilation_contexts != _UNBOUND or \
copts_filter != _UNBOUND or \
separate_module_headers != _UNBOUND or \
module_interfaces != _UNBOUND or \
non_compilation_additional_inputs != _UNBOUND:
cc_common_internal.check_private_api(allowlist = _PRIVATE_STARLARKIFICATION_ALLOWLIST)

Expand All @@ -724,10 +726,12 @@ def _compile(
copts_filter = None
if separate_module_headers == _UNBOUND:
separate_module_headers = []
if module_interfaces == _UNBOUND:
module_interfaces = []
if non_compilation_additional_inputs == _UNBOUND:
non_compilation_additional_inputs = []

has_tuple = _check_all_sources_contain_tuples_or_none_of_them([srcs, private_hdrs, public_hdrs])
has_tuple = _check_all_sources_contain_tuples_or_none_of_them([srcs, module_interfaces, private_hdrs, public_hdrs])
if has_tuple:
cc_common_internal.check_private_api(allowlist = _PRIVATE_STARLARKIFICATION_ALLOWLIST)

Expand All @@ -737,6 +741,7 @@ def _compile(
cc_toolchain = cc_toolchain,
name = name,
srcs = srcs,
module_interfaces = module_interfaces,
public_hdrs = public_hdrs,
private_hdrs = private_hdrs,
textual_hdrs = textual_hdrs,
Expand Down
52 changes: 38 additions & 14 deletions src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -944,26 +944,37 @@ def _map_to_list(m):
result.append((k, v))
return result

# 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).
def _get_srcs(ctx):
if not hasattr(ctx.attr, "srcs"):
return []
def _calculate_artifact_label_map(attr_list, attr_name):
"""
Converts a label_list attribute into a list of (Artifact, Label) tuples.

# "srcs" attribute is a LABEL_LIST in cc_rules, which might also contain files.
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).
"""
artifact_label_map = {}
for src in ctx.attr.srcs:
if DefaultInfo in src:
for artifact in src[DefaultInfo].files.to_list():
for attr in attr_list:
if DefaultInfo in attr:
for artifact in attr[DefaultInfo].files.to_list():
if "." + artifact.extension not in CC_HEADER:
old_label = artifact_label_map.get(artifact, None)
artifact_label_map[artifact] = src.label
if old_label != None and not _are_labels_equal(old_label, src.label) and "." + artifact.extension in CC_AND_OBJC:
artifact_label_map[artifact] = attr.label
if old_label != None and not _are_labels_equal(old_label, attr.label) and ("." + artifact.extension in CC_AND_OBJC or attr_name == "module_interfaces"):
fail(
"Artifact '{}' is duplicated (through '{}' and '{}')".format(artifact, old_label, src),
attr = "srcs",
"Artifact '{}' is duplicated (through '{}' and '{}')".format(artifact, old_label, attr),
attr = attr_name,
)
return artifact_label_map

def _get_srcs(ctx):
if not hasattr(ctx.attr, "srcs"):
return []
artifact_label_map = _calculate_artifact_label_map(ctx.attr.srcs, "srcs")
return _map_to_list(artifact_label_map)

def _get_cpp20module_interfaces(ctx):
if not hasattr(ctx.attr, "module_interfaces"):
return []
artifact_label_map = _calculate_artifact_label_map(ctx.attr.module_interfaces, "module_interfaces")
return _map_to_list(artifact_label_map)

# Returns a list of (Artifact, Label) tuples. Each tuple represents an input source
Expand Down Expand Up @@ -1176,6 +1187,17 @@ def _should_use_pic(ctx, cc_toolchain, feature_configuration):
)
)

def _check_cpp20_modules(ctx, feature_configuration):
if len(ctx.files.module_interfaces) == 0:
return
if not ctx.fragments.cpp.experimental_cpp20_modules():
fail("requires --experimental_cpp20_modules", attr = "module_interfaces")
if not cc_common.is_enabled(
feature_configuration = feature_configuration,
feature_name = "cpp20_modules",
):
fail("to use C++20 Modules, the feature cpp20_modules must be enabled")

cc_helper = struct(
CPP_TOOLCHAIN_TYPE = _CPP_TOOLCHAIN_TYPE,
merge_cc_debug_contexts = _merge_cc_debug_contexts,
Expand Down Expand Up @@ -1225,6 +1247,7 @@ cc_helper = struct(
get_local_defines_for_runfiles_lookup = _get_local_defines_for_runfiles_lookup,
are_labels_equal = _are_labels_equal,
get_srcs = _get_srcs,
get_cpp20module_interfaces = _get_cpp20module_interfaces,
get_private_hdrs = _get_private_hdrs,
get_public_hdrs = _get_public_hdrs,
report_invalid_options = _report_invalid_options,
Expand All @@ -1242,4 +1265,5 @@ cc_helper = struct(
package_source_root = _package_source_root,
tokenize = _tokenize,
should_use_pic = _should_use_pic,
check_cpp20_modules = _check_cpp20_modules,
)
3 changes: 3 additions & 0 deletions src/main/starlark/builtins_bzl/common/cc/cc_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def _cc_library_impl(ctx):
unsupported_features = ctx.disabled_features,
)

cc_helper.check_cpp20_modules(ctx, feature_configuration)

precompiled_files = cc_helper.build_precompiled_files(ctx = ctx)

semantics.validate_attributes(ctx = ctx)
Expand All @@ -63,6 +65,7 @@ def _cc_library_impl(ctx):
copts_filter = cc_helper.copts_filter(ctx, additional_make_variable_substitutions),
purpose = "cc_library-compile",
srcs = cc_helper.get_srcs(ctx),
module_interfaces = cc_helper.get_cpp20module_interfaces(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
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ load(
)

_FEATURE_NAMES = struct(
cpp20_modules = "cpp20_modules",
generate_pdb_file = "generate_pdb_file",
no_legacy_features = "no_legacy_features",
do_not_split_linking_cmdline = "do_not_split_linking_cmdline",
Expand Down Expand Up @@ -120,6 +121,11 @@ _FEATURE_NAMES = struct(
generate_linkmap = "generate_linkmap",
)

_cpp20_modules_feature = feature(
name = _FEATURE_NAMES.cpp20_modules,
enabled = False,
)

_no_copts_tokenization_feature = feature(name = _FEATURE_NAMES.no_copts_tokenization)

_disable_pbh_feature = feature(name = _FEATURE_NAMES.disable_pbh)
Expand Down Expand Up @@ -1330,6 +1336,7 @@ _generate_linkmap_feature = feature(
)

_feature_name_to_feature = {
_FEATURE_NAMES.cpp20_modules: _cpp20_modules_feature,
_FEATURE_NAMES.no_legacy_features: _no_legacy_features_feature,
_FEATURE_NAMES.do_not_split_linking_cmdline: _do_not_split_linking_cmdline_feature,
_FEATURE_NAMES.supports_dynamic_linker: _supports_dynamic_linker_feature,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7176,7 +7176,13 @@ def _impl(ctx):
else:
include_system_dirs_feature = None

cpp20_modules_feature = feature(
name = "cpp20_modules",
enabled = False,
)

features = [
cpp20_modules_feature,
default_compile_flags_feature,
default_link_flags_feature,
no_legacy_features_feature,
Expand Down
Loading
Loading