Skip to content

Commit 6522472

Browse files
benjaminpcopybara-github
authored andcommitted
Wire up include scanning.
Enable Bazel to use C/C++ include scanning if the --experimental_include_scanning flag is given. Include scanning can improve performance and incrementality by decreasing the size of compilation input trees. This change gives the community an opportunity to try it out. Include scanning must not be enabled by default because limitations of the builtin include parser can break builds. Closes #13871. PiperOrigin-RevId: 414955626
1 parent fc4d9d6 commit 6522472

File tree

17 files changed

+213
-72
lines changed

17 files changed

+213
-72
lines changed

src/main/java/com/google/devtools/build/lib/bazel/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ java_library(
139139
"//src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions",
140140
"//src/main/java/com/google/devtools/build/lib/buildeventservice",
141141
"//src/main/java/com/google/devtools/build/lib/dynamic",
142+
"//src/main/java/com/google/devtools/build/lib/includescanning",
142143
"//src/main/java/com/google/devtools/build/lib/metrics:memory-use-recorder",
143144
"//src/main/java/com/google/devtools/build/lib/metrics:metrics_module",
144145
"//src/main/java/com/google/devtools/build/lib/network:noop_connectivity",

src/main/java/com/google/devtools/build/lib/bazel/Bazel.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.common.collect.ImmutableMap;
1818
import com.google.devtools.build.lib.analysis.BlazeVersionInfo;
1919
import com.google.devtools.build.lib.bazel.repository.starlark.StarlarkRepositoryDebugModule;
20+
import com.google.devtools.build.lib.includescanning.IncludeScanningModule;
2021
import com.google.devtools.build.lib.runtime.BlazeModule;
2122
import com.google.devtools.build.lib.runtime.BlazeRuntime;
2223
import java.io.IOException;
@@ -77,7 +78,8 @@ public final class Bazel {
7778
com.google.devtools.build.lib.metrics.PostGCMemoryUseRecorder.GcAfterBuildModule.class,
7879
com.google.devtools.build.lib.packages.metrics.PackageMetricsModule.class,
7980
com.google.devtools.build.lib.metrics.MetricsModule.class,
80-
BazelBuiltinCommandModule.class);
81+
BazelBuiltinCommandModule.class,
82+
IncludeScanningModule.class);
8183

