public static void init()

in src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java [108:496]


  public static void init(
      CppSemantics semantics,
      RuleContext ruleContext,
      RuleConfiguredTargetBuilder targetBuilder,
      ImmutableList<String> additionalCopts,
      PathFragment soFilename,
      boolean alwaysLink,
      boolean neverLink,
      boolean linkStatic,
      boolean addDynamicRuntimeInputArtifactsToRunfiles)
      throws RuleErrorException, InterruptedException {
    semantics.validateDeps(ruleContext);
    if (ruleContext.hasErrors()) {
      addEmptyRequiredProviders(targetBuilder);
      return;
    }

    CppConfiguration cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
    if (!cppConfiguration.experimentalCcImplementationDeps()
        && ruleContext.attributes().isAttributeValueExplicitlySpecified("implementation_deps")) {
      ruleContext.attributeError(
          "implementation_deps", "requires --experimental_cc_implementation_deps");
    }

    final CcCommon common = new CcCommon(ruleContext);
    common.reportInvalidOptions(ruleContext);

    CcToolchainProvider ccToolchain = common.getToolchain();

    ImmutableMap.Builder<String, String> toolchainMakeVariables = ImmutableMap.builder();
    ccToolchain.addGlobalMakeVariables(toolchainMakeVariables);
    ruleContext.initConfigurationMakeVariableContext(
        new MapBackedMakeVariableSupplier(toolchainMakeVariables.buildOrThrow()),
        new CcFlagsSupplier(ruleContext));

    FdoContext fdoContext = common.getFdoContext();
    FeatureConfiguration featureConfiguration =
        CcCommon.configureFeaturesOrReportRuleError(ruleContext, ccToolchain, semantics);
    PrecompiledFiles precompiledFiles = new PrecompiledFiles(ruleContext);

    semantics.validateAttributes(ruleContext);
    if (ruleContext.hasErrors()) {
      addEmptyRequiredProviders(targetBuilder);
      return;
    }

    ImmutableList<TransitiveInfoCollection> deps =
        ImmutableList.copyOf(ruleContext.getPrerequisites("deps"));
    if (ruleContext.hasErrors()) {
      addEmptyRequiredProviders(targetBuilder);
      return;
    }
    Iterable<CcInfo> ccInfosFromDeps = AnalysisUtils.getProviders(deps, CcInfo.PROVIDER);
    CcCompilationHelper compilationHelper =
        new CcCompilationHelper(
                ruleContext,
                ruleContext,
                ruleContext.getLabel(),
                CppHelper.getGrepIncludes(ruleContext),
                semantics,
                featureConfiguration,
                ccToolchain,
                fdoContext,
                TargetUtils.getExecutionInfo(
                    ruleContext.getRule(), ruleContext.isAllowTagsPropagation()),
                /* shouldProcessHeaders= */ true)
            .fromCommon(common, additionalCopts)
            .addSources(common.getSources())
            .addPrivateHeaders(common.getPrivateHeaders())
            .addPublicHeaders(common.getHeaders())
            .setCodeCoverageEnabled(CcCompilationHelper.isCodeCoverageEnabled(ruleContext))
            .addCcCompilationContexts(
                Streams.stream(ccInfosFromDeps)
                    .map(CcInfo::getCcCompilationContext)
                    .collect(ImmutableList.toImmutableList()))
            .addCcCompilationContexts(
                ImmutableList.of(CcCompilationHelper.getStlCcCompilationContext(ruleContext)))
            .addImplementationDepsCcCompilationContexts(
                CppHelper.getCompilationContextsFromDeps(
                    ImmutableList.copyOf(ruleContext.getPrerequisites("implementation_deps"))))
            .setHeadersCheckingMode(semantics.determineHeadersCheckingMode(ruleContext));

    CcLinkingHelper linkingHelper =
        new CcLinkingHelper(
                ruleContext,
                ruleContext.getLabel(),
                ruleContext,
                ruleContext,
                semantics,
                featureConfiguration,
                ccToolchain,
                fdoContext,
                ruleContext.getConfiguration(),
                ruleContext.getFragment(CppConfiguration.class),
                ruleContext.getSymbolGenerator(),
                TargetUtils.getExecutionInfo(
                    ruleContext.getRule(), ruleContext.isAllowTagsPropagation()))
            .fromCommon(ruleContext, common)
            .addCcLinkingContexts(
                CppHelper.getLinkingContextsFromDeps(
                    ImmutableList.copyOf(ruleContext.getPrerequisites("implementation_deps"))))
            .setGrepIncludes(CppHelper.getGrepIncludes(ruleContext))
            .setTestOrTestOnlyTarget(ruleContext.isTestOnlyTarget())
            .addLinkopts(common.getLinkopts())
            .emitInterfaceSharedLibraries(true)
            .setAlwayslink(alwaysLink)
            .setNeverLink(neverLink)
            .addLinkstamps(ruleContext.getPrerequisites("linkstamp"));

    Artifact soImplArtifact = null;
    boolean supportsDynamicLinker = ccToolchain.supportsDynamicLinker(featureConfiguration);
    // TODO(djasper): This is hacky. We should actually try to figure out whether we generate
    // ccOutputs.
    boolean createDynamicLibrary =
        !linkStatic
            && supportsDynamicLinker
            && (appearsToHaveObjectFiles(ruleContext.attributes())
                || featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN));
    if (soFilename != null) {
      if (!soFilename.getPathString().endsWith(".so")) {
        ruleContext.attributeError("outs", "file name must end in '.so'");
      }
      if (createDynamicLibrary) {
        soImplArtifact = ruleContext.getBinArtifact(soFilename);
      }
    }

    if (ruleContext.getRule().isAttrDefined("textual_hdrs", BuildType.LABEL_LIST)) {
      compilationHelper.addPublicTextualHeaders(
          ruleContext.getPrerequisiteArtifacts("textual_hdrs").list());
    }
    if (ruleContext.getRule().isAttrDefined("include_prefix", Type.STRING)
        && ruleContext.attributes().isAttributeValueExplicitlySpecified("include_prefix")) {
      compilationHelper.setIncludePrefix(
          ruleContext.attributes().get("include_prefix", Type.STRING));
    }
    if (ruleContext.getRule().isAttrDefined("strip_include_prefix", Type.STRING)
        && ruleContext.attributes().isAttributeValueExplicitlySpecified("strip_include_prefix")) {
      compilationHelper.setStripIncludePrefix(
          ruleContext.attributes().get("strip_include_prefix", Type.STRING));
    }

    if (common.getLinkopts().contains("-static")) {
      ruleContext.attributeWarning("linkopts", "Using '-static' here won't work. "
                                   + "Did you mean to use 'linkstatic=1' instead?");
    }

    linkingHelper.setShouldCreateDynamicLibrary(createDynamicLibrary);
    linkingHelper.setLinkerOutputArtifact(soImplArtifact);

    // If the reason we're not creating a dynamic library is that the toolchain
    // doesn't support it, then register an action which complains when triggered,
    // which only happens when some rule explicitly depends on the dynamic library.
    if (!createDynamicLibrary && !supportsDynamicLinker) {
      ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
      dynamicLibraries.add(
          CppHelper.getLinkedArtifact(
              ruleContext,
              ccToolchain,
              ruleContext.getConfiguration(),
              LinkTargetType.NODEPS_DYNAMIC_LIBRARY,
              CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration)));
      if (CppHelper.useInterfaceSharedLibraries(
          cppConfiguration, ccToolchain, featureConfiguration)) {
        dynamicLibraries.add(
            CppHelper.getLinkedArtifact(
                ruleContext,
                ccToolchain,
                ruleContext.getConfiguration(),
                LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
      }
      ruleContext.registerAction(
          new FailAction(
              ruleContext.getActionOwner(),
              dynamicLibraries.build(),
              "Toolchain does not support dynamic linking",
              Code.DYNAMIC_LINKING_NOT_SUPPORTED));
    } else if (!createDynamicLibrary
        && ruleContext.attributes().isConfigurable("srcs")) {
      // If "srcs" is configurable, the .so output is always declared because the logic that
      // determines implicit outs doesn't know which value of "srcs" will ultimately get chosen.
      // Here, where we *do* have the correct value, it may not contain any source files to
      // generate an .so with. If that's the case, register a fake generating action to prevent
      // a "no generating action for this artifact" error.
      ImmutableList.Builder<Artifact> dynamicLibraries = ImmutableList.builder();
      dynamicLibraries.add(
          CppHelper.getLinkedArtifact(
              ruleContext,
              ccToolchain,
              ruleContext.getConfiguration(),
              LinkTargetType.NODEPS_DYNAMIC_LIBRARY,
              CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration)));
      if (CppHelper.useInterfaceSharedLibraries(
          cppConfiguration, ccToolchain, featureConfiguration)) {
        dynamicLibraries.add(
            CppHelper.getLinkedArtifact(
                ruleContext,
                ccToolchain,
                ruleContext.getConfiguration(),
                LinkTargetType.INTERFACE_DYNAMIC_LIBRARY));
      }
      ruleContext.registerAction(
          new FailAction(
              ruleContext.getActionOwner(),
              dynamicLibraries.build(),
              "configurable \"srcs\" triggers an implicit .so output even though there are no"
                  + " sources to compile in this configuration",
              Code.SOURCE_FILES_MISSING));
    }

    CompilationInfo compilationInfo = compilationHelper.compile(ruleContext);
    CcCompilationOutputs precompiledFilesObjects =
        CcCompilationOutputs.builder()
            .addObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ true))
            .addPicObjectFiles(precompiledFiles.getObjectFiles(/* usePic= */ true))
            .build();
    CcCompilationOutputs ccCompilationOutputs =
        CcCompilationOutputs.builder()
            .merge(precompiledFilesObjects)
            .merge(compilationInfo.getCcCompilationOutputs())
            .build();

    // Generate .a and .so outputs even without object files to fulfill the rule class
    // contract wrt. implicit output files, if the contract says so. Behavior here differs
    // between Bazel and Blaze.
    CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY;
    if (semantics.createEmptyArchive() || !ccCompilationOutputs.isEmpty()) {
      if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
        String dllNameSuffix = CppHelper.getDLLHashSuffix(ruleContext, featureConfiguration);
        linkingHelper.setLinkedDLLNameSuffix(dllNameSuffix);
        Artifact generatedDefFile = null;

        Artifact defParser = common.getDefParser();
        if (defParser != null) {
          generatedDefFile =
              CppHelper.createDefFileActions(
                  ruleContext,
                  defParser,
                  ccCompilationOutputs.getObjectFiles(false),
                  ccToolchain
                      .getFeatures()
                      .getArtifactNameForCategory(
                          ArtifactCategory.DYNAMIC_LIBRARY,
                          ruleContext.getLabel().getName() + dllNameSuffix));
          targetBuilder.addOutputGroup(DEF_FILE_OUTPUT_GROUP_NAME, generatedDefFile);
        }
        linkingHelper.setDefFile(
            CppHelper.getWindowsDefFileForLinking(
                ruleContext, common.getWinDefFile(), generatedDefFile, featureConfiguration));
      }
      ccLinkingOutputs = linkingHelper.link(ccCompilationOutputs);
    }

    ImmutableSortedMap.Builder<String, NestedSet<Artifact>> outputGroups =
        ImmutableSortedMap.naturalOrder();
    if (!ccLinkingOutputs.isEmpty()) {
      outputGroups.putAll(
          addLinkerOutputArtifacts(
              ruleContext,
              ccToolchain,
              cppConfiguration,
              ruleContext.getConfiguration(),
              ccCompilationOutputs,
              featureConfiguration));
    }
    List<LibraryToLink> precompiledLibraries =
        convertPrecompiledLibrariesToLibraryToLink(
            ruleContext,
            common,
            ruleContext.getFragment(CppConfiguration.class).forcePic(),
            precompiledFiles);

    if (!ccCompilationOutputs.isEmpty()) {
      checkIfLinkOutputsCollidingWithPrecompiledFiles(
          ruleContext, ccLinkingOutputs, precompiledLibraries);
    }

    ImmutableList<LibraryToLink> libraryToLinks =
        createLibrariesToLinkList(
            ccLinkingOutputs.getLibraryToLink(),
            precompiledLibraries,
            ccCompilationOutputs.isEmpty());

    CcLinkingContext ccLinkingContext =
        linkingHelper.buildCcLinkingContextFromLibrariesToLink(
            neverLink ? ImmutableList.of() : libraryToLinks,
            compilationInfo.getCcCompilationContext());
    CcNativeLibraryInfo ccNativeLibraryInfo =
        CppHelper.collectNativeCcLibraries(ruleContext.getPrerequisites("deps"), libraryToLinks);

    /*
     * We always generate a static library, even if there aren't any source files.
     * This keeps things simpler by avoiding special cases when making use of the library.
     * For example, this is needed to ensure that building a library with "bazel build"
     * will also build all of the library's "deps".
     * However, we only generate a dynamic library if there are source files.
     */
    // For now, we don't add the precompiled libraries to the files to build.

    NestedSetBuilder<Artifact> filesBuilder = NestedSetBuilder.stableOrder();
    if (!ccLinkingOutputs.isEmpty()) {
      LibraryToLink artifactsToBuild = ccLinkingOutputs.getLibraryToLink();
      if (artifactsToBuild.getStaticLibrary() != null) {
        filesBuilder.add(artifactsToBuild.getStaticLibrary());
      }
      if (artifactsToBuild.getPicStaticLibrary() != null) {
        filesBuilder.add(artifactsToBuild.getPicStaticLibrary());
      }
      if (!featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) {
        if (artifactsToBuild.getResolvedSymlinkDynamicLibrary() != null) {
          filesBuilder.add(artifactsToBuild.getResolvedSymlinkDynamicLibrary());
        } else if (artifactsToBuild.getDynamicLibrary() != null) {
          filesBuilder.add(artifactsToBuild.getDynamicLibrary());
        }
        if (artifactsToBuild.getResolvedSymlinkInterfaceLibrary() != null) {
          filesBuilder.add(artifactsToBuild.getResolvedSymlinkInterfaceLibrary());
        } else if (artifactsToBuild.getInterfaceLibrary() != null) {
          filesBuilder.add(artifactsToBuild.getInterfaceLibrary());
        }
      }
    }

    if (!featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULE_CODEGEN)) {
      warnAboutEmptyLibraries(ruleContext, ccCompilationOutputs, linkStatic);
    }
    NestedSet<Artifact> filesToBuild = filesBuilder.build();

    List<Artifact> instrumentedObjectFiles = new ArrayList<>();
    instrumentedObjectFiles.addAll(compilationInfo.getCcCompilationOutputs().getObjectFiles(false));
    instrumentedObjectFiles.addAll(compilationInfo.getCcCompilationOutputs().getObjectFiles(true));
    InstrumentedFilesInfo instrumentedFilesProvider =
        common.getInstrumentedFilesProvider(
            instrumentedObjectFiles,
            /* withBaselineCoverage= */ true,
            /* virtualToOriginalHeaders= */ NestedSetBuilder.create(Order.STABLE_ORDER),
            /* additionalMetadata= */ null);
    CppHelper.maybeAddStaticLinkMarkerProvider(targetBuilder, ruleContext);

    Runfiles.Builder builder = new Runfiles.Builder(ruleContext.getWorkspaceName());
    builder.addDataDeps(ruleContext);
    builder.add(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);
    if (addDynamicRuntimeInputArtifactsToRunfiles) {
      try {
        builder.addTransitiveArtifacts(
            ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration));
      } catch (EvalException e) {
        throw ruleContext.throwWithRuleError(e);
      }
    }
    Runfiles runfiles = builder.build();
    Runfiles.Builder defaultRunfiles =
        new Runfiles.Builder(ruleContext.getWorkspaceName())
            .merge(runfiles)
            .addArtifacts(LibraryToLink.getDynamicLibrariesForRuntime(!neverLink, libraryToLinks));

    Runfiles.Builder dataRunfiles =
        new Runfiles.Builder(ruleContext.getWorkspaceName())
            .merge(runfiles)
            .addArtifacts(
                LibraryToLink.getDynamicLibrariesForRuntime(
                    /* linkingStatically= */ false, libraryToLinks));

    Map<String, NestedSet<Artifact>> currentOutputGroups =
        CcCompilationHelper.buildOutputGroupsForEmittingCompileProviders(
            compilationInfo.getCcCompilationOutputs(),
            compilationInfo.getCcCompilationContext(),
            ruleContext.getFragment(CppConfiguration.class),
            ccToolchain,
            featureConfiguration,
            ruleContext,
            /* generateHiddenTopLevelGroup= */ true);
    CcStarlarkApiProvider.maybeAdd(ruleContext, targetBuilder);
    targetBuilder
        .setFilesToBuild(filesToBuild)
        .addNativeDeclaredProvider(
            CcInfo.builder()
                .setCcCompilationContext(compilationInfo.getCcCompilationContext())
                .setCcLinkingContext(ccLinkingContext)
                .setCcDebugInfoContext(
                    CppHelper.mergeCcDebugInfoContexts(
                        compilationInfo.getCcCompilationOutputs(), ccInfosFromDeps))
                .setCcNativeLibraryInfo(ccNativeLibraryInfo)
                .build())
        .addOutputGroups(
            CcCommon.mergeOutputGroups(
                ImmutableList.of(currentOutputGroups, outputGroups.buildOrThrow())))
        .addNativeDeclaredProvider(instrumentedFilesProvider)
        .addProvider(RunfilesProvider.withData(defaultRunfiles.build(), dataRunfiles.build()));
  }