diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java index 2ad53edc424a74..98f7e45252cb0a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.io.Files; import com.google.devtools.build.lib.actions.ActionRegistry; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact; @@ -53,6 +54,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -1368,8 +1370,15 @@ private CcCompilationOutputs createCcCompileActions() throws RuleErrorException } outputNameMap = calculateOutputNameMapByType(compilationUnitSources, outputNamePrefixDir); + Set compiledBasenames = new HashSet<>(); for (CppSource source : compilationUnitSources.values()) { Artifact sourceArtifact = source.getSource(); + + // Headers compilations will be created in the loop below. + if (!sourceArtifact.isTreeArtifact() && source.getType() == CppSource.Type.HEADER) { + continue; + } + Label sourceLabel = source.getLabel(); CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact); @@ -1385,33 +1394,27 @@ private CcCompilationOutputs createCcCompileActions() throws RuleErrorException String outputName = outputNameMap.get(sourceArtifact); if (!sourceArtifact.isTreeArtifact()) { - switch (source.getType()) { - case HEADER: - createHeaderAction(sourceLabel, outputName, result, builder); - break; - default: - createSourceAction( - sourceLabel, - outputName, - result, - sourceArtifact, - builder, - // TODO(plf): Continue removing CLIF logic from C++. Follow up changes would include - // refactoring CppSource.Type and ArtifactCategory to be classes instead of enums - // that could be instantiated with arbitrary values. - source.getType() == CppSource.Type.CLIF_INPUT_PROTO - ? ArtifactCategory.CLIF_OUTPUT_PROTO - : ArtifactCategory.OBJECT_FILE, - ccCompilationContext.getCppModuleMap(), - /* addObject= */ true, - isCodeCoverageEnabled, - // The source action does not generate dwo when it has bitcode - // output (since it isn't generating a native object with debug - // info). In that case the LtoBackendAction will generate the dwo. - ccToolchain.shouldCreatePerObjectDebugInfo(featureConfiguration, cppConfiguration), - bitcodeOutput); - break; - } + compiledBasenames.add(Files.getNameWithoutExtension(sourceArtifact.getExecPathString())); + createSourceAction( + sourceLabel, + outputName, + result, + sourceArtifact, + builder, + // TODO(plf): Continue removing CLIF logic from C++. Follow up changes would include + // refactoring CppSource.Type and ArtifactCategory to be classes instead of enums + // that could be instantiated with arbitrary values. + source.getType() == CppSource.Type.CLIF_INPUT_PROTO + ? ArtifactCategory.CLIF_OUTPUT_PROTO + : ArtifactCategory.OBJECT_FILE, + ccCompilationContext.getCppModuleMap(), + /* addObject= */ true, + isCodeCoverageEnabled, + // The source action does not generate dwo when it has bitcode + // output (since it isn't generating a native object with debug + // info). In that case the LtoBackendAction will generate the dwo. + ccToolchain.shouldCreatePerObjectDebugInfo(featureConfiguration, cppConfiguration), + bitcodeOutput); } else { switch (source.getType()) { case HEADER: @@ -1455,6 +1458,26 @@ private CcCompilationOutputs createCcCompileActions() throws RuleErrorException } } } + for (CppSource source : compilationUnitSources.values()) { + Artifact artifact = source.getSource(); + if (source.getType() != CppSource.Type.HEADER || artifact.isTreeArtifact()) { + // These are already handled above. + continue; + } + if (cppConfiguration.getParseHeadersSkippedIfCorrespondingSrcsFound() + && compiledBasenames.contains( + Files.getNameWithoutExtension(artifact.getExecPathString()))) { + continue; + } + CppCompileActionBuilder builder = initializeCompileAction(artifact); + builder + .setSemantics(semantics) + .addMandatoryInputs(additionalCompilationInputs) + .addAdditionalIncludeScanningRoots(additionalIncludeScanningRoots); + + String outputName = outputNameMap.get(artifact); + createHeaderAction(source.getLabel(), outputName, result, builder); + } return result.build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java index e240fdfffe387e..cc50ad69cd545d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java @@ -445,6 +445,10 @@ public boolean getParseHeadersVerifiesModules() { return cppOptions.parseHeadersVerifiesModules; } + public boolean getParseHeadersSkippedIfCorrespondingSrcsFound() { + return cppOptions.parseHeadersSkippedIfCorrespondingSrcsFound; + } + public boolean getUseInterfaceSharedLibraries() { return cppOptions.useInterfaceSharedObjects; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java index a3dc59d0e9ce41..781fffe061636e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java @@ -742,6 +742,16 @@ public Label getPropellerOptimizeLabel() { ) public boolean parseHeadersVerifiesModules; + @Option( + name = "experimental_parse_headers_skipped_if_corresponding_srcs_found", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.BUILD_TIME_OPTIMIZATION, + effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS, OptionEffectTag.AFFECTS_OUTPUTS}, + help = + "If enabled, the parse_headers feature does not create a separate header compile action " + + "if a source with the same basename is found in the same target.") + public boolean parseHeadersSkippedIfCorrespondingSrcsFound; + @Option( name = "experimental_omitfp", defaultValue = "false", @@ -1142,6 +1152,7 @@ public FragmentOptions getHost() { host.disableNoCopts = disableNoCopts; host.loadCcRulesFromBzl = loadCcRulesFromBzl; host.validateTopLevelHeaderInclusions = validateTopLevelHeaderInclusions; + host.parseHeadersSkippedIfCorrespondingSrcsFound = parseHeadersSkippedIfCorrespondingSrcsFound; // Save host options for further use. host.hostCoptList = hostCoptList;