8284
public static void main(String[] args) {
8385
BlazeVersionInfo.setBuildInfo(tryGetBuildInfo());

src/main/java/com/google/devtools/build/lib/bazel/rules/CcRules.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void init(ConfiguredRuleClassProvider.Builder builder) {
8080
builder.addRuleDefinition(new BazelCppRuleClasses.CcLibraryBaseRule());
8181
builder.addRuleDefinition(new BazelCcLibraryRule());
8282
builder.addRuleDefinition(new BazelCcImportRule());
83-
builder.addRuleDefinition(new CcIncludeScanningRule());
83+
builder.addRuleDefinition(new CcIncludeScanningRule(/* addGrepIncludes= */ false));
8484
builder.addRuleDefinition(new FdoProfileRule());
8585
builder.addRuleDefinition(new FdoPrefetchHintsRule());
8686
builder.addRuleDefinition(new CcLinkingRule());

src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ java_library(
4242
name = "bazel_cpp_semantics",
4343
srcs = ["BazelCppSemantics.java"],
4444
deps = [
45+
"//src/main/java/com/google/devtools/build/lib/actions:artifacts",
4546
"//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
4647
"//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
4748
"//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_collection",

src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package com.google.devtools.build.lib.bazel.rules.cpp;
1616

1717
import com.google.common.collect.ImmutableSet;
18+
import com.google.devtools.build.lib.actions.Artifact;
1819
import com.google.devtools.build.lib.analysis.RuleContext;
1920
import com.google.devtools.build.lib.analysis.RuleErrorConsumer;
2021
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
@@ -31,6 +32,7 @@
3132
import com.google.devtools.build.lib.rules.cpp.CppCompileActionBuilder;
3233
import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
3334
import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
35+
import com.google.devtools.build.lib.rules.cpp.CppFileTypes;
3436
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
3537

3638
/** C++ compilation semantics. */
@@ -78,15 +80,20 @@ public void finalizeCompileActionBuilder(
7880
RuleErrorConsumer ruleErrorConsumer) {
7981
CcToolchainProvider toolchain = actionBuilder.getToolchain();
8082
if (language == Language.CPP) {
83+
CppConfiguration cppConfig = configuration.getFragment(CppConfiguration.class);
84+
Artifact sourceFile = actionBuilder.getSourceFile();
8185
actionBuilder
8286
.addTransitiveMandatoryInputs(
83-
configuration.getFragment(CppConfiguration.class).useSpecificToolFiles()
84-
&& !actionBuilder.getSourceFile().isTreeArtifact()
87+
cppConfig.useSpecificToolFiles() && !actionBuilder.getSourceFile().isTreeArtifact()
8588
? (actionBuilder.getActionName().equals(CppActionNames.ASSEMBLE)
8689
? toolchain.getAsFiles()
8790
: toolchain.getCompilerFiles())
8891
: toolchain.getAllFiles())
89-
.setShouldScanIncludes(false);
92+
.setShouldScanIncludes(
93+
cppConfig.experimentalIncludeScanning()
94+
&& featureConfiguration.getRequestedFeatures().contains("cc_include_scanning")
95+
&& !sourceFile.isFileType(CppFileTypes.ASSEMBLER)
96+
&& !sourceFile.isFileType(CppFileTypes.CPP_MODULE));
9097
} else {
9198
actionBuilder
9299
.addTransitiveMandatoryInputs(toolchain.getAllFilesIncludingLibc())
@@ -110,7 +117,7 @@ public HeadersCheckingMode determineStarlarkHeadersCheckingMode(
110117

111118
@Override
112119
public boolean allowIncludeScanning() {
113-
return false;
120+
return true;
114121
}
115122

116123
@Override

src/main/java/com/google/devtools/build/lib/includescanning/IncludeParser.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ public String toString() {
138138
}
139139

140140
/** {@link SkyValue} encapsulating the source-state-dependent part of {@link Hints}. */
141-
public static class HintsRules implements SkyValue {
141+
public static final class HintsRules implements SkyValue {
142+
static final HintsRules EMPTY = new HintsRules(ImmutableList.of());
142143
private final ImmutableList<Rule> rules;
143144

144145
private HintsRules(ImmutableList<Rule> rules) {

src/main/java/com/google/devtools/build/lib/includescanning/IncludeScanningModule.java

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@
3333
import com.google.devtools.build.lib.buildtool.BuildRequest;
3434
import com.google.devtools.build.lib.concurrent.ExecutorUtil;
3535
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadHostile;
36+
import com.google.devtools.build.lib.events.Event;
3637
import com.google.devtools.build.lib.exec.ExecutorBuilder;
3738
import com.google.devtools.build.lib.exec.ExecutorLifecycleListener;
3839
import com.google.devtools.build.lib.exec.ModuleActionContextRegistry;
3940
import com.google.devtools.build.lib.includescanning.IncludeParser.Inclusion;
4041
import com.google.devtools.build.lib.rules.cpp.CppIncludeExtractionContext;
4142
import com.google.devtools.build.lib.rules.cpp.CppIncludeScanningContext;
43+
import com.google.devtools.build.lib.rules.cpp.CppOptions;
4244
import com.google.devtools.build.lib.rules.cpp.IncludeScanner.IncludeScanningHeaderData;
4345
import com.google.devtools.build.lib.rules.cpp.SwigIncludeScanningContext;
4446
import com.google.devtools.build.lib.runtime.BlazeModule;
@@ -66,6 +68,7 @@
6668
import java.util.concurrent.ThreadPoolExecutor;
6769
import java.util.concurrent.TimeUnit;
6870
import java.util.function.Supplier;
71+
import javax.annotation.Nullable;
6972

7073
/**
7174
* Module that provides implementations of {@link CppIncludeExtractionContext},
@@ -74,16 +77,14 @@
7477
public class IncludeScanningModule extends BlazeModule {
7578
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
7679

77-
private static final PathFragment INCLUDE_HINTS_FILENAME =
78-
PathFragment.create("tools/cpp/INCLUDE_HINTS");
79-
8080
private final MutableSupplier<SpawnIncludeScanner> spawnIncludeScannerSupplier =
8181
new MutableSupplier<>();
8282
private final MutableSupplier<ArtifactFactory> artifactFactory = new MutableSupplier<>();
8383
private IncludeScannerLifecycleManager lifecycleManager;
8484

85+
@Nullable
8586
protected PathFragment getIncludeHintsFilename() {
86-
return INCLUDE_HINTS_FILENAME;
87+
return null;
8788
}
8889

8990
@Override
@@ -106,7 +107,8 @@ public void registerActionContexts(
106107
@ThreadHostile
107108
public void executorInit(CommandEnvironment env, BuildRequest request, ExecutorBuilder builder) {
108109
lifecycleManager =
109-
new IncludeScannerLifecycleManager(env, request, spawnIncludeScannerSupplier);
110+
new IncludeScannerLifecycleManager(
111+
env, request, spawnIncludeScannerSupplier, getIncludeHintsFilename() != null);
110112
builder.addExecutorLifecycleListener(lifecycleManager);
111113
}
112114

@@ -119,6 +121,11 @@ public Iterable<Class<? extends OptionsBase>> getCommandOptions(Command command)
119121

120122
@Override
121123
public void beforeCommand(CommandEnvironment env) {
124+
CppOptions cppOptions = env.getOptions().getOptions(CppOptions.class);
125+
if (cppOptions != null && cppOptions.experimentalIncludeScanning) {
126+
env.getReporter()
127+
.handle(Event.warn("Include scanning enabled. This feature is unsupported."));
128+
}
122129
artifactFactory.set(env.getSkyframeBuildView().getArtifactFactory());
123130
}
124131

@@ -137,10 +144,13 @@ public void workspaceInit(
137144

138145
@VisibleForTesting
139146
public static ImmutableMap<SkyFunctionName, SkyFunction> getSkyFunctions(
140-
PathFragment includeHintsFile) {
141-
return ImmutableMap.of(
142-
IncludeScanningSkyFunctions.INCLUDE_HINTS,
143-
new IncludeHintsFunction(includeHintsFile));
147+
@Nullable PathFragment includeHintsFile) {
148+
ImmutableMap.Builder<SkyFunctionName, SkyFunction> skyFunctions = ImmutableMap.builder();
149+
if (includeHintsFile != null) {
150+
skyFunctions.put(
151+
IncludeScanningSkyFunctions.INCLUDE_HINTS, new IncludeHintsFunction(includeHintsFile));
152+
}
153+
return skyFunctions.buildOrThrow();
144154
}
145155

146156
/**
@@ -225,6 +235,7 @@ public void extractSwigIncludes(
225235
private static final class IncludeScannerLifecycleManager implements ExecutorLifecycleListener {
226236
private final CommandEnvironment env;
227237
private final IncludeScanningOptions options;
238+
private final boolean useIncludeHints;
228239

229240
private final Supplier<SpawnIncludeScanner> spawnScannerSupplier;
230241
private IncludeScannerSupplier includeScannerSupplier;
@@ -233,9 +244,11 @@ private static final class IncludeScannerLifecycleManager implements ExecutorLif
233244
IncludeScannerLifecycleManager(
234245
CommandEnvironment env,
235246
BuildRequest buildRequest,
236-
MutableSupplier<SpawnIncludeScanner> spawnScannerSupplier) {
247+
MutableSupplier<SpawnIncludeScanner> spawnScannerSupplier,
248+
boolean useIncludeHints) {
237249
this.env = env;
238250
this.options = buildRequest.getOptions(IncludeScanningOptions.class);
251+
this.useIncludeHints = useIncludeHints;
239252

240253
spawnScannerSupplier.set(
241254
new SpawnIncludeScanner(
@@ -258,26 +271,32 @@ private SwigIncludeScanningContextImpl getSwigActionContext() {
258271
public void executionPhaseStarting(
259272
ActionGraph actionGraph, Supplier<ImmutableSet<Artifact>> topLevelArtifacts)
260273
throws AbruptExitException, InterruptedException {
261-
try {
262-
includeScannerSupplier.init(
263-
new IncludeParser(
264-
new IncludeParser.Hints(
265-
(IncludeParser.HintsRules)
266-
env.getSkyframeExecutor()
267-
.evaluateSkyKeyForExecutionSetup(
268-
env.getReporter(), IncludeHintsFunction.INCLUDE_HINTS_KEY),
269-
env.getSkyframeBuildView().getArtifactFactory())));
270-
} catch (ExecException e) {
271-
throw new AbruptExitException(
272-
DetailedExitCode.of(
273-
FailureDetail.newBuilder()
274-
.setMessage("could not initialize include hints: " + e.getMessage())
275-
.setIncludeScanning(
276-
IncludeScanning.newBuilder()
277-
.setCode(IncludeScanning.Code.INITIALIZE_INCLUDE_HINTS_ERROR))
278-
.build()),
279-
e);
274+
IncludeParser.HintsRules hintsRules;
275+
if (useIncludeHints) {
276+
try {
277+
hintsRules =
278+
(IncludeParser.HintsRules)
279+
env.getSkyframeExecutor()
280+
.evaluateSkyKeyForExecutionSetup(
281+
env.getReporter(), IncludeHintsFunction.INCLUDE_HINTS_KEY);
282+
} catch (ExecException e) {
283+
throw new AbruptExitException(
284+
DetailedExitCode.of(
285+
FailureDetail.newBuilder()
286+
.setMessage("could not initialize include hints: " + e.getMessage())
287+
.setIncludeScanning(
288+
IncludeScanning.newBuilder()
289+
.setCode(IncludeScanning.Code.INITIALIZE_INCLUDE_HINTS_ERROR))
290+
.build()),
291+
e);
292+
}
293+
} else {
294+
hintsRules = IncludeParser.HintsRules.EMPTY;
280295
}
296+
includeScannerSupplier.init(
297+
new IncludeParser(
298+
new IncludeParser.Hints(
299+
hintsRules, env.getSkyframeBuildView().getArtifactFactory())));
281300
}
282301

283302
@Override

src/main/java/com/google/devtools/build/lib/includescanning/LegacyIncludeScanner.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,19 +537,13 @@ private Artifact locateRelative(
537537
}
538538
ArtifactRoot root = includer.getRoot();
539539
Artifact sourceArtifact =
540-
artifactFactory.resolveSourceArtifactWithAncestor(
541-
name, parentDirectory, root, RepositoryName.MAIN);
540+
artifactFactory.resolveSourceArtifactWithAncestor(name, parent, root, RepositoryName.MAIN);
542541
if (sourceArtifact == null) {
543542
// If the name had up-level references, this path may not be under any package. Otherwise,
544543
// we must have gotten an artifact, since it should be under the same package as the
545544
// including artifact.
546545
Preconditions.checkState(
547-
name.containsUplevelReferences(),
548-
"%s %s %s %s",
549-
name,
550-
parentDirectory,
551-
rootRelativePath,
552-
root);
546+
name.containsUplevelReferences(), "%s %s %s %s", name, parent, rootRelativePath, root);
553547
}
554548
return sourceArtifact;
555549
}

src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,10 @@ public boolean generateLlvmLCov() {
837837
return cppOptions.generateLlvmLcov;
838838
}
839839

840+
public boolean experimentalIncludeScanning() {
841+
return cppOptions.experimentalIncludeScanning;
842+
}
843+
840844
public boolean objcShouldScanIncludes() {
841845
return cppOptions.objcScanIncludes;
842846
}

src/main/java/com/google/devtools/build/lib/rules/cpp/CppOptions.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,25 @@ public Label getPropellerOptimizeLabel() {
10051005
help = "If enabled, write CppCompileAction exposed action.args to parameters file.")
10061006
public boolean useArgsParamsFile;
10071007

1008+
@Option(
1009+
name = "experimental_unsupported_and_brittle_include_scanning",
1010+
defaultValue = "false",
1011+
documentationCategory = OptionDocumentationCategory.BUILD_TIME_OPTIMIZATION,
1012+
effectTags = {
1013+
OptionEffectTag.LOADING_AND_ANALYSIS,
1014+
OptionEffectTag.EXECUTION,
1015+
OptionEffectTag.CHANGES_INPUTS
1016+
},
1017+
help =
1018+
"Whether to narrow inputs to C/C++ compilation by parsing #include lines from input"
1019+
+ " files. This can improve performance and incrementality by decreasing the size of"
1020+
+ " compilation input trees. However, it can also break builds because the include"
1021+
+ " scanner does not fully implement C preprocessor semantics. In particular, it does"
1022+
+ " not understand dynamic #include directives and ignores preprocessor conditional"
1023+
+ " logic. Use at your own risk. Any issues relating to this flag that are filed will"
1024+
+ " be closed.")
1025+
public boolean experimentalIncludeScanning;
1026+
10081027
@Option(
10091028
name = "experimental_objc_include_scanning",
10101029
defaultValue = "false",
@@ -1175,6 +1194,7 @@ public FragmentOptions getHost() {
11751194
host.parseHeadersSkippedIfCorrespondingSrcsFound = parseHeadersSkippedIfCorrespondingSrcsFound;
11761195
host.strictSystemIncludes = strictSystemIncludes;
11771196
host.useArgsParamsFile = useArgsParamsFile;
1197+
host.experimentalIncludeScanning = experimentalIncludeScanning;
11781198

11791199
// Save host options for further use.
11801200
host.hostCoptList = hostCoptList;

0 commit comments

Comments
 (0)