<commit_before>// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.rules.cpp;

import static com.google.devtools.build.lib.packages.BuildType.LABEL;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.FailAction;
import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
import com.google.devtools.build.lib.rules.cpp.Link.Picness;
import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * Representation of a C/C++ compilation. Its purpose is to share the code that creates compilation
 * actions between all classes that need to do so. It follows the builder pattern - load up the
 * necessary settings and then call {@link #createCcCompileActions}.
 *
 * <p>This class is not thread-safe, and it should only be used once for each set of source files,
 * i.e. calling {@link #createCcCompileActions} will throw an Exception if called twice.
 */
public final class CppModel {

  /** Name of the build variable for the path to the source file being compiled. */
  public static final String SOURCE_FILE_VARIABLE_NAME = "source_file";

  /** Name of the build variable for the path to the input file being processed. */
  public static final String INPUT_FILE_VARIABLE_NAME = "input_file";

  /** Name of the build variable for the path to the compilation output file. */
  public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";

  /**
   * Name of the build variable for the path to the compilation output file in case of assembly
   * source.
   */
  public static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";

  /**
   * Name of the build variable for the path to the compilation output file in case of preprocessed
   * source.
   */
  public static final String OUTPUT_PREPROCESS_FILE_VARIABLE_NAME = "output_preprocess_file";

  /** Name of the build variable for the path to the output file when output is an object file. */
  public static final String OUTPUT_OBJECT_FILE_VARIABLE_NAME = "output_object_file";

  /** Name of the build variable for the module file name. */
  public static final String MODULE_NAME_VARIABLE_NAME = "module_name";

  /** Name of the build variable for the module map file name. */
  public static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";

  /** Name of the build variable for the dependent module map file name. */
  public static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
      "dependent_module_map_files";

  /** Name of the build variable for the collection of module files. */
  public static final String MODULE_FILES_VARIABLE_NAME = "module_files";

  /**
   * Name of the build variable for includes that compiler needs to include into sources to be
   * compiled.
   */
  public static final String INCLUDES_VARIABLE_NAME = "includes";

  /**
   * Name of the build variable for the collection of include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String INCLUDE_PATHS_VARIABLE_NAME = "include_paths";

  /**
   * Name of the build variable for the collection of quote include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String QUOTE_INCLUDE_PATHS_VARIABLE_NAME = "quote_include_paths";

  /**
   * Name of the build variable for the collection of system include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String SYSTEM_INCLUDE_PATHS_VARIABLE_NAME = "system_include_paths";

  /** Name of the build variable for the dependency file path */
  public static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";

  /** Name of the build variable for the collection of macros defined for preprocessor. */
  public static final String PREPROCESSOR_DEFINES_VARIABLE_NAME = "preprocessor_defines";

  /** Name of the build variable present when the output is compiled as position independent. */
  public static final String PIC_VARIABLE_NAME = "pic";

  /** Name of the build variable for the gcov coverage file path. */
  public static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";

  /** Name of the build variable for the per object debug info file. */
  public static final String PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME =
      "per_object_debug_info_file";

  /** Name of the build variable for the LTO indexing bitcode file. */
  public static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";

  /** Name of the build variable for stripopts for the strip action. */
  public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";

  /**
   * Build variable for all flags coming from legacy crosstool fields, such as compiler_flag,
   * optional_compiler_flag, cxx_flag, optional_cxx_flag.
   */
  public static final String LEGACY_COMPILE_FLAGS_VARIABLE_NAME = "legacy_compile_flags";

  /**
   * Build variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
   * --conlyopt options.
   */
  public static final String USER_COMPILE_FLAGS_VARIABLE_NAME = "user_compile_flags";

  /** Build variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
  public static final String UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME = "unfiltered_compile_flags";

  /** Name of the build variable for the sysroot path variable name. */
  public static final String SYSROOT_VARIABLE_NAME = "sysroot";

  private static final String PIC_CONFIGURATION_ERROR =
      "PIC compilation is requested but the toolchain does not support it";

  private final CppSemantics semantics;
  private final RuleContext ruleContext;
  private final BuildConfiguration configuration;
  private final CppConfiguration cppConfiguration;

  // compile model
  private CppCompilationContext context;
  private final Set<CppSource> sourceFiles = new LinkedHashSet<>();
  private final List<Artifact> compilationMandatoryInputs = new ArrayList<>();
  private final List<Artifact> additionalIncludeScanningRoots = new ArrayList<>();
  private final ImmutableList<String> copts;
  private final Predicate<String> coptsFilter;
  private boolean fake;
  private boolean maySaveTemps;
  private CcCompilationOutputs compilationOutputs;

  // link model
  private final List<String> linkopts = new ArrayList<>();
  private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
  private boolean neverLink;
  private final List<Artifact> linkActionInputs = new ArrayList<>();
  private boolean allowInterfaceSharedObjects;
  private boolean createDynamicLibrary = true;
  private boolean createStaticLibraries = true;
  private Artifact soImplArtifact;
  private FeatureConfiguration featureConfiguration;
  private List<VariablesExtension> variablesExtensions = new ArrayList<>();
  private final CcToolchainProvider ccToolchain;
  private final FdoSupportProvider fdoSupport;
  private String linkedArtifactNameSuffix = "";
  private final ImmutableSet<String> features;
  private boolean generateNoPic = true;

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      ImmutableList<String> copts) {
    this(
        ruleContext,
        semantics,
        ccToolchain,
        fdoSupport,
        ruleContext.getConfiguration(),
        copts,
        Predicates.alwaysTrue());
  }

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      ImmutableList<String> copts,
      Predicate<String> coptsFilter) {
    this(
        ruleContext,
        semantics,
        ccToolchain,
        fdoSupport,
        ruleContext.getConfiguration(),
        copts,
        coptsFilter);
 }

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      BuildConfiguration configuration,
      ImmutableList<String> copts,
      Predicate<String> coptsFilter) {
    this.ruleContext = Preconditions.checkNotNull(ruleContext);
    this.semantics = semantics;
    this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
    this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
    this.configuration = configuration;
    this.copts = copts;
    this.coptsFilter = Preconditions.checkNotNull(coptsFilter);
    cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
    features = ruleContext.getFeatures();
  }

  private Artifact getDwoFile(Artifact outputFile) {
    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ".dwo");
  }

  private Artifact getLtoIndexingFile(Artifact outputFile) {
    String ext = Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions());
    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ext);
  }

  /**
   * If the cpp compilation is a fake, then it creates only a single compile action without PIC.
   * Defaults to false.
   */
  public CppModel setFake(boolean fake) {
    this.fake = fake;
    return this;
  }

  /**
   * Whether to create actions for temps. This defaults to false.
   */
  public CppModel setSaveTemps(boolean maySaveTemps) {
    this.maySaveTemps = maySaveTemps;
    return this;
  }

  /**
   * Sets the compilation context, i.e. include directories and allowed header files inclusions.
   */
  public CppModel setContext(CppCompilationContext context) {
    this.context = context;
    return this;
  }

  /**
   * Adds a single source file to be compiled. Note that this should only be called for primary
   * compilation units, including module files or headers to be parsed or preprocessed.
   */
  public CppModel addCompilationUnitSources(
      Iterable<Artifact> sourceFiles, Label sourceLabel, CppSource.Type type) {
    for (Artifact sourceFile : sourceFiles) {
      this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, type));
    }
    return this;
  }

  /**
   * Adds all the source files. Note that this should only be called for primary compilation units,
   * including module files or headers to be parsed or preprocessed.
   */
  public CppModel addCompilationUnitSources(Set<CppSource> sources) {
    this.sourceFiles.addAll(sources);
    return this;
  }

  /** Adds compilation mandatory inputs. */
  public CppModel addCompilationMandatoryInputs(Collection<Artifact> compilationMandatoryInputs) {
    this.compilationMandatoryInputs.addAll(compilationMandatoryInputs);
    return this;
  }

  /** Adds additional includes to be scanned. */
  public CppModel addAdditionalIncludeScanningRoots(
      Collection<Artifact> additionalIncludeScanningRoots) {
    this.additionalIncludeScanningRoots.addAll(additionalIncludeScanningRoots);
    return this;
  }

  /**
   * Adds the given linkopts to the optional dynamic library link command.
   */
  public CppModel addLinkopts(Collection<String> linkopts) {
    this.linkopts.addAll(linkopts);
    return this;
  }

  /**
   * Adds the given variablesExensions for templating the crosstool.
   *
   * <p>In general, we prefer the build variables (especially those that derive strictly from
   * the configuration) be learned by inspecting the CcToolchain, as passed to the rule in the
   * CcToolchainProvider.  However, for build variables that must be injected into the rule
   * implementation (ex. build variables learned from the BUILD file), should be added using the
   * VariablesExtension abstraction.  This allows the injection to construct non-trivial build
   * variables (lists, ect.).
   */
  public CppModel addVariablesExtension(Collection<VariablesExtension> variablesExtensions) {
    this.variablesExtensions.addAll(variablesExtensions);
    return this;
  }

  /**
   * Sets the link type used for the link actions. Note that only static links are supported at this
   * time.
   */
  public CppModel setLinkTargetType(LinkTargetType linkType) {
    this.linkType = linkType;
    return this;
  }

  public CppModel setNeverLink(boolean neverLink) {
    this.neverLink = neverLink;
    return this;
  }

  /**
   * Adds an artifact to the inputs of any link actions created by this CppModel.
   */
  public CppModel addLinkActionInputs(Collection<Artifact> inputs) {
    this.linkActionInputs.addAll(inputs);
    return this;
  }

  /**
   * Whether to allow interface dynamic libraries. Note that setting this to true only has an effect
   * if the configuration allows it. Defaults to false.
   */
  public CppModel setAllowInterfaceSharedObjects(boolean allowInterfaceSharedObjects) {
    // TODO(bazel-team): Set the default to true, and require explicit action to disable it.
    this.allowInterfaceSharedObjects = allowInterfaceSharedObjects;
    return this;
  }

  public CppModel setCreateDynamicLibrary(boolean createDynamicLibrary) {
    this.createDynamicLibrary = createDynamicLibrary;
    return this;
  }

  public CppModel setCreateStaticLibraries(boolean createStaticLibraries) {
    this.createStaticLibraries = createStaticLibraries;
    return this;
  }

  public CppModel setDynamicLibrary(Artifact soImplFilename) {
    this.soImplArtifact = soImplFilename;
    return this;
  }

  /** Sets the feature configuration to be used for C/C++ actions. */
  public CppModel setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
    this.featureConfiguration = featureConfiguration;
    return this;
  }

  /*
   * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
   * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
   * generate the same linked artifact and therefore lead to artifact conflicts. This method
   * provides a way to avoid this artifact conflict by allowing different callers acting on the same
   * rule to provide a suffix that will be used to scope their own linked artifacts.
   */
  public CppModel setLinkedArtifactNameSuffix(String suffix) {
    this.linkedArtifactNameSuffix = suffix;
    return this;
  }

  /** no-PIC actions won't be generated. */
  public CppModel setGenerateNoPic(boolean generateNoPic) {
    this.generateNoPic = generateNoPic;
    return this;
  }

  /**
   * @returns whether we want to provide header modules for the current target.
   */
  private boolean shouldProvideHeaderModules() {
    return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
        && !cppConfiguration.isLipoContextCollector();
  }

  /**
   * @return the non-pic header module artifact for the current target.
   */
  public Artifact getHeaderModule(Artifact moduleMapArtifact) {
    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
    return ruleContext.getRelatedArtifact(outputName, ".pcm");
  }

  /**
   * @return the pic header module artifact for the current target.
   */
  public Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
    return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
  }

  /** @return whether this target needs to generate pic actions. */
  private boolean getGeneratePicActions() {
    return featureConfiguration.isEnabled(CppRuleClasses.PIC)
        && CppHelper.usePic(ruleContext, ccToolchain, false);
  }

  /** @return whether this target needs to generate non-pic actions. */
  private boolean getGenerateNoPicActions() {
    if (!generateNoPic) {
      return false;
    }
    boolean picFeatureEnabled = featureConfiguration.isEnabled(CppRuleClasses.PIC);
    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, true);
    boolean usePicForNonBinaries = CppHelper.usePic(ruleContext, ccToolchain, false);

    if (!usePicForNonBinaries) {
      // This means you have to be prepared to use non-pic output for dynamic libraries.
      return true;
    }

    // Either you're only making a dynamic library (onlySingleOutput) or pic should be used
    // in all cases.
    if (usePicForBinaries) {
      if (picFeatureEnabled) {<commit_msg>Automated rollback of commit 17830c25a816d67ba79e783acaa6a085b516bd43.<commit_after>// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.rules.cpp;

import static com.google.devtools.build.lib.packages.BuildType.LABEL;

import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.FailAction;
import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.StringSequenceBuilder;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension;
import com.google.devtools.build.lib.rules.cpp.CppCompileAction.DotdFile;
import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness;
import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
import com.google.devtools.build.lib.rules.cpp.Link.Picness;
import com.google.devtools.build.lib.rules.cpp.Link.Staticness;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * Representation of a C/C++ compilation. Its purpose is to share the code that creates compilation
 * actions between all classes that need to do so. It follows the builder pattern - load up the
 * necessary settings and then call {@link #createCcCompileActions}.
 *
 * <p>This class is not thread-safe, and it should only be used once for each set of source files,
 * i.e. calling {@link #createCcCompileActions} will throw an Exception if called twice.
 */
public final class CppModel {

  /** Name of the build variable for the path to the source file being compiled. */
  public static final String SOURCE_FILE_VARIABLE_NAME = "source_file";

  /** Name of the build variable for the path to the input file being processed. */
  public static final String INPUT_FILE_VARIABLE_NAME = "input_file";

  /** Name of the build variable for the path to the compilation output file. */
  public static final String OUTPUT_FILE_VARIABLE_NAME = "output_file";

  /**
   * Name of the build variable for the path to the compilation output file in case of assembly
   * source.
   */
  public static final String OUTPUT_ASSEMBLY_FILE_VARIABLE_NAME = "output_assembly_file";

  /**
   * Name of the build variable for the path to the compilation output file in case of preprocessed
   * source.
   */
  public static final String OUTPUT_PREPROCESS_FILE_VARIABLE_NAME = "output_preprocess_file";

  /** Name of the build variable for the path to the output file when output is an object file. */
  public static final String OUTPUT_OBJECT_FILE_VARIABLE_NAME = "output_object_file";

  /** Name of the build variable for the module file name. */
  public static final String MODULE_NAME_VARIABLE_NAME = "module_name";

  /** Name of the build variable for the module map file name. */
  public static final String MODULE_MAP_FILE_VARIABLE_NAME = "module_map_file";

  /** Name of the build variable for the dependent module map file name. */
  public static final String DEPENDENT_MODULE_MAP_FILES_VARIABLE_NAME =
      "dependent_module_map_files";

  /** Name of the build variable for the collection of module files. */
  public static final String MODULE_FILES_VARIABLE_NAME = "module_files";

  /**
   * Name of the build variable for includes that compiler needs to include into sources to be
   * compiled.
   */
  public static final String INCLUDES_VARIABLE_NAME = "includes";

  /**
   * Name of the build variable for the collection of include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String INCLUDE_PATHS_VARIABLE_NAME = "include_paths";

  /**
   * Name of the build variable for the collection of quote include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String QUOTE_INCLUDE_PATHS_VARIABLE_NAME = "quote_include_paths";

  /**
   * Name of the build variable for the collection of system include paths.
   *
   * @see CppCompilationContext#getIncludeDirs().
   */
  public static final String SYSTEM_INCLUDE_PATHS_VARIABLE_NAME = "system_include_paths";

  /** Name of the build variable for the dependency file path */
  public static final String DEPENDENCY_FILE_VARIABLE_NAME = "dependency_file";

  /** Name of the build variable for the collection of macros defined for preprocessor. */
  public static final String PREPROCESSOR_DEFINES_VARIABLE_NAME = "preprocessor_defines";

  /** Name of the build variable present when the output is compiled as position independent. */
  public static final String PIC_VARIABLE_NAME = "pic";

  /** Name of the build variable for the gcov coverage file path. */
  public static final String GCOV_GCNO_FILE_VARIABLE_NAME = "gcov_gcno_file";

  /** Name of the build variable for the per object debug info file. */
  public static final String PER_OBJECT_DEBUG_INFO_FILE_VARIABLE_NAME =
      "per_object_debug_info_file";

  /** Name of the build variable for the LTO indexing bitcode file. */
  public static final String LTO_INDEXING_BITCODE_FILE_VARIABLE_NAME = "lto_indexing_bitcode_file";

  /** Name of the build variable for stripopts for the strip action. */
  public static final String STRIPOPTS_VARIABLE_NAME = "stripopts";

  /**
   * Build variable for all flags coming from legacy crosstool fields, such as compiler_flag,
   * optional_compiler_flag, cxx_flag, optional_cxx_flag.
   */
  public static final String LEGACY_COMPILE_FLAGS_VARIABLE_NAME = "legacy_compile_flags";

  /**
   * Build variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
   * --conlyopt options.
   */
  public static final String USER_COMPILE_FLAGS_VARIABLE_NAME = "user_compile_flags";

  /** Build variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
  public static final String UNFILTERED_COMPILE_FLAGS_VARIABLE_NAME = "unfiltered_compile_flags";

  /** Name of the build variable for the sysroot path variable name. */
  public static final String SYSROOT_VARIABLE_NAME = "sysroot";

  private static final String PIC_CONFIGURATION_ERROR =
      "PIC compilation is requested but the toolchain does not support it";

  private final CppSemantics semantics;
  private final RuleContext ruleContext;
  private final BuildConfiguration configuration;
  private final CppConfiguration cppConfiguration;

  // compile model
  private CppCompilationContext context;
  private final Set<CppSource> sourceFiles = new LinkedHashSet<>();
  private final List<Artifact> compilationMandatoryInputs = new ArrayList<>();
  private final List<Artifact> additionalIncludeScanningRoots = new ArrayList<>();
  private final ImmutableList<String> copts;
  private final Predicate<String> coptsFilter;
  private boolean fake;
  private boolean maySaveTemps;
  private boolean onlySingleOutput;
  private CcCompilationOutputs compilationOutputs;

  // link model
  private final List<String> linkopts = new ArrayList<>();
  private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY;
  private boolean neverLink;
  private final List<Artifact> linkActionInputs = new ArrayList<>();
  private boolean allowInterfaceSharedObjects;
  private boolean createDynamicLibrary = true;
  private boolean createStaticLibraries = true;
  private Artifact soImplArtifact;
  private FeatureConfiguration featureConfiguration;
  private List<VariablesExtension> variablesExtensions = new ArrayList<>();
  private final CcToolchainProvider ccToolchain;
  private final FdoSupportProvider fdoSupport;
  private String linkedArtifactNameSuffix = "";
  private final ImmutableSet<String> features;
  private boolean generateNoPic = true;

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      ImmutableList<String> copts) {
    this(
        ruleContext,
        semantics,
        ccToolchain,
        fdoSupport,
        ruleContext.getConfiguration(),
        copts,
        Predicates.alwaysTrue());
  }

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      ImmutableList<String> copts,
      Predicate<String> coptsFilter) {
    this(
        ruleContext,
        semantics,
        ccToolchain,
        fdoSupport,
        ruleContext.getConfiguration(),
        copts,
        coptsFilter);
 }

  public CppModel(
      RuleContext ruleContext,
      CppSemantics semantics,
      CcToolchainProvider ccToolchain,
      FdoSupportProvider fdoSupport,
      BuildConfiguration configuration,
      ImmutableList<String> copts,
      Predicate<String> coptsFilter) {
    this.ruleContext = Preconditions.checkNotNull(ruleContext);
    this.semantics = semantics;
    this.ccToolchain = Preconditions.checkNotNull(ccToolchain);
    this.fdoSupport = Preconditions.checkNotNull(fdoSupport);
    this.configuration = configuration;
    this.copts = copts;
    this.coptsFilter = Preconditions.checkNotNull(coptsFilter);
    cppConfiguration = ruleContext.getFragment(CppConfiguration.class);
    features = ruleContext.getFeatures();
  }

  private Artifact getDwoFile(Artifact outputFile) {
    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ".dwo");
  }

  private Artifact getLtoIndexingFile(Artifact outputFile) {
    String ext = Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions());
    return ruleContext.getRelatedArtifact(outputFile.getRootRelativePath(), ext);
  }

  /**
   * If the cpp compilation is a fake, then it creates only a single compile action without PIC.
   * Defaults to false.
   */
  public CppModel setFake(boolean fake) {
    this.fake = fake;
    return this;
  }

  /**
   * If set, the CppModel only creates a single .o output that can be linked into a dynamic library,
   * i.e., it never generates both PIC and non-PIC outputs. Otherwise it creates outputs that can be
   * linked into both static binaries and dynamic libraries (if both require PIC or both require
   * non-PIC, then it still only creates a single output). Defaults to false.
   */
  public CppModel setOnlySingleOutput(boolean onlySingleOutput) {
    this.onlySingleOutput = onlySingleOutput;
    return this;
  }

  /**
   * Whether to create actions for temps. This defaults to false.
   */
  public CppModel setSaveTemps(boolean maySaveTemps) {
    this.maySaveTemps = maySaveTemps;
    return this;
  }

  /**
   * Sets the compilation context, i.e. include directories and allowed header files inclusions.
   */
  public CppModel setContext(CppCompilationContext context) {
    this.context = context;
    return this;
  }

  /**
   * Adds a single source file to be compiled. Note that this should only be called for primary
   * compilation units, including module files or headers to be parsed or preprocessed.
   */
  public CppModel addCompilationUnitSources(
      Iterable<Artifact> sourceFiles, Label sourceLabel, CppSource.Type type) {
    for (Artifact sourceFile : sourceFiles) {
      this.sourceFiles.add(CppSource.create(sourceFile, sourceLabel, type));
    }
    return this;
  }

  /**
   * Adds all the source files. Note that this should only be called for primary compilation units,
   * including module files or headers to be parsed or preprocessed.
   */
  public CppModel addCompilationUnitSources(Set<CppSource> sources) {
    this.sourceFiles.addAll(sources);
    return this;
  }

  /** Adds compilation mandatory inputs. */
  public CppModel addCompilationMandatoryInputs(Collection<Artifact> compilationMandatoryInputs) {
    this.compilationMandatoryInputs.addAll(compilationMandatoryInputs);
    return this;
  }

  /** Adds additional includes to be scanned. */
  public CppModel addAdditionalIncludeScanningRoots(
      Collection<Artifact> additionalIncludeScanningRoots) {
    this.additionalIncludeScanningRoots.addAll(additionalIncludeScanningRoots);
    return this;
  }

  /**
   * Adds the given linkopts to the optional dynamic library link command.
   */
  public CppModel addLinkopts(Collection<String> linkopts) {
    this.linkopts.addAll(linkopts);
    return this;
  }

  /**
   * Adds the given variablesExensions for templating the crosstool.
   *
   * <p>In general, we prefer the build variables (especially those that derive strictly from
   * the configuration) be learned by inspecting the CcToolchain, as passed to the rule in the
   * CcToolchainProvider.  However, for build variables that must be injected into the rule
   * implementation (ex. build variables learned from the BUILD file), should be added using the
   * VariablesExtension abstraction.  This allows the injection to construct non-trivial build
   * variables (lists, ect.).
   */
  public CppModel addVariablesExtension(Collection<VariablesExtension> variablesExtensions) {
    this.variablesExtensions.addAll(variablesExtensions);
    return this;
  }

  /**
   * Sets the link type used for the link actions. Note that only static links are supported at this
   * time.
   */
  public CppModel setLinkTargetType(LinkTargetType linkType) {
    this.linkType = linkType;
    return this;
  }

  public CppModel setNeverLink(boolean neverLink) {
    this.neverLink = neverLink;
    return this;
  }

  /**
   * Adds an artifact to the inputs of any link actions created by this CppModel.
   */
  public CppModel addLinkActionInputs(Collection<Artifact> inputs) {
    this.linkActionInputs.addAll(inputs);
    return this;
  }

  /**
   * Whether to allow interface dynamic libraries. Note that setting this to true only has an effect
   * if the configuration allows it. Defaults to false.
   */
  public CppModel setAllowInterfaceSharedObjects(boolean allowInterfaceSharedObjects) {
    // TODO(bazel-team): Set the default to true, and require explicit action to disable it.
    this.allowInterfaceSharedObjects = allowInterfaceSharedObjects;
    return this;
  }

  public CppModel setCreateDynamicLibrary(boolean createDynamicLibrary) {
    this.createDynamicLibrary = createDynamicLibrary;
    return this;
  }

  public CppModel setCreateStaticLibraries(boolean createStaticLibraries) {
    this.createStaticLibraries = createStaticLibraries;
    return this;
  }

  public CppModel setDynamicLibrary(Artifact soImplFilename) {
    this.soImplArtifact = soImplFilename;
    return this;
  }

  /** Sets the feature configuration to be used for C/C++ actions. */
  public CppModel setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
    this.featureConfiguration = featureConfiguration;
    return this;
  }

  /*
   * Adds a suffix for paths of linked artifacts. Normally their paths are derived solely from rule
   * labels. In the case of multiple callers (e.g., aspects) acting on a single rule, they may
   * generate the same linked artifact and therefore lead to artifact conflicts. This method
   * provides a way to avoid this artifact conflict by allowing different callers acting on the same
   * rule to provide a suffix that will be used to scope their own linked artifacts.
   */
  public CppModel setLinkedArtifactNameSuffix(String suffix) {
    this.linkedArtifactNameSuffix = suffix;
    return this;
  }

  /** no-PIC actions won't be generated. */
  public CppModel setGenerateNoPic(boolean generateNoPic) {
    this.generateNoPic = generateNoPic;
    return this;
  }

  /**
   * @returns whether we want to provide header modules for the current target.
   */
  private boolean shouldProvideHeaderModules() {
    return featureConfiguration.isEnabled(CppRuleClasses.HEADER_MODULES)
        && !cppConfiguration.isLipoContextCollector();
  }

  /**
   * @return the non-pic header module artifact for the current target.
   */
  public Artifact getHeaderModule(Artifact moduleMapArtifact) {
    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
    return ruleContext.getRelatedArtifact(outputName, ".pcm");
  }

  /**
   * @return the pic header module artifact for the current target.
   */
  public Artifact getPicHeaderModule(Artifact moduleMapArtifact) {
    PathFragment objectDir = CppHelper.getObjDirectory(ruleContext.getLabel());
    PathFragment outputName = objectDir.getRelative(moduleMapArtifact.getRootRelativePath());
    return ruleContext.getRelatedArtifact(outputName, ".pic.pcm");
  }

  /** @return whether this target needs to generate pic actions. */
  private boolean getGeneratePicActions() {
    return featureConfiguration.isEnabled(CppRuleClasses.PIC)
        && CppHelper.usePic(ruleContext, ccToolchain, false);
  }

  /** @return whether this target needs to generate non-pic actions. */
  private boolean getGenerateNoPicActions() {
    if (!generateNoPic) {
      return false;
    }
    boolean picFeatureEnabled = featureConfiguration.isEnabled(CppRuleClasses.PIC);
    boolean usePicForBinaries = CppHelper.usePic(ruleContext, ccToolchain, true);
    boolean usePicForNonBinaries = CppHelper.usePic(ruleContext, ccToolchain, false);

    if (!usePicForNonBinaries) {
      // This means you have to be prepared to use non-pic output for dynamic libraries.
      return true;
    }

    // Either you're only making a dynamic library (onlySingleOutput) or pic should be used
    // in all cases.
    if (onlySingleOutput || usePicForBinaries) {
      if (picFeatureEnabled) {
{'fraction_non_alphanumeric': 0.07580897703549061, 'fraction_numerical': 0.0010960334029227557, 'mean_word_length': 4.1743181204428845, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6889770', 'n_tokens_mistral': 10769, 'n_tokens_neox': 10478, 'n_words': 3289}