diff options
author | Googler <noreply@google.com> | 2016-04-18 14:00:44 +0000 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2016-04-19 09:40:29 +0000 |
commit | 98aacfe14b7f5a79614efa26c30e3b7dea5fab91 (patch) | |
tree | 6fa402654ac5f14b1b53aea324e575da11e14c84 /src | |
parent | 812227f8733a2b6679cd9b06cea26fe238afb8dd (diff) |
Add the option to have non-interface dependencies. This can greatly speed up
builds with C++ modules as modules can be built without waiting on dependencies
that are only required for the module's implementation.
--
MOS_MIGRATED_REVID=120119435
Diffstat (limited to 'src')
5 files changed, 89 insertions, 29 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java index 9f8f98d46c..dc7f035353 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java @@ -201,7 +201,8 @@ public final class CcLibraryHelper { @Nullable private Pattern nocopts; private final List<String> linkopts = new ArrayList<>(); private final Set<String> defines = new LinkedHashSet<>(); - private final List<TransitiveInfoCollection> deps = new ArrayList<>(); + private final List<TransitiveInfoCollection> implementationDeps = new ArrayList<>(); + private final List<TransitiveInfoCollection> interfaceDeps = new ArrayList<>(); private final List<Artifact> linkstamps = new ArrayList<>(); private final List<Artifact> prerequisites = new ArrayList<>(); private final List<PathFragment> looseIncludeDirs = new ArrayList<>(); @@ -513,7 +514,26 @@ public final class CcLibraryHelper { Preconditions.checkArgument(dep.getConfiguration() == null || configuration.equalsOrIsSupersetOf(dep.getConfiguration()), "dep " + dep.getLabel() + " has a different config than " + ruleContext.getLabel()); - this.deps.add(dep); + this.implementationDeps.add(dep); + this.interfaceDeps.add(dep); + } + return this; + } + + /** + * Similar to @{link addDeps}, but adds the given targets as implementation dependencies. + * Implementation dependencies are required to actually build a target, but are not required to + * build the target's interface, e.g. header module. Thus, implementation dependencies are always + * a superset of interface dependencies. Whatever is required to build the interface is also + * required to build the implementation. + */ + public CcLibraryHelper addImplementationDeps(Iterable<? extends TransitiveInfoCollection> deps) { + for (TransitiveInfoCollection dep : deps) { + Preconditions.checkArgument( + dep.getConfiguration() == null + || configuration.equalsOrIsSupersetOf(dep.getConfiguration()), + "dep " + dep.getLabel() + " has a different config than " + ruleContext.getLabel()); + this.implementationDeps.add(dep); } return this; } @@ -727,15 +747,26 @@ public final class CcLibraryHelper { if (checkDepsGenerateCpp) { for (LanguageDependentFragment dep : - AnalysisUtils.getProviders(deps, LanguageDependentFragment.class)) { + AnalysisUtils.getProviders(implementationDeps, LanguageDependentFragment.class)) { LanguageDependentFragment.Checker.depSupportsLanguage( ruleContext, dep, CppRuleClasses.LANGUAGE); } } CppModel model = initializeCppModel(); - CppCompilationContext cppCompilationContext = initializeCppCompilationContext(model); + CppCompilationContext cppCompilationContext = + initializeCppCompilationContext(model, /*forInterface=*/ false); model.setContext(cppCompilationContext); + + // If we actually have different interface deps, we need a separate compilation context + // for the interface. Otherwise, we can just re-use the normal cppCompilationContext. + CppCompilationContext interfaceCompilationContext = cppCompilationContext; + // As implemenationDeps is a superset of interfaceDeps, comparing the size proves equality. + if (implementationDeps.size() != interfaceDeps.size()) { + interfaceCompilationContext = initializeCppCompilationContext(model, /*forInterface=*/ true); + } + model.setInterfaceContext(interfaceCompilationContext); + boolean compileHeaderModules = featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES); Preconditions.checkState( !compileHeaderModules || cppCompilationContext.getCppModuleMap() != null, @@ -781,7 +812,8 @@ public final class CcLibraryHelper { .build(); } - DwoArtifactsCollector dwoArtifacts = DwoArtifactsCollector.transitiveCollector(ccOutputs, deps); + DwoArtifactsCollector dwoArtifacts = + DwoArtifactsCollector.transitiveCollector(ccOutputs, implementationDeps); Runfiles cppStaticRunfiles = collectCppRunfiles(ccLinkingOutputs, true); Runfiles cppSharedRunfiles = collectCppRunfiles(ccLinkingOutputs, false); @@ -791,7 +823,7 @@ public final class CcLibraryHelper { new LinkedHashMap<>(); providers.put(CppRunfilesProvider.class, new CppRunfilesProvider(cppStaticRunfiles, cppSharedRunfiles)); - providers.put(CppCompilationContext.class, cppCompilationContext); + providers.put(CppCompilationContext.class, interfaceCompilationContext); providers.put(CppDebugFileProvider.class, new CppDebugFileProvider( dwoArtifacts.getDwoArtifacts(), dwoArtifacts.getPicDwoArtifacts())); providers.put(TransitiveLipoInfoProvider.class, collectTransitiveLipoInfo(ccOutputs)); @@ -855,9 +887,10 @@ public final class CcLibraryHelper { /** * Create context for cc compile action from generated inputs. */ - private CppCompilationContext initializeCppCompilationContext(CppModel model) { + private CppCompilationContext initializeCppCompilationContext( + CppModel model, boolean forInterface) { CppCompilationContext.Builder contextBuilder = - new CppCompilationContext.Builder(ruleContext); + new CppCompilationContext.Builder(ruleContext, forInterface); // Setup the include path; local include directories come before those inherited from deps or // from the toolchain; in case of aliasing (same include file found on different entries), @@ -881,7 +914,8 @@ public final class CcLibraryHelper { } contextBuilder.mergeDependentContexts( - AnalysisUtils.getProviders(deps, CppCompilationContext.class)); + AnalysisUtils.getProviders( + forInterface ? interfaceDeps : implementationDeps, CppCompilationContext.class)); CppHelper.mergeToolchainDependentContext(ruleContext, contextBuilder); // But defines come after those inherited from deps. @@ -952,13 +986,13 @@ public final class CcLibraryHelper { * Creates context for cc compile action from generated inputs. */ public CppCompilationContext initializeCppCompilationContext() { - return initializeCppCompilationContext(initializeCppModel()); + return initializeCppCompilationContext(initializeCppModel(), /*forInterface=*/ false); } private Iterable<CppModuleMap> collectModuleMaps() { // Cpp module maps may be null for some rules. We filter the nulls out at the end. List<CppModuleMap> result = new ArrayList<>(); - Iterables.addAll(result, Iterables.transform(deps, CPP_DEPS_TO_MODULES)); + Iterables.addAll(result, Iterables.transform(interfaceDeps, CPP_DEPS_TO_MODULES)); if (ruleContext.getRule().getAttributeDefinition(":stl") != null) { CppCompilationContext stl = ruleContext.getPrerequisite(":stl", Mode.TARGET, CppCompilationContext.class); @@ -990,7 +1024,7 @@ public final class CcLibraryHelper { } for (TransitiveLipoInfoProvider dep : - AnalysisUtils.getProviders(deps, TransitiveLipoInfoProvider.class)) { + AnalysisUtils.getProviders(implementationDeps, TransitiveLipoInfoProvider.class)) { scannableBuilder.addTransitive(dep.getTransitiveIncludeScannables()); } @@ -1004,8 +1038,8 @@ public final class CcLibraryHelper { private Runfiles collectCppRunfiles( CcLinkingOutputs ccLinkingOutputs, boolean linkingStatically) { Runfiles.Builder builder = new Runfiles.Builder(ruleContext.getWorkspaceName()); - builder.addTargets(deps, RunfilesProvider.DEFAULT_RUNFILES); - builder.addTargets(deps, CppRunfilesProvider.runfilesFunction(linkingStatically)); + builder.addTargets(implementationDeps, RunfilesProvider.DEFAULT_RUNFILES); + builder.addTargets(implementationDeps, CppRunfilesProvider.runfilesFunction(linkingStatically)); // Add the shared libraries to the runfiles. builder.addArtifacts(ccLinkingOutputs.getLibrariesForRunfiles(linkingStatically)); return builder.build(); @@ -1019,7 +1053,7 @@ public final class CcLibraryHelper { protected void collect(CcLinkParams.Builder builder, boolean linkingStatically, boolean linkShared) { builder.addLinkstamps(linkstamps, cppCompilationContext); - builder.addTransitiveTargets(deps, + builder.addTransitiveTargets(implementationDeps, CcLinkParamsProvider.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS); if (!neverlink) { builder.addLibraries(ccLinkingOutputs.getPreferredLibraries(linkingStatically, @@ -1033,8 +1067,8 @@ public final class CcLibraryHelper { private NestedSet<LinkerInput> collectNativeCcLibraries(CcLinkingOutputs ccLinkingOutputs) { NestedSetBuilder<LinkerInput> result = NestedSetBuilder.linkOrder(); result.addAll(ccLinkingOutputs.getDynamicLibraries()); - for (CcNativeLibraryProvider dep : AnalysisUtils.getProviders( - deps, CcNativeLibraryProvider.class)) { + for (CcNativeLibraryProvider dep : + AnalysisUtils.getProviders(implementationDeps, CcNativeLibraryProvider.class)) { result.addTransitive(dep.getTransitiveCcNativeLibraries()); } @@ -1051,7 +1085,7 @@ public final class CcLibraryHelper { NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder(); for (CcExecutionDynamicLibrariesProvider dep : - AnalysisUtils.getProviders(deps, CcExecutionDynamicLibrariesProvider.class)) { + AnalysisUtils.getProviders(implementationDeps, CcExecutionDynamicLibrariesProvider.class)) { builder.addTransitive(dep.getExecutionDynamicLibraryArtifacts()); } return builder.isEmpty() diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java index b7bf3f48cc..41124222bb 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java @@ -999,7 +999,7 @@ public class CcToolchainFeatures implements Serializable { /** * @return whether the given {@code feature} is enabled. */ - boolean isEnabled(String feature) { + public boolean isEnabled(String feature) { return enabledFeatureNames.contains(feature); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java index 4afd941c0b..af3bbba851 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java @@ -614,7 +614,7 @@ public final class CppCompilationContext implements TransitiveInfoProvider { * Builder class for {@link CppCompilationContext}. */ public static class Builder { - private String purpose = "cpp_compilation_prerequisites"; + private String purpose; private final Set<Artifact> compilationPrerequisites = new LinkedHashSet<>(); private final Set<PathFragment> includeDirs = new LinkedHashSet<>(); private final Set<PathFragment> quoteIncludeDirs = new LinkedHashSet<>(); @@ -654,7 +654,17 @@ public final class CppCompilationContext implements TransitiveInfoProvider { * Creates a new builder for a {@link CppCompilationContext} instance. */ public Builder(RuleContext ruleContext) { + this(ruleContext, /*forInterface=*/ false); + } + + /** + * Creates a new builder for a {@link CppCompilationContext} instance. + * + * @param forInterface if true, this context is designated for the compilation of an interface. + */ + public Builder(RuleContext ruleContext, boolean forInterface) { this.ruleContext = ruleContext; + this.purpose = forInterface ? "cpp_interface_prerequisites" : "cpp_compilation_prerequisites"; } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java index 0132191c30..579e8492d8 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java @@ -61,6 +61,7 @@ public final class CppModel { // compile model private CppCompilationContext context; + private CppCompilationContext interfaceContext; private final List<Pair<Artifact, Label>> sourceFiles = new ArrayList<>(); private final List<String> copts = new ArrayList<>(); private final List<PathFragment> additionalIncludes = new ArrayList<>(); @@ -121,6 +122,15 @@ public final class CppModel { this.context = context; return this; } + + /** + * Sets the compilation context, i.e. include directories and allowed header files inclusions, for + * the compilation of this model's interface, e.g. header module. + */ + public CppModel setInterfaceContext(CppCompilationContext context) { + this.interfaceContext = context; + return this; + } /** * Adds a single source file to be compiled. Note that this should only be called for primary @@ -279,9 +289,10 @@ public final class CppModel { * Returns a {@code CppCompileActionBuilder} with the common fields for a C++ compile action * being initialized. */ - private CppCompileActionBuilder initializeCompileAction(Artifact sourceArtifact, - Label sourceLabel) { - CppCompileActionBuilder builder = createCompileActionBuilder(sourceArtifact, sourceLabel); + private CppCompileActionBuilder initializeCompileAction( + Artifact sourceArtifact, Label sourceLabel, boolean forInterface) { + CppCompileActionBuilder builder = + createCompileActionBuilder(sourceArtifact, sourceLabel, forInterface); if (nocopts != null) { builder.addNocopts(nocopts); } @@ -395,7 +406,8 @@ public final class CppModel { Artifact moduleMapArtifact = context.getCppModuleMap().getArtifact(); Label moduleMapLabel = Label.parseAbsoluteUnchecked(context.getCppModuleMap().getName()); PathFragment outputName = getObjectOutputPath(moduleMapArtifact, objectDir); - CppCompileActionBuilder builder = initializeCompileAction(moduleMapArtifact, moduleMapLabel); + CppCompileActionBuilder builder = + initializeCompileAction(moduleMapArtifact, moduleMapLabel, /*forInterface=*/ true); // A header module compile action is just like a normal compile action, but: // - the compiled source file is the module map @@ -408,7 +420,8 @@ public final class CppModel { Artifact sourceArtifact = source.getFirst(); Label sourceLabel = source.getSecond(); PathFragment outputName = getObjectOutputPath(sourceArtifact, objectDir); - CppCompileActionBuilder builder = initializeCompileAction(sourceArtifact, sourceLabel); + CppCompileActionBuilder builder = + initializeCompileAction(sourceArtifact, sourceLabel, /*forInterface=*/ false); if (CppFileTypes.CPP_HEADER.matches(source.first.getExecPath())) { createHeaderAction(outputName, result, env, builder); @@ -734,13 +747,11 @@ public final class CppModel { * crosstool inputs, output and dotd file names, compilation context and copts. */ private CppCompileActionBuilder createCompileActionBuilder( - Artifact source, Label label) { + Artifact source, Label label, boolean forInterface) { CppCompileActionBuilder builder = new CppCompileActionBuilder( ruleContext, source, label); - builder - .setContext(context) - .addCopts(copts); + builder.setContext(forInterface ? interfaceContext : context).addCopts(copts); return builder; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java index 77a9719923..2d71008e23 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java @@ -88,6 +88,11 @@ public class CppRuleClasses { * A string constant for the preprocess_headers feature. */ public static final String PREPROCESS_HEADERS = "preprocess_headers"; + + /** + * A string constant for the disable_pbh feature. + */ + public static final String DISABLE_PBH = "disable_pbh"; /** * A string constant for the module_maps feature; this is a precondition to the layering_check and |