/**
   * Build a {@link HeaderSymlinkTree} of all the shared libraries found via the top-level rule's
   * transitive dependencies.
   */
  public static SymlinkTree createSharedLibrarySymlinkTree(
      TargetGraph targetGraph,
      BuildRuleParams params,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      Predicate<Object> traverse) {

    BuildTarget symlinkTreeTarget =
        createSharedLibrarySymlinkTreeTarget(params.getBuildTarget(), cxxPlatform.getFlavor());
    Path symlinkTreeRoot =
        getSharedLibrarySymlinkTreePath(params.getBuildTarget(), cxxPlatform.getFlavor());

    ImmutableSortedMap<String, SourcePath> libraries =
        NativeLinkables.getTransitiveSharedLibraries(
            targetGraph, cxxPlatform, params.getDeps(), Linker.LinkableDepType.SHARED, traverse);

    ImmutableMap.Builder<Path, SourcePath> links = ImmutableMap.builder();
    for (Map.Entry<String, SourcePath> ent : libraries.entrySet()) {
      links.put(Paths.get(ent.getKey()), ent.getValue());
    }
    try {
      return new SymlinkTree(
          params.copyWithChanges(
              symlinkTreeTarget,
              Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()),
              Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
          pathResolver,
          symlinkTreeRoot,
          links.build());
    } catch (SymlinkTree.InvalidSymlinkTreeException e) {
      throw new RuntimeException(e.getMessage());
    }
  }
示例#2
0
  @Override
  public NativeLinkableInput getNativeLinkableInput(
      TargetGraph targetGraph, CxxPlatform cxxPlatform, Linker.LinkableDepType type) {

    if (!isPlatformSupported(cxxPlatform)) {
      return NativeLinkableInput.of();
    }

    if (headerOnly.apply(cxxPlatform)) {
      return NativeLinkableInput.of(
          ImmutableList.<Arg>of(),
          Preconditions.checkNotNull(frameworks),
          ImmutableSet.<FrameworkPath>of());
    }

    // Build up the arguments used to link this library.  If we're linking the
    // whole archive, wrap the library argument in the necessary "ld" flags.
    ImmutableList.Builder<Arg> linkerArgsBuilder = ImmutableList.builder();
    linkerArgsBuilder.addAll(Preconditions.checkNotNull(exportedLinkerFlags.apply(cxxPlatform)));

    if (type != Linker.LinkableDepType.SHARED || linkage == Linkage.STATIC) {
      BuildRule rule =
          requireBuildRule(
              targetGraph,
              cxxPlatform.getFlavor(),
              type == Linker.LinkableDepType.STATIC
                  ? CxxDescriptionEnhancer.STATIC_FLAVOR
                  : CxxDescriptionEnhancer.STATIC_PIC_FLAVOR);
      Arg library =
          new SourcePathArg(getResolver(), new BuildTargetSourcePath(rule.getBuildTarget()));
      if (linkWhole) {
        Linker linker = cxxPlatform.getLd();
        linkerArgsBuilder.addAll(linker.linkWhole(library));
      } else {
        linkerArgsBuilder.add(library);
      }
    } else {
      BuildRule rule =
          requireBuildRule(
              targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR);
      linkerArgsBuilder.add(
          new SourcePathArg(getResolver(), new BuildTargetSourcePath(rule.getBuildTarget())));
    }
    final ImmutableList<Arg> linkerArgs = linkerArgsBuilder.build();

    return NativeLinkableInput.of(
        linkerArgs, Preconditions.checkNotNull(frameworks), Preconditions.checkNotNull(libraries));
  }
示例#3
0
  @Override
  public CxxPreprocessorInput getCxxPreprocessorInput(
      CxxPlatform cxxPlatform, HeaderVisibility headerVisibility)
      throws NoSuchBuildTargetException {
    CxxPreprocessorInput.Builder builder = CxxPreprocessorInput.builder();

    switch (headerVisibility) {
      case PUBLIC:
        if (Preconditions.checkNotNull(hasHeaders.apply(cxxPlatform))) {
          CxxPreprocessables.addHeaderSymlinkTree(
              builder,
              getBuildTarget(),
              ruleResolver,
              cxxPlatform.getFlavor(),
              headerVisibility,
              CxxPreprocessables.IncludeType.SYSTEM);
        }
        builder.putAllPreprocessorFlags(
            Preconditions.checkNotNull(exportedPreprocessorFlags.apply(cxxPlatform)));
        // Just pass the include dirs as system includes.
        builder.addAllSystemIncludeRoots(
            Iterables.transform(includeDirs, getProjectFilesystem().getAbsolutifier()));
        return builder.build();
      case PRIVATE:
        return builder.build();
    }

    // We explicitly don't put this in a default statement because we
    // want the compiler to warn if someone modifies the HeaderVisibility enum.
    throw new RuntimeException("Invalid header visibility: " + headerVisibility);
  }
