예제 #1
0
 /** Returns 0, 0 for an unknown line */
 @Override
 Pair<Integer, Integer> getOffsetsForLine(int line) {
   for (int ii = 0, len = table.size(); ii < len; ii++) {
     if (table.get(ii).line == line) {
       return Pair.of(
           table.get(ii).offset, ii < len - 1 ? table.get(ii + 1).offset : bufferLength);
     }
   }
   return Pair.of(0, 0);
 }
예제 #2
0
 /**
  * Creates a {@link MiddlemanType#AGGREGATING_MIDDLEMAN aggregating} middleman.
  *
  * @param owner the owner of the action that will be created; must not be null
  * @param purpose the purpose for which this middleman is created. This should be a string which
  *     is suitable for use as a filename. A single rule may have many middlemen with distinct
  *     purposes.
  * @param inputs the set of artifacts for which the created artifact is to be the middleman.
  * @param middlemanDir the directory in which to place the middleman.
  * @return null iff {@code inputs} is empty; the single element of {@code inputs} if there's only
  *     one; a new aggregating middleman for the {@code inputs} otherwise
  */
 public Artifact createAggregatingMiddleman(
     ActionOwner owner, String purpose, Iterable<Artifact> inputs, Root middlemanDir) {
   if (hasExactlyOneInput(inputs)) { // Optimization: No middleman for just one input.
     return Iterables.getOnlyElement(inputs);
   }
   Pair<Artifact, Action> result =
       createMiddleman(
           owner,
           Label.print(owner.getLabel()),
           purpose,
           inputs,
           middlemanDir,
           MiddlemanType.AGGREGATING_MIDDLEMAN);
   return result == null ? null : result.getFirst();
 }
예제 #3
0
 /**
  * Add a map of generated source or header Artifact to an output Artifact after grepping the
  * file for include statements.
  */
 public Builder addPregreppedHeaderMap(Map<Artifact, Artifact> pregrepped) {
   addCompilationPrerequisites(pregrepped.values());
   for (Map.Entry<Artifact, Artifact> entry : pregrepped.entrySet()) {
     this.pregreppedHdrs.add(Pair.of(entry.getKey(), entry.getValue()));
   }
   return this;
 }
예제 #4
0
 @Override
 Pair<Integer, Integer> getOffsetsForLine(int line) {
   if (line <= 0 || line >= linestart.length) {
     throw new IllegalArgumentException("Illegal line: " + line);
   }
   return Pair.of(
       linestart[line], line < linestart.length - 1 ? linestart[line + 1] : bufferLength);
 }
예제 #5
0
 /**
  * Adds a header to {@code publicHeaders} and in case header processing is switched on for the
  * file type also to compilationUnitSources.
  */
 private void addHeader(Artifact header, Label label) {
   boolean isHeader = CppFileTypes.CPP_HEADER.matches(header.getExecPath());
   boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(header.getExecPath());
   publicHeaders.add(header);
   if (isTextualInclude || !isHeader || !shouldProcessHeaders()) {
     return;
   }
   compilationUnitSources.add(Pair.of(header, label));
 }
예제 #6
0
 /**
  * Extracts the repository name from a PathFragment that was created with {@code
  * PackageIdentifier.getPathFragment}.
  *
  * @return a {@code Pair} of the extracted repository name and the path fragment with stripped of
  *     "external/"-prefix and repository name, or null if none was found or the repository name
  *     was invalid.
  */
 public static Pair<RepositoryName, PathFragment> fromPathFragment(PathFragment path) {
   if (path.segmentCount() < 2 || !path.getSegment(0).equals(Label.EXTERNAL_PATH_PREFIX)) {
     return null;
   }
   try {
     RepositoryName repoName = RepositoryName.create("@" + path.getSegment(1));
     PathFragment subPath = path.subFragment(2, path.segmentCount());
     return Pair.of(repoName, subPath);
   } catch (LabelSyntaxException e) {
     return null;
   }
 }
예제 #7
0
 /**
  * Adds a source to {@code compilationUnitSources} if it is a compiled file type (including
  * parsed/preprocessed header) and to {@code privateHeaders} if it is a header.
  */
 private void addSource(Artifact source, Label label) {
   boolean isHeader = CppFileTypes.CPP_HEADER.matches(source.getExecPath());
   boolean isTextualInclude = CppFileTypes.CPP_TEXTUAL_INCLUDE.matches(source.getExecPath());
   boolean isCompiledSource = SOURCE_TYPES.matches(source.getExecPathString());
   if (isHeader || isTextualInclude) {
     privateHeaders.add(source);
   }
   if (isTextualInclude || !isCompiledSource || (isHeader && !shouldProcessHeaders())) {
     return;
   }
   compilationUnitSources.add(Pair.of(source, label));
 }
