@Test public void depfileBasedRuleKeyAvoidsRecompilingAfterChangeToUnusedHeader() throws Exception { CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(FakeBuckConfig.builder().build())); BuildTarget target = BuildTargetFactory.newInstance("//:binary_with_unused_header"); String unusedHeaderName = "unused_header.h"; String sourceName = "source.cpp"; BuildTarget preprocessTarget = getPreprocessTarget(cxxPlatform, target, sourceName, AbstractCxxSource.Type.CXX); // Run the build and verify that the C++ source was preprocessed. workspace.runBuckBuild("--config", "build.depfiles=true", target.toString()).assertSuccess(); BuckBuildLog.BuildLogEntry firstRunEntry = workspace.getBuildLog().getLogEntry(preprocessTarget); assertThat( firstRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Now modify the unused header. workspace.writeContentsToPath( "static inline int newFunction() { return 20; }", unusedHeaderName); // Run the build again and verify that got a matching depfile rule key, and therefore // didn't recompile. workspace.runBuckBuild("--config", "build.depfiles=true", target.toString()).assertSuccess(); BuckBuildLog.BuildLogEntry secondRunEntry = workspace.getBuildLog().getLogEntry(preprocessTarget); assertThat( secondRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_DEP_FILE_RULE_KEY))); // Also, make sure the original rule keys are actually different. assertThat(secondRunEntry.getRuleKey(), Matchers.not(equalTo(firstRunEntry.getRuleKey()))); }
@Test public void depfileBasedRuleKeyRebuildsAfterChangeToUsedHeaderUsingFileRelativeInclusion() throws Exception { CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(FakeBuckConfig.builder().build())); BuildTarget target = BuildTargetFactory.newInstance("//:binary_with_used_relative_header"); String usedHeaderName = "source_relative_header.h"; String sourceName = "source_relative_header.cpp"; BuildTarget preprocessTarget = getPreprocessTarget(cxxPlatform, target, sourceName, AbstractCxxSource.Type.CXX); // Run the build and verify that the C++ source was preprocessed. workspace.runBuckBuild("--config", "build.depfiles=true", target.toString()).assertSuccess(); BuckBuildLog.BuildLogEntry firstRunEntry = workspace.getBuildLog().getLogEntry(preprocessTarget); assertThat( firstRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Modify the used header. workspace.writeContentsToPath("static inline int newFunction() { return 20; }", usedHeaderName); // Run the build again and verify that we recompiled as the header caused the depfile rule key // to change. workspace.runBuckBuild("--config", "build.depfiles=true", target.toString()).assertSuccess(); BuckBuildLog.BuildLogEntry secondRunEntry = workspace.getBuildLog().getLogEntry(preprocessTarget); assertThat( secondRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Also, make sure all three rule keys are actually different. assertThat(secondRunEntry.getRuleKey(), Matchers.not(equalTo(firstRunEntry.getRuleKey()))); }
@Test public void testPathsUnderDirectories() throws CmdLineException, IOException { ProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); Path resDir = Paths.get("some/resources/dir"); BuildTarget androidResourceTarget = BuildTargetFactory.newInstance("//:res"); TargetNode<?> androidResourceNode = AndroidResourceBuilder.createBuilder(androidResourceTarget).setRes(resDir).build(); Path genSrc = resDir.resolve("foo.txt"); BuildTarget genTarget = BuildTargetFactory.newInstance("//:res"); TargetNode<?> genNode = GenruleBuilder.newGenruleBuilder(genTarget) .setSrcs(ImmutableList.<SourcePath>of(new PathSourcePath(projectFilesystem, genSrc))) .build(); TargetGraph targetGraph = TargetGraphFactory.newInstance(androidResourceNode, genNode); SortedMap<String, TargetNode<?>> matchingBuildRules; // Specifying a resource under the resource directory causes a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(resDir.resolve("some_resource.txt"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals(ImmutableSet.of(androidResourceTarget.toString()), matchingBuildRules.keySet()); // Specifying a resource with the same string-like common prefix, but not under the above // resource dir, should not trigger a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of( ImmutableSet.of( Paths.get(resDir.toString() + "_extra").resolve("some_resource.txt"))), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertTrue(matchingBuildRules.isEmpty()); // Specifying a resource with the same string-like common prefix, but not under the above // resource dir, should not trigger a match. matchingBuildRules = targetsCommand.getMatchingNodes( targetGraph, Optional.of(ImmutableSet.of(genSrc)), Optional.<ImmutableSet<BuildTarget>>absent(), Optional.<ImmutableSet<BuildRuleType>>absent(), false, "BUCK"); assertEquals( ImmutableSet.of(androidResourceTarget.toString(), genTarget.toString()), matchingBuildRules.keySet()); }
@Test public void inputBasedRuleKeyAvoidsRerunningIfGeneratedSourceDoesNotChange() throws Exception { CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(FakeBuckConfig.builder().build())); BuildTarget target = BuildTargetFactory.newInstance(workspace.getDestPath(), "//:binary_using_generated_source"); String unusedGenruleInput = "unused.dat"; BuildTarget genrule = BuildTargetFactory.newInstance("//:gensource"); String sourceName = "bar.cpp"; CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(workspace.getDestPath(), target, cxxPlatform); BuildTarget preprocessTarget = cxxSourceRuleFactory.createPreprocessBuildTarget( sourceName, AbstractCxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); BuildTarget compileTarget = cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC); // Run the build and verify that the C++ source was (preprocessed and) compiled. workspace.runBuckBuild(target.toString()).assertSuccess(); if (mode == CxxPreprocessMode.SEPARATE) { assertThat( workspace.getBuildLog().getLogEntry(preprocessTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); } assertThat( workspace.getBuildLog().getLogEntry(compileTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Now modify the unused genrule input. workspace.writeContentsToPath("SOMETHING ELSE", unusedGenruleInput); // Run the build again and verify that got a matching input-based rule key, and therefore // didn't recompile. workspace.runBuckBuild(target.toString()).assertSuccess(); // Verify that the genrule actually re-ran. assertThat( workspace.getBuildLog().getLogEntry(genrule).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Verify that the (preprocess and) compile rules aren't re-run. if (mode == CxxPreprocessMode.SEPARATE) { assertThat( workspace.getBuildLog().getLogEntry(preprocessTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_INPUT_BASED_RULE_KEY))); } assertThat( workspace.getBuildLog().getLogEntry(compileTarget).getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_INPUT_BASED_RULE_KEY))); }
@Test public void resolveHeadersBehindSymlinkTreesInPreprocessedOutput() throws IOException { BuckConfig buckConfig = new FakeBuckConfig(); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(buckConfig)); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "resolved", tmp); workspace.setUp(); workspace.writeContentsToPath("", "lib2.h"); BuildTarget target = BuildTargetFactory.newInstance("//:bin"); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform); workspace.runBuckCommand("build", target.toString()).assertSuccess(); // Verify that the preprocessed source contains no references to the symlink tree used to // setup the headers. BuildTarget ppTarget = cxxSourceRuleFactory.createPreprocessBuildTarget( "bin.cpp", CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); Path output = cxxSourceRuleFactory.getPreprocessOutputPath(ppTarget, CxxSource.Type.CXX, "bin.cpp"); String contents = workspace.getFileContents(output.toString()); assertThat(contents, Matchers.not(Matchers.containsString(BuckConstant.SCRATCH_DIR))); assertThat(contents, Matchers.not(Matchers.containsString(BuckConstant.GEN_DIR))); assertThat(contents, Matchers.containsString("# 1 \"bin.h")); assertThat(contents, Matchers.containsString("# 1 \"lib1.h")); assertThat(contents, Matchers.containsString("# 1 \"lib2.h")); }
@Test public void testInferCxxBinaryDepsCaching() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); workspace.enableDirCache(); // enable the cache 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 building after clean will use the cache */ workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); for (BuildTarget buildTarget : buildLog.getAllTargets()) { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } /* * Check that if the file in the binary target changes, then all the deps will be fetched * from the cache */ String sourceName = "src_with_deps.c"; workspace.replaceFileContents("foo/" + sourceName, "10", "30"); workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); buildLog = workspace.getBuildLog(); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform); BuildTarget captureBuildTarget = cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName); // this is flavored, and denotes the analysis step (generates a local report) BuildTarget inferAnalysisTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE); // this is the flavored version of the top level target (the one give in input to buck) BuildTarget inferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER); String bt; for (BuildTarget buildTarget : buildLog.getAllTargets()) { bt = buildTarget.toString(); if (bt.equals(inferAnalysisTarget.toString()) || bt.equals(captureBuildTarget.toString()) || bt.equals(inferReportTarget.toString())) { buildLog.assertTargetBuiltLocally(bt); } else { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } } }
@Test public void inputBasedRuleKeyAvoidsRecompilingAfterChangeToUnusedHeader() throws Exception { // This test is only meant to check the separate flow, as we want to avoid recompiling if only // unused headers have changed. assumeTrue("only tests \"separate\" preprocess mode", mode == CxxPreprocessMode.SEPARATE); CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(FakeBuckConfig.builder().build())); BuildTarget target = BuildTargetFactory.newInstance("//:binary_with_unused_header"); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(workspace.getDestPath(), target, cxxPlatform); String unusedHeaderName = "unused_header.h"; String sourceName = "source.cpp"; BuildTarget compileTarget = cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC); // Run the build and verify that the C++ source was compiled. workspace.runBuckBuild(target.toString()); BuckBuildLog.BuildLogEntry firstRunEntry = workspace.getBuildLog().getLogEntry(compileTarget); assertThat( firstRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.BUILT_LOCALLY))); // Now modify the unused header. workspace.writeContentsToPath( "static inline int newFunction() { return 20; }", unusedHeaderName); // Run the build again and verify that got a matching input-based rule key, and therefore // didn't recompile. workspace.runBuckBuild(target.toString()); BuckBuildLog.BuildLogEntry secondRunEntry = workspace.getBuildLog().getLogEntry(compileTarget); assertThat( secondRunEntry.getSuccessType(), equalTo(Optional.of(BuildRuleSuccessType.MATCHING_INPUT_BASED_RULE_KEY))); // Also, make sure the original rule keys are actually different. assertThat(secondRunEntry.getRuleKey(), Matchers.not(equalTo(firstRunEntry.getRuleKey()))); }
@Test public void testInferCxxBinaryWithCachedDepsGetsAllItsTransitiveDeps() throws IOException { assumeTrue(Platform.detect() != Platform.WINDOWS); ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp); workspace.enableDirCache(); // enable the cache BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:binary_with_chain_deps"); String inputBuildTargetName = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName(); /* * Build the given target and check that it succeeds. */ workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); /* * Check that building after clean will use the cache */ workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); BuckBuildLog buildLog = workspace.getBuildLog(); for (BuildTarget buildTarget : buildLog.getAllTargets()) { buildLog.assertTargetWasFetchedFromCache(buildTarget.toString()); } /* * Check that if the file in the top target changes, then all the transitive deps will be * fetched from the cache (even those that are not direct dependencies). * Make sure there's the specs file of the dependency that has distance 2 from * the binary target. */ String sourceName = "top_chain.c"; workspace.replaceFileContents("foo/" + sourceName, "*p += 1", "*p += 10"); workspace.runBuckCommand("clean").assertSuccess(); workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess(); // Check all the buildrules were fetched from the cache (and there's the specs file) assertTrue( "Expected specs file for func_ret_null() in chain_dep_two.c not found", workspace .getPath( "buck-out/gen/foo/infer-analysis-chain_dep_two#default,infer-analyze/specs/" + "mockedSpec.specs") .toFile() .exists()); }
@Test public void findDepsFromParamsSetsUpDepsForFlavoredTarget() { // Create the thrift target and implicit dep. BuildTarget thriftTarget = BuildTargetFactory.newInstance("//bar:thrift_compiler"); FakeBuildRule implicitDep = createFakeBuildRule("//foo:implicit_dep", new SourcePathResolver(new BuildRuleResolver())); // Setup the default values returned by the language specific enhancer. String language = "fake"; Flavor flavor = ImmutableFlavor.of("fake"); ImmutableSet<String> options = ImmutableSet.of(); ImmutableSet<BuildTarget> implicitDeps = ImmutableSet.of(implicitDep.getBuildTarget()); BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift"); BuildTarget flavoredTarget = BuildTargets.createFlavoredBuildTarget(unflavoredTarget.checkUnflavored(), flavor); // Setup an empty thrift buck config and description. FakeBuckConfig buckConfig = new FakeBuckConfig( ImmutableMap.of("thrift", ImmutableMap.of("compiler", thriftTarget.toString()))); ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig); ThriftLanguageSpecificEnhancer enhancer = new FakeThriftLanguageSpecificEnhancer(language, flavor, implicitDeps, options); ThriftLibraryDescription desc = new ThriftLibraryDescription(thriftBuckConfig, ImmutableList.of(enhancer)); ThriftConstructorArg constructorArg = desc.createUnpopulatedConstructorArg(); constructorArg.deps = Optional.of(ImmutableSortedSet.<BuildTarget>of()); // Now call the find deps methods and verify it returns nothing. Iterable<BuildTarget> results = desc.findDepsForTargetFromConstructorArgs(flavoredTarget, constructorArg); assertEquals( ImmutableSet.<BuildTarget>builder() .add(unflavoredTarget) .add(thriftTarget) .addAll(implicitDeps) .build(), ImmutableSet.copyOf(results)); }
@Test public void resolveHeadersBehindSymlinkTreesInError() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "resolved", tmp); workspace.setUp(); workspace.writeContentsToPath("#invalid_pragma", "lib2.h"); BuildTarget target = BuildTargetFactory.newInstance("//:bin"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.toString()); result.assertFailure(); // Verify that the preprocessed source contains no references to the symlink tree used to // setup the headers. String error = result.getStderr(); assertThat(error, Matchers.not(Matchers.containsString(BuckConstant.SCRATCH_DIR))); assertThat(error, Matchers.not(Matchers.containsString(BuckConstant.GEN_DIR))); assertThat(error, Matchers.containsString("In file included from lib1.h:1")); assertThat(error, Matchers.containsString("from bin.h:1")); assertThat(error, Matchers.containsString("from bin.cpp:1:")); assertThat(error, Matchers.containsString("lib2.h:1:2: error: invalid preprocessing")); }
@Override public String getValueString() { return buildTarget.toString(); }
@Test public void testSimpleCxxBinaryWithDependencyOnCxxLibraryWithHeader() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "simple", tmp); workspace.setUp(); // Setup variables pointing to the sources and targets of the top-level binary rule. CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig())); BuildTarget target = BuildTargetFactory.newInstance("//foo:binary_with_dep"); CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform); BuildTarget binaryTarget = CxxDescriptionEnhancer.createCxxLinkTarget(target); String sourceName = "foo.cpp"; 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); // Setup variables pointing to the sources and targets of the library dep. BuildTarget depTarget = BuildTargetFactory.newInstance("//foo:library_with_header"); CxxSourceRuleFactory depCxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(depTarget, cxxPlatform); String depSourceName = "bar.cpp"; String depSourceFull = "foo/" + depSourceName; String depHeaderName = "bar.h"; String depHeaderFull = "foo/" + depHeaderName; BuildTarget depPreprocessTarget = depCxxSourceRuleFactory.createPreprocessBuildTarget( depSourceName, CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC); BuildTarget depCompileTarget = depCxxSourceRuleFactory.createCompileBuildTarget( depSourceName, CxxSourceRuleFactory.PicType.PDC); BuildTarget depHeaderSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE); BuildTarget depHeaderExportedSymlinkTreeTarget = CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( depTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC); BuildTarget depArchiveTarget = CxxDescriptionEnhancer.createStaticLibraryBuildTarget( depTarget, cxxPlatform.getFlavor(), CxxSourceRuleFactory.PicType.PDC); // 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( depHeaderSymlinkTreeTarget, depHeaderExportedSymlinkTreeTarget, depPreprocessTarget, depCompileTarget, depArchiveTarget, depTarget, headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target), buildLog.getAllTargets()); buildLog.assertTargetBuiltLocally(depHeaderSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(depPreprocessTarget.toString()); buildLog.assertTargetBuiltLocally(depCompileTarget.toString()); buildLog.assertTargetBuiltLocally(depArchiveTarget.toString()); buildLog.assertTargetBuiltLocally(depTarget.toString()); 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(depHeaderFull, "int x", "int y"); // 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( depHeaderSymlinkTreeTarget, depHeaderExportedSymlinkTreeTarget, depPreprocessTarget, depCompileTarget, depArchiveTarget, depTarget, headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(depHeaderSymlinkTreeTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depHeaderExportedSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(depPreprocessTarget.toString()); buildLog.assertTargetBuiltLocally(depCompileTarget.toString()); buildLog.assertTargetBuiltLocally(depArchiveTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depTarget.toString()); 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()); // Clear for new build. workspace.resetBuildLogFile(); // Update the source file. workspace.replaceFileContents(depSourceFull, "x + 5", "x + 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( depHeaderSymlinkTreeTarget, depHeaderExportedSymlinkTreeTarget, depPreprocessTarget, depCompileTarget, depArchiveTarget, depTarget, compileTarget, binaryTarget, target), buildLog.getAllTargets()); buildLog.assertTargetHadMatchingRuleKey(depHeaderSymlinkTreeTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depHeaderExportedSymlinkTreeTarget.toString()); buildLog.assertTargetBuiltLocally(depPreprocessTarget.toString()); buildLog.assertTargetBuiltLocally(depCompileTarget.toString()); buildLog.assertTargetBuiltLocally(depArchiveTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(depTarget.toString()); buildLog.assertTargetHadMatchingRuleKey(compileTarget.toString()); buildLog.assertTargetBuiltLocally(binaryTarget.toString()); buildLog.assertTargetBuiltLocally(target.toString()); }
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()); }