示例#4
0
 @Override
 public PythonPackageComponents getPythonPackageComponents(
     TargetGraph targetGraph, PythonPlatform pythonPlatform, CxxPlatform cxxPlatform) {
   if (headerOnly.apply(cxxPlatform)) {
     return PythonPackageComponents.of();
   }
   if (linkage == Linkage.STATIC) {
     return PythonPackageComponents.of();
   }
   if (!isPlatformSupported(cxxPlatform)) {
     return PythonPackageComponents.of();
   }
   ImmutableMap.Builder<Path, SourcePath> libs = ImmutableMap.builder();
   String sharedLibrarySoname =
       soname.or(
           CxxDescriptionEnhancer.getDefaultSharedLibrarySoname(getBuildTarget(), cxxPlatform));
   BuildRule sharedLibraryBuildRule =
       requireBuildRule(
           targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR);
   libs.put(
       Paths.get(sharedLibrarySoname),
       new BuildTargetSourcePath(sharedLibraryBuildRule.getBuildTarget()));
   return PythonPackageComponents.of(
       /* modules */ ImmutableMap.<Path, SourcePath>of(),
       /* resources */ ImmutableMap.<Path, SourcePath>of(),
       /* nativeLibraries */ libs.build(),
       /* prebuiltLibraries */ ImmutableSet.<SourcePath>of(),
       /* zipSafe */ Optional.<Boolean>absent());
 }
  @Test
  public void testSimpleCxxBinaryWithHeader() throws IOException {
    ProjectWorkspace workspace =
        TestDataHelper.createProjectWorkspaceForScenario(this, "simple", tmp);
    workspace.setUp();

    CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig()));
    BuildTarget target = BuildTargetFactory.newInstance("//foo:simple_with_header");
    CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform);
    BuildTarget binaryTarget = CxxDescriptionEnhancer.createCxxLinkTarget(target);
    String sourceName = "simple_with_header.cpp";
    String headerName = "simple_with_header.h";
    String headerFull = "foo/" + headerName;
    BuildTarget preprocessTarget =
        cxxSourceRuleFactory.createPreprocessBuildTarget(
            sourceName, CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC);
    BuildTarget compileTarget =
        cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC);
    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            target, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);

    // Do a clean build, verify that it succeeds, and check that all expected targets built
    // successfully.
    workspace.runBuckCommand("build", target.toString()).assertSuccess();
    BuckBuildLog buildLog = workspace.getBuildLog();
    assertEquals(
        ImmutableSet.of(
            headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target),
        buildLog.getAllTargets());
    buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString());
    buildLog.assertTargetBuiltLocally(preprocessTarget.toString());
    buildLog.assertTargetBuiltLocally(compileTarget.toString());
    buildLog.assertTargetBuiltLocally(binaryTarget.toString());
    buildLog.assertTargetBuiltLocally(target.toString());

    // Clear for new build.
    workspace.resetBuildLogFile();

    // Update the source file.
    workspace.replaceFileContents(headerFull, "blah = 5", "blah = 6");

    // Check that running a build again makes the source get recompiled and the binary
    // re-linked, but does not cause the header rules to re-run.
    workspace.runBuckCommand("build", target.toString()).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(
        ImmutableSet.of(
            headerSymlinkTreeTarget, preprocessTarget, compileTarget, binaryTarget, target),
        buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString());
    buildLog.assertTargetBuiltLocally(preprocessTarget.toString());
    buildLog.assertTargetBuiltLocally(compileTarget.toString());
    assertThat(
        buildLog.getLogEntry(binaryTarget).getSuccessType().get(),
        Matchers.not(Matchers.equalTo(BuildRuleSuccessType.MATCHING_RULE_KEY)));
    buildLog.assertTargetBuiltLocally(target.toString());
  }
  public static HeaderSymlinkTree createHeaderSymlinkTree(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      boolean includeLexYaccHeaders,
      ImmutableMap<String, SourcePath> lexSources,
      ImmutableMap<String, SourcePath> yaccSources,
      ImmutableMap<Path, SourcePath> headers,
      HeaderVisibility headerVisibility) {

    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility);
    Path headerSymlinkTreeRoot =
        CxxDescriptionEnhancer.getHeaderSymlinkTreePath(
            params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility);
    Optional<Path> headerMapLocation = Optional.absent();
    if (cxxPlatform.getCpp().supportsHeaderMaps() && cxxPlatform.getCxxpp().supportsHeaderMaps()) {
      headerMapLocation =
          Optional.of(
              getHeaderMapPath(params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility));
    }

    CxxHeaderSourceSpec lexYaccSources;
    if (includeLexYaccHeaders) {
      lexYaccSources =
          requireLexYaccSources(
              params, ruleResolver, pathResolver, cxxPlatform, lexSources, yaccSources);
    } else {
      lexYaccSources = CxxHeaderSourceSpec.builder().build();
    }

    return CxxPreprocessables.createHeaderSymlinkTreeBuildRule(
        pathResolver,
        headerSymlinkTreeTarget,
        params,
        headerSymlinkTreeRoot,
        headerMapLocation,
        ImmutableMap.<Path, SourcePath>builder()
            .putAll(headers)
            .putAll(lexYaccSources.getCxxHeaders())
            .build());
  }
