@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()); }
@Test public void testCreateBuildRule() throws Exception { // Set up a #halide-compiler rule, then set up a halide_library rule, and // check that the library rule depends on the compiler rule. BuildTarget compilerTarget = BuildTargetFactory.newInstance("//:rule") .withFlavors(HalideLibraryDescription.HALIDE_COMPILER_FLAVOR); BuildTarget libTarget = BuildTargetFactory.newInstance("//:rule"); ProjectFilesystem filesystem = new FakeProjectFilesystem(); HalideLibraryBuilder compilerBuilder = new HalideLibraryBuilder(compilerTarget); compilerBuilder.setSrcs( ImmutableSortedSet.of(SourceWithFlags.of(new FakeSourcePath("main.cpp")))); HalideLibraryBuilder libBuilder = new HalideLibraryBuilder(libTarget); TargetGraph targetGraph = TargetGraphFactory.newInstance(compilerBuilder.build(), libBuilder.build()); BuildRuleResolver resolver = new BuildRuleResolver(targetGraph, new BuildTargetNodeToBuildRuleTransformer()); CxxBinary compiler = (CxxBinary) compilerBuilder.build(resolver, filesystem, targetGraph); HalideLibrary lib = (HalideLibrary) libBuilder.build(resolver, filesystem, targetGraph); // Check that we picked up the implicit dependency on the #halide-compiler // version of the rule. assertEquals(lib.getDeps(), ImmutableSortedSet.<BuildRule>of(compiler)); // Check that the library rule has the correct preprocessor input. CxxPlatform cxxPlatform = CxxLibraryBuilder.createDefaultPlatform(); String headerName = "rule.h"; Path headerPath = BuildTargets.getGenPath(libTarget, "%s/" + headerName); Path headerRoot = CxxDescriptionEnhancer.getHeaderSymlinkTreePath( libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC); assertEquals( CxxPreprocessorInput.builder() .addRules( CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC)) .setIncludes( CxxHeaders.builder() .putNameToPathMap( Paths.get(headerName), new BuildTargetSourcePath(libTarget, headerPath)) .putFullNameToPathMap( headerRoot.resolve(headerName), new BuildTargetSourcePath(libTarget, headerPath)) .build()) .addSystemIncludeRoots(headerRoot) .build(), lib.getCxxPreprocessorInput(cxxPlatform, HeaderVisibility.PUBLIC)); // Check that the library rule has the correct native linkable input. NativeLinkableInput input = lib.getNativeLinkableInput(cxxPlatform, Linker.LinkableDepType.STATIC); BuildRule buildRule = FluentIterable.from(input.getArgs()) .transformAndConcat(Arg.getDepsFunction(new SourcePathResolver(resolver))) .get(0); assertTrue(buildRule instanceof HalideLibrary); }
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()); }
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; }
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()); }