예제 #8
0
  /**
   * Splits the link command-line into a part to be written to a parameter file, and the remaining
   * actual command line to be executed (which references the parameter file). Should only be used
   * if getParamFile() is not null.
   *
   * @throws IllegalStateException if the command-line cannot be split
   */
  @VisibleForTesting
  final Pair<List<String>, List<String>> splitCommandline() {
    List<String> args = getRawLinkArgv();
    if (linkTargetType.isStaticLibraryLink()) {
      // Ar link commands can also generate huge command lines.
      List<String> paramFileArgs = args.subList(1, args.size());
      List<String> commandlineArgs = new ArrayList<>();
      commandlineArgs.add(args.get(0));

      commandlineArgs.add("@" + paramFile.getExecPath().getPathString());
      return Pair.of(commandlineArgs, paramFileArgs);
    } else {
      // Gcc link commands tend to generate humongous commandlines for some targets, which may
      // not fit on some remote execution machines. To work around this we will employ the help of
      // a parameter file and pass any linker options through it.
      List<String> paramFileArgs = new ArrayList<>();
      List<String> commandlineArgs = new ArrayList<>();
      extractArgumentsForParamFile(args, commandlineArgs, paramFileArgs);

      commandlineArgs.add("-Wl,@" + paramFile.getExecPath().getPathString());
      return Pair.of(commandlineArgs, paramFileArgs);
    }
  }
예제 #9
0
  /**
   * Creates both normal and scheduling middlemen.
   *
   * <p>Note: there's no need to synchronize this method; the only use of a field is via a call to
   * another synchronized method (getArtifact()).
   *
   * @return null iff {@code inputs} is null or empty; the middleman file and the middleman action
   *     otherwise
   */
  private Pair<Artifact, Action> createMiddleman(
      ActionOwner owner,
      String middlemanName,
      String purpose,
      Iterable<Artifact> inputs,
      Root middlemanDir,
      MiddlemanType middlemanType) {
    if (inputs == null || Iterables.isEmpty(inputs)) {
      return null;
    }

    Artifact stampFile = getStampFileArtifact(middlemanName, purpose, middlemanDir);
    Action action = new MiddlemanAction(owner, inputs, stampFile, purpose, middlemanType);
    actionRegistry.registerAction(action);
    return Pair.of(stampFile, action);
  }
예제 #10
0
  @Test
  public void testSetGlobPaths() throws Exception {
    // This pattern matches no files.
    String pattern = "fake*.java";
    assertThat(cache.getKeySet()).doesNotContain(pattern);

    List<String> results = cache.getGlob(pattern, false);

    assertThat(cache.getKeySet()).contains(Pair.of(pattern, false));
    assertThat(results).isEmpty();

    cache.setGlobPaths(
        pattern,
        false,
        Futures.<List<Path>>immediateFuture(
            Lists.newArrayList(
                scratch.resolve("isolated/fake.txt"), scratch.resolve("isolated/fake.py"))));

    assertThat(cache.getGlob(pattern, false)).containsExactly("fake.py", "fake.txt");
  }
