Java tutorial
// 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.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.ActionInput; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.SequenceBuilder; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.List; /** Enum covering all build variables we create for all various {@link CppLinkAction}. */ public enum LinkBuildVariables { /** Entries in the linker runtime search path (usually set by -rpath flag) */ RUNTIME_LIBRARY_SEARCH_DIRECTORIES("runtime_library_search_directories"), /** Entries in the linker search path (usually set by -L flag) */ LIBRARY_SEARCH_DIRECTORIES("library_search_directories"), /** Flags providing files to link as inputs in the linker invocation */ LIBRARIES_TO_LINK("libraries_to_link"), /** Thinlto param file produced by thinlto-indexing action consumed by the final link action. */ THINLTO_PARAM_FILE("thinlto_param_file"), /** Location of def file used on Windows with MSVC */ DEF_FILE_PATH("def_file_path"), /** Location where hinlto should write thinlto_param_file flags when indexing. */ THINLTO_INDEXING_PARAM_FILE("thinlto_indexing_param_file"), THINLTO_PREFIX_REPLACE("thinlto_prefix_replace"), /** * A build variable to let the LTO indexing step know how to map from the minimized bitcode file * to the full bitcode file used by the LTO Backends. */ THINLTO_OBJECT_SUFFIX_REPLACE("thinlto_object_suffix_replace"), /** * A build variable for the path to the merged object file, which is an object file that is * created during the LTO indexing step and needs to be passed to the final link. */ THINLTO_MERGED_OBJECT_FILE("thinlto_merged_object_file"), /** Location of linker param file created by bazel to overcome command line length limit */ LINKER_PARAM_FILE("linker_param_file"), /** execpath of the output of the linker. */ OUTPUT_EXECPATH("output_execpath"), /** "yes"|"no" depending on whether interface library should be generated. */ GENERATE_INTERFACE_LIBRARY("generate_interface_library"), /** Path to the interface library builder tool. */ INTERFACE_LIBRARY_BUILDER("interface_library_builder_path"), /** Input for the interface library ifso builder tool. */ INTERFACE_LIBRARY_INPUT("interface_library_input_path"), /** Path where to generate interface library using the ifso builder tool. */ INTERFACE_LIBRARY_OUTPUT("interface_library_output_path"), /** Linker flags coming from the legacy crosstool fields. */ LEGACY_LINK_FLAGS("legacy_link_flags"), /** Linker flags coming from the --linkopt or linkopts attribute. */ USER_LINK_FLAGS("user_link_flags"), /** Path to which to write symbol counts. */ SYMBOL_COUNTS_OUTPUT("symbol_counts_output"), /** A build variable giving linkstamp paths. */ LINKSTAMP_PATHS("linkstamp_paths"), /** Presence of this variable indicates that PIC code should be generated. */ FORCE_PIC("force_pic"), /** Presence of this variable indicates that the debug symbols should be stripped. */ STRIP_DEBUG_SYMBOLS("strip_debug_symbols"), @Deprecated IS_CC_TEST_LINK_ACTION("is_cc_test_link_action"), @Deprecated IS_NOT_CC_TEST_LINK_ACTION("is_not_cc_test_link_action"), /** Truthy when current action is a cc_test linking action, falsey otherwise. */ IS_CC_TEST("is_cc_test"), /** * Presence of this variable indicates that files were compiled with fission (debug info is in * .dwo files instead of .o files and linker needs to know). */ IS_USING_FISSION("is_using_fission"); private final String variableName; LinkBuildVariables(String variableName) { this.variableName = variableName; } public String getVariableName() { return variableName; } public static CcToolchainVariables setupVariables(boolean isUsingLinkerNotArchiver, BuildConfiguration configuration, Artifact outputArtifact, boolean isCreatingSharedLibrary, Artifact paramFile, Artifact thinltoParamFile, Artifact thinltoMergedObjectFile, boolean mustKeepDebug, Artifact symbolCounts, CcToolchainProvider ccToolchainProvider, FeatureConfiguration featureConfiguration, boolean useTestOnlyFlags, boolean isLtoIndexing, ImmutableList<String> userLinkFlags, Artifact interfaceLibraryBuilder, Artifact interfaceLibraryOutput, PathFragment ltoOutputRootPrefix, ActionInput defFile, FdoSupportProvider fdoSupport, Iterable<String> runtimeLibrarySearchDirectories, SequenceBuilder librariesToLink, Iterable<String> librarySearchDirectories, boolean isLegacyFullyStaticLinkingMode, boolean isStaticLinkingMode) throws EvalException { CcToolchainVariables.Builder buildVariables = new CcToolchainVariables.Builder(); // symbol counting if (symbolCounts != null) { buildVariables.addStringVariable(SYMBOL_COUNTS_OUTPUT.getVariableName(), symbolCounts.getExecPathString()); } // pic if (ccToolchainProvider.getForcePic()) { buildVariables.addStringVariable(FORCE_PIC.getVariableName(), ""); } if (!mustKeepDebug && ccToolchainProvider.getShouldStripBinaries()) { buildVariables.addStringVariable(STRIP_DEBUG_SYMBOLS.getVariableName(), ""); } if (isUsingLinkerNotArchiver && ccToolchainProvider.shouldCreatePerObjectDebugInfo(featureConfiguration)) { buildVariables.addStringVariable(IS_USING_FISSION.getVariableName(), ""); } if (useTestOnlyFlags) { buildVariables.addIntegerVariable(IS_CC_TEST.getVariableName(), 1); buildVariables.addStringVariable(IS_CC_TEST_LINK_ACTION.getVariableName(), ""); } else { buildVariables.addIntegerVariable(IS_CC_TEST.getVariableName(), 0); buildVariables.addStringVariable(IS_NOT_CC_TEST_LINK_ACTION.getVariableName(), ""); } if (runtimeLibrarySearchDirectories != null) { buildVariables.addStringSequenceVariable(RUNTIME_LIBRARY_SEARCH_DIRECTORIES.getVariableName(), runtimeLibrarySearchDirectories); } buildVariables.addCustomBuiltVariable(LIBRARIES_TO_LINK.getVariableName(), librariesToLink); // TODO(b/72803478): Remove once existing crosstools have been migrated buildVariables.addStringVariable("libs_to_link_dont_emit_objects_for_archiver", ""); buildVariables.addStringSequenceVariable(LIBRARY_SEARCH_DIRECTORIES.getVariableName(), librarySearchDirectories); if (paramFile != null) { buildVariables.addStringVariable(LINKER_PARAM_FILE.getVariableName(), paramFile.getExecPathString()); } // output exec path if (outputArtifact != null && !isLtoIndexing) { buildVariables.addStringVariable(OUTPUT_EXECPATH.getVariableName(), outputArtifact.getExecPathString()); } if (isLtoIndexing) { if (thinltoParamFile != null) { // This is a lto-indexing action and we want it to populate param file. buildVariables.addStringVariable(THINLTO_INDEXING_PARAM_FILE.getVariableName(), thinltoParamFile.getExecPathString()); // TODO(b/33846234): Remove once all the relevant crosstools don't depend on the variable. buildVariables.addStringVariable("thinlto_optional_params_file", "=" + thinltoParamFile.getExecPathString()); } else { buildVariables.addStringVariable(THINLTO_INDEXING_PARAM_FILE.getVariableName(), ""); // TODO(b/33846234): Remove once all the relevant crosstools don't depend on the variable. buildVariables.addStringVariable("thinlto_optional_params_file", ""); } buildVariables.addStringVariable(THINLTO_PREFIX_REPLACE.getVariableName(), configuration.getBinDirectory().getExecPathString() + ";" + configuration.getBinDirectory().getExecPath().getRelative(ltoOutputRootPrefix)); String objectFileExtension; try { objectFileExtension = ccToolchainProvider.getFeatures() .getArtifactNameExtensionForCategory(ArtifactCategory.OBJECT_FILE); } catch (InvalidConfigurationException e) { throw new EvalException(null, "artifact name pattern for object_file must be specified", e); } buildVariables.addStringVariable(THINLTO_OBJECT_SUFFIX_REPLACE.getVariableName(), Iterables.getOnlyElement(CppFileTypes.LTO_INDEXING_OBJECT_FILE.getExtensions()) + ";" + objectFileExtension); if (thinltoMergedObjectFile != null) { buildVariables.addStringVariable(THINLTO_MERGED_OBJECT_FILE.getVariableName(), thinltoMergedObjectFile.getExecPathString()); } } else { if (thinltoParamFile != null) { // This is a normal link action and we need to use param file created by lto-indexing. buildVariables.addStringVariable(THINLTO_PARAM_FILE.getVariableName(), thinltoParamFile.getExecPathString()); } } boolean shouldGenerateInterfaceLibrary = outputArtifact != null && interfaceLibraryBuilder != null && interfaceLibraryOutput != null && !isLtoIndexing; buildVariables.addStringVariable(GENERATE_INTERFACE_LIBRARY.getVariableName(), shouldGenerateInterfaceLibrary ? "yes" : "no"); buildVariables.addStringVariable(INTERFACE_LIBRARY_BUILDER.getVariableName(), shouldGenerateInterfaceLibrary ? interfaceLibraryBuilder.getExecPathString() : "ignored"); buildVariables.addStringVariable(INTERFACE_LIBRARY_INPUT.getVariableName(), shouldGenerateInterfaceLibrary ? outputArtifact.getExecPathString() : "ignored"); buildVariables.addStringVariable(INTERFACE_LIBRARY_OUTPUT.getVariableName(), shouldGenerateInterfaceLibrary ? interfaceLibraryOutput.getExecPathString() : "ignored"); if (defFile != null) { buildVariables.addStringVariable(DEF_FILE_PATH.getVariableName(), defFile.getExecPathString()); } fdoSupport.getFdoSupport().getLinkOptions(featureConfiguration, buildVariables); ImmutableList<String> userLinkFlagsWithLtoIndexingIfNeeded; if (!isLtoIndexing) { userLinkFlagsWithLtoIndexingIfNeeded = ImmutableList.copyOf(userLinkFlags); } else { List<String> opts = new ArrayList<>(userLinkFlags); opts.addAll(featureConfiguration.getCommandLine("lto-indexing", buildVariables.build(), /* expander= */ null)); opts.addAll(ccToolchainProvider.getCppConfiguration().getLtoIndexOptions()); userLinkFlagsWithLtoIndexingIfNeeded = ImmutableList.copyOf(opts); } // For now, silently ignore linkopts if this is a static library userLinkFlagsWithLtoIndexingIfNeeded = isUsingLinkerNotArchiver ? userLinkFlagsWithLtoIndexingIfNeeded : ImmutableList.of(); buildVariables.addStringSequenceVariable(LinkBuildVariables.USER_LINK_FLAGS.getVariableName(), removePieIfCreatingSharedLibrary(isCreatingSharedLibrary, userLinkFlagsWithLtoIndexingIfNeeded)); buildVariables.addStringSequenceVariable(LinkBuildVariables.LEGACY_LINK_FLAGS.getVariableName(), getToolchainFlags(isLegacyFullyStaticLinkingMode, isStaticLinkingMode, isUsingLinkerNotArchiver, featureConfiguration, ccToolchainProvider, useTestOnlyFlags, isCreatingSharedLibrary, userLinkFlags)); return buildVariables.build(); } private static ImmutableList<String> getToolchainFlags(boolean isLegacyFullyStaticLinkingMode, boolean isStaticLinkingMode, boolean isUsingLinkerNotArchiver, FeatureConfiguration featureConfiguration, CcToolchainProvider ccToolchainProvider, boolean useTestOnlyFlags, boolean isCreatingSharedLibrary, List<String> userLinkFlags) { if (!isUsingLinkerNotArchiver) { return ImmutableList.of(); } CppConfiguration cppConfiguration = ccToolchainProvider.getCppConfiguration(); boolean sharedLinkopts = isCreatingSharedLibrary || userLinkFlags.contains("-shared") || cppConfiguration.hasSharedLinkOption(); List<String> result = new ArrayList<>(); // Extra toolchain link options based on the output's link staticness. if (isLegacyFullyStaticLinkingMode) { result.addAll( CppHelper.getFullyStaticLinkOptions(cppConfiguration, ccToolchainProvider, sharedLinkopts)); } else if (isStaticLinkingMode) { if (!featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINKING_MODE)) { result.addAll(CppHelper.getMostlyStaticLinkOptions(cppConfiguration, ccToolchainProvider, sharedLinkopts, featureConfiguration.isEnabled(CppRuleClasses.STATIC_LINK_CPP_RUNTIMES))); } else { result.addAll(ccToolchainProvider.getLegacyLinkOptions()); } } else { if (!featureConfiguration.isEnabled(CppRuleClasses.DYNAMIC_LINKING_MODE)) { result.addAll( CppHelper.getDynamicLinkOptions(cppConfiguration, ccToolchainProvider, sharedLinkopts)); } else { result.addAll(ccToolchainProvider.getLegacyLinkOptions()); } } // Extra test-specific link options. if (useTestOnlyFlags) { result.addAll(ccToolchainProvider.getTestOnlyLinkOptions()); } result.addAll(ccToolchainProvider.getLinkOptions()); // -pie is not compatible with shared and should be // removed when the latter is part of the link command. Should we need to further // distinguish between shared libraries and executables, we could add additional // command line / CROSSTOOL flags that distinguish them. But as long as this is // the only relevant use case we're just special-casing it here. return ImmutableList.copyOf(removePieIfCreatingSharedLibrary(isCreatingSharedLibrary, result)); } private static Iterable<String> removePieIfCreatingSharedLibrary(boolean isCreatingSharedLibrary, List<String> flags) { if (isCreatingSharedLibrary) { return Iterables.filter(flags, Predicates.not(Predicates.equalTo("-pie"))); } else { return flags; } } }