com.google.devtools.build.lib.rules.cpp.CompileBuildVariables.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.rules.cpp.CompileBuildVariables.java

Source

// 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 com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.StringSequenceBuilder;
import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.VariablesExtension;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.util.FileType;
import com.google.devtools.build.lib.vfs.PathFragment;

/** Enum covering all build variables we create for all various {@link CppCompileAction}. */
public enum CompileBuildVariables {
    /** Variable for the path to the source file being compiled. */
    SOURCE_FILE("source_file"),
    /**
     * Variable for all flags coming from copt rule attribute, and from --copt, --cxxopt, or
     * --conlyopt options.
     */
    USER_COMPILE_FLAGS("user_compile_flags"),
    /**
     * Variable for all flags coming from legacy crosstool fields, such as compiler_flag,
     * optional_compiler_flag, cxx_flag.
     */
    LEGACY_COMPILE_FLAGS("legacy_compile_flags"),
    /** Variable for flags coming from unfiltered_cxx_flag CROSSTOOL fields. */
    UNFILTERED_COMPILE_FLAGS("unfiltered_compile_flags"),
    /** Variable for the path to the output file when output is an object file. */
    OUTPUT_OBJECT_FILE("output_object_file"),
    /** Variable for the path to the compilation output file. */
    OUTPUT_FILE("output_file"),
    /** Variable for the dependency file path */
    DEPENDENCY_FILE("dependency_file"),
    /** Variable for the module file name. */
    MODULE_NAME("module_name"),
    /**
     * Variable for the collection of include paths.
     *
     * @see CcCompilationContext#getIncludeDirs().
     */
    INCLUDE_PATHS("include_paths"),
    /**
     * Variable for the collection of quote include paths.
     *
     * @see CcCompilationContext#getIncludeDirs().
     */
    QUOTE_INCLUDE_PATHS("quote_include_paths"),
    /**
     * Variable for the collection of system include paths.
     *
     * @see CcCompilationContext#getIncludeDirs().
     */
    SYSTEM_INCLUDE_PATHS("system_include_paths"),
    /** Variable for the module map file name. */
    MODULE_MAP_FILE("module_map_file"),
    /** Variable for the dependent module map file name. */
    DEPENDENT_MODULE_MAP_FILES("dependent_module_map_files"),
    /** Variable for the collection of module files. */
    MODULE_FILES("module_files"),
    /** Variable for the collection of macros defined for preprocessor. */
    PREPROCESSOR_DEFINES("preprocessor_defines"),
    /** Variable for the gcov coverage file path. */
    GCOV_GCNO_FILE("gcov_gcno_file"),
    /** Variable for the LTO indexing bitcode file. */
    LTO_INDEXING_BITCODE_FILE("lto_indexing_bitcode_file"),
    /** Variable for the per object debug info file. */
    PER_OBJECT_DEBUG_INFO_FILE("per_object_debug_info_file"),
    /** Variable present when the output is compiled as position independent. */
    PIC("pic"),
    /** Variable marking that we are generating preprocessed sources (from --save_temps). */
    OUTPUT_PREPROCESS_FILE("output_preprocess_file"),
    /** Variable marking that we are generating assembly source (from --save_temps). */
    OUTPUT_ASSEMBLY_FILE("output_assembly_file"),
    /** Path to the fdo instrument artifact */
    FDO_INSTRUMENT_PATH("fdo_instrument_path"),
    /** Path to the fdo profile artifact */
    FDO_PROFILE_PATH("fdo_profile_path"),
    /** Path to the cache prefetch profile artifact */
    FDO_PREFETCH_HINTS_PATH("fdo_prefetch_hints_path"),
    /** Variable for includes that compiler needs to include into sources. */
    INCLUDES("includes");

    private final String variableName;

    CompileBuildVariables(String variableName) {
        this.variableName = variableName;
    }

