/** * Build a {@link HeaderSymlinkTree} of all the shared libraries found via the top-level rule's * transitive dependencies. */ public static SymlinkTree createSharedLibrarySymlinkTree( TargetGraph targetGraph, BuildRuleParams params, SourcePathResolver pathResolver, CxxPlatform cxxPlatform, Predicate<Object> traverse) { BuildTarget symlinkTreeTarget = createSharedLibrarySymlinkTreeTarget(params.getBuildTarget(), cxxPlatform.getFlavor()); Path symlinkTreeRoot = getSharedLibrarySymlinkTreePath(params.getBuildTarget(), cxxPlatform.getFlavor()); ImmutableSortedMap<String, SourcePath> libraries = NativeLinkables.getTransitiveSharedLibraries( targetGraph, cxxPlatform, params.getDeps(), Linker.LinkableDepType.SHARED, traverse); ImmutableMap.Builder<Path, SourcePath> links = ImmutableMap.builder(); for (Map.Entry<String, SourcePath> ent : libraries.entrySet()) { links.put(Paths.get(ent.getKey()), ent.getValue()); } try { return new SymlinkTree( params.copyWithChanges( symlinkTreeTarget, Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()), Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())), pathResolver, symlinkTreeRoot, links.build()); } catch (SymlinkTree.InvalidSymlinkTreeException e) { throw new RuntimeException(e.getMessage()); } }
@Override public NativeLinkableInput getNativeLinkableInput( TargetGraph targetGraph, CxxPlatform cxxPlatform, Linker.LinkableDepType type) { if (!isPlatformSupported(cxxPlatform)) { return NativeLinkableInput.of(); } if (headerOnly.apply(cxxPlatform)) { return NativeLinkableInput.of( ImmutableList.<Arg>of(), Preconditions.checkNotNull(frameworks), ImmutableSet.<FrameworkPath>of()); } // Build up the arguments used to link this library. If we're linking the // whole archive, wrap the library argument in the necessary "ld" flags. ImmutableList.Builder<Arg> linkerArgsBuilder = ImmutableList.builder(); linkerArgsBuilder.addAll(Preconditions.checkNotNull(exportedLinkerFlags.apply(cxxPlatform))); if (type != Linker.LinkableDepType.SHARED || linkage == Linkage.STATIC) { BuildRule rule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), type == Linker.LinkableDepType.STATIC ? CxxDescriptionEnhancer.STATIC_FLAVOR : CxxDescriptionEnhancer.STATIC_PIC_FLAVOR); Arg library = new SourcePathArg(getResolver(), new BuildTargetSourcePath(rule.getBuildTarget())); if (linkWhole) { Linker linker = cxxPlatform.getLd(); linkerArgsBuilder.addAll(linker.linkWhole(library)); } else { linkerArgsBuilder.add(library); } } else { BuildRule rule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR); linkerArgsBuilder.add( new SourcePathArg(getResolver(), new BuildTargetSourcePath(rule.getBuildTarget()))); } final ImmutableList<Arg> linkerArgs = linkerArgsBuilder.build(); return NativeLinkableInput.of( linkerArgs, Preconditions.checkNotNull(frameworks), Preconditions.checkNotNull(libraries)); }
@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); }
@Override public PythonPackageComponents getPythonPackageComponents( TargetGraph targetGraph, PythonPlatform pythonPlatform, CxxPlatform cxxPlatform) { if (headerOnly.apply(cxxPlatform)) { return PythonPackageComponents.of(); } if (linkage == Linkage.STATIC) { return PythonPackageComponents.of(); } if (!isPlatformSupported(cxxPlatform)) { return PythonPackageComponents.of(); } ImmutableMap.Builder<Path, SourcePath> libs = ImmutableMap.builder(); String sharedLibrarySoname = soname.or( CxxDescriptionEnhancer.getDefaultSharedLibrarySoname(getBuildTarget(), cxxPlatform)); BuildRule sharedLibraryBuildRule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR); libs.put( Paths.get(sharedLibrarySoname), new BuildTargetSourcePath(sharedLibraryBuildRule.getBuildTarget())); return PythonPackageComponents.of( /* modules */ ImmutableMap.<Path, SourcePath>of(), /* resources */ ImmutableMap.<Path, SourcePath>of(), /* nativeLibraries */ libs.build(), /* prebuiltLibraries */ ImmutableSet.<SourcePath>of(), /* zipSafe */ Optional.<Boolean>absent()); }
@Test public void testSimpleCxxBinaryWithHeader() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "simple", tmp); workspace.setUp(); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget target = BuildTargetFactory.newInstance("//foo:simple_with_header"); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform); BuildTarget binaryTarget = CxxDescriptionEnhancer.createCxxLinkTarget(target); String sourceName = "simple_with_header.cpp"; String headerName = "simple_with_header.h"; String headerFull = "foo/" + headerName; BuildTarget preprocessTarget = cxxSourceRuleFactory.createPreprocessBuildTarget( sourceName, CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); BuildTarget compileTarget = cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC); BuildTarget headerSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( target, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); // Do a clean build, verify that it succeeds, and check that all expected targets built // successfully. workspace.runBuckCommand("build", target.toString()).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); assertEquals( ImmutableSet.of( headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target), buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(preprocessTarget.toString()); buildLog.assertTargetBuiltLocally(compileTarget.toString()); buildLog.assertTargetBuiltLocally(binaryTarget.toString()); buildLog.assertTargetBuiltLocally(target.toString()); // Clear for new build. workspace.resetBuildLogFile(); // Update the source file. workspace.replaceFileContents(headerFull, "blah = 5", "blah = 6"); // Check that running a build again makes the source get recompiled and the binary // re-linked, but does not cause the header rules to re-run. workspace.runBuckCommand("build", target.toString()).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals( ImmutableSet.of( headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(preprocessTarget.toString()); buildLog.assertTargetBuiltLocally(compileTarget.toString()); assertThat( buildLog.getLogEntry(binaryTarget).getSuccessType().get(), Matchers.not(Matchers.equalTo(BuildRuleSuccessType.MATCHING_RULE_KEY))); buildLog.assertTargetBuiltLocally(target.toString()); }
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) { return CxxPreprocessables.getCxxPreprocessorInput( targetGraph, params, ruleResolver, cxxPlatform.getFlavor(), headerVisibility, CxxPreprocessables.IncludeType.LOCAL, exportedPreprocessorFlags.apply(cxxPlatform), cxxPlatform, frameworks); }
public static ImmutableMap<String, CxxSource> parseCxxSources( BuildRuleParams params, BuildRuleResolver resolver, CxxPlatform cxxPlatform, ImmutableSortedSet<SourceWithFlags> srcs, PatternMatchedCollection<ImmutableSortedSet<SourceWithFlags>> platformSrcs) { ImmutableMap.Builder<String, SourceWithFlags> sources = ImmutableMap.builder(); SourcePathResolver pathResolver = new SourcePathResolver(resolver); putAllSources(srcs, sources, pathResolver, params.getBuildTarget()); for (ImmutableSortedSet<SourceWithFlags> sourcesWithFlags : platformSrcs.getMatchingValues(cxxPlatform.getFlavor().toString())) { putAllSources(sourcesWithFlags, sources, pathResolver, params.getBuildTarget()); } return CxxCompilableEnhancer.resolveCxxSources(sources.build()); }
/** * @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 String getDefaultSharedLibrarySoname(BuildTarget target, CxxPlatform platform) { String libName = Joiner.on('_') .join( ImmutableList.builder() .addAll( FluentIterable.from(target.getBasePath()) .transform(Functions.toStringFunction()) .filter(Predicates.not(Predicates.equalTo("")))) .add( target .withoutFlavors(ImmutableSet.of(platform.getFlavor())) .getShortNameAndFlavorPostfix()) .build()); String extension = platform.getSharedLibraryExtension(); return String.format("lib%s.%s", libName, extension); }
/** * Makes sure all build rules needed to produce the shared library are added to the action graph. * * @return the {@link SourcePath} representing the actual shared library. */ private SourcePath requireSharedLibrary(CxxPlatform cxxPlatform) throws NoSuchBuildTargetException { Path sharedLibraryPath = PrebuiltCxxLibraryDescription.getSharedLibraryPath( getBuildTarget(), params.getCellRoots(), ruleResolver, cxxPlatform, libDir, libName); // If the shared library is prebuilt, just return a reference to it. if (params.getProjectFilesystem().exists(sharedLibraryPath)) { return new PathSourcePath(params.getProjectFilesystem(), sharedLibraryPath); } // Otherwise, generate it's build rule. BuildRule sharedLibrary = ruleResolver.requireRule( getBuildTarget() .withFlavors(cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR)); return new BuildTargetSourcePath(sharedLibrary.getBuildTarget()); }
@Override public ImmutableMap<BuildTarget, CxxPreprocessorInput> getTransitiveCxxPreprocessorInput( TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) { Pair<Flavor, HeaderVisibility> key = new Pair<>(cxxPlatform.getFlavor(), headerVisibility); ImmutableMap<BuildTarget, CxxPreprocessorInput> result = cxxPreprocessorInputCache.get(key); if (result == null) { Map<BuildTarget, CxxPreprocessorInput> builder = Maps.newLinkedHashMap(); builder.put( getBuildTarget(), getCxxPreprocessorInput(targetGraph, cxxPlatform, headerVisibility)); for (BuildRule dep : getDeps()) { if (dep instanceof CxxPreprocessorDep) { builder.putAll( ((CxxPreprocessorDep) dep) .getTransitiveCxxPreprocessorInput(targetGraph, cxxPlatform, headerVisibility)); } } result = ImmutableMap.copyOf(builder); cxxPreprocessorInputCache.put(key, result); } return result; }
@Override public ImmutableMap<String, SourcePath> getSharedLibraries( TargetGraph targetGraph, CxxPlatform cxxPlatform) { if (headerOnly.apply(cxxPlatform)) { return ImmutableMap.of(); } if (linkage == Linkage.STATIC) { return ImmutableMap.of(); } if (!isPlatformSupported(cxxPlatform)) { return ImmutableMap.of(); } ImmutableMap.Builder<String, SourcePath> libs = ImmutableMap.builder(); String sharedLibrarySoname = soname.or( CxxDescriptionEnhancer.getDefaultSharedLibrarySoname(getBuildTarget(), cxxPlatform)); BuildRule sharedLibraryBuildRule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR); libs.put( sharedLibrarySoname, new BuildTargetSourcePath(sharedLibraryBuildRule.getBuildTarget())); return libs.build(); }
public static HeaderSymlinkTree requireHeaderSymlinkTree( 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); // Check the cache... Optional<BuildRule> rule = ruleResolver.getRuleOptional(headerSymlinkTreeTarget); if (rule.isPresent()) { Preconditions.checkState(rule.get() instanceof HeaderSymlinkTree); return (HeaderSymlinkTree) rule.get(); } HeaderSymlinkTree symlinkTree = createHeaderSymlinkTree( params, ruleResolver, pathResolver, cxxPlatform, includeLexYaccHeaders, lexSources, yaccSources, headers, headerVisibility); ruleResolver.addToIndex(symlinkTree); return symlinkTree; }
@Override public NativeLinkableInput getNativeLinkableInput( TargetGraph targetGraph, CxxPlatform cxxPlatform, Linker.LinkableDepType type) { if (!isPlatformSupported(cxxPlatform)) { return NativeLinkableInput.of(); } if (headerOnly.apply(cxxPlatform)) { return NativeLinkableInput.of( ImmutableList.<SourcePath>of(), ImmutableList.<String>of(), Preconditions.checkNotNull(frameworks), ImmutableSet.<FrameworkPath>of()); } // Build up the arguments used to link this library. If we're linking the // whole archive, wrap the library argument in the necessary "ld" flags. final Pair<ImmutableList<String>, ImmutableSet<SourcePath>> flagsAndBuildInputs = exportedLinkerFlags.apply(cxxPlatform); ImmutableList.Builder<String> linkerArgsBuilder = ImmutableList.builder(); linkerArgsBuilder.addAll(flagsAndBuildInputs.getFirst()); final BuildRule libraryRule; if (type != Linker.LinkableDepType.SHARED || linkage == Linkage.STATIC) { libraryRule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), type == Linker.LinkableDepType.STATIC ? CxxDescriptionEnhancer.STATIC_FLAVOR : CxxDescriptionEnhancer.STATIC_PIC_FLAVOR); Path staticLibraryPath = CxxDescriptionEnhancer.getStaticLibraryPath( getBuildTarget(), cxxPlatform.getFlavor(), type == Linker.LinkableDepType.STATIC ? CxxSourceRuleFactory.PicType.PDC : CxxSourceRuleFactory.PicType.PIC); if (linkWhole) { Linker linker = cxxPlatform.getLd(); linkerArgsBuilder.addAll(linker.linkWhole(staticLibraryPath.toString())); } else { linkerArgsBuilder.add(staticLibraryPath.toString()); } } else { String sharedLibrarySoname = soname.or( CxxDescriptionEnhancer.getDefaultSharedLibrarySoname( params.getBuildTarget(), cxxPlatform)); Path sharedLibraryPath = CxxDescriptionEnhancer.getSharedLibraryPath( getBuildTarget(), sharedLibrarySoname, cxxPlatform); libraryRule = requireBuildRule( targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR); linkerArgsBuilder.add(sharedLibraryPath.toString()); } final ImmutableList<String> linkerArgs = linkerArgsBuilder.build(); return NativeLinkableInput.of( ImmutableList.<SourcePath>builder() .add(new BuildTargetSourcePath(libraryRule.getBuildTarget())) .addAll(flagsAndBuildInputs.getSecond()) .build(), linkerArgs, Preconditions.checkNotNull(frameworks), Preconditions.checkNotNull(libraries)); }
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 void doTestSimpleCxxBinaryBuilds(String preprocessMode, boolean expectPreprocessorOutput) throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "simple", tmp); workspace.setUp(); workspace.writeContentsToPath( String.format("[cxx]\npreprocess_mode = %s\n", preprocessMode), ".buckconfig"); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget target = BuildTargetFactory.newInstance("//foo:simple"); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform); BuildTarget binaryTarget = CxxDescriptionEnhancer.createCxxLinkTarget(target); String sourceName = "simple.cpp"; String sourceFull = "foo/" + sourceName; BuildTarget preprocessTarget = cxxSourceRuleFactory.createPreprocessBuildTarget( sourceName, CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); BuildTarget compileTarget = cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC); BuildTarget headerSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( target, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); // Do a clean build, verify that it succeeds, and check that all expected targets built // successfully. workspace.runBuckCommand("build", target.toString()).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); ImmutableSet<BuildTarget> expectedTargets = ImmutableSet.<BuildTarget>builder() .addAll(ImmutableSet.of(headerSymlinkTreeTarget, compileTarget, binaryTarget, target)) .addAll( (expectPreprocessorOutput ? ImmutableSet.of(preprocessTarget) : ImmutableSet.<BuildTarget>of())) .build(); assertEquals(expectedTargets, buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString()); if (expectPreprocessorOutput) { buildLog.assertTargetBuiltLocally(preprocessTarget.toString()); } buildLog.assertTargetBuiltLocally(compileTarget.toString()); buildLog.assertTargetBuiltLocally(binaryTarget.toString()); buildLog.assertTargetBuiltLocally(target.toString()); // Clear for new build. workspace.resetBuildLogFile(); // Check that running a build again results in no builds since everything is up to // date. workspace.runBuckCommand("build", target.toString()).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals(ImmutableSet.of(target, binaryTarget), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(binaryTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(target.toString()); // Clear for new build. workspace.resetBuildLogFile(); // Update the source file. workspace.replaceFileContents(sourceFull, "{}", "{ return 0; }"); // Check that running a build again makes the source get recompiled and the binary // re-linked, but does not cause the header rules to re-run. workspace.runBuckCommand("build", target.toString()).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals(expectedTargets, buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString()); if (expectPreprocessorOutput) { buildLog.assertTargetBuiltLocally(preprocessTarget.toString()); } buildLog.assertTargetBuiltLocally(compileTarget.toString()); assertThat( buildLog.getLogEntry(binaryTarget).getSuccessType().get(), Matchers.not(Matchers.equalTo(BuildRuleSuccessType.MATCHING_RULE_KEY))); buildLog.assertTargetBuiltLocally(target.toString()); // Clear for new build. workspace.resetBuildLogFile(); // Update the source file. workspace.replaceFileContents(sourceFull, "{ return 0; }", "won't compile"); // Check that running a build again makes the source get recompiled and the binary // re-linked, but does not cause the header rules to re-run. workspace.runBuckCommand("build", target.toString()).assertFailure(); buildLog = workspace.getBuildLog(); assertEquals(expectedTargets, buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString()); if (expectPreprocessorOutput) { buildLog.assertTargetBuiltLocally(preprocessTarget.toString()); } assertThat( buildLog.getLogEntry(binaryTarget).getStatus(), Matchers.equalTo(BuildRuleStatus.CANCELED)); assertThat( buildLog.getLogEntry(target).getStatus(), Matchers.equalTo(BuildRuleStatus.CANCELED)); }
@Test public void testInferCxxBinaryWithDeps() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:binary_with_deps"); String inputBuildTargetName = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName(); /* * Build the given target and check that it succeeds. */ workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); /* * Check that all the required build targets have been generated. */ String sourceName = "src_with_deps.c"; CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform); // 1. create the targets of binary_with_deps // this is unflavored, but bounded to the InferCapture build rule BuildTarget topCaptureBuildTarget = cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName); // this is unflavored, but necessary to run the compiler successfully BuildTarget topHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( inputBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); // this is flavored, and denotes the analysis step (generates a local report) BuildTarget topInferAnalysisTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE); // this is flavored and corresponds to the top level target (the one give in input to buck) BuildTarget topInferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER); // 2. create the targets of dep_one BuildTarget depOneBuildTarget = BuildTargetFactory.newInstance("//foo:dep_one"); String depOneSourceName = "dep_one.c"; String depOneSourceFull = "foo/" + depOneSourceName; CxxSourceRuleFactory depOneSourceRuleFactory = CxxSourceRuleFactoryHelper.of(depOneBuildTarget, cxxPlatform); BuildTarget depOneCaptureBuildTarget = depOneSourceRuleFactory.createInferCaptureBuildTarget(depOneSourceName); BuildTarget depOneHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depOneBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); BuildTarget depOneExportedHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depOneBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC); BuildTarget depOneInferAnalysisTarget = depOneCaptureBuildTarget.withFlavors( cxxPlatform.getFlavor(), CxxInferEnhancer.INFER_ANALYZE); // 3. create the targets of dep_two BuildTarget depTwoBuildTarget = BuildTargetFactory.newInstance("//foo:dep_two"); CxxSourceRuleFactory depTwoSourceRuleFactory = CxxSourceRuleFactoryHelper.of(depTwoBuildTarget, cxxPlatform); BuildTarget depTwoCaptureBuildTarget = depTwoSourceRuleFactory.createInferCaptureBuildTarget("dep_two.c"); BuildTarget depTwoHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depTwoBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); BuildTarget depTwoExportedHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depTwoBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC); BuildTarget depTwoInferAnalysisTarget = depTwoCaptureBuildTarget.withFlavors( cxxPlatform.getFlavor(), CxxInferEnhancer.INFER_ANALYZE); // Check all the targets are in the buildLog assertEquals( ImmutableSet.of( topCaptureBuildTarget, topHeaderSymlinkTreeTarget, topInferAnalysisTarget, topInferReportTarget, depOneCaptureBuildTarget, depOneHeaderSymlinkTreeTarget, depOneExportedHeaderSymlinkTreeTarget, depOneInferAnalysisTarget, depTwoCaptureBuildTarget, depTwoHeaderSymlinkTreeTarget, depTwoExportedHeaderSymlinkTreeTarget, depTwoInferAnalysisTarget), workspace.getBuildLog().getAllTargets()); /* * Check that running a build again results in no builds since nothing has changed. */ workspace.resetBuildLogFile(); // clear for new build workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); assertEquals(ImmutableSet.of(topInferReportTarget), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(topInferReportTarget.toString()); /* * Check that if a library source file changes then the capture/analysis rules run again on * the main target and on dep_one only. */ workspace.resetBuildLogFile(); workspace.replaceFileContents(depOneSourceFull, "flag > 0", "flag < 0"); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals( ImmutableSet.of( topInferAnalysisTarget, // analysis runs again topInferReportTarget, // report runs again topCaptureBuildTarget, // cached depTwoInferAnalysisTarget, // cached depOneCaptureBuildTarget, // capture of the changed file runs again depOneExportedHeaderSymlinkTreeTarget, // cached depOneHeaderSymlinkTreeTarget, // cached depOneInferAnalysisTarget), // analysis of the library runs again buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(topInferAnalysisTarget.toString()); buildLog.assertTargetBuiltLocally(topInferReportTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(topCaptureBuildTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depTwoInferAnalysisTarget.toString()); buildLog.assertTargetBuiltLocally(depOneCaptureBuildTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depOneExportedHeaderSymlinkTreeTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depOneHeaderSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(depOneInferAnalysisTarget.toString()); }
@Test public void testInferCxxBinaryWithoutDeps() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:simple"); String inputBuildTargetName = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName(); /* * Build the given target and check that it succeeds. */ workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); /* * Check that all the required build targets have been generated. */ String sourceName = "simple.cpp"; String sourceFull = "foo/" + sourceName; CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform); // this is unflavored, but bounded to the InferCapture build rule BuildTarget captureBuildTarget = cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName); // this is unflavored, but necessary to run the compiler successfully BuildTarget headerSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( inputBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); // this is flavored, and denotes the analysis step (generates a local report) BuildTarget inferAnalysisTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE); // this is flavored and corresponds to the top level target (the one give in input to buck) BuildTarget inferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER); ImmutableSet<BuildTarget> expectedTargets = ImmutableSet.<BuildTarget>builder() .addAll( ImmutableSet.of( headerSymlinkTreeTarget, captureBuildTarget, inferAnalysisTarget, inferReportTarget)) .build(); BuckBuildLog buildLog = workspace.getBuildLog(); assertEquals(expectedTargets, buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(captureBuildTarget.toString()); buildLog.assertTargetBuiltLocally(inferAnalysisTarget.toString()); buildLog.assertTargetBuiltLocally(inferReportTarget.toString()); /* * Check that running a build again results in no builds since nothing has changed. */ workspace.resetBuildLogFile(); // clear for new build workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals(ImmutableSet.of(inferReportTarget), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(inferReportTarget.toString()); /* * Check that changing the source file results in running the capture/analysis rules again. */ workspace.resetBuildLogFile(); workspace.replaceFileContents(sourceFull, "*s = 42;", ""); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); buildLog = workspace.getBuildLog(); assertEquals(expectedTargets, buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(captureBuildTarget.toString()); buildLog.assertTargetBuiltLocally(inferAnalysisTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString()); }
private boolean isPlatformSupported(CxxPlatform cxxPlatform) { return !supportedPlatformsRegex.isPresent() || supportedPlatformsRegex.get().matcher(cxxPlatform.getFlavor().toString()).find(); }
public static Path getSharedLibraryPath(BuildTarget target, String soname, CxxPlatform platform) { return BuildTargets.getGenPath( createSharedLibraryBuildTarget(target, platform.getFlavor()), "%s/" + soname); }