@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")); }
/** * @param buildTargets the build targets to generate a dependency graph for. * @param defaultIncludes the files to include before executing build files. * @param eventBus used to log events while parsing. * @return the dependency graph containing the build targets and their related targets. */ public DependencyGraph parseBuildFilesForTargets( Iterable<BuildTarget> buildTargets, Iterable<String> defaultIncludes, BuckEventBus eventBus) throws BuildFileParseException, BuildTargetException, IOException { // Make sure that knownBuildTargets is initially populated with the BuildRuleBuilders for the // seed BuildTargets for the traversal. eventBus.post(ParseEvent.started(buildTargets)); DependencyGraph graph = null; try (ProjectBuildFileParser buildFileParser = buildFileParserFactory.createParser(defaultIncludes)) { if (!isCacheComplete(defaultIncludes)) { Set<File> buildTargetFiles = Sets.newHashSet(); for (BuildTarget buildTarget : buildTargets) { File buildFile = buildTarget.getBuildFile(projectFilesystem); boolean isNewElement = buildTargetFiles.add(buildFile); if (isNewElement) { parseBuildFile(buildFile, defaultIncludes, buildFileParser); } } } graph = findAllTransitiveDependencies(buildTargets, defaultIncludes, buildFileParser); return graph; } finally { eventBus.post(ParseEvent.finished(buildTargets, Optional.fromNullable(graph))); } }
@Test public void testAppleLibraryBuildsFramework() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); assumeTrue(AppleNativeIntegrationTestUtils.isApplePlatformAvailable(ApplePlatform.MACOSX)); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_library_builds_something", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance( "//Libraries/TestLibrary:TestLibrary#framework,macosx-x86_64,no-debug"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path frameworkPath = workspace.getPath( BuildTargets.getGenPath( filesystem, BuildTarget.builder(target) .addFlavors(AppleDescriptions.INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s") .resolve("TestLibrary.framework")); assertThat(Files.exists(frameworkPath), is(true)); assertThat(Files.exists(frameworkPath.resolve("Resources/Info.plist")), is(true)); Path libraryPath = frameworkPath.resolve("TestLibrary"); assertThat(Files.exists(libraryPath), is(true)); assertThat( workspace.runCommand("file", libraryPath.toString()).getStdout().get(), containsString("dynamically linked shared library")); }
@Test public void frameworkDependenciesDoNotContainTransitiveDependencies() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); assumeTrue(AppleNativeIntegrationTestUtils.isApplePlatformAvailable(ApplePlatform.MACOSX)); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_library_with_library_dependencies", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance( "//Libraries/TestLibrary:TestLibrary#framework,macosx-x86_64"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path frameworkPath = workspace.getPath( BuildTargets.getGenPath( filesystem, BuildTarget.builder(target) .addFlavors(AppleDebugFormat.DWARF.getFlavor()) .addFlavors(AppleDescriptions.INCLUDE_FRAMEWORKS_FLAVOR) .build(), "%s") .resolve("TestLibrary.framework")); assertThat(Files.exists(frameworkPath), is(true)); Path frameworksPath = frameworkPath.resolve("Frameworks"); assertThat(Files.exists(frameworksPath), is(true)); Path depFrameworksPath = frameworksPath.resolve("TestLibraryDep.framework/Frameworks"); assertThat(Files.exists(depFrameworksPath), is(false)); }
@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 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 noIncludeFrameworksDoesntContainFrameworkDependencies() throws Exception { assumeTrue(Platform.detect() == Platform.MACOS); assumeTrue(AppleNativeIntegrationTestUtils.isApplePlatformAvailable(ApplePlatform.MACOSX)); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_library_with_library_dependencies", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget target = BuildTargetFactory.newInstance( "//Libraries/TestLibrary:TestLibrary#" + "dwarf-and-dsym,framework,macosx-x86_64,no-include-frameworks"); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", target.getFullyQualifiedName()); result.assertSuccess(); Path frameworkPath = workspace.getPath( BuildTargets.getGenPath(filesystem, target, "%s").resolve("TestLibrary.framework")); assertThat(Files.exists(frameworkPath), is(true)); assertThat(Files.exists(frameworkPath.resolve("Resources/Info.plist")), is(true)); Path libraryPath = frameworkPath.resolve("TestLibrary"); assertThat(Files.exists(libraryPath), is(true)); assertThat( workspace.runCommand("file", libraryPath.toString()).getStdout().get(), containsString("dynamically linked shared library")); Path frameworksPath = frameworkPath.resolve("Contents/Frameworks"); assertThat(Files.exists(frameworksPath), is(false)); }
@Test public void testAppleLibraryExportedHeaderSymlinkTree() throws IOException { assumeTrue(Platform.detect() == Platform.MACOS); ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "apple_library_header_symlink_tree", tmp); workspace.setUp(); ProjectFilesystem filesystem = new ProjectFilesystem(workspace.getDestPath()); BuildTarget buildTarget = BuildTargetFactory.newInstance( "//Libraries/TestLibrary:TestLibrary#" + "default," + CxxDescriptionEnhancer.EXPORTED_HEADER_SYMLINK_TREE_FLAVOR); ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("build", buildTarget.getFullyQualifiedName()); result.assertSuccess(); Path inputPath = workspace.getPath(buildTarget.getBasePath()).toRealPath(); Path outputPath = workspace.getPath(BuildTargets.getGenPath(filesystem, buildTarget, "%s")).toRealPath(); assertIsSymbolicLink( outputPath.resolve("TestLibrary/PublicHeader.h"), inputPath.resolve("PublicHeader.h")); }
@Test public void testUberCompilationDatabase() throws IOException { ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "compilation_database", tmp); workspace.setUp(); BuildTarget target = BuildTargetFactory.newInstance("//:test#default,uber-compilation-database"); ProjectFilesystem filesystem = new FakeProjectFilesystem(); Path compilationDatabase = workspace.buildAndReturnOutput(target.getFullyQualifiedName()); Path rootPath = tmp.getRoot(); assertEquals( BuildTargets.getGenPath( filesystem, target, "uber-compilation-database-%s/compile_commands.json"), rootPath.relativize(compilationDatabase)); Path binaryHeaderSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, target.withFlavors( ImmutableFlavor.of("default"), CxxDescriptionEnhancer.HEADER_SYMLINK_TREE_FLAVOR), "%s"); Path binaryExportedHeaderSymlinkTreeFolder = BuildTargets.getGenPath( filesystem, target.withFlavors( ImmutableFlavor.of("default"), CxxDescriptionEnhancer.EXPORTED_HEADER_SYMLINK_TREE_FLAVOR), "%s"); Map<String, CxxCompilationDatabaseEntry> fileToEntry = CxxCompilationDatabaseUtils.parseCompilationDatabaseJsonFile(compilationDatabase); assertEquals(1, fileToEntry.size()); assertHasEntry( fileToEntry, "test.cpp", new ImmutableList.Builder<String>() .add(COMPILER_PATH) .add("-fPIC") .add("-fPIC") .add("-I") .add(headerSymlinkTreePath(binaryHeaderSymlinkTreeFolder).toString()) .add("-I") .add(headerSymlinkTreePath(binaryExportedHeaderSymlinkTreeFolder).toString()) .addAll(getExtraFlagsForHeaderMaps(filesystem)) .addAll(COMPILER_SPECIFIC_FLAGS) .add("-x") .add("c++") .add("-c") .add("-o") .add( BuildTargets.getGenPath( filesystem, target.withFlavors( ImmutableFlavor.of("default"), ImmutableFlavor.of("compile-pic-" + sanitize("test.cpp.o"))), "%s/test.cpp.o") .toString()) .add(rootPath.resolve(Paths.get("test.cpp")).toRealPath().toString()) .build()); }
@Test public void baseModule() throws Exception { BuildTarget target = BuildTargetFactory.newInstance("//foo:lib"); String sourceName = "main.py"; SourcePath source = new FakeSourcePath("foo/" + sourceName); // Run without a base module set and verify it defaults to using the build target // base name. PythonLibrary normal = (PythonLibrary) new PythonLibraryBuilder(target) .setSrcs(SourceList.ofUnnamedSources(ImmutableSortedSet.of(source))) .build( new BuildRuleResolver( TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer())); assertEquals( ImmutableMap.of(target.getBasePath().resolve(sourceName), source), normal.getSrcs(PythonTestUtils.PYTHON_PLATFORM)); // Run *with* a base module set and verify it gets used to build the main module path. String baseModule = "blah"; PythonLibrary withBaseModule = (PythonLibrary) new PythonLibraryBuilder(target) .setSrcs(SourceList.ofUnnamedSources(ImmutableSortedSet.of(source))) .setBaseModule("blah") .build( new BuildRuleResolver( TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer())); assertEquals( ImmutableMap.of(Paths.get(baseModule).resolve(sourceName), source), withBaseModule.getSrcs(PythonTestUtils.PYTHON_PLATFORM)); }
@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()); }
GenAidl( BuildRuleParams params, SourcePathResolver resolver, Path aidlFilePath, String importPath) { super(params, resolver); this.aidlFilePath = aidlFilePath; this.importPath = importPath; BuildTarget buildTarget = params.getBuildTarget(); this.genPath = BuildTargets.getGenPath(buildTarget, "%s"); this.output = genPath.resolve( String.format("lib%s%s", buildTarget.getShortNameAndFlavorPostfix(), SRC_ZIP)); }
public JavaLibraryGraphEnhancer( BuildTarget buildTarget, BuildRuleParams buildRuleParams, AbstractBuildRuleBuilderParams buildRuleBuilderParams) { Preconditions.checkNotNull(buildTarget); this.dummyRDotJavaBuildTarget = new BuildTarget( buildTarget.getBaseName(), buildTarget.getShortName(), DUMMY_R_DOT_JAVA_FLAVOR); this.originalBuildRuleParams = Preconditions.checkNotNull(buildRuleParams); this.buildRuleBuilderParams = Preconditions.checkNotNull(buildRuleBuilderParams); }
protected AndroidManifest( BuildTarget buildTarget, SourcePath skeletonFile, Set<String> manifestFiles) { this.buildTarget = Preconditions.checkNotNull(buildTarget); this.skeletonFile = Preconditions.checkNotNull(skeletonFile); this.manifestFiles = ImmutableSortedSet.copyOf(manifestFiles); this.pathToOutputFile = Paths.get( BuckConstant.GEN_DIR, buildTarget.getBasePath(), "AndroidManifest__" + buildTarget.getShortName() + "__.xml"); }
@Nullable public String getBuildTargetForAliasAsString(String possiblyFlavoredAlias) { Pair<BuildTarget, Integer> buildTargetPoundIdx = getBuildTargetForAlias(possiblyFlavoredAlias); BuildTarget buildTarget = buildTargetPoundIdx.getFirst(); int poundIdx = buildTargetPoundIdx.getSecond(); if (buildTarget != null) { return buildTarget.getFullyQualifiedName() + (poundIdx == -1 ? "" : possiblyFlavoredAlias.substring(poundIdx)); } else { return null; } }
/** * Creates/finds the set of build rules that correspond to pre-dex'd artifacts that should be * merged to create the final classes.dex for the APK. * * <p>This method may modify {@code ruleResolver}, inserting new rules into its index. */ @VisibleForTesting BuildRule createPreDexMergeRule(UberRDotJava uberRDotJava) { ImmutableSet.Builder<DexProducedFromJavaLibrary> preDexDeps = ImmutableSet.builder(); ImmutableSet<JavaLibrary> transitiveJavaDeps = Classpaths.getClasspathEntries(originalDeps).keySet(); for (JavaLibrary javaLibrary : transitiveJavaDeps) { // If the rule has no output file (which happens when a java_library has no srcs or // resources, but export_deps is true), then there will not be anything to dx. if (javaLibrary.getPathToOutputFile() == null) { continue; } // If the rule is in the no_dx list, then do not pre-dex it. if (buildRulesToExcludeFromDex.contains(javaLibrary.getBuildTarget())) { continue; } // See whether the corresponding IntermediateDexRule has already been added to the // ruleResolver. BuildTarget originalTarget = javaLibrary.getBuildTarget(); BuildTarget preDexTarget = new BuildTarget(originalTarget.getBaseName(), originalTarget.getShortName(), DEX_FLAVOR); BuildRule preDexRule = ruleResolver.get(preDexTarget); if (preDexRule != null) { preDexDeps.add((DexProducedFromJavaLibrary) preDexRule.getBuildable()); continue; } // Create the IntermediateDexRule and add it to both the ruleResolver and preDexDeps. DexProducedFromJavaLibrary preDex = new DexProducedFromJavaLibrary(preDexTarget, javaLibrary); buildRuleAndAddToIndex( preDex, BuildRuleType.PRE_DEX, preDexTarget, ImmutableSortedSet.of(ruleResolver.get(javaLibrary.getBuildTarget()))); preDexDeps.add(preDex); } ImmutableSet<DexProducedFromJavaLibrary> allPreDexDeps = preDexDeps.build(); BuildTarget buildTargetForDexMerge = createBuildTargetWithFlavor(DEX_MERGE_FLAVOR); PreDexMerge preDexMerge = new PreDexMerge( buildTargetForDexMerge, primaryDexPath, dexSplitMode, allPreDexDeps, uberRDotJava); BuildRule preDexMergeBuildRule = buildRuleAndAddToIndex( preDexMerge, BuildRuleType.DEX_MERGE, buildTargetForDexMerge, getDexMergeDeps(uberRDotJava, allPreDexDeps)); return preDexMergeBuildRule; }
@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))); }
@Override public ImmutableList<Step> getBuildSteps( BuildContext context, BuildableContext buildableContext) { ImmutableList.Builder<Step> commands = ImmutableList.builder(); commands.add(new MakeCleanDirectoryStep(getProjectFilesystem(), genPath)); BuildTarget target = getBuildTarget(); Path outputDirectory = BuildTargets.getScratchPath(target, "__%s.aidl"); commands.add(new MakeCleanDirectoryStep(getProjectFilesystem(), outputDirectory)); AidlStep command = new AidlStep( getProjectFilesystem(), target, getResolver().getAbsolutePath(aidlFilePath), ImmutableSet.of(importPath), outputDirectory); commands.add(command); // Files must ultimately be written to GEN_DIR to be used as source paths. Path genDirectory = Paths.get(BuckConstant.GEN_DIR, importPath); // Warn the user if the genDirectory is not under the output directory. if (!importPath.startsWith(target.getBasePath().toString())) { // TODO(shs96c): Make this fatal. Give people some time to clean up their rules. context .getEventBus() .post( ConsoleEvent.warning( "%s, gen_aidl import path (%s) should be a child of %s", target, importPath, target.getBasePath())); } commands.add(new MkdirStep(getProjectFilesystem(), genDirectory)); commands.add( new JarDirectoryStep( getProjectFilesystem(), output, ImmutableSortedSet.of(outputDirectory), /* main class */ null, /* manifest */ null)); buildableContext.recordArtifact(output); return commands.build(); }
/** * @param values Collection whose entries identify fields for the generated {@code BuildConfig} * class. The values for fields can be overridden by values from the {@code valuesFile} file, * if present. * @param valuesFile Path to a file with values to override those in {@code values}. */ static AndroidBuildConfigJavaLibrary createBuildRule( BuildRuleParams params, String javaPackage, BuildConfigFields values, Optional<SourcePath> valuesFile, boolean useConstantExpressions) { // Create one build rule to generate BuildConfig.java. BuildRuleParams buildConfigParams = params.copyWithChanges( GEN_JAVA_TYPE, BuildTarget.builder(params.getBuildTarget()).setFlavor(GEN_JAVA_FLAVOR).build(), params.getDeclaredDeps(), params.getExtraDeps()); AndroidBuildConfig androidBuildConfig = new AndroidBuildConfig( buildConfigParams, javaPackage, values, valuesFile, useConstantExpressions); // Create a second build rule to compile BuildConfig.java and expose it as a JavaLibrary. BuildRuleParams javaLibraryParams = params.copyWithChanges( TYPE, params.getBuildTarget(), /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(androidBuildConfig), /* extraDeps */ ImmutableSortedSet.<BuildRule>of()); return new AndroidBuildConfigJavaLibrary(javaLibraryParams, androidBuildConfig); }
/** * If the source paths specified contains one source path to a non-generated file then we should * return the correct source tmp corresponding to that non-generated source path. Especially when * the generated file comes first in the ordered set. */ @Test public void testMixedSourceFile() { Path pathToGenFile = GEN_PATH.resolve("com/facebook/GeneratedFile.java"); Path pathToNonGenFile1 = Paths.get("package/src/SourceFile1.java"); Path pathToNonGenFile2 = Paths.get("package/src-gen/SourceFile2.java"); ImmutableSortedSet<Path> javaSrcs = ImmutableSortedSet.of(pathToGenFile, pathToNonGenFile1, pathToNonGenFile2); DefaultJavaPackageFinder defaultJavaPackageFinder = createMock(DefaultJavaPackageFinder.class); expect(defaultJavaPackageFinder.getPathsFromRoot()).andReturn(pathsFromRoot).times(2); expect(defaultJavaPackageFinder.getPathElements()).andReturn(pathElements).times(2); JavaLibrary javaLibrary = new FakeJavaLibrary( BuildTarget.builder("//foo", "bar").build(), new SourcePathResolver(new BuildRuleResolver())) .setJavaSrcs(javaSrcs); replay(defaultJavaPackageFinder); ImmutableSet<String> result = TestRunning.getPathToSourceFolders( javaLibrary, Optional.of(defaultJavaPackageFinder), new FakeProjectFilesystem()); assertEquals( "The non-generated source files are under two different source folders.", ImmutableSet.of("./package/src-gen/", "./package/src/"), result); verify(defaultJavaPackageFinder); }
/** * If the source paths specified are from the new unified source tmp then we should return the * correct source tmp corresponding to the unified source path. */ @Test public void testUnifiedSourceFile() { Path pathToNonGenFile = Paths.get("java/package/SourceFile1.java"); assertFalse(MorePaths.isGeneratedFile(pathToNonGenFile)); ImmutableSortedSet<Path> javaSrcs = ImmutableSortedSet.of(pathToNonGenFile); JavaLibrary javaLibrary = new FakeJavaLibrary( BuildTarget.builder("//foo", "bar").build(), new SourcePathResolver(new BuildRuleResolver())) .setJavaSrcs(javaSrcs); DefaultJavaPackageFinder defaultJavaPackageFinder = createMock(DefaultJavaPackageFinder.class); expect(defaultJavaPackageFinder.getPathsFromRoot()).andReturn(pathsFromRoot); Object[] mocks = new Object[] {defaultJavaPackageFinder}; replay(mocks); ImmutableSet<String> result = TestRunning.getPathToSourceFolders( javaLibrary, Optional.of(defaultJavaPackageFinder), new FakeProjectFilesystem()); assertEquals( "All non-generated source files are under one source tmp.", ImmutableSet.of("java/"), result); verify(mocks); }
/** * Build the {@link HeaderSymlinkTree} rule using the original build params from a target node. In * particular, make sure to drop all dependencies from the original build rule params, as these * are modeled via {@link CxxPreprocessAndCompile}. */ public static HeaderSymlinkTree createHeaderSymlinkTreeBuildRule( SourcePathResolver resolver, BuildTarget target, BuildRuleParams params, Path root, Optional<Path> headerMapPath, ImmutableMap<Path, SourcePath> links) { // Symlink trees never need to depend on anything. BuildRuleParams paramsWithoutDeps = params.copyWithChanges( target, Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()), Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())); try { if (headerMapPath.isPresent()) { return new HeaderSymlinkTreeWithHeaderMap( paramsWithoutDeps, resolver, root, headerMapPath.get(), links); } else { return new HeaderSymlinkTree(paramsWithoutDeps, resolver, root, links); } } catch (SymlinkTree.InvalidSymlinkTreeException e) { throw e.getHumanReadableExceptionForBuildTarget(target.getUnflavoredBuildTarget()); } }
@Test public void coerceCrossRepoBuildTarget() throws CoerceFailedException, IOException { final Path helloRoot = Paths.get("/opt/src/hello"); cellRoots = new Function<Optional<String>, Path>() { @Override public Path apply(Optional<String> input) { if (!input.isPresent()) { return projectFilesystem.getRootPath(); } if ("hello".equals(input.get())) { return helloRoot; } throw new RuntimeException("Boom!"); } }; SourcePath sourcePath = sourcePathTypeCoercer.coerce( cellRoots, projectFilesystem, pathRelativeToProjectRoot, "@hello//:hello"); assertEquals( new BuildTargetSourcePath( BuildTarget.of( UnflavoredBuildTarget.of(helloRoot, Optional.of("hello"), "//", "hello"), ImmutableSortedSet.<Flavor>of())), sourcePath); }
public ImmutableSet<TargetNode<?>> getAllTargetNodes( final BuckEventBus eventBus, final Cell cell, ProjectBuildFileParser parser, final Path buildFile, final TargetNodeListener nodeListener) throws BuildFileParseException, InterruptedException { Preconditions.checkState(buildFile.isAbsolute()); invalidateIfProjectBuildFileParserStateChanged(cell); try { List<Map<String, Object>> allRawNodes = loadRawNodes(cell, buildFile, parser); ImmutableSet.Builder<TargetNode<?>> nodes = ImmutableSet.builder(); for (final Map<String, Object> rawNode : allRawNodes) { UnflavoredBuildTarget unflavored = parseBuildTargetFromRawRule(cell.getRoot(), rawNode); final BuildTarget target = BuildTarget.of(unflavored); TargetNode<?> node = allTargetNodes.get( target, new Callable<TargetNode<?>>() { @Override public TargetNode<?> call() throws Exception { return createTargetNode( eventBus, cell, buildFile, target, rawNode, nodeListener); } }); nodes.add(node); } return nodes.build(); } catch (UncheckedExecutionException | ExecutionException e) { throw propagate(e); } }
private Cell getCell(BuildTarget target) { Cell cell = cells.get(target.getCellPath()); if (cell != null) { return cell; } for (Cell possibleOwner : cells.values()) { Optional<Cell> maybe = possibleOwner.getCellIfKnown(target); if (maybe.isPresent()) { register(maybe.get()); return maybe.get(); } } throw new HumanReadableException( "From %s, unable to find cell rooted at: %s", target, target.getCellPath()); }
/** * If the source paths specified are all generated files, then our path to source tmp should be * absent. */ @Test public void testGeneratedSourceFile() { Path pathToGenFile = GEN_PATH.resolve("GeneratedFile.java"); assertTrue(MorePaths.isGeneratedFile(pathToGenFile)); ImmutableSortedSet<Path> javaSrcs = ImmutableSortedSet.of(pathToGenFile); JavaLibrary javaLibrary = new FakeJavaLibrary( BuildTarget.builder("//foo", "bar").build(), new SourcePathResolver(new BuildRuleResolver())) .setJavaSrcs(javaSrcs); DefaultJavaPackageFinder defaultJavaPackageFinder = createMock(DefaultJavaPackageFinder.class); Object[] mocks = new Object[] {defaultJavaPackageFinder}; replay(mocks); ImmutableSet<String> result = TestRunning.getPathToSourceFolders( javaLibrary, Optional.of(defaultJavaPackageFinder), new FakeProjectFilesystem()); assertTrue( "No path should be returned if the library contains only generated files.", result.isEmpty()); verify(mocks); }
/** * Note that if this Parser is populated via {@link #filterAllTargetsInProject}, then this method * should not be called. */ private void parseBuildFileContainingTarget( BuildTarget buildTarget, Iterable<String> defaultIncludes, ProjectBuildFileParser buildFileParser) throws BuildFileParseException, BuildTargetException, IOException { if (isCacheComplete(defaultIncludes)) { // In this case, all of the build rules should have been loaded into the knownBuildTargets // Map before this method was invoked. Therefore, there should not be any more build files to // parse. This must be the result of traversing a non-existent dep in a build rule, so an // error is reported to the user. Unfortunately, the source of the build file where the // non-existent rule was declared is not known at this point, which is why it is not included // in the error message. throw new HumanReadableException("No such build target: %s.", buildTarget); } File buildFile = buildTarget.getBuildFile(projectFilesystem); if (isCached(buildFile, defaultIncludes)) { throw new HumanReadableException( "The build file that should contain %s has already been parsed (%s), " + "but %s was not found. Please make sure that %s is defined in %s.", buildTarget, buildFile, buildTarget, buildTarget, buildFile); } parseBuildFile(buildFile, defaultIncludes, buildFileParser); }
/** * @return the {@link BuildTarget} to use for the {@link BuildRule} generating the symlink tree of * shared libraries. */ public static BuildTarget createSharedLibrarySymlinkTreeTarget( BuildTarget target, Flavor platform) { return BuildTarget.builder(target) .addFlavors(SHARED_LIBRARY_SYMLINK_TREE_FLAVOR) .addFlavors(platform) .build(); }
public static BuildTarget createStaticLibraryBuildTarget( BuildTarget target, Flavor platform, CxxSourceRuleFactory.PicType pic) { return BuildTarget.builder(target) .addFlavors(platform) .addFlavors(pic == CxxSourceRuleFactory.PicType.PDC ? STATIC_FLAVOR : STATIC_PIC_FLAVOR) .build(); }
/** * @return the {@link BuildTarget} to use for the {@link BuildRule} generating the symlink tree of * headers. */ public static BuildTarget createHeaderSymlinkTreeTarget( BuildTarget target, Flavor platform, HeaderVisibility headerVisibility) { return BuildTarget.builder(target) .addFlavors(platform) .addFlavors(getHeaderSymlinkTreeFlavor(headerVisibility)) .build(); }