示例#7
0
 @Override
 public CxxPreprocessorInput getCxxPreprocessorInput(
     TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) {
   return CxxPreprocessables.getCxxPreprocessorInput(
       targetGraph,
       params,
       ruleResolver,
       cxxPlatform.getFlavor(),
       headerVisibility,
       CxxPreprocessables.IncludeType.LOCAL,
       exportedPreprocessorFlags.apply(cxxPlatform),
       cxxPlatform,
       frameworks);
 }
 public static ImmutableMap<String, CxxSource> parseCxxSources(
     BuildRuleParams params,
     BuildRuleResolver resolver,
     CxxPlatform cxxPlatform,
     ImmutableSortedSet<SourceWithFlags> srcs,
     PatternMatchedCollection<ImmutableSortedSet<SourceWithFlags>> platformSrcs) {
   ImmutableMap.Builder<String, SourceWithFlags> sources = ImmutableMap.builder();
   SourcePathResolver pathResolver = new SourcePathResolver(resolver);
   putAllSources(srcs, sources, pathResolver, params.getBuildTarget());
   for (ImmutableSortedSet<SourceWithFlags> sourcesWithFlags :
       platformSrcs.getMatchingValues(cxxPlatform.getFlavor().toString())) {
     putAllSources(sourcesWithFlags, sources, pathResolver, params.getBuildTarget());
   }
   return CxxCompilableEnhancer.resolveCxxSources(sources.build());
 }
 /**
  * @return a map of header locations to input {@link SourcePath} objects formed by parsing the
  *     input {@link SourcePath} objects for the "headers" parameter.
  */
 public static ImmutableMap<Path, SourcePath> parseHeaders(
     BuildRuleParams params,
     BuildRuleResolver resolver,
     CxxPlatform cxxPlatform,
     CxxConstructorArg args) {
   ImmutableMap.Builder<String, SourcePath> headers = ImmutableMap.builder();
   SourcePathResolver pathResolver = new SourcePathResolver(resolver);
   putAllHeaders(args.headers.get(), headers, pathResolver, "headers", params.getBuildTarget());
   for (SourceList sourceList :
       args.platformHeaders.get().getMatchingValues(cxxPlatform.getFlavor().toString())) {
     putAllHeaders(sourceList, headers, pathResolver, "platform_headers", params.getBuildTarget());
   }
   return CxxPreprocessables.resolveHeaderMap(
       args.headerNamespace.transform(MorePaths.TO_PATH).or(params.getBuildTarget().getBasePath()),
       headers.build());
 }
 public static String getDefaultSharedLibrarySoname(BuildTarget target, CxxPlatform platform) {
   String libName =
       Joiner.on('_')
           .join(
               ImmutableList.builder()
                   .addAll(
                       FluentIterable.from(target.getBasePath())
                           .transform(Functions.toStringFunction())
                           .filter(Predicates.not(Predicates.equalTo(""))))
                   .add(
                       target
                           .withoutFlavors(ImmutableSet.of(platform.getFlavor()))
                           .getShortNameAndFlavorPostfix())
                   .build());
   String extension = platform.getSharedLibraryExtension();
   return String.format("lib%s.%s", libName, extension);
 }
示例#11
0
  /**
   * Makes sure all build rules needed to produce the shared library are added to the action graph.
   *
   * @return the {@link SourcePath} representing the actual shared library.
   */
  private SourcePath requireSharedLibrary(CxxPlatform cxxPlatform)
      throws NoSuchBuildTargetException {
    Path sharedLibraryPath =
        PrebuiltCxxLibraryDescription.getSharedLibraryPath(
            getBuildTarget(), params.getCellRoots(), ruleResolver, cxxPlatform, libDir, libName);

    // If the shared library is prebuilt, just return a reference to it.
    if (params.getProjectFilesystem().exists(sharedLibraryPath)) {
      return new PathSourcePath(params.getProjectFilesystem(), sharedLibraryPath);
    }

    // Otherwise, generate it's build rule.
    BuildRule sharedLibrary =
        ruleResolver.requireRule(
            getBuildTarget()
                .withFlavors(cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR));

    return new BuildTargetSourcePath(sharedLibrary.getBuildTarget());
  }