    public static CcToolchainVariables setupVariablesOrReportRuleError(RuleContext ruleContext,
            FeatureConfiguration featureConfiguration, CcToolchainProvider ccToolchainProvider, String sourceFile,
            String outputFile, String gcnoFile, String dwoFile, String ltoIndexingFile,
            ImmutableList<String> includes, Iterable<String> userCompileFlags, CppModuleMap cppModuleMap,
            boolean usePic, PathFragment fakeOutputFile, String fdoStamp, String dotdFileExecPath,
            ImmutableList<VariablesExtension> variablesExtensions,
            ImmutableMap<String, String> additionalBuildVariables, Iterable<Artifact> directModuleMaps,
            Iterable<PathFragment> includeDirs, Iterable<PathFragment> quoteIncludeDirs,
            Iterable<PathFragment> systemIncludeDirs, Iterable<String> defines) {
        try {
            return setupVariablesOrThrowEvalException(featureConfiguration, ccToolchainProvider, sourceFile,
                    outputFile, gcnoFile, dwoFile, ltoIndexingFile, includes, userCompileFlags, cppModuleMap,
                    usePic, toPathString(fakeOutputFile), fdoStamp, dotdFileExecPath, variablesExtensions,
                    additionalBuildVariables, directModuleMaps, getSafePathStrings(includeDirs),
                    getSafePathStrings(quoteIncludeDirs), getSafePathStrings(systemIncludeDirs), defines,
                    /* addLegacyCxxOptions= */ CppFileTypes.CPP_SOURCE.matches(sourceFile)
                            || CppFileTypes.CPP_HEADER.matches(sourceFile)
                            || CppFileTypes.CPP_MODULE_MAP.matches(sourceFile)
                            || CppFileTypes.CLIF_INPUT_PROTO.matches(sourceFile));
        } catch (EvalException e) {
            ruleContext.ruleError(e.getMessage());
            return CcToolchainVariables.EMPTY;
        }
    }

    public static CcToolchainVariables setupVariablesOrThrowEvalException(FeatureConfiguration featureConfiguration,
            CcToolchainProvider ccToolchainProvider, String sourceFile,
            // TODO(b/76195763): Remove once blaze with cl/189769259 is released and crosstools are
            // updated.
            String outputFile, String gcnoFile, String dwoFile, String ltoIndexingFile,
            ImmutableList<String> includes, Iterable<String> userCompileFlags, CppModuleMap cppModuleMap,
            boolean usePic, String fakeOutputFile, String fdoStamp, String dotdFileExecPath,
            ImmutableList<VariablesExtension> variablesExtensions,
            ImmutableMap<String, String> additionalBuildVariables, Iterable<Artifact> directModuleMaps,
            Iterable<String> includeDirs, Iterable<String> quoteIncludeDirs, Iterable<String> systemIncludeDirs,
            Iterable<String> defines, boolean addLegacyCxxOptions) throws EvalException {
        Preconditions.checkNotNull(directModuleMaps);
        Preconditions.checkNotNull(includeDirs);
        Preconditions.checkNotNull(quoteIncludeDirs);
        Preconditions.checkNotNull(systemIncludeDirs);
        Preconditions.checkNotNull(defines);
        CcToolchainVariables.Builder buildVariables = new CcToolchainVariables.Builder(
                ccToolchainProvider.getBuildVariables());

        buildVariables.addStringSequenceVariable(USER_COMPILE_FLAGS.getVariableName(), userCompileFlags);

        buildVariables.addLazyStringSequenceVariable(LEGACY_COMPILE_FLAGS.getVariableName(),
                getLegacyCompileFlagsSupplier(ccToolchainProvider, addLegacyCxxOptions));

        if (sourceFile != null) {
            buildVariables.addStringVariable(SOURCE_FILE.getVariableName(), sourceFile);
        }

        if (sourceFile == null || (!CppFileTypes.OBJC_SOURCE.matches(sourceFile)
                && !CppFileTypes.OBJCPP_SOURCE.matches(sourceFile))) {
            buildVariables.addLazyStringSequenceVariable(UNFILTERED_COMPILE_FLAGS.getVariableName(),
                    getUnfilteredCompileFlagsSupplier(ccToolchainProvider));
        }

        String fakeOutputFileOrRealOutputFile = fakeOutputFile != null ? fakeOutputFile : outputFile;

        if (outputFile != null) {
            // TODO(b/76195763): Remove once blaze with cl/189769259 is released and crosstools are
            // updated.
            if (!FileType.contains(PathFragment.create(outputFile), CppFileTypes.ASSEMBLER,
                    CppFileTypes.PIC_ASSEMBLER, CppFileTypes.PREPROCESSED_C, CppFileTypes.PREPROCESSED_CPP,
                    CppFileTypes.PIC_PREPROCESSED_C, CppFileTypes.PIC_PREPROCESSED_CPP)) {
                buildVariables.addStringVariable(OUTPUT_OBJECT_FILE.getVariableName(),
                        fakeOutputFileOrRealOutputFile);
            }

            buildVariables.addStringVariable(OUTPUT_FILE.getVariableName(), fakeOutputFileOrRealOutputFile);
        }

        // Set dependency_file to enable <object>.d file generation.
        if (dotdFileExecPath != null) {
            buildVariables.addStringVariable(DEPENDENCY_FILE.getVariableName(), dotdFileExecPath);
        }

        if (featureConfiguration.isEnabled(CppRuleClasses.MODULE_MAPS) && cppModuleMap != null) {
            // If the feature is enabled and cppModuleMap is null, we are about to fail during analysis
            // in any case, but don't crash.
            buildVariables.addStringVariable(MODULE_NAME.getVariableName(), cppModuleMap.getName());
            buildVariables.addStringVariable(MODULE_MAP_FILE.getVariableName(),
                    cppModuleMap.getArtifact().getExecPathString());
            StringSequenceBuilder sequence = new StringSequenceBuilder();
            for (Artifact artifact : directModuleMaps) {
                sequence.addValue(artifact.getExecPathString());
            }
            buildVariables.addCustomBuiltVariable(DEPENDENT_MODULE_MAP_FILES.getVariableName(), sequence);
        }
        if (featureConfiguration.isEnabled(CppRuleClasses.USE_HEADER_MODULES)) {
            // Module inputs will be set later when the action is executed.
            buildVariables.addStringSequenceVariable(MODULE_FILES.getVariableName(), ImmutableSet.of());
        }
        if (featureConfiguration.isEnabled(CppRuleClasses.INCLUDE_PATHS)) {
            buildVariables.addStringSequenceVariable(INCLUDE_PATHS.getVariableName(), includeDirs);
            buildVariables.addStringSequenceVariable(QUOTE_INCLUDE_PATHS.getVariableName(), quoteIncludeDirs);
            buildVariables.addStringSequenceVariable(SYSTEM_INCLUDE_PATHS.getVariableName(), systemIncludeDirs);
        }

        if (!includes.isEmpty()) {
            buildVariables.addStringSequenceVariable(INCLUDES.getVariableName(), includes);
        }

        if (featureConfiguration.isEnabled(CppRuleClasses.PREPROCESSOR_DEFINES)) {
            Iterable<String> allDefines;
            if (fdoStamp != null) {
                // Stamp FDO builds with FDO subtype string
                allDefines = ImmutableList.<String>builder().addAll(defines)
                        .add(CppConfiguration.FDO_STAMP_MACRO + "=\"" + fdoStamp + "\"").build();
            } else {
                allDefines = defines;
            }

            buildVariables.addStringSequenceVariable(PREPROCESSOR_DEFINES.getVariableName(), allDefines);
        }

        if (usePic) {
            if (!featureConfiguration.isEnabled(CppRuleClasses.PIC)) {
                throw new EvalException(Location.BUILTIN, CcCommon.PIC_CONFIGURATION_ERROR);
            }
            buildVariables.addStringVariable(PIC.getVariableName(), "");
        }

        if (gcnoFile != null) {
            buildVariables.addStringVariable(GCOV_GCNO_FILE.getVariableName(), gcnoFile);
        }

        if (dwoFile != null) {
            buildVariables.addStringVariable(PER_OBJECT_DEBUG_INFO_FILE.getVariableName(), dwoFile);
        }

        if (ltoIndexingFile != null) {
            buildVariables.addStringVariable(LTO_INDEXING_BITCODE_FILE.getVariableName(), ltoIndexingFile);
        }

        buildVariables.addAllStringVariables(additionalBuildVariables);
        for (VariablesExtension extension : variablesExtensions) {
            extension.addVariables(buildVariables);
        }

        return buildVariables.build();
    }

