@Override public ImmutableList<String> load(@Nonnull CxxSource.Type type) { ImmutableList.Builder<String> builder = ImmutableList.builder(); for (CxxPreprocessorInput input : getCxxPreprocessorInput()) { builder.addAll(input.getPreprocessorFlags().get(type)); } return builder.build(); }
@Override public CxxPreprocessorInput getCxxPreprocessorInput( CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) throws NoSuchBuildTargetException { CxxPreprocessorInput.Builder builder = CxxPreprocessorInput.builder(); switch (headerVisibility) { case PUBLIC: if (Preconditions.checkNotNull(hasHeaders.apply(cxxPlatform))) { CxxPreprocessables.addHeaderSymlinkTree( builder, getBuildTarget(), ruleResolver, cxxPlatform.getFlavor(), headerVisibility, CxxPreprocessables.IncludeType.SYSTEM); } builder.putAllPreprocessorFlags( Preconditions.checkNotNull(exportedPreprocessorFlags.apply(cxxPlatform))); // Just pass the include dirs as system includes. builder.addAllSystemIncludeRoots( Iterables.transform(includeDirs, getProjectFilesystem().getAbsolutifier())); return builder.build(); case PRIVATE: return builder.build(); } // We explicitly don't put this in a default statement because we // want the compiler to warn if someone modifies the HeaderVisibility enum. throw new RuntimeException("Invalid header visibility: " + headerVisibility); }
@Value.Lazy protected ImmutableList<BuildRule> getPreprocessDeps() { ImmutableList.Builder<BuildRule> builder = ImmutableList.builder(); for (CxxPreprocessorInput input : getCxxPreprocessorInput()) { // Depend on the rules that generate the sources and headers we're compiling. builder.addAll( getPathResolver() .filterBuildRuleInputs( ImmutableList.<SourcePath>builder() .addAll(input.getIncludes().getNameToPathMap().values()) .build())); // Also add in extra deps from the preprocessor input, such as the symlink tree rules. builder.addAll( BuildRules.toBuildRulesFor( getParams().getBuildTarget(), getResolver(), input.getRules())); } return builder.build(); }
@Test public void nonTestLibraryDepDoesNotIncludePrivateHeadersOfLibrary() throws Exception { SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); BuildTarget libTarget = BuildTargetFactory.newInstance("//:lib"); BuildRuleParams libParams = new FakeBuildRuleParamsBuilder(libTarget).build(); FakeCxxLibrary libRule = new FakeCxxLibrary( libParams, pathResolver, BuildTargetFactory.newInstance("//:header"), BuildTargetFactory.newInstance("//:symlink"), Paths.get("symlink/tree/lib"), BuildTargetFactory.newInstance("//:privateheader"), BuildTargetFactory.newInstance("//:privatesymlink"), Paths.get("private/symlink/tree/lib"), new FakeBuildRule("//:archive", pathResolver), new FakeBuildRule("//:shared", pathResolver), Paths.get("output/path/lib.so"), "lib.so", // This library has no tests. ImmutableSortedSet.<BuildTarget>of()); BuildTarget otherLibDepTarget = BuildTargetFactory.newInstance("//:other"); BuildRuleParams otherLibDepParams = new FakeBuildRuleParamsBuilder(otherLibDepTarget) .setDeclaredDeps(ImmutableSortedSet.<BuildRule>of(libRule)) .build(); ImmutableList<CxxPreprocessorInput> otherInput = CxxDescriptionEnhancer.collectCxxPreprocessorInput( TargetGraph.EMPTY, otherLibDepParams, CxxPlatformUtils.DEFAULT_PLATFORM, ImmutableMultimap.<CxxSource.Type, String>of(), ImmutableList.<HeaderSymlinkTree>of(), ImmutableSet.<FrameworkPath>of(), CxxPreprocessables.getTransitiveCxxPreprocessorInput( TargetGraph.EMPTY, CxxPlatformUtils.DEFAULT_PLATFORM, FluentIterable.from(otherLibDepParams.getDeps()) .filter(Predicates.instanceOf(CxxPreprocessorDep.class)))); assertThat( "Non-test rule with library dep should include public and not private headers", CxxPreprocessorInput.concat(otherInput).getIncludeRoots(), allOf( hasItem(Paths.get("symlink/tree/lib")), not(hasItem(Paths.get("private/symlink/tree/lib"))))); }
@Test public void libraryTestIncludesPrivateHeadersOfLibraryUnderTest() throws Exception { SourcePathResolver pathResolver = new SourcePathResolver(new BuildRuleResolver()); BuildTarget libTarget = BuildTargetFactory.newInstance("//:lib"); BuildTarget testTarget = BuildTargetFactory.newInstance("//:test"); BuildRuleParams libParams = new FakeBuildRuleParamsBuilder(libTarget).build(); FakeCxxLibrary libRule = new FakeCxxLibrary( libParams, pathResolver, BuildTargetFactory.newInstance("//:header"), BuildTargetFactory.newInstance("//:symlink"), Paths.get("symlink/tree/lib"), BuildTargetFactory.newInstance("//:privateheader"), BuildTargetFactory.newInstance("//:privatesymlink"), Paths.get("private/symlink/tree/lib"), new FakeBuildRule("//:archive", pathResolver), new FakeBuildRule("//:shared", pathResolver), Paths.get("output/path/lib.so"), "lib.so", // Ensure the test is listed as a dep of the lib. ImmutableSortedSet.of(testTarget)); BuildRuleParams testParams = new FakeBuildRuleParamsBuilder(testTarget) .setDeclaredDeps(ImmutableSortedSet.<BuildRule>of(libRule)) .build(); ImmutableList<CxxPreprocessorInput> combinedInput = CxxDescriptionEnhancer.collectCxxPreprocessorInput( TargetGraph.EMPTY, testParams, CxxPlatformUtils.DEFAULT_PLATFORM, ImmutableMultimap.<CxxSource.Type, String>of(), ImmutableList.<HeaderSymlinkTree>of(), ImmutableSet.<FrameworkPath>of(), CxxPreprocessables.getTransitiveCxxPreprocessorInput( TargetGraph.EMPTY, CxxPlatformUtils.DEFAULT_PLATFORM, FluentIterable.from(testParams.getDeps()) .filter(Predicates.instanceOf(CxxPreprocessorDep.class)))); assertThat( "Test of library should include both public and private headers", CxxPreprocessorInput.concat(combinedInput).getIncludeRoots(), hasItems(Paths.get("symlink/tree/lib"), Paths.get("private/symlink/tree/lib"))); }
/** Builds a {@link CxxPreprocessorInput} for a rule. */ public static CxxPreprocessorInput getCxxPreprocessorInput( BuildRuleParams params, BuildRuleResolver ruleResolver, Flavor flavor, HeaderVisibility headerVisibility, IncludeType includeType, Multimap<CxxSource.Type, String> exportedPreprocessorFlags, Iterable<FrameworkPath> frameworks) throws NoSuchBuildTargetException { CxxPreprocessorInput.Builder builder = addHeaderSymlinkTree( CxxPreprocessorInput.builder(), params.getBuildTarget(), ruleResolver, flavor, headerVisibility, includeType); return builder .putAllPreprocessorFlags(exportedPreprocessorFlags) .addAllFrameworks(frameworks) .build(); }
public static ImmutableList<CxxPreprocessorInput> collectCxxPreprocessorInput( TargetGraph targetGraph, BuildRuleParams params, CxxPlatform cxxPlatform, ImmutableMultimap<CxxSource.Type, String> preprocessorFlags, ImmutableList<HeaderSymlinkTree> headerSymlinkTrees, ImmutableSet<Path> frameworkSearchPaths, Iterable<CxxPreprocessorInput> cxxPreprocessorInputFromDeps) { // Add the private includes of any rules which list this rule as a test. BuildTarget targetWithoutFlavor = BuildTarget.of(params.getBuildTarget().getUnflavoredBuildTarget()); ImmutableList.Builder<CxxPreprocessorInput> cxxPreprocessorInputFromTestedRulesBuilder = ImmutableList.builder(); for (BuildRule rule : params.getDeps()) { if (rule instanceof NativeTestable) { NativeTestable testable = (NativeTestable) rule; if (testable.isTestedBy(targetWithoutFlavor)) { LOG.debug( "Adding private includes of tested rule %s to testing rule %s", rule.getBuildTarget(), params.getBuildTarget()); cxxPreprocessorInputFromTestedRulesBuilder.add( testable.getCxxPreprocessorInput(targetGraph, cxxPlatform, HeaderVisibility.PRIVATE)); } } } ImmutableList<CxxPreprocessorInput> cxxPreprocessorInputFromTestedRules = cxxPreprocessorInputFromTestedRulesBuilder.build(); LOG.verbose( "Rules tested by target %s added private includes %s", params.getBuildTarget(), cxxPreprocessorInputFromTestedRules); ImmutableMap.Builder<Path, SourcePath> allLinks = ImmutableMap.builder(); ImmutableMap.Builder<Path, SourcePath> allFullLinks = ImmutableMap.builder(); ImmutableList.Builder<Path> allIncludeRoots = ImmutableList.builder(); ImmutableSet.Builder<Path> allHeaderMaps = ImmutableSet.builder(); for (HeaderSymlinkTree headerSymlinkTree : headerSymlinkTrees) { allLinks.putAll(headerSymlinkTree.getLinks()); allFullLinks.putAll(headerSymlinkTree.getFullLinks()); allIncludeRoots.add(headerSymlinkTree.getIncludePath()); allHeaderMaps.addAll(headerSymlinkTree.getHeaderMap().asSet()); } CxxPreprocessorInput localPreprocessorInput = CxxPreprocessorInput.builder() .addAllRules(Iterables.transform(headerSymlinkTrees, HasBuildTarget.TO_TARGET)) .putAllPreprocessorFlags(preprocessorFlags) .setIncludes( CxxHeaders.builder() .putAllNameToPathMap(allLinks.build()) .putAllFullNameToPathMap(allFullLinks.build()) .build()) .addAllIncludeRoots(allIncludeRoots.build()) .addAllHeaderMaps(allHeaderMaps.build()) .addAllFrameworkRoots(frameworkSearchPaths) .build(); return ImmutableList.<CxxPreprocessorInput>builder() .add(localPreprocessorInput) .addAll(cxxPreprocessorInputFromDeps) .addAll(cxxPreprocessorInputFromTestedRules) .build(); }