@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); }
@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"))))); }
@Override public CxxPreprocessorInput getCxxPreprocessorInput( TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) { return CxxPreprocessables.getCxxPreprocessorInput( targetGraph, params, ruleResolver, cxxPlatform.getFlavor(), headerVisibility, CxxPreprocessables.IncludeType.LOCAL, exportedPreprocessorFlags.apply(cxxPlatform), cxxPlatform, frameworks); }
@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"))); }
/** * @return a map of header locations to input {@link SourcePath} objects formed by parsing the * input {@link SourcePath} objects for the "headers" parameter. */ public static ImmutableMap<Path, SourcePath> parseHeaders( BuildRuleParams params, BuildRuleResolver resolver, CxxPlatform cxxPlatform, CxxConstructorArg args) { ImmutableMap.Builder<String, SourcePath> headers = ImmutableMap.builder(); SourcePathResolver pathResolver = new SourcePathResolver(resolver); putAllHeaders(args.headers.get(), headers, pathResolver, "headers", params.getBuildTarget()); for (SourceList sourceList : args.platformHeaders.get().getMatchingValues(cxxPlatform.getFlavor().toString())) { putAllHeaders(sourceList, headers, pathResolver, "platform_headers", params.getBuildTarget()); } return CxxPreprocessables.resolveHeaderMap( args.headerNamespace.transform(MorePaths.TO_PATH).or(params.getBuildTarget().getBasePath()), headers.build()); }
public static HeaderSymlinkTree createHeaderSymlinkTree( BuildRuleParams params, BuildRuleResolver ruleResolver, SourcePathResolver pathResolver, CxxPlatform cxxPlatform, boolean includeLexYaccHeaders, ImmutableMap<String, SourcePath> lexSources, ImmutableMap<String, SourcePath> yaccSources, ImmutableMap<Path, SourcePath> headers, HeaderVisibility headerVisibility) { BuildTarget headerSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility); Path headerSymlinkTreeRoot = CxxDescriptionEnhancer.getHeaderSymlinkTreePath( params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility); Optional<Path> headerMapLocation = Optional.absent(); if (cxxPlatform.getCpp().supportsHeaderMaps() && cxxPlatform.getCxxpp().supportsHeaderMaps()) { headerMapLocation = Optional.of( getHeaderMapPath(params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility)); } CxxHeaderSourceSpec lexYaccSources; if (includeLexYaccHeaders) { lexYaccSources = requireLexYaccSources( params, ruleResolver, pathResolver, cxxPlatform, lexSources, yaccSources); } else { lexYaccSources = CxxHeaderSourceSpec.builder().build(); } return CxxPreprocessables.createHeaderSymlinkTreeBuildRule( pathResolver, headerSymlinkTreeTarget, params, headerSymlinkTreeRoot, headerMapLocation, ImmutableMap.<Path, SourcePath>builder() .putAll(headers) .putAll(lexYaccSources.getCxxHeaders()) .build()); }
@Override public CxxPreprocessorInput getCxxPreprocessorInput( TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) { switch (headerVisibility) { case PUBLIC: return CxxPreprocessorInput.builder() .from( CxxPreprocessables.getCxxPreprocessorInput( targetGraph, params, ruleResolver, cxxPlatform.getFlavor(), headerVisibility, CxxPreprocessables.IncludeType.SYSTEM, ImmutableMultimap.<CxxSource.Type, String>of(), /* exportedPreprocessorFlags */ cxxPlatform, ImmutableList.<FrameworkPath>of())) /* frameworks */ .build(); case PRIVATE: return CxxPreprocessorInput.EMPTY; } throw new RuntimeException("Invalid header visibility: " + headerVisibility); }
private <A extends Arg> BuildRule createExtensionBuildRule( TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver ruleResolver, CxxPlatform cxxPlatform, A args) { SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver); // Extract all C/C++ sources from the constructor arg. ImmutableMap<String, CxxSource> srcs = CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver, cxxPlatform, args); ImmutableMap<Path, SourcePath> headers = CxxDescriptionEnhancer.parseHeaders(params, ruleResolver, cxxPlatform, args); ImmutableMap<String, SourcePath> lexSrcs = CxxDescriptionEnhancer.parseLexSources(params, ruleResolver, args); ImmutableMap<String, SourcePath> yaccSrcs = CxxDescriptionEnhancer.parseYaccSources(params, ruleResolver, args); CxxHeaderSourceSpec lexYaccSources = CxxDescriptionEnhancer.createLexYaccBuildRules( params, ruleResolver, cxxPlatform, ImmutableList.<String>of(), lexSrcs, ImmutableList.<String>of(), yaccSrcs); // Setup the header symlink tree and combine all the preprocessor input from this rule // and all dependencies. HeaderSymlinkTree headerSymlinkTree = CxxDescriptionEnhancer.requireHeaderSymlinkTree( params, ruleResolver, new SourcePathResolver(ruleResolver), cxxPlatform, /* includeLexYaccHeaders */ true, lexSrcs, yaccSrcs, headers, HeaderVisibility.PRIVATE); ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput = CxxDescriptionEnhancer.collectCxxPreprocessorInput( targetGraph, params, cxxPlatform, CxxFlags.getLanguageFlags( args.preprocessorFlags, args.platformPreprocessorFlags, args.langPreprocessorFlags, cxxPlatform), args.prefixHeaders.get(), ImmutableList.of(headerSymlinkTree), ImmutableSet.<Path>of(), CxxPreprocessables.getTransitiveCxxPreprocessorInput( targetGraph, cxxPlatform, params.getDeps())); ImmutableMap<String, CxxSource> allSources = ImmutableMap.<String, CxxSource>builder() .putAll(srcs) .putAll(lexYaccSources.getCxxSources()) .build(); // Generate rule to build the object files. ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects = CxxSourceRuleFactory.requirePreprocessAndCompileRules( params, ruleResolver, pathResolver, cxxPlatform, cxxPreprocessorInput, CxxFlags.getFlags(args.compilerFlags, args.platformCompilerFlags, cxxPlatform), cxxBuckConfig.getPreprocessMode(), allSources, CxxSourceRuleFactory.PicType.PIC); // Setup the rules to link the shared library. String extensionName = getExtensionName(params.getBuildTarget()); Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor()); return CxxLinkableEnhancer.createCxxLinkableBuildRule( targetGraph, cxxPlatform, params, pathResolver, /* extraLdFlags */ CxxFlags.getFlags( args.linkerFlags, args.platformLinkerFlags, cxxPlatform), getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()), Linker.LinkType.SHARED, Optional.of(extensionName), extensionPath, picObjects.values(), Linker.LinkableDepType.SHARED, params.getDeps(), args.cxxRuntimeType, Optional.<SourcePath>absent()); }
public static CxxLinkAndCompileRules createBuildRulesForCxxBinary( TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, CxxPlatform cxxPlatform, ImmutableMap<String, CxxSource> srcs, ImmutableMap<Path, SourcePath> headers, ImmutableMap<String, SourcePath> lexSrcs, ImmutableMap<String, SourcePath> yaccSrcs, CxxPreprocessMode preprocessMode, Linker.LinkableDepType linkStyle, Optional<ImmutableList<String>> preprocessorFlags, Optional<PatternMatchedCollection<ImmutableList<String>>> platformPreprocessorFlags, Optional<ImmutableMap<CxxSource.Type, ImmutableList<String>>> langPreprocessorFlags, Optional<ImmutableSortedSet<FrameworkPath>> frameworks, Optional<ImmutableList<String>> compilerFlags, Optional<PatternMatchedCollection<ImmutableList<String>>> platformCompilerFlags, Optional<SourcePath> prefixHeader, Optional<ImmutableList<String>> linkerFlags, Optional<PatternMatchedCollection<ImmutableList<String>>> platformLinkerFlags, Optional<Linker.CxxRuntimeType> cxxRuntimeType) { SourcePathResolver sourcePathResolver = new SourcePathResolver(resolver); Path linkOutput = getLinkOutputPath(params.getBuildTarget()); ImmutableList.Builder<Arg> argsBuilder = ImmutableList.builder(); CommandTool.Builder executableBuilder = new CommandTool.Builder(); // Setup the rules to run lex/yacc. CxxHeaderSourceSpec lexYaccSources = requireLexYaccSources(params, resolver, sourcePathResolver, cxxPlatform, lexSrcs, yaccSrcs); // Setup the header symlink tree and combine all the preprocessor input from this rule // and all dependencies. HeaderSymlinkTree headerSymlinkTree = requireHeaderSymlinkTree( params, resolver, sourcePathResolver, cxxPlatform, /* includeLexYaccHeaders */ true, lexSrcs, yaccSrcs, headers, HeaderVisibility.PRIVATE); ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput = collectCxxPreprocessorInput( targetGraph, params, cxxPlatform, CxxFlags.getLanguageFlags( preprocessorFlags, platformPreprocessorFlags, langPreprocessorFlags, cxxPlatform), ImmutableList.of(headerSymlinkTree), getFrameworkSearchPaths(frameworks, cxxPlatform, new SourcePathResolver(resolver)), CxxPreprocessables.getTransitiveCxxPreprocessorInput( targetGraph, cxxPlatform, FluentIterable.from(params.getDeps()) .filter(Predicates.instanceOf(CxxPreprocessorDep.class)))); // The complete list of input sources. ImmutableMap<String, CxxSource> sources = ImmutableMap.<String, CxxSource>builder() .putAll(srcs) .putAll(lexYaccSources.getCxxSources()) .build(); // Generate and add all the build rules to preprocess and compile the source to the // resolver and get the `SourcePath`s representing the generated object files. ImmutableMap<CxxPreprocessAndCompile, SourcePath> objects = CxxSourceRuleFactory.requirePreprocessAndCompileRules( params, resolver, sourcePathResolver, cxxPlatform, cxxPreprocessorInput, CxxFlags.getFlags(compilerFlags, platformCompilerFlags, cxxPlatform), prefixHeader, preprocessMode, sources, linkStyle == Linker.LinkableDepType.STATIC ? CxxSourceRuleFactory.PicType.PDC : CxxSourceRuleFactory.PicType.PIC); // Build up the linker flags, which support macro expansion. ImmutableList<String> resolvedLinkerFlags = CxxFlags.getFlags(linkerFlags, platformLinkerFlags, cxxPlatform); argsBuilder.addAll( FluentIterable.from(resolvedLinkerFlags) .transform( MacroArg.toMacroArgFunction( MACRO_HANDLER, params.getBuildTarget(), params.getCellRoots(), resolver, params.getProjectFilesystem()))); // Special handling for dynamically linked binaries. if (linkStyle == Linker.LinkableDepType.SHARED) { // Create a symlink tree with for all shared libraries needed by this binary. SymlinkTree sharedLibraries = resolver.addToIndex( createSharedLibrarySymlinkTree( targetGraph, params, sourcePathResolver, cxxPlatform, Predicates.instanceOf(NativeLinkable.class))); // Embed a origin-relative library path into the binary so it can find the shared libraries. argsBuilder.addAll( StringArg.from( Linkers.iXlinker( "-rpath", String.format( "%s/%s", cxxPlatform.getLd().origin(), linkOutput.getParent().relativize(sharedLibraries.getRoot()).toString())))); // Add all the shared libraries and the symlink tree as inputs to the tool that represents // this binary, so that users can attach the proper deps. executableBuilder.addDep(sharedLibraries); executableBuilder.addInputs(sharedLibraries.getLinks().values()); } // Add object files into the args. argsBuilder.addAll(SourcePathArg.from(sourcePathResolver, objects.values())); // Generate the final link rule. We use the top-level target as the link rule's // target, so that it corresponds to the actual binary we build. CxxLink cxxLink = CxxLinkableEnhancer.createCxxLinkableBuildRule( targetGraph, cxxPlatform, params, sourcePathResolver, createCxxLinkTarget(params.getBuildTarget()), Linker.LinkType.EXECUTABLE, Optional.<String>absent(), linkOutput, argsBuilder.build(), linkStyle, params.getDeps(), cxxRuntimeType, Optional.<SourcePath>absent(), ImmutableSet.<BuildTarget>of()); resolver.addToIndex(cxxLink); // Add the output of the link as the lone argument needed to invoke this binary as a tool. executableBuilder.addArg(new BuildTargetSourcePath(cxxLink.getBuildTarget())); return new CxxLinkAndCompileRules( cxxLink, ImmutableSortedSet.copyOf(objects.keySet()), executableBuilder.build()); }
private ImmutableList<com.facebook.buck.rules.args.Arg> getExtensionArgs( BuildRuleParams params, BuildRuleResolver ruleResolver, SourcePathResolver pathResolver, CxxPlatform cxxPlatform, Arg args) throws NoSuchBuildTargetException { // Extract all C/C++ sources from the constructor arg. ImmutableMap<String, CxxSource> srcs = CxxDescriptionEnhancer.parseCxxSources( params.getBuildTarget(), pathResolver, cxxPlatform, args); ImmutableMap<Path, SourcePath> headers = CxxDescriptionEnhancer.parseHeaders( params.getBuildTarget(), pathResolver, Optional.of(cxxPlatform), args); // Setup the header symlink tree and combine all the preprocessor input from this rule // and all dependencies. HeaderSymlinkTree headerSymlinkTree = CxxDescriptionEnhancer.requireHeaderSymlinkTree( params, ruleResolver, new SourcePathResolver(ruleResolver), cxxPlatform, headers, HeaderVisibility.PRIVATE); ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput = CxxDescriptionEnhancer.collectCxxPreprocessorInput( params, cxxPlatform, CxxFlags.getLanguageFlags( args.preprocessorFlags, args.platformPreprocessorFlags, args.langPreprocessorFlags, cxxPlatform), ImmutableList.of(headerSymlinkTree), ImmutableSet.<FrameworkPath>of(), CxxPreprocessables.getTransitiveCxxPreprocessorInput(cxxPlatform, params.getDeps())); // Generate rule to build the object files. ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects = CxxSourceRuleFactory.requirePreprocessAndCompileRules( params, ruleResolver, pathResolver, cxxBuckConfig, cxxPlatform, cxxPreprocessorInput, CxxFlags.getLanguageFlags( args.compilerFlags, args.platformCompilerFlags, args.langCompilerFlags, cxxPlatform), args.prefixHeader, cxxBuckConfig.getPreprocessMode(), srcs, CxxSourceRuleFactory.PicType.PIC); ImmutableList.Builder<com.facebook.buck.rules.args.Arg> argsBuilder = ImmutableList.builder(); argsBuilder.addAll( StringArg.from(CxxFlags.getFlags(args.linkerFlags, args.platformLinkerFlags, cxxPlatform))); // Embed a origin-relative library path into the binary so it can find the shared libraries. argsBuilder.addAll( StringArg.from( Linkers.iXlinker( "-rpath", String.format("%s/", cxxPlatform.getLd().resolve(ruleResolver).libOrigin())))); // Add object files into the args. argsBuilder.addAll(SourcePathArg.from(pathResolver, picObjects.values())); return argsBuilder.build(); }