    /** Get the safe path strings for a list of paths to use in the build variables. */
    private static ImmutableList<String> getSafePathStrings(Iterable<PathFragment> paths) {
        // Using ImmutableSet first to remove duplicates, then ImmutableList for smaller memory
        // footprint.
        return ImmutableSet.copyOf(paths).stream().map(PathFragment::getSafePathString)
                .collect(ImmutableList.toImmutableList());
    }

    /**
     * Supplier that computes legacy_compile_flags lazily at the execution phase.
     *
     * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
     * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
     */
    private static Supplier<ImmutableList<String>> getLegacyCompileFlagsSupplier(CcToolchainProvider toolchain,
            boolean addLegacyCxxOptions) {
        return () -> {
            ImmutableList.Builder<String> legacyCompileFlags = ImmutableList.builder();
            legacyCompileFlags.addAll(toolchain.getLegacyCompileOptions());
            if (addLegacyCxxOptions) {
                legacyCompileFlags.addAll(toolchain.getLegacyCxxOptions());
            }
            return legacyCompileFlags.build();
        };
    }

    /**
     * Supplier that computes unfiltered_compile_flags lazily at the execution phase.
     *
     * <p>Dear friends of the lambda, this method exists to limit the scope of captured variables only
     * to arguments (to prevent accidental capture of enclosing instance which could regress memory).
     */
    private static Supplier<ImmutableList<String>> getUnfilteredCompileFlagsSupplier(
            CcToolchainProvider ccToolchain) {
        return () -> ccToolchain.getUnfilteredCompilerOptions();
    }

    private static String toPathString(PathFragment a) {
        return a == null ? null : a.getSafePathString();
    }

    public String getVariableName() {
        return variableName;
    }
}