示例#12
0
 @Override
 public ImmutableMap<BuildTarget, CxxPreprocessorInput> getTransitiveCxxPreprocessorInput(
     TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) {
   Pair<Flavor, HeaderVisibility> key = new Pair<>(cxxPlatform.getFlavor(), headerVisibility);
   ImmutableMap<BuildTarget, CxxPreprocessorInput> result = cxxPreprocessorInputCache.get(key);
   if (result == null) {
     Map<BuildTarget, CxxPreprocessorInput> builder = Maps.newLinkedHashMap();
     builder.put(
         getBuildTarget(), getCxxPreprocessorInput(targetGraph, cxxPlatform, headerVisibility));
     for (BuildRule dep : getDeps()) {
       if (dep instanceof CxxPreprocessorDep) {
         builder.putAll(
             ((CxxPreprocessorDep) dep)
                 .getTransitiveCxxPreprocessorInput(targetGraph, cxxPlatform, headerVisibility));
       }
     }
     result = ImmutableMap.copyOf(builder);
     cxxPreprocessorInputCache.put(key, result);
   }
   return result;
 }
示例#13
0
 @Override
 public ImmutableMap<String, SourcePath> getSharedLibraries(
     TargetGraph targetGraph, CxxPlatform cxxPlatform) {
   if (headerOnly.apply(cxxPlatform)) {
     return ImmutableMap.of();
   }
   if (linkage == Linkage.STATIC) {
     return ImmutableMap.of();
   }
   if (!isPlatformSupported(cxxPlatform)) {
     return ImmutableMap.of();
   }
   ImmutableMap.Builder<String, SourcePath> libs = ImmutableMap.builder();
   String sharedLibrarySoname =
       soname.or(
           CxxDescriptionEnhancer.getDefaultSharedLibrarySoname(getBuildTarget(), cxxPlatform));
   BuildRule sharedLibraryBuildRule =
       requireBuildRule(
           targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR);
   libs.put(
       sharedLibrarySoname, new BuildTargetSourcePath(sharedLibraryBuildRule.getBuildTarget()));
   return libs.build();
 }
  public static HeaderSymlinkTree requireHeaderSymlinkTree(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      boolean includeLexYaccHeaders,
      ImmutableMap<String, SourcePath> lexSources,
      ImmutableMap<String, SourcePath> yaccSources,
      ImmutableMap<Path, SourcePath> headers,
      HeaderVisibility headerVisibility) {
    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility);

    // Check the cache...
    Optional<BuildRule> rule = ruleResolver.getRuleOptional(headerSymlinkTreeTarget);
    if (rule.isPresent()) {
      Preconditions.checkState(rule.get() instanceof HeaderSymlinkTree);
      return (HeaderSymlinkTree) rule.get();
    }

    HeaderSymlinkTree symlinkTree =
        createHeaderSymlinkTree(
            params,
            ruleResolver,
            pathResolver,
            cxxPlatform,
            includeLexYaccHeaders,
            lexSources,
            yaccSources,
            headers,
            headerVisibility);

    ruleResolver.addToIndex(symlinkTree);

    return symlinkTree;
  }
