示例#1
0
  /**
   * Generates an empty manifest for a rule that does not directly specify resources.
   *
   * <p><strong>Note:</strong> This generated manifest can then be used as the primary manifest when
   * merging with dependencies.
   *
   * @return the generated ApplicationManifest
   */
  public static ApplicationManifest generatedManifest(RuleContext ruleContext) {
    Artifact generatedManifest =
        ruleContext.getUniqueDirectoryArtifact(
            ruleContext.getRule().getName() + "_generated",
            new PathFragment("AndroidManifest.xml"),
            ruleContext.getBinOrGenfilesDirectory());

    String manifestPackage;
    if (ruleContext.attributes().isAttributeValueExplicitlySpecified("custom_package")) {
      manifestPackage = ruleContext.attributes().get("custom_package", Type.STRING);
    } else {
      manifestPackage =
          JavaUtil.getJavaFullClassname(ruleContext.getRule().getPackage().getNameFragment());
    }
    String contents =
        Joiner.on("\n")
            .join(
                "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
                "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
                "          package=\"" + manifestPackage + "\">",
                "   <application>",
                "   </application>",
                "</manifest>");
    ruleContext
        .getAnalysisEnvironment()
        .registerAction(
            new FileWriteAction(
                ruleContext.getActionOwner(),
                generatedManifest,
                contents,
                false /* makeExecutable */));
    return new ApplicationManifest(generatedManifest);
  }
  /**
   * Create a Rule Configured Target from the ruleContext and the ruleImplementation. The
   * registeredProviderTypes map indicates which keys in structs returned by skylark rules should be
   * interpreted as native TransitiveInfoProvider instances of type (map value).
   */
  public static ConfiguredTarget buildRule(
      RuleContext ruleContext,
      BaseFunction ruleImplementation,
      Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes)
      throws InterruptedException {
    String expectFailure = ruleContext.attributes().get("expect_failure", Type.STRING);
    try (Mutability mutability = Mutability.create("configured target")) {
      SkylarkRuleContext skylarkRuleContext = new SkylarkRuleContext(ruleContext, Kind.RULE);
      Environment env =
          Environment.builder(mutability)
              .setSkylark()
              .setCallerLabel(ruleContext.getLabel())
              .setGlobals(
                  ruleContext
                      .getRule()
                      .getRuleClassObject()
                      .getRuleDefinitionEnvironment()
                      .getGlobals())
              .setEventHandler(ruleContext.getAnalysisEnvironment().getEventHandler())
              .build(); // NB: loading phase functions are not available: this is analysis already,
      // so we do *not* setLoadingPhase().
      Object target =
          ruleImplementation.call(
              ImmutableList.<Object>of(skylarkRuleContext),
              ImmutableMap.<String, Object>of(),
              /*ast=*/ null,
              env);

      if (ruleContext.hasErrors()) {
        return null;
      } else if (!(target instanceof SkylarkClassObject)
          && target != Runtime.NONE
          && !(target instanceof Iterable)) {
        ruleContext.ruleError(
            String.format(
                "Rule should return a return a struct or a list, but got %s",
                SkylarkType.typeOf(target)));
        return null;
      } else if (!expectFailure.isEmpty()) {
        ruleContext.ruleError("Expected failure not found: " + expectFailure);
        return null;
      }
      ConfiguredTarget configuredTarget =
          createTarget(ruleContext, target, registeredProviderTypes);
      SkylarkProviderValidationUtil.checkOrphanArtifacts(ruleContext);
      return configuredTarget;
    } catch (EvalException e) {
      addRuleToStackTrace(e, ruleContext.getRule(), ruleImplementation);
      // If the error was expected, return an empty target.
      if (!expectFailure.isEmpty() && getMessageWithoutStackTrace(e).matches(expectFailure)) {
        return new com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder(ruleContext)
            .add(RunfilesProvider.class, RunfilesProvider.EMPTY)
            .build();
      }
      ruleContext.ruleError("\n" + e.print());
      return null;
    }
  }
