aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompilationContext.java410
1 files changed, 245 insertions, 165 deletions
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 0a6e8b5248..43192b932d 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
@@ -30,6 +30,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -54,25 +55,10 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
*/
private final NestedSet<Artifact> directModuleMaps;
- /**
- * All declared headers of the current module, if compiled as a header module.
- */
- private final NestedSet<Artifact> headerModuleSrcs;
-
- /**
- * All header modules in the transitive closure of {@code topLevelHeaderModules}.
- */
- private final NestedSet<Artifact> impliedHeaderModules;
- private final NestedSet<Artifact> picImpliedHeaderModules;
-
private final NestedSet<Pair<Artifact, Artifact>> pregreppedHdrs;
-
- /**
- * All header modules in our transitive closure that are not in the transitive closure of
- * another header module in our transitive closure.
- */
- private final NestedSet<Artifact> topLevelHeaderModules;
- private final NestedSet<Artifact> picTopLevelHeaderModules;
+
+ private final ModuleInfo moduleInfo;
+ private final ModuleInfo picModuleInfo;
/**
* The module maps from all targets the current target depends on transitively.
@@ -80,8 +66,6 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
private final NestedSet<Artifact> transitiveModuleMaps;
private final CppModuleMap cppModuleMap;
- private final Artifact headerModule;
- private final Artifact picHeaderModule;
// True if this context is for a compilation that needs transitive module maps.
private final boolean provideTransitiveModuleMaps;
@@ -99,16 +83,11 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
NestedSet<PathFragment> declaredIncludeWarnDirs,
NestedSet<Artifact> declaredIncludeSrcs,
NestedSet<Pair<Artifact, Artifact>> pregreppedHdrs,
- NestedSet<Artifact> headerModuleSrcs,
- NestedSet<Artifact> topLevelHeaderModules,
- NestedSet<Artifact> picTopLevelHeaderModules,
- NestedSet<Artifact> impliedHeaderModules,
- NestedSet<Artifact> picImpliedHeaderModules,
+ ModuleInfo moduleInfo,
+ ModuleInfo picModuleInfo,
NestedSet<Artifact> transitiveModuleMaps,
NestedSet<Artifact> directModuleMaps,
CppModuleMap cppModuleMap,
- Artifact headerModule,
- Artifact picHeaderModule,
boolean provideTransitiveModuleMaps,
boolean useHeaderModules) {
Preconditions.checkNotNull(commandLineContext);
@@ -117,16 +96,11 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
this.declaredIncludeWarnDirs = declaredIncludeWarnDirs;
this.declaredIncludeSrcs = declaredIncludeSrcs;
this.directModuleMaps = directModuleMaps;
- this.headerModuleSrcs = headerModuleSrcs;
- this.impliedHeaderModules = impliedHeaderModules;
- this.picImpliedHeaderModules = picImpliedHeaderModules;
this.pregreppedHdrs = pregreppedHdrs;
- this.topLevelHeaderModules = topLevelHeaderModules;
- this.picTopLevelHeaderModules = picTopLevelHeaderModules;
+ this.moduleInfo = moduleInfo;
+ this.picModuleInfo = picModuleInfo;
this.transitiveModuleMaps = transitiveModuleMaps;
this.cppModuleMap = cppModuleMap;
- this.headerModule = headerModule;
- this.picHeaderModule = picHeaderModule;
this.provideTransitiveModuleMaps = provideTransitiveModuleMaps;
this.useHeaderModules = useHeaderModules;
this.compilationPrerequisites = compilationPrerequisites;
@@ -236,22 +210,27 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
NestedSet<Pair<Artifact, Artifact>> getPregreppedHeaders() {
return pregreppedHdrs;
}
+
+ public NestedSet<Artifact> getTransitiveModules(boolean usePic) {
+ return usePic ? picModuleInfo.transitiveModules : moduleInfo.transitiveModules;
+ }
+
+ public Set<Artifact> getTopLevelModules(boolean usePic) {
+ return usePic ? picModuleInfo.getTopLevelModules() : moduleInfo.getTopLevelModules();
+ }
+
+ public Collection<Artifact> getUsedModules(boolean usePic, Set<Artifact> usedHeaders) {
+ return usePic
+ ? picModuleInfo.getUsedModules(usedHeaders)
+ : moduleInfo.getUsedModules(usedHeaders);
+ }
/**
* Returns the immutable set of additional transitive inputs needed for
* compilation, like C++ module map artifacts.
*/
- public NestedSet<Artifact> getAdditionalInputs(boolean usePic) {
+ public NestedSet<Artifact> getAdditionalInputs() {
NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder();
- if (useHeaderModules) {
- if (usePic) {
- builder.addTransitive(picTopLevelHeaderModules);
- builder.addTransitive(picImpliedHeaderModules);
- } else {
- builder.addTransitive(topLevelHeaderModules);
- builder.addTransitive(impliedHeaderModules);
- }
- }
builder.addTransitive(directModuleMaps);
if (provideTransitiveModuleMaps) {
builder.addTransitive(transitiveModuleMaps);
@@ -259,7 +238,6 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
if (cppModuleMap != null) {
builder.add(cppModuleMap.getArtifact());
}
-
return builder.build();
}
@@ -281,23 +259,8 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
* @return all declared headers of the current module if the current target
* is compiled as a module.
*/
- protected NestedSet<Artifact> getHeaderModuleSrcs() {
- return headerModuleSrcs;
- }
-
- /**
- * @return all header modules in our transitive closure that are not in the transitive closure
- * of another header module in our transitive closure.
- */
- protected NestedSet<Artifact> getTopLevelHeaderModules(boolean usePic) {
- return usePic ? picTopLevelHeaderModules : topLevelHeaderModules;
- }
-
- /**
- * @return all header modules in the transitive closure of {@code getTopLevelHeaderModules()}.
- */
- protected NestedSet<Artifact> getImpliedHeaderModules(boolean usePic) {
- return usePic ? picImpliedHeaderModules : impliedHeaderModules;
+ protected Set<Artifact> getHeaderModuleSrcs() {
+ return moduleInfo.headerModuleSrcs;
}
/**
@@ -321,16 +284,11 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
NestedSetBuilder.<PathFragment>emptySet(Order.STABLE_ORDER),
context.declaredIncludeSrcs,
context.pregreppedHdrs,
- context.headerModuleSrcs,
- context.topLevelHeaderModules,
- context.picTopLevelHeaderModules,
- context.impliedHeaderModules,
- context.picImpliedHeaderModules,
+ context.moduleInfo,
+ context.picModuleInfo,
context.transitiveModuleMaps,
context.directModuleMaps,
context.cppModuleMap,
- context.headerModule,
- context.picHeaderModule,
context.provideTransitiveModuleMaps,
context.useHeaderModules);
}
@@ -365,6 +323,12 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
ImmutableSet.Builder<Artifact> prerequisites = ImmutableSet.builder();
prerequisites.addAll(ownerContext.compilationPrerequisites);
prerequisites.addAll(libContext.compilationPrerequisites);
+ ModuleInfo.Builder moduleInfo = new ModuleInfo.Builder();
+ moduleInfo.merge(ownerContext.moduleInfo);
+ moduleInfo.merge(libContext.moduleInfo);
+ ModuleInfo.Builder picModuleInfo = new ModuleInfo.Builder();
+ picModuleInfo.merge(ownerContext.picModuleInfo);
+ picModuleInfo.merge(libContext.picModuleInfo);
return new CppCompilationContext(
libContext.commandLineContext,
prerequisites.build(),
@@ -372,16 +336,11 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
mergeSets(ownerContext.declaredIncludeWarnDirs, libContext.declaredIncludeWarnDirs),
mergeSets(ownerContext.declaredIncludeSrcs, libContext.declaredIncludeSrcs),
mergeSets(ownerContext.pregreppedHdrs, libContext.pregreppedHdrs),
- mergeSets(ownerContext.headerModuleSrcs, libContext.headerModuleSrcs),
- mergeSets(ownerContext.topLevelHeaderModules, libContext.topLevelHeaderModules),
- mergeSets(ownerContext.picTopLevelHeaderModules, libContext.picTopLevelHeaderModules),
- mergeSets(ownerContext.impliedHeaderModules, libContext.impliedHeaderModules),
- mergeSets(ownerContext.picImpliedHeaderModules, libContext.picImpliedHeaderModules),
+ moduleInfo.build(),
+ picModuleInfo.build(),
mergeSets(ownerContext.transitiveModuleMaps, libContext.transitiveModuleMaps),
mergeSets(ownerContext.directModuleMaps, libContext.directModuleMaps),
libContext.cppModuleMap,
- libContext.headerModule,
- libContext.picHeaderModule,
libContext.provideTransitiveModuleMaps,
libContext.useHeaderModules);
}
@@ -404,20 +363,6 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
}
/**
- * @return the non-pic C++ header module of the owner.
- */
- private Artifact getHeaderModule() {
- return headerModule;
- }
-
- /**
- * @return the pic C++ header module of the owner.
- */
- private Artifact getPicHeaderModule() {
- return picHeaderModule;
- }
-
- /**
* The parts of the compilation context that influence the command line of
* compilation actions.
*/
@@ -456,24 +401,12 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
NestedSetBuilder.stableOrder();
private final NestedSetBuilder<Pair<Artifact, Artifact>> pregreppedHdrs =
NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> headerModuleSrcs =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> topLevelHeaderModules =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> picTopLevelHeaderModules =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> impliedHeaderModules =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> picImpliedHeaderModules =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> transitiveModuleMaps =
- NestedSetBuilder.stableOrder();
- private final NestedSetBuilder<Artifact> directModuleMaps =
- NestedSetBuilder.stableOrder();
+ private final ModuleInfo.Builder moduleInfo = new ModuleInfo.Builder();
+ private final ModuleInfo.Builder picModuleInfo = new ModuleInfo.Builder();
+ private final NestedSetBuilder<Artifact> transitiveModuleMaps = NestedSetBuilder.stableOrder();
+ private final NestedSetBuilder<Artifact> directModuleMaps = NestedSetBuilder.stableOrder();
private final Set<String> defines = new LinkedHashSet<>();
private CppModuleMap cppModuleMap;
- private Artifact headerModule;
- private Artifact picHeaderModule;
private boolean provideTransitiveModuleMaps = false;
private boolean useHeaderModules = false;
@@ -531,42 +464,23 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
declaredIncludeWarnDirs.addTransitive(otherContext.getDeclaredIncludeWarnDirs());
declaredIncludeSrcs.addTransitive(otherContext.getDeclaredIncludeSrcs());
pregreppedHdrs.addTransitive(otherContext.getPregreppedHeaders());
+ moduleInfo.addTransitive(otherContext.moduleInfo);
+ picModuleInfo.addTransitive(otherContext.picModuleInfo);
NestedSet<Artifact> othersTransitiveModuleMaps = otherContext.getTransitiveModuleMaps();
NestedSet<Artifact> othersDirectModuleMaps = otherContext.getDirectModuleMaps();
- NestedSet<Artifact> othersTopLevelHeaderModules =
- otherContext.getTopLevelHeaderModules(/*usePic=*/ false);
- NestedSet<Artifact> othersPicTopLevelHeaderModules =
- otherContext.getTopLevelHeaderModules(/*usePic=*/ true);
// Forward transitive information.
// The other target's transitive module maps do not include its direct module maps, so we
// add both.
transitiveModuleMaps.addTransitive(othersTransitiveModuleMaps);
transitiveModuleMaps.addTransitive(othersDirectModuleMaps);
- impliedHeaderModules.addTransitive(otherContext.getImpliedHeaderModules(/*usePic=*/ false));
- picImpliedHeaderModules.addTransitive(otherContext.getImpliedHeaderModules(/*usePic=*/ true));
- topLevelHeaderModules.addTransitive(othersTopLevelHeaderModules);
- picTopLevelHeaderModules.addTransitive(othersPicTopLevelHeaderModules);
// All module maps of direct dependencies are inputs to the current compile independently of
// the build type.
if (otherContext.getCppModuleMap() != null) {
directModuleMaps.add(otherContext.getCppModuleMap().getArtifact());
}
- if (otherContext.getHeaderModule() != null || otherContext.getPicHeaderModule() != null) {
- // If the other context is for a target that compiles a header module, that context's
- // header module becomes our top-level header module, and its top-level header modules
- // become our implied header modules.
- impliedHeaderModules.addTransitive(othersTopLevelHeaderModules);
- picImpliedHeaderModules.addTransitive(othersPicTopLevelHeaderModules);
- if (otherContext.getHeaderModule() != null) {
- topLevelHeaderModules.add(otherContext.getHeaderModule());
- }
- if (otherContext.getPicHeaderModule() != null) {
- picTopLevelHeaderModules.add(otherContext.getPicHeaderModule());
- }
- }
defines.addAll(otherContext.getDefines());
return this;
@@ -674,7 +588,8 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
public Builder addDeclaredIncludeSrc(Artifact header) {
declaredIncludeSrcs.add(header);
compilationPrerequisites.add(header);
- headerModuleSrcs.add(header);
+ moduleInfo.addHeader(header);
+ picModuleInfo.addHeader(header);
return this;
}
@@ -682,9 +597,10 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
* Adds multiple headers that have been declared in the {@code src} or {@code headers
* attribute}. The headers will also be added to the compilation prerequisites.
*/
- public Builder addDeclaredIncludeSrcs(Iterable<Artifact> declaredIncludeSrcs) {
+ public Builder addDeclaredIncludeSrcs(Collection<Artifact> declaredIncludeSrcs) {
this.declaredIncludeSrcs.addAll(declaredIncludeSrcs);
- this.headerModuleSrcs.addAll(declaredIncludeSrcs);
+ this.moduleInfo.addHeaders(declaredIncludeSrcs);
+ this.picModuleInfo.addHeaders(declaredIncludeSrcs);
return addCompilationPrerequisites(declaredIncludeSrcs);
}
@@ -726,17 +642,19 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
/**
* Sets the C++ header module in non-pic mode.
+ * @param headerModule The .pcm file generated for this library.
*/
public Builder setHeaderModule(Artifact headerModule) {
- this.headerModule = headerModule;
+ this.moduleInfo.setHeaderModule(headerModule);
return this;
}
/**
* Sets the C++ header module in pic mode.
+ * @param picHeaderModule The .pic.pcm file generated for this library.
*/
public Builder setPicHeaderModule(Artifact picHeaderModule) {
- this.picHeaderModule = picHeaderModule;
+ this.picModuleInfo.setHeaderModule(picHeaderModule);
return this;
}
@@ -768,16 +686,6 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
@VisibleForTesting // productionVisibility = Visibility.PRIVATE
public CppCompilationContext build(ActionOwner owner, MiddlemanFactory middlemanFactory) {
- // During merging we might have put header modules into topLevelHeaderModules that were
- // also in the transitive closure of a different header module; we need to filter those out.
- NestedSet<Artifact> impliedHeaderModules = this.impliedHeaderModules.build();
- NestedSet<Artifact> topLevelHeaderModules =
- filterTopLevelHeaderModules(this.topLevelHeaderModules.build(), impliedHeaderModules);
- NestedSet<Artifact> picImpliedHeaderModules = this.picImpliedHeaderModules.build();
- NestedSet<Artifact> picTopLevelHeaderModules =
- filterTopLevelHeaderModules(
- this.picTopLevelHeaderModules.build(), picImpliedHeaderModules);
-
// We don't create middlemen in LIPO collector subtree, because some target CT
// will do that instead.
Artifact prerequisiteStampFile = (ruleContext != null
@@ -798,37 +706,16 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
declaredIncludeWarnDirs.build(),
declaredIncludeSrcs.build(),
pregreppedHdrs.build(),
- headerModuleSrcs.build(),
- topLevelHeaderModules,
- picTopLevelHeaderModules,
- impliedHeaderModules,
- picImpliedHeaderModules,
+ moduleInfo.build(),
+ picModuleInfo.build(),
transitiveModuleMaps.build(),
directModuleMaps.build(),
cppModuleMap,
- headerModule,
- picHeaderModule,
provideTransitiveModuleMaps,
useHeaderModules);
}
/**
- * Filter out artifacts from {@code topLevelHeaderModuels} that are also in
- * {@code impliedHeaderModules}.
- */
- private static NestedSet<Artifact> filterTopLevelHeaderModules(
- NestedSet<Artifact> topLevelHeaderModules, NestedSet<Artifact> impliedHeaderModules) {
- NestedSetBuilder<Artifact> filtered = NestedSetBuilder.stableOrder();
- Set<Artifact> impliedHeaderModulesSet = impliedHeaderModules.toSet();
- for (Artifact artifact : topLevelHeaderModules) {
- if (!impliedHeaderModulesSet.contains(artifact)) {
- filtered.add(artifact);
- }
- }
- return filtered.build();
- }
-
- /**
* Creates a middleman for the compilation prerequisites.
*
* @return the middleman or null if there are no prerequisites
@@ -879,4 +766,197 @@ public final class CppCompilationContext implements TransitiveInfoProvider {
ruleContext.getRule().getRepository()));
}
}
+
+ /**
+ * Gathers data about the direct and transitive .pcm files belonging to this context. Can be to
+ * either gather data on PIC or on no-PIC .pcm files.
+ */
+ @Immutable
+ public static final class ModuleInfo {
+ /**
+ * The module built for this context. If null, then no module is being compiled for this
+ * context.
+ */
+ private final Artifact headerModule;
+
+ /**
+ * All header files that are compiled into this module.
+ */
+ private final ImmutableSet<Artifact> headerModuleSrcs;
+
+ /**
+ * All transitive modules that this context depends on, excluding headerModule.
+ */
+ private final NestedSet<Artifact> transitiveModules;
+
+ /**
+ * All implied modules that this context depends on, i.e. all transitiveModules, that are also
+ * a dependency of other transitiveModules.
+ */
+ private final NestedSet<Artifact> impliedModules;
+
+ /**
+ * All information about mapping transitive headers to transitive modules.
+ */
+ public final NestedSet<TransitiveModuleHeaders> transitiveModuleHeaders;
+
+ public ModuleInfo(
+ Artifact headerModule,
+ ImmutableSet<Artifact> headerModuleSrcs,
+ NestedSet<Artifact> transitiveModules,
+ NestedSet<Artifact> impliedModules,
+ NestedSet<TransitiveModuleHeaders> transitiveModuleHeaders) {
+ this.headerModule = headerModule;
+ this.headerModuleSrcs = headerModuleSrcs;
+ this.transitiveModules = transitiveModules;
+ this.impliedModules = impliedModules;
+ this.transitiveModuleHeaders = transitiveModuleHeaders;
+ }
+
+ public Set<Artifact> getTopLevelModules() {
+ Set<Artifact> impliedModules = this.impliedModules.toSet();
+ Set<Artifact> topLevelModules = new LinkedHashSet<>();
+ for (Artifact module : transitiveModules) {
+ if (!impliedModules.contains(module)) {
+ topLevelModules.add(module);
+ }
+ }
+ return topLevelModules;
+ }
+
+ public Collection<Artifact> getUsedModules(Set<Artifact> usedHeaders) {
+ Set<Artifact> result = new LinkedHashSet<>();
+ for (TransitiveModuleHeaders transitiveModule : transitiveModuleHeaders) {
+ if (result.contains(transitiveModule.module)) {
+ // If result already contains this module, we will have added it and all its
+ // transitive dependencies to result already. No need to check whether to add it again.
+ continue;
+ }
+ boolean providesUsedHeader = false;
+ for (Artifact header : transitiveModule.headers) {
+ if (usedHeaders.contains(header)) {
+ providesUsedHeader = true;
+ break;
+ }
+ }
+ if (providesUsedHeader) {
+ result.addAll(transitiveModule.transitiveModules.toCollection());
+ if (!transitiveModule.module.equals(headerModule)) {
+ // Only add the module itself if it is not the main headerModule. This is done because
+ // we don't want to pass the header module when compiling the translation unit that
+ // defines it. Due to how modules are implemented, #includes from a translation unit to
+ // the headers that it implements remain textual. Thus, adding this header module as a
+ // dependency would only prolong the build without any possible benefit.
+ result.add(transitiveModule.module);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Builder class for {@link ModuleInfo}.
+ */
+ public static class Builder {
+ private Artifact headerModule = null;
+ private Set<Artifact> headerModuleSrcs = new LinkedHashSet<>();
+ private NestedSetBuilder<Artifact> transitiveModules = NestedSetBuilder.stableOrder();
+ private NestedSetBuilder<Artifact> impliedModules = NestedSetBuilder.stableOrder();
+ private NestedSetBuilder<TransitiveModuleHeaders> transitiveModuleHeaders =
+ NestedSetBuilder.stableOrder();
+
+ public Builder setHeaderModule(Artifact headerModule) {
+ this.headerModule = headerModule;
+ return this;
+ }
+
+ public Builder addHeaders(Collection<Artifact> headers) {
+ this.headerModuleSrcs.addAll(headers);
+ return this;
+ }
+
+ public Builder addHeader(Artifact header) {
+ this.headerModuleSrcs.add(header);
+ return this;
+ }
+
+ /**
+ * Merges a {@link ModuleInfo} into this one. In contrast to addTransitive, this doesn't add
+ * the dependent module to transitiveModules, but just merges the transitive sets. The main
+ * usage is to merge multiple {@link ModuleInfo} instances for Lipo.
+ */
+ public Builder merge(ModuleInfo other) {
+ if (headerModule == null) {
+ headerModule = other.headerModule;
+ }
+ headerModuleSrcs.addAll(other.headerModuleSrcs);
+ transitiveModules.addTransitive(other.transitiveModules);
+ impliedModules.addTransitive(other.impliedModules);
+ transitiveModuleHeaders.addTransitive(other.transitiveModuleHeaders);
+ return this;
+ }
+
+ /**
+ * Adds the {@link ModuleInfo} of a dependency and builds up the transitive data structures.
+ */
+ public Builder addTransitive(ModuleInfo moduleInfo) {
+ if (moduleInfo.headerModule != null) {
+ transitiveModules.add(moduleInfo.headerModule);
+ impliedModules.addTransitive(moduleInfo.transitiveModules);
+ } else {
+ impliedModules.addTransitive(moduleInfo.impliedModules);
+ }
+ transitiveModules.addTransitive(moduleInfo.transitiveModules);
+ impliedModules.addTransitive(moduleInfo.impliedModules);
+ transitiveModuleHeaders.addTransitive(moduleInfo.transitiveModuleHeaders);
+ return this;
+ }
+
+ public ModuleInfo build() {
+ ImmutableSet<Artifact> headerModuleSrcs = ImmutableSet.copyOf(this.headerModuleSrcs);
+ NestedSet<Artifact> transitiveModules = this.transitiveModules.build();
+ if (headerModule != null) {
+ transitiveModuleHeaders.add(
+ new TransitiveModuleHeaders(headerModule, headerModuleSrcs, transitiveModules));
+ }
+ return new ModuleInfo(
+ headerModule,
+ headerModuleSrcs,
+ transitiveModules,
+ impliedModules.build(),
+ transitiveModuleHeaders.build());
+ }
+ }
+ }
+
+ /**
+ * Collects data for a specific module in a special format that makes pruning easy.
+ */
+ @Immutable
+ public static final class TransitiveModuleHeaders {
+ /**
+ * The module that we are calculating information for.
+ */
+ private final Artifact module;
+
+ /**
+ * The headers compiled into this module.
+ */
+ private final ImmutableSet<Artifact> headers;
+
+ /**
+ * This nested set contains 'module' as well as all targets it transitively depends on.
+ * If any of the 'headers' is used, all of these modules a required for the compilation.
+ */
+ private final NestedSet<Artifact> transitiveModules;
+
+ public TransitiveModuleHeaders(
+ Artifact module,
+ ImmutableSet<Artifact> headers,
+ NestedSet<Artifact> transitiveModules) {
+ this.module = module;
+ this.headers = headers;
+ this.transitiveModules = transitiveModules;
+ }
+ }
}