예제 #11
0
  @Override
  public ConfiguredTarget create(RuleContext ruleContext)
      throws RuleErrorException, InterruptedException {
    TransitiveInfoCollection lipoContextCollector =
        ruleContext.getPrerequisite(":lipo_context_collector", Mode.DONT_CHECK);
    if (lipoContextCollector != null
        && lipoContextCollector.getProvider(LipoContextProvider.class) == null) {
      ruleContext.ruleError("--lipo_context must point to a cc_binary or a cc_test rule");
      return null;
    }

    CppConfiguration cppConfiguration =
        Preconditions.checkNotNull(ruleContext.getFragment(CppConfiguration.class));
    Path fdoZip =
        ruleContext.getConfiguration().getCompilationMode() == CompilationMode.OPT
            ? cppConfiguration.getFdoZip()
            : null;
    SkyKey fdoKey =
        FdoSupportValue.key(
            cppConfiguration.getLipoMode(), fdoZip, cppConfiguration.getFdoInstrument());

    SkyFunction.Environment skyframeEnv = ruleContext.getAnalysisEnvironment().getSkyframeEnv();
    FdoSupportValue fdoSupport;
    try {
      fdoSupport =
          (FdoSupportValue)
              skyframeEnv.getValueOrThrow(fdoKey, FdoException.class, IOException.class);
    } catch (FdoException | IOException e) {
      ruleContext.ruleError("cannot initialize FDO: " + e.getMessage());
      return null;
    }

    if (skyframeEnv.valuesMissing()) {
      return null;
    }

    final Label label = ruleContext.getLabel();
    final NestedSet<Artifact> crosstool =
        ruleContext
            .getPrerequisite("all_files", Mode.HOST)
            .getProvider(FileProvider.class)
            .getFilesToBuild();
    final NestedSet<Artifact> crosstoolMiddleman = getFiles(ruleContext, "all_files");
    final NestedSet<Artifact> compile = getFiles(ruleContext, "compiler_files");
    final NestedSet<Artifact> strip = getFiles(ruleContext, "strip_files");
    final NestedSet<Artifact> objcopy = getFiles(ruleContext, "objcopy_files");
    final NestedSet<Artifact> link = getFiles(ruleContext, "linker_files");
    final NestedSet<Artifact> dwp = getFiles(ruleContext, "dwp_files");
    final NestedSet<Artifact> libcLink = inputsForLibc(ruleContext);
    String purposePrefix = Actions.escapeLabel(label) + "_";
    String runtimeSolibDirBase = "_solib_" + "_" + Actions.escapeLabel(label);
    final PathFragment runtimeSolibDir =
        ruleContext.getConfiguration().getBinFragment().getRelative(runtimeSolibDirBase);

    // Static runtime inputs.
    TransitiveInfoCollection staticRuntimeLibDep =
        selectDep(ruleContext, "static_runtime_libs", cppConfiguration.getStaticRuntimeLibsLabel());
    final NestedSet<Artifact> staticRuntimeLinkInputs;
    final Artifact staticRuntimeLinkMiddleman;
    if (cppConfiguration.supportsEmbeddedRuntimes()) {
      staticRuntimeLinkInputs =
          staticRuntimeLibDep.getProvider(FileProvider.class).getFilesToBuild();
    } else {
      staticRuntimeLinkInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }

    if (!staticRuntimeLinkInputs.isEmpty()) {
      NestedSet<Artifact> staticRuntimeLinkMiddlemanSet =
          CompilationHelper.getAggregatingMiddleman(
              ruleContext, purposePrefix + "static_runtime_link", staticRuntimeLibDep);
      staticRuntimeLinkMiddleman =
          staticRuntimeLinkMiddlemanSet.isEmpty()
              ? null
              : Iterables.getOnlyElement(staticRuntimeLinkMiddlemanSet);
    } else {
      staticRuntimeLinkMiddleman = null;
    }

    Preconditions.checkState(
        (staticRuntimeLinkMiddleman == null) == staticRuntimeLinkInputs.isEmpty());

    // Dynamic runtime inputs.
    TransitiveInfoCollection dynamicRuntimeLibDep =
        selectDep(
            ruleContext, "dynamic_runtime_libs", cppConfiguration.getDynamicRuntimeLibsLabel());
    final NestedSet<Artifact> dynamicRuntimeLinkInputs;
    final Artifact dynamicRuntimeLinkMiddleman;
    if (cppConfiguration.supportsEmbeddedRuntimes()) {
      NestedSetBuilder<Artifact> dynamicRuntimeLinkInputsBuilder = NestedSetBuilder.stableOrder();
      for (Artifact artifact :
          dynamicRuntimeLibDep.getProvider(FileProvider.class).getFilesToBuild()) {
        if (CppHelper.SHARED_LIBRARY_FILETYPES.matches(artifact.getFilename())) {
          dynamicRuntimeLinkInputsBuilder.add(
              SolibSymlinkAction.getCppRuntimeSymlink(
                  ruleContext, artifact, runtimeSolibDirBase, ruleContext.getConfiguration()));
        } else {
          dynamicRuntimeLinkInputsBuilder.add(artifact);
        }
      }
      dynamicRuntimeLinkInputs = dynamicRuntimeLinkInputsBuilder.build();
    } else {
      dynamicRuntimeLinkInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
    }

    if (!dynamicRuntimeLinkInputs.isEmpty()) {
      List<Artifact> dynamicRuntimeLinkMiddlemanSet =
          CppHelper.getAggregatingMiddlemanForCppRuntimes(
              ruleContext,
              purposePrefix + "dynamic_runtime_link",
              dynamicRuntimeLibDep,
              runtimeSolibDirBase,
              ruleContext.getConfiguration());
      dynamicRuntimeLinkMiddleman =
          dynamicRuntimeLinkMiddlemanSet.isEmpty()
              ? null
              : Iterables.getOnlyElement(dynamicRuntimeLinkMiddlemanSet);
    } else {
      dynamicRuntimeLinkMiddleman = null;
    }

    Preconditions.checkState(
        (dynamicRuntimeLinkMiddleman == null) == dynamicRuntimeLinkInputs.isEmpty());

    CppCompilationContext.Builder contextBuilder = new CppCompilationContext.Builder(ruleContext);
    CppModuleMap moduleMap = createCrosstoolModuleMap(ruleContext);
    if (moduleMap != null) {
      contextBuilder.setCppModuleMap(moduleMap);
    }
    final CppCompilationContext context = contextBuilder.build();
    boolean supportsParamFiles = ruleContext.attributes().get("supports_param_files", BOOLEAN);
    boolean supportsHeaderParsing =
        ruleContext.attributes().get("supports_header_parsing", BOOLEAN);

    NestedSetBuilder<Pair<String, String>> coverageEnvironment = NestedSetBuilder.compileOrder();

    coverageEnvironment.add(
        Pair.of("COVERAGE_GCOV_PATH", cppConfiguration.getGcovExecutable().getPathString()));
    if (cppConfiguration.getFdoInstrument() != null) {
      coverageEnvironment.add(
          Pair.of("FDO_DIR", cppConfiguration.getFdoInstrument().getPathString()));
    }

    CcToolchainProvider provider =
        new CcToolchainProvider(
            cppConfiguration,
            crosstool,
            fullInputsForCrosstool(ruleContext, crosstoolMiddleman),
            compile,
            strip,
            objcopy,
            fullInputsForLink(ruleContext, link),
            dwp,
            libcLink,
            staticRuntimeLinkInputs,
            staticRuntimeLinkMiddleman,
            dynamicRuntimeLinkInputs,
            dynamicRuntimeLinkMiddleman,
            runtimeSolibDir,
            context,
            supportsParamFiles,
            supportsHeaderParsing,
            getBuildVariables(ruleContext),
            getBuiltinIncludes(ruleContext),
            coverageEnvironment.build());
    RuleConfiguredTargetBuilder builder =
        new RuleConfiguredTargetBuilder(ruleContext)
            .add(CcToolchainProvider.class, provider)
            .add(FdoSupportProvider.class, new FdoSupportProvider(fdoSupport.getFdoSupport()))
            .setFilesToBuild(new NestedSetBuilder<Artifact>(Order.STABLE_ORDER).build())
            .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY));

    // If output_license is specified on the cc_toolchain rule, override the transitive licenses
    // with that one. This is necessary because cc_toolchain is used in the target configuration,
    // but it is sort-of-kind-of a tool, but various parts of it are linked into the output...
    // ...so we trust the judgment of the author of the cc_toolchain rule to figure out what
    // licenses should be propagated to C++ targets.
    License outputLicense = ruleContext.getRule().getToolOutputLicense(ruleContext.attributes());
    if (outputLicense != null && outputLicense != License.NO_LICENSE) {
      final NestedSet<TargetLicense> license =
          NestedSetBuilder.create(
              Order.STABLE_ORDER, new TargetLicense(ruleContext.getLabel(), outputLicense));
      LicensesProvider licensesProvider =
          new LicensesProvider() {
            @Override
            public NestedSet<TargetLicense> getTransitiveLicenses() {
              return license;
            }
          };

      builder.add(LicensesProvider.class, licensesProvider);
    }

    return builder.build();
  }
예제 #12
0
  @Test
  public void testGetKeySet() throws Exception {
    assertThat(cache.getKeySet()).isEmpty();

    cache.getGlob("*.java");
    assertThat(cache.getKeySet()).containsExactly(Pair.of("*.java", false));

    cache.getGlob("*.java");
    assertThat(cache.getKeySet()).containsExactly(Pair.of("*.java", false));

    cache.getGlob("*.js");
    assertThat(cache.getKeySet()).containsExactly(Pair.of("*.java", false), Pair.of("*.js", false));

    cache.getGlob("*.java", true);
    assertThat(cache.getKeySet())
        .containsExactly(Pair.of("*.java", false), Pair.of("*.js", false), Pair.of("*.java", true));

    try {
      cache.getGlob("invalid?");
      fail("Expected an invalid regex exception");
    } catch (BadGlobException expected) {
    }
    assertThat(cache.getKeySet())
        .containsExactly(Pair.of("*.java", false), Pair.of("*.js", false), Pair.of("*.java", true));

    cache.getGlob("foo/first.*");
    assertThat(cache.getKeySet())
        .containsExactly(
            Pair.of("*.java", false),
            Pair.of("*.java", true),
            Pair.of("*.js", false),
            Pair.of("foo/first.*", false));
  }