示例#3
0
 /**
  * Returns the crosstool-derived link action inputs for a given rule. Adds the given set of
  * artifacts as extra inputs.
  */
 protected NestedSet<Artifact> fullInputsForLink(
     RuleContext ruleContext, NestedSet<Artifact> link) {
   return NestedSetBuilder.<Artifact>stableOrder()
       .addTransitive(link)
       .addTransitive(AnalysisUtils.getMiddlemanFor(ruleContext, ":libc_top"))
       .add(
           ruleContext
               .getAnalysisEnvironment()
               .getEmbeddedToolArtifact(CppRuleClasses.BUILD_INTERFACE_SO))
       .build();
 }
  private static Artifact derivedArtifact(
      ConfiguredTarget base, RuleContext ruleContext, String suffix) {
    BuildConfiguration configuration = ruleContext.getConfiguration();
    assert configuration != null;
    Root genfilesDirectory = configuration.getGenfilesDirectory();

    PathFragment derivedFilePath = getOutputFilePath(base, ruleContext, suffix);

    return ruleContext
        .getAnalysisEnvironment()
        .getDerivedArtifact(derivedFilePath, genfilesDirectory);
  }
  /**
   * Creates a builder from a rule. This also uses the configuration and artifact factory from the
   * rule.
   */
  public CppCompileActionBuilder(RuleContext ruleContext, Artifact sourceFile, Label sourceLabel) {
    this.owner = ruleContext.getActionOwner();
    this.actionContext = CppCompileActionContext.class;
    this.cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
    this.analysisEnvironment = ruleContext.getAnalysisEnvironment();
    this.sourceFile = sourceFile;
    this.sourceLabel = sourceLabel;
    this.configuration = ruleContext.getConfiguration();
    this.mandatoryInputsBuilder = NestedSetBuilder.stableOrder();
    this.pluginInputsBuilder = NestedSetBuilder.stableOrder();
    this.lipoScannableMap = getLipoScannableMap(ruleContext);
    this.ruleContext = ruleContext;

    features.addAll(ruleContext.getFeatures());
  }
  /** Create a Rule Configured Target from the ruleContext and the ruleImplementation. */
  public static ConfiguredTarget buildRule(
      RuleContext ruleContext, BaseFunction ruleImplementation) {
    String expectFailure = ruleContext.attributes().get("expect_failure", Type.STRING);
    try {
      SkylarkRuleContext skylarkRuleContext = new SkylarkRuleContext(ruleContext);
      SkylarkEnvironment env =
          ruleContext
              .getRule()
              .getRuleClassObject()
              .getRuleDefinitionEnvironment()
              .cloneEnv(ruleContext.getAnalysisEnvironment().getEventHandler());
      // Collect the symbols to disable statically and pass at the next call, so we don't need to
      // clone the RuleDefinitionEnvironment.
      env.disableOnlyLoadingPhaseObjects();
      Object target =
          ruleImplementation.call(
              ImmutableList.<Object>of(skylarkRuleContext),
              ImmutableMap.<String, Object>of(),
              null,
              env);

      if (ruleContext.hasErrors()) {
        return null;
      } else if (!(target instanceof SkylarkClassObject) && target != Environment.NONE) {
        ruleContext.ruleError("Rule implementation doesn't return a struct");
        return null;
      } else if (!expectFailure.isEmpty()) {
        ruleContext.ruleError("Expected failure not found: " + expectFailure);
        return null;
      }
      ConfiguredTarget configuredTarget = createTarget(ruleContext, target);
      checkOrphanArtifacts(ruleContext);
      return configuredTarget;

    } catch (InterruptedException e) {
      ruleContext.ruleError(e.getMessage());
      return null;
    } catch (EvalException e) {
      // If the error was expected, return an empty target.
      if (!expectFailure.isEmpty() && e.getMessage().matches(expectFailure)) {
        return new com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder(ruleContext)
            .add(RunfilesProvider.class, RunfilesProvider.EMPTY)
            .build();
      }
      ruleContext.ruleError("\n" + e.print());
      return null;
    }
  }
 private static void checkOrphanArtifacts(RuleContext ruleContext) throws EvalException {
   ImmutableSet<Artifact> orphanArtifacts =
       ruleContext.getAnalysisEnvironment().getOrphanArtifacts();
   if (!orphanArtifacts.isEmpty()) {
     throw new EvalException(
         null,
         "The following files have no generating action:\n"
             + Joiner.on("\n")
                 .join(
                     Iterables.transform(
                         orphanArtifacts,
                         new Function<Artifact, String>() {
                           @Override
                           public String apply(Artifact artifact) {
                             return artifact.getRootRelativePathString();
                           }
                         })));
   }
 }
示例#8
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();
  }
