@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"));
  }
Example #2
0
  /**
   * @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));
  }
Example #11
0
  @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());
  }
Example #12
0
 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);
 }
Example #14
0
 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");
 }
Example #15
0
 @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)));
  }
Example #18
0
  @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);
  }
Example #20
0
  /**
   * 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);
  }
Example #21
0
  /**
   * 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);
  }
Example #22
0
  /**
   * 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);
  }
Example #24
0
  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);
    }
  }
Example #25
0
  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());
  }
Example #26
0
  /**
   * 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);
  }
Example #27
0
  /**
   * 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();
 }