示例#15
0
  @Override
  public NativeLinkableInput getNativeLinkableInput(
      TargetGraph targetGraph, CxxPlatform cxxPlatform, Linker.LinkableDepType type) {

    if (!isPlatformSupported(cxxPlatform)) {
      return NativeLinkableInput.of();
    }

    if (headerOnly.apply(cxxPlatform)) {
      return NativeLinkableInput.of(
          ImmutableList.<SourcePath>of(),
          ImmutableList.<String>of(),
          Preconditions.checkNotNull(frameworks),
          ImmutableSet.<FrameworkPath>of());
    }

    // Build up the arguments used to link this library.  If we're linking the
    // whole archive, wrap the library argument in the necessary "ld" flags.
    final Pair<ImmutableList<String>, ImmutableSet<SourcePath>> flagsAndBuildInputs =
        exportedLinkerFlags.apply(cxxPlatform);
    ImmutableList.Builder<String> linkerArgsBuilder = ImmutableList.builder();
    linkerArgsBuilder.addAll(flagsAndBuildInputs.getFirst());

    final BuildRule libraryRule;
    if (type != Linker.LinkableDepType.SHARED || linkage == Linkage.STATIC) {
      libraryRule =
          requireBuildRule(
              targetGraph,
              cxxPlatform.getFlavor(),
              type == Linker.LinkableDepType.STATIC
                  ? CxxDescriptionEnhancer.STATIC_FLAVOR
                  : CxxDescriptionEnhancer.STATIC_PIC_FLAVOR);
      Path staticLibraryPath =
          CxxDescriptionEnhancer.getStaticLibraryPath(
              getBuildTarget(),
              cxxPlatform.getFlavor(),
              type == Linker.LinkableDepType.STATIC
                  ? CxxSourceRuleFactory.PicType.PDC
                  : CxxSourceRuleFactory.PicType.PIC);
      if (linkWhole) {
        Linker linker = cxxPlatform.getLd();
        linkerArgsBuilder.addAll(linker.linkWhole(staticLibraryPath.toString()));
      } else {
        linkerArgsBuilder.add(staticLibraryPath.toString());
      }
    } else {
      String sharedLibrarySoname =
          soname.or(
              CxxDescriptionEnhancer.getDefaultSharedLibrarySoname(
                  params.getBuildTarget(), cxxPlatform));
      Path sharedLibraryPath =
          CxxDescriptionEnhancer.getSharedLibraryPath(
              getBuildTarget(), sharedLibrarySoname, cxxPlatform);
      libraryRule =
          requireBuildRule(
              targetGraph, cxxPlatform.getFlavor(), CxxDescriptionEnhancer.SHARED_FLAVOR);
      linkerArgsBuilder.add(sharedLibraryPath.toString());
    }
    final ImmutableList<String> linkerArgs = linkerArgsBuilder.build();

    return NativeLinkableInput.of(
        ImmutableList.<SourcePath>builder()
            .add(new BuildTargetSourcePath(libraryRule.getBuildTarget()))
            .addAll(flagsAndBuildInputs.getSecond())
            .build(),
        linkerArgs,
        Preconditions.checkNotNull(frameworks),
        Preconditions.checkNotNull(libraries));
  }
  private <A extends Arg> BuildRule createExtensionBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      CxxPlatform cxxPlatform,
      A args) {
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

    // Extract all C/C++ sources from the constructor arg.
    ImmutableMap<String, CxxSource> srcs =
        CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<Path, SourcePath> headers =
        CxxDescriptionEnhancer.parseHeaders(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<String, SourcePath> lexSrcs =
        CxxDescriptionEnhancer.parseLexSources(params, ruleResolver, args);
    ImmutableMap<String, SourcePath> yaccSrcs =
        CxxDescriptionEnhancer.parseYaccSources(params, ruleResolver, args);

    CxxHeaderSourceSpec lexYaccSources =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            ruleResolver,
            cxxPlatform,
            ImmutableList.<String>of(),
            lexSrcs,
            ImmutableList.<String>of(),
            yaccSrcs);

    // Setup the header symlink tree and combine all the preprocessor input from this rule
    // and all dependencies.
    HeaderSymlinkTree headerSymlinkTree =
        CxxDescriptionEnhancer.requireHeaderSymlinkTree(
            params,
            ruleResolver,
            new SourcePathResolver(ruleResolver),
            cxxPlatform,
            /* includeLexYaccHeaders */ true,
            lexSrcs,
            yaccSrcs,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        CxxDescriptionEnhancer.collectCxxPreprocessorInput(
            targetGraph,
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                args.preprocessorFlags,
                args.platformPreprocessorFlags,
                args.langPreprocessorFlags,
                cxxPlatform),
            args.prefixHeaders.get(),
            ImmutableList.of(headerSymlinkTree),
            ImmutableSet.<Path>of(),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(
                targetGraph, cxxPlatform, params.getDeps()));

    ImmutableMap<String, CxxSource> allSources =
        ImmutableMap.<String, CxxSource>builder()
            .putAll(srcs)
            .putAll(lexYaccSources.getCxxSources())
            .build();

    // Generate rule to build the object files.
    ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects =
        CxxSourceRuleFactory.requirePreprocessAndCompileRules(
            params,
            ruleResolver,
            pathResolver,
            cxxPlatform,
            cxxPreprocessorInput,
            CxxFlags.getFlags(args.compilerFlags, args.platformCompilerFlags, cxxPlatform),
            cxxBuckConfig.getPreprocessMode(),
            allSources,
            CxxSourceRuleFactory.PicType.PIC);

    // Setup the rules to link the shared library.
    String extensionName = getExtensionName(params.getBuildTarget());
    Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor());
    return CxxLinkableEnhancer.createCxxLinkableBuildRule(
        targetGraph,
        cxxPlatform,
        params,
        pathResolver,
        /* extraLdFlags */ CxxFlags.getFlags(
            args.linkerFlags, args.platformLinkerFlags, cxxPlatform),
        getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()),
        Linker.LinkType.SHARED,
        Optional.of(extensionName),
        extensionPath,
        picObjects.values(),
        Linker.LinkableDepType.SHARED,
        params.getDeps(),
        args.cxxRuntimeType,
        Optional.<SourcePath>absent());
  }
  public void doTestSimpleCxxBinaryBuilds(String preprocessMode, boolean expectPreprocessorOutput)
      throws IOException {
    ProjectWorkspace workspace =
        TestDataHelper.createProjectWorkspaceForScenario(this, "simple", tmp);
    workspace.setUp();
    workspace.writeContentsToPath(
        String.format("[cxx]\npreprocess_mode = %s\n", preprocessMode), ".buckconfig");
    CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig()));
    BuildTarget target = BuildTargetFactory.newInstance("//foo:simple");
    CxxSourceRuleFactory cxxSourceRuleFactory = CxxSourceRuleFactoryHelper.of(target, cxxPlatform);
    BuildTarget binaryTarget = CxxDescriptionEnhancer.createCxxLinkTarget(target);
    String sourceName = "simple.cpp";
    String sourceFull = "foo/" + sourceName;
    BuildTarget preprocessTarget =
        cxxSourceRuleFactory.createPreprocessBuildTarget(
            sourceName, CxxSource.Type.CXX, CxxSourceRuleFactory.PicType.PDC);
    BuildTarget compileTarget =
        cxxSourceRuleFactory.createCompileBuildTarget(sourceName, CxxSourceRuleFactory.PicType.PDC);
    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            target, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);

    // Do a clean build, verify that it succeeds, and check that all expected targets built
    // successfully.
    workspace.runBuckCommand("build", target.toString()).assertSuccess();
    BuckBuildLog buildLog = workspace.getBuildLog();
    ImmutableSet<BuildTarget> expectedTargets =
        ImmutableSet.<BuildTarget>builder()
            .addAll(ImmutableSet.of(headerSymlinkTreeTarget, compileTarget, binaryTarget, target))
            .addAll(
                (expectPreprocessorOutput
                    ? ImmutableSet.of(preprocessTarget)
                    : ImmutableSet.<BuildTarget>of()))
            .build();

    assertEquals(expectedTargets, buildLog.getAllTargets());
    buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString());
    if (expectPreprocessorOutput) {
      buildLog.assertTargetBuiltLocally(preprocessTarget.toString());
    }
    buildLog.assertTargetBuiltLocally(compileTarget.toString());
    buildLog.assertTargetBuiltLocally(binaryTarget.toString());
    buildLog.assertTargetBuiltLocally(target.toString());

    // Clear for new build.
    workspace.resetBuildLogFile();

    // Check that running a build again results in no builds since everything is up to
    // date.
    workspace.runBuckCommand("build", target.toString()).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(ImmutableSet.of(target, binaryTarget), buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(binaryTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(target.toString());

    // Clear for new build.
    workspace.resetBuildLogFile();

    // Update the source file.
    workspace.replaceFileContents(sourceFull, "{}", "{ return 0; }");

    // Check that running a build again makes the source get recompiled and the binary
    // re-linked, but does not cause the header rules to re-run.
    workspace.runBuckCommand("build", target.toString()).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(expectedTargets, buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString());
    if (expectPreprocessorOutput) {
      buildLog.assertTargetBuiltLocally(preprocessTarget.toString());
    }
    buildLog.assertTargetBuiltLocally(compileTarget.toString());
    assertThat(
        buildLog.getLogEntry(binaryTarget).getSuccessType().get(),
        Matchers.not(Matchers.equalTo(BuildRuleSuccessType.MATCHING_RULE_KEY)));
    buildLog.assertTargetBuiltLocally(target.toString());

    // Clear for new build.
    workspace.resetBuildLogFile();

    // Update the source file.
    workspace.replaceFileContents(sourceFull, "{ return 0; }", "won't compile");

    // Check that running a build again makes the source get recompiled and the binary
    // re-linked, but does not cause the header rules to re-run.
    workspace.runBuckCommand("build", target.toString()).assertFailure();
    buildLog = workspace.getBuildLog();
    assertEquals(expectedTargets, buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString());
    if (expectPreprocessorOutput) {
      buildLog.assertTargetBuiltLocally(preprocessTarget.toString());
    }
    assertThat(
        buildLog.getLogEntry(binaryTarget).getStatus(), Matchers.equalTo(BuildRuleStatus.CANCELED));
    assertThat(
        buildLog.getLogEntry(target).getStatus(), Matchers.equalTo(BuildRuleStatus.CANCELED));
  }
  @Test
  public void testInferCxxBinaryWithDeps() throws IOException {
    assumeTrue(Platform.detect() != Platform.WINDOWS);
    ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp);

    CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig()));
    BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:binary_with_deps");
    String inputBuildTargetName =
        inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName();

    /*
     * Build the given target and check that it succeeds.
     */
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();

    /*
     * Check that all the required build targets have been generated.
     */
    String sourceName = "src_with_deps.c";
    CxxSourceRuleFactory cxxSourceRuleFactory =
        CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform);
    // 1. create the targets of binary_with_deps
    // this is unflavored, but bounded to the InferCapture build rule
    BuildTarget topCaptureBuildTarget =
        cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName);

    // this is unflavored, but necessary to run the compiler successfully
    BuildTarget topHeaderSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            inputBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);

    // this is flavored, and denotes the analysis step (generates a local report)
    BuildTarget topInferAnalysisTarget =
        inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE);

    // this is flavored and corresponds to the top level target (the one give in input to buck)
    BuildTarget topInferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER);

    // 2. create the targets of dep_one
    BuildTarget depOneBuildTarget = BuildTargetFactory.newInstance("//foo:dep_one");
    String depOneSourceName = "dep_one.c";
    String depOneSourceFull = "foo/" + depOneSourceName;
    CxxSourceRuleFactory depOneSourceRuleFactory =
        CxxSourceRuleFactoryHelper.of(depOneBuildTarget, cxxPlatform);

    BuildTarget depOneCaptureBuildTarget =
        depOneSourceRuleFactory.createInferCaptureBuildTarget(depOneSourceName);

    BuildTarget depOneHeaderSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            depOneBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);

    BuildTarget depOneExportedHeaderSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            depOneBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC);

    BuildTarget depOneInferAnalysisTarget =
        depOneCaptureBuildTarget.withFlavors(
            cxxPlatform.getFlavor(), CxxInferEnhancer.INFER_ANALYZE);

    // 3. create the targets of dep_two
    BuildTarget depTwoBuildTarget = BuildTargetFactory.newInstance("//foo:dep_two");
    CxxSourceRuleFactory depTwoSourceRuleFactory =
        CxxSourceRuleFactoryHelper.of(depTwoBuildTarget, cxxPlatform);

    BuildTarget depTwoCaptureBuildTarget =
        depTwoSourceRuleFactory.createInferCaptureBuildTarget("dep_two.c");

    BuildTarget depTwoHeaderSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            depTwoBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);

    BuildTarget depTwoExportedHeaderSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            depTwoBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC);

    BuildTarget depTwoInferAnalysisTarget =
        depTwoCaptureBuildTarget.withFlavors(
            cxxPlatform.getFlavor(), CxxInferEnhancer.INFER_ANALYZE);

    // Check all the targets are in the buildLog
    assertEquals(
        ImmutableSet.of(
            topCaptureBuildTarget,
            topHeaderSymlinkTreeTarget,
            topInferAnalysisTarget,
            topInferReportTarget,
            depOneCaptureBuildTarget,
            depOneHeaderSymlinkTreeTarget,
            depOneExportedHeaderSymlinkTreeTarget,
            depOneInferAnalysisTarget,
            depTwoCaptureBuildTarget,
            depTwoHeaderSymlinkTreeTarget,
            depTwoExportedHeaderSymlinkTreeTarget,
            depTwoInferAnalysisTarget),
        workspace.getBuildLog().getAllTargets());

    /*
     * Check that running a build again results in no builds since nothing has changed.
     */
    workspace.resetBuildLogFile(); // clear for new build
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();
    BuckBuildLog buildLog = workspace.getBuildLog();
    assertEquals(ImmutableSet.of(topInferReportTarget), buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(topInferReportTarget.toString());

    /*
     * Check that if a library source file changes then the capture/analysis rules run again on
     * the main target and on dep_one only.
     */
    workspace.resetBuildLogFile();
    workspace.replaceFileContents(depOneSourceFull, "flag > 0", "flag < 0");
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(
        ImmutableSet.of(
            topInferAnalysisTarget, // analysis runs again
            topInferReportTarget, // report runs again
            topCaptureBuildTarget, // cached
            depTwoInferAnalysisTarget, // cached
            depOneCaptureBuildTarget, // capture of the changed file runs again
            depOneExportedHeaderSymlinkTreeTarget, // cached
            depOneHeaderSymlinkTreeTarget, // cached
            depOneInferAnalysisTarget), // analysis of the library runs again
        buildLog.getAllTargets());
    buildLog.assertTargetBuiltLocally(topInferAnalysisTarget.toString());
    buildLog.assertTargetBuiltLocally(topInferReportTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(topCaptureBuildTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(depTwoInferAnalysisTarget.toString());
    buildLog.assertTargetBuiltLocally(depOneCaptureBuildTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(depOneExportedHeaderSymlinkTreeTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(depOneHeaderSymlinkTreeTarget.toString());
    buildLog.assertTargetBuiltLocally(depOneInferAnalysisTarget.toString());
  }
  @Test
  public void testInferCxxBinaryWithoutDeps() throws IOException {
    assumeTrue(Platform.detect() != Platform.WINDOWS);
    ProjectWorkspace workspace = InferHelper.setupCxxInferWorkspace(this, tmp);

    CxxPlatform cxxPlatform = DefaultCxxPlatforms.build(new CxxBuckConfig(new FakeBuckConfig()));
    BuildTarget inputBuildTarget = BuildTargetFactory.newInstance("//foo:simple");
    String inputBuildTargetName =
        inputBuildTarget.withFlavors(CxxInferEnhancer.INFER).getFullyQualifiedName();

    /*
     * Build the given target and check that it succeeds.
     */
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();

    /*
     * Check that all the required build targets have been generated.
     */
    String sourceName = "simple.cpp";
    String sourceFull = "foo/" + sourceName;

    CxxSourceRuleFactory cxxSourceRuleFactory =
        CxxSourceRuleFactoryHelper.of(inputBuildTarget, cxxPlatform);
    // this is unflavored, but bounded to the InferCapture build rule
    BuildTarget captureBuildTarget = cxxSourceRuleFactory.createInferCaptureBuildTarget(sourceName);
    // this is unflavored, but necessary to run the compiler successfully
    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            inputBuildTarget, cxxPlatform.getFlavor(), HeaderVisibility.PRIVATE);
    // this is flavored, and denotes the analysis step (generates a local report)
    BuildTarget inferAnalysisTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER_ANALYZE);

    // this is flavored and corresponds to the top level target (the one give in input to buck)
    BuildTarget inferReportTarget = inputBuildTarget.withFlavors(CxxInferEnhancer.INFER);

    ImmutableSet<BuildTarget> expectedTargets =
        ImmutableSet.<BuildTarget>builder()
            .addAll(
                ImmutableSet.of(
                    headerSymlinkTreeTarget,
                    captureBuildTarget,
                    inferAnalysisTarget,
                    inferReportTarget))
            .build();

    BuckBuildLog buildLog = workspace.getBuildLog();
    assertEquals(expectedTargets, buildLog.getAllTargets());
    buildLog.assertTargetBuiltLocally(headerSymlinkTreeTarget.toString());
    buildLog.assertTargetBuiltLocally(captureBuildTarget.toString());
    buildLog.assertTargetBuiltLocally(inferAnalysisTarget.toString());
    buildLog.assertTargetBuiltLocally(inferReportTarget.toString());

    /*
     * Check that running a build again results in no builds since nothing has changed.
     */
    workspace.resetBuildLogFile(); // clear for new build
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(ImmutableSet.of(inferReportTarget), buildLog.getAllTargets());
    buildLog.assertTargetHadMatchingRuleKey(inferReportTarget.toString());

    /*
     * Check that changing the source file results in running the capture/analysis rules again.
     */
    workspace.resetBuildLogFile();
    workspace.replaceFileContents(sourceFull, "*s = 42;", "");
    workspace.runBuckCommand("build", inputBuildTargetName).assertSuccess();
    buildLog = workspace.getBuildLog();
    assertEquals(expectedTargets, buildLog.getAllTargets());
    buildLog.assertTargetBuiltLocally(captureBuildTarget.toString());
    buildLog.assertTargetBuiltLocally(inferAnalysisTarget.toString());
    buildLog.assertTargetHadMatchingRuleKey(headerSymlinkTreeTarget.toString());
  }
示例#20
0
 private boolean isPlatformSupported(CxxPlatform cxxPlatform) {
   return !supportedPlatformsRegex.isPresent()
       || supportedPlatformsRegex.get().matcher(cxxPlatform.getFlavor().toString()).find();
 }
 public static Path getSharedLibraryPath(BuildTarget target, String soname, CxxPlatform platform) {
   return BuildTargets.getGenPath(
       createSharedLibraryBuildTarget(target, platform.getFlavor()), "%s/" + soname);
 }