示例#9
0
 /** Builds the {@link CppCompilationContext}. */
 public CppCompilationContext build() {
   return build(
       ruleContext == null ? null : ruleContext.getActionOwner(),
       ruleContext == null ? null : ruleContext.getAnalysisEnvironment().getMiddlemanFactory());
 }
示例#10
0
  /**
   * Constructs the C++ linker actions. It generally generates two actions, one for a static library
   * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries,
   * it additionally creates a third action to generate a PIC static library.
   *
   * <p>For dynamic libraries, this method can additionally create an interface shared library that
   * can be used for linking, but doesn't contain any executable code. This increases the number of
   * cache hits for link actions. Call {@link #setAllowInterfaceSharedObjects(boolean)} to enable
   * this behavior.
   *
   * @throws RuleErrorException
   */
  public CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs)
      throws RuleErrorException {
    // For now only handle static links. Note that the dynamic library link below ignores linkType.
    // TODO(bazel-team): Either support non-static links or move this check to setLinkType().
    Preconditions.checkState(linkType.isStaticLibraryLink(), "can only handle static links");

    CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder();
    if (cppConfiguration.isLipoContextCollector()) {
      // Don't try to create LIPO link actions in collector mode,
      // because it needs some data that's not available at this point.
      return result.build();
    }

    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();
    boolean usePicForBinaries = CppHelper.usePic(ruleContext, true);
    boolean usePicForSharedLibs = CppHelper.usePic(ruleContext, false);

    // Create static library (.a). The linkType only reflects whether the library is alwayslink or
    // not. The PIC-ness is determined by whether we need to use PIC or not. There are three cases
    // for (usePicForSharedLibs usePicForBinaries):
    //
    // (1) (false false) -> no pic code
    // (2) (true false)  -> shared libraries as pic, but not binaries
    // (3) (true true)   -> both shared libraries and binaries as pic
    //
    // In case (3), we always need PIC, so only create one static library containing the PIC object
    // files. The name therefore does not match the content.
    //
    // Presumably, it is done this way because the .a file is an implicit output of every cc_library
    // rule, so we can't use ".pic.a" that in the always-PIC case.

    // If the crosstool is configured to select an output artifact, we use that selection.
    // Otherwise, we use linux defaults.
    Artifact linkedArtifact = getLinkedArtifact(linkType);

    CppLinkAction maybePicAction =
        newLinkActionBuilder(linkedArtifact)
            .addNonLibraryInputs(ccOutputs.getObjectFiles(usePicForBinaries))
            .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles())
            .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
            .setLinkType(linkType)
            .setLinkStaticness(LinkStaticness.FULLY_STATIC)
            .setFeatureConfiguration(featureConfiguration)
            .build();
    env.registerAction(maybePicAction);
    result.addStaticLibrary(maybePicAction.getOutputLibrary());

    // Create a second static library (.pic.a). Only in case (2) do we need both PIC and non-PIC
    // static libraries. In that case, the first static library contains the non-PIC code, and this
    // one contains the PIC code, so the names match the content.
    if (!usePicForBinaries && usePicForSharedLibs) {
      LinkTargetType picLinkType =
          (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY)
              ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY
              : LinkTargetType.PIC_STATIC_LIBRARY;

      // If the crosstool is configured to select an output artifact, we use that selection.
      // Otherwise, we use linux defaults.
      Artifact picArtifact = getLinkedArtifact(picLinkType);

      CppLinkAction picAction =
          newLinkActionBuilder(picArtifact)
              .addNonLibraryInputs(ccOutputs.getObjectFiles(true))
              .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles())
              .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
              .setLinkType(picLinkType)
              .setLinkStaticness(LinkStaticness.FULLY_STATIC)
              .setFeatureConfiguration(featureConfiguration)
              .build();
      env.registerAction(picAction);
      result.addPicStaticLibrary(picAction.getOutputLibrary());
    }

    if (!createDynamicLibrary) {
      return result.build();
    }

    // Create dynamic library.
    Artifact soImpl;
    if (soImplArtifact == null) {
      // If the crosstool is configured to select an output artifact, we use that selection.
      // Otherwise, we use linux defaults.
      soImpl = getLinkedArtifact(LinkTargetType.DYNAMIC_LIBRARY);
    } else {
      soImpl = soImplArtifact;
    }

    List<String> sonameLinkopts = ImmutableList.of();
    Artifact soInterface = null;
    if (cppConfiguration.useInterfaceSharedObjects() && allowInterfaceSharedObjects) {
      soInterface =
          CppHelper.getLinuxLinkedArtifact(ruleContext, LinkTargetType.INTERFACE_DYNAMIC_LIBRARY);
      sonameLinkopts =
          ImmutableList.of(
              "-Wl,-soname="
                  + SolibSymlinkAction.getDynamicLibrarySoname(
                      soImpl.getRootRelativePath(), false));
    }

    // Should we also link in any libraries that this library depends on?
    // That is required on some systems...
    CppLinkActionBuilder linkActionBuilder =
        newLinkActionBuilder(soImpl)
            .setInterfaceOutput(soInterface)
            .addNonLibraryInputs(ccOutputs.getObjectFiles(usePicForSharedLibs))
            .addNonLibraryInputs(ccOutputs.getHeaderTokenFiles())
            .addLTOBitcodeFiles(ccOutputs.getLtoBitcodeFiles())
            .setLinkType(LinkTargetType.DYNAMIC_LIBRARY)
            .setLinkStaticness(LinkStaticness.DYNAMIC)
            .addLinkopts(linkopts)
            .addLinkopts(sonameLinkopts)
            .setRuntimeInputs(
                CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkMiddleman(),
                CppHelper.getToolchain(ruleContext).getDynamicRuntimeLinkInputs())
            .setFeatureConfiguration(featureConfiguration);

    if (!ccOutputs.getLtoBitcodeFiles().isEmpty()
        && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) {
      linkActionBuilder.setLTOIndexing(true);
      CppLinkAction indexAction = linkActionBuilder.build();
      env.registerAction(indexAction);

      for (LTOBackendArtifacts ltoArtifacts : indexAction.getAllLTOBackendArtifacts()) {
        ltoArtifacts.scheduleLTOBackendAction(ruleContext, usePicForSharedLibs);
      }

      linkActionBuilder.setLTOIndexing(false);
    }

    CppLinkAction action = linkActionBuilder.build();
    env.registerAction(action);

    LibraryToLink dynamicLibrary = action.getOutputLibrary();
    LibraryToLink interfaceLibrary = action.getInterfaceOutputLibrary();
    if (interfaceLibrary == null) {
      interfaceLibrary = dynamicLibrary;
    }

    // If shared library has neverlink=1, then leave it untouched. Otherwise,
    // create a mangled symlink for it and from now on reference it through
    // mangled name only.
    if (neverLink) {
      result.addDynamicLibrary(interfaceLibrary);
      result.addExecutionDynamicLibrary(dynamicLibrary);
    } else {
      LibraryToLink libraryLink =
          SolibSymlinkAction.getDynamicLibrarySymlink(
              ruleContext,
              interfaceLibrary.getArtifact(),
              false,
              false,
              ruleContext.getConfiguration());
      result.addDynamicLibrary(libraryLink);
      LibraryToLink implLibraryLink =
          SolibSymlinkAction.getDynamicLibrarySymlink(
              ruleContext,
              dynamicLibrary.getArtifact(),
              false,
              false,
              ruleContext.getConfiguration());
      result.addExecutionDynamicLibrary(implLibraryLink);
    }
    return result.build();
  }
示例#11
0
  /**
   * Constructs the C++ compiler actions. It generally creates one action for every specified source
   * file. It takes into account LIPO, fake-ness, coverage, and PIC, in addition to using the
   * settings specified on the current object. This method should only be called once.
   */
  public CcCompilationOutputs createCcCompileActions() {
    CcCompilationOutputs.Builder result = new CcCompilationOutputs.Builder();
    Preconditions.checkNotNull(context);
    AnalysisEnvironment env = ruleContext.getAnalysisEnvironment();

    if (shouldProvideHeaderModules()) {
      Artifact moduleMapArtifact = context.getCppModuleMap().getArtifact();
      Label moduleMapLabel = Label.parseAbsoluteUnchecked(context.getCppModuleMap().getName());
      CppCompileActionBuilder builder =
          initializeCompileAction(moduleMapArtifact, moduleMapLabel, /*forInterface=*/ true);

      // A header module compile action is just like a normal compile action, but:
      // - the compiled source file is the module map
      // - it creates a header module (.pcm file).
      createSourceAction(
          FileSystemUtils.removeExtension(semantics.getEffectiveSourcePath(moduleMapArtifact))
              .getPathString(),
          result,
          env,
          moduleMapArtifact,
          builder,
          ArtifactCategory.CPP_MODULE,
          /*addObject=*/ false,
          /*enableCoverage=*/ false,
          /*generateDwo=*/ false,
          CppFileTypes.mustProduceDotdFile(moduleMapArtifact.getFilename()),
          ImmutableMap.<String, String>of());
    }

    for (CppSource source : sourceFiles) {
      Artifact sourceArtifact = source.getSource();
      Label sourceLabel = source.getLabel();
      String outputName =
          FileSystemUtils.removeExtension(semantics.getEffectiveSourcePath(sourceArtifact))
              .getPathString();
      CppCompileActionBuilder builder =
          initializeCompileAction(sourceArtifact, sourceLabel, /*forInterface=*/ false);

      if (CppFileTypes.CPP_HEADER.matches(source.getSource().getExecPath())) {
        createHeaderAction(
            outputName,
            result,
            env,
            builder,
            CppFileTypes.mustProduceDotdFile(sourceArtifact.getFilename()));
      } else {
        createSourceAction(
            outputName,
            result,
            env,
            sourceArtifact,
            builder,
            ArtifactCategory.OBJECT_FILE,
            /*addObject=*/ true,
            isCodeCoverageEnabled(),
            /*generateDwo=*/ cppConfiguration.useFission(),
            CppFileTypes.mustProduceDotdFile(sourceArtifact.getFilename()),
            source.getBuildVariables());
      }
    }

    compilationOutputs = result.build();
    return compilationOutputs;
  }
  private static ConfiguredTarget addStructFieldsAndBuild(
      RuleContext ruleContext,
      RuleConfiguredTargetBuilder builder,
      Object target,
      Artifact executable,
      Map<String, Class<? extends TransitiveInfoProvider>> registeredProviderTypes)
      throws EvalException {
    Location loc = null;
    Runfiles statelessRunfiles = null;
    Runfiles dataRunfiles = null;
    Runfiles defaultRunfiles = null;
    if (target instanceof SkylarkClassObject) {
      SkylarkClassObject struct = (SkylarkClassObject) target;
      loc = struct.getCreationLoc();
      for (String key : struct.getKeys()) {
        if (key.equals("files")) {
          // If we specify files_to_build we don't have the executable in it by default.
          builder.setFilesToBuild(
              cast("files", struct, SkylarkNestedSet.class, Artifact.class, loc)
                  .getSet(Artifact.class));
        } else if (key.equals("runfiles")) {
          statelessRunfiles = cast("runfiles", struct, Runfiles.class, loc);
        } else if (key.equals("data_runfiles")) {
          dataRunfiles = cast("data_runfiles", struct, Runfiles.class, loc);
        } else if (key.equals("default_runfiles")) {
          defaultRunfiles = cast("default_runfiles", struct, Runfiles.class, loc);
        } else if (key.equals("output_groups")) {
          addOutputGroups(struct.getValue(key), loc, builder);
        } else if (key.equals("instrumented_files")) {
          SkylarkClassObject insStruct =
              cast("instrumented_files", struct, SkylarkClassObject.class, loc);
          Location insLoc = insStruct.getCreationLoc();
          FileTypeSet fileTypeSet = FileTypeSet.ANY_FILE;
          if (insStruct.getKeys().contains("extensions")) {
            @SuppressWarnings("unchecked")
            List<String> exts =
                cast("extensions", insStruct, SkylarkList.class, String.class, insLoc);
            if (exts.isEmpty()) {
              fileTypeSet = FileTypeSet.NO_FILE;
            } else {
              FileType[] fileTypes = new FileType[exts.size()];
              for (int i = 0; i < fileTypes.length; i++) {
                fileTypes[i] = FileType.of(exts.get(i));
              }
              fileTypeSet = FileTypeSet.of(fileTypes);
            }
          }
          List<String> dependencyAttributes = Collections.emptyList();
          if (insStruct.getKeys().contains("dependency_attributes")) {
            dependencyAttributes =
                cast("dependency_attributes", insStruct, SkylarkList.class, String.class, insLoc);
          }
          List<String> sourceAttributes = Collections.emptyList();
          if (insStruct.getKeys().contains("source_attributes")) {
            sourceAttributes =
                cast("source_attributes", insStruct, SkylarkList.class, String.class, insLoc);
          }
          InstrumentationSpec instrumentationSpec =
              new InstrumentationSpec(fileTypeSet)
                  .withSourceAttributes(sourceAttributes.toArray(new String[0]))
                  .withDependencyAttributes(dependencyAttributes.toArray(new String[0]));
          InstrumentedFilesProvider instrumentedFilesProvider =
              InstrumentedFilesCollector.collect(
                  ruleContext,
                  instrumentationSpec,
                  InstrumentedFilesCollector.NO_METADATA_COLLECTOR,
                  Collections.<Artifact>emptySet());
          builder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider);
        } else if (registeredProviderTypes.containsKey(key)) {
          Class<? extends TransitiveInfoProvider> providerType = registeredProviderTypes.get(key);
          TransitiveInfoProvider provider = cast(key, struct, providerType, loc);
          builder.addProvider(providerType, provider);
        } else if (key.equals("providers")) {
          Iterable iterable = cast(key, struct, Iterable.class, loc);
          for (Object o : iterable) {
            SkylarkClassObject declaredProvider =
                SkylarkType.cast(
                    o,
                    SkylarkClassObject.class,
                    loc,
                    "The value of 'providers' should be a sequence of declared providers");
            builder.addSkylarkDeclaredProvider(declaredProvider, loc);
          }
        } else if (!key.equals("executable")) {
          // We handled executable already.
          builder.addSkylarkTransitiveInfo(key, struct.getValue(key), loc);
        }
      }
    } else if (target instanceof Iterable) {
      loc = ruleContext.getRule().getRuleClassObject().getConfiguredTargetFunction().getLocation();
      for (Object o : (Iterable) target) {
        SkylarkClassObject declaredProvider =
            SkylarkType.cast(
                o,
                SkylarkClassObject.class,
                loc,
                "A return value of rule implementation function should be "
                    + "a sequence of declared providers");
        Location creationLoc = declaredProvider.getCreationLocOrNull();
        builder.addSkylarkDeclaredProvider(
            declaredProvider, creationLoc != null ? creationLoc : loc);
      }
    }

    if ((statelessRunfiles != null) && (dataRunfiles != null || defaultRunfiles != null)) {
      throw new EvalException(
          loc,
          "Cannot specify the provider 'runfiles' "
              + "together with 'data_runfiles' or 'default_runfiles'");
    }

    if (statelessRunfiles == null && dataRunfiles == null && defaultRunfiles == null) {
      // No runfiles specified, set default
      statelessRunfiles = Runfiles.EMPTY;
    }

    RunfilesProvider runfilesProvider =
        statelessRunfiles != null
            ? RunfilesProvider.simple(merge(statelessRunfiles, executable, ruleContext))
            : RunfilesProvider.withData(
                // The executable doesn't get into the default runfiles if we have runfiles states.
                // This is to keep skylark genrule consistent with the original genrule.
                defaultRunfiles != null ? defaultRunfiles : Runfiles.EMPTY,
                dataRunfiles != null ? dataRunfiles : Runfiles.EMPTY);
    builder.addProvider(RunfilesProvider.class, runfilesProvider);

    Runfiles computedDefaultRunfiles = runfilesProvider.getDefaultRunfiles();
    // This works because we only allowed to call a rule *_test iff it's a test type rule.
    boolean testRule = TargetUtils.isTestRuleName(ruleContext.getRule().getRuleClass());
    if (testRule && computedDefaultRunfiles.isEmpty()) {
      throw new EvalException(loc, "Test rules have to define runfiles");
    }
    if (executable != null || testRule) {
      RunfilesSupport runfilesSupport =
          computedDefaultRunfiles.isEmpty()
              ? null
              : RunfilesSupport.withExecutable(ruleContext, computedDefaultRunfiles, executable);
      builder.setRunfilesSupport(runfilesSupport, executable);
    }

    if (ruleContext.getRule().getRuleClassObject().isSkylarkTestable()) {
      SkylarkClassObject actions =
          ActionsProvider.create(ruleContext.getAnalysisEnvironment().getRegisteredActions());
      builder.addSkylarkDeclaredProvider(actions, loc);
    }

    try {
      return builder.build();
    } catch (IllegalArgumentException e) {
      throw new EvalException(loc, e.getMessage());
    }
  }