diff options
author | 2016-08-03 16:12:21 +0000 | |
---|---|---|
committer | 2016-08-03 17:16:01 +0000 | |
commit | 84de2cc636947aaa41fdec6c2d30232faeaabbdd (patch) | |
tree | 903b87d6ffc03b07fa6bbbf92304c8e5e2d9d0ec /src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java | |
parent | 3437d2f89730b72dfe89284a007798c67f75b162 (diff) |
Refactor CppLinkAction to construct its command line using the crosstool instead of a hardcoded switch. Add action configs to CppConfiguration for each link type.
--
MOS_MIGRATED_REVID=129221108
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java | 573 |
1 files changed, 546 insertions, 27 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java index 3ec9843777..bde2ee0ce3 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java @@ -17,6 +17,7 @@ package com.google.devtools.build.lib.rules.cpp; import static java.nio.charset.StandardCharsets.ISO_8859_1; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -37,6 +38,8 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.RuleErrorConsumer; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariablesExtension; import com.google.devtools.build.lib.rules.cpp.CppLinkAction.Context; import com.google.devtools.build.lib.rules.cpp.CppLinkAction.LinkArtifactFactory; import com.google.devtools.build.lib.rules.cpp.Link.LinkStaticness; @@ -45,7 +48,6 @@ import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink; import com.google.devtools.build.lib.util.Preconditions; 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.HashMap; @@ -53,11 +55,57 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; - import javax.annotation.Nullable; /** Builder class to construct {@link CppLinkAction}s. */ public class CppLinkActionBuilder { + + /** A build variable for clang flags that set the root of the linker search path. */ + public static final String RUNTIME_ROOT_FLAGS_VARIABLE = "runtime_root_flags"; + + /** A build variable for entries in the linker search path. */ + public static final String RUNTIME_ROOT_ENTRIES_VARIABLE = "runtime_root_entries"; + + /** + * A build variable for options applying to specific libraries in the linker invocation that + * either identify a library to be linked or add a directory to the runtime library search path. + */ + public static final String LIBOPTS_VARIABLE = "libopts"; + + /** + * A build variable for flags providing files to link as inputs in the linker invocation that + * should not go in a -whole_archive block. + */ + public static final String LINKER_INPUT_PARAMS_VARIABLE = "linker_input_params"; + + /** + * A build variable for flags providing files to link as inputs in the linker invocation that + * should go in a -whole_archive block. + */ + public static final String WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE = + "whole_archive_linker_params"; + + /** A build variable whose presence indicates that whole archive flags should be applied. */ + public static final String GLOBAL_WHOLE_ARCHIVE_VARIABLE = "global_whole_archive"; + + /** A build variable for the execpath of the output of the linker. */ + public static final String OUTPUT_EXECPATH_VARIABLE = "output_execpath"; + + /** + * A build variable that is set to indicate a mostly static linking for which the linked binary + * should be piped to /dev/null. + */ + public static final String SKIP_MOSTLY_STATIC_VARIABLE = "skip_mostly_static"; + + /** A build variable giving a path to which to write symbol counts. */ + public static final String SYMBOL_COUNTS_OUTPUT_VARIABLE = "symbol_counts_output"; + + /** A build variable giving linkstamp paths. */ + public static final String LINKSTAMP_PATHS_VARIABLE = "linkstamp_paths"; + + /** A build variable whose presence indicates that PIC code should be generated. */ + public static final String FORCE_PIC_VARIABLE = "force_pic"; + // Builder-only // Null when invoked from tests (e.g. via createTestBuilder). @Nullable private final RuleContext ruleContext; @@ -72,8 +120,6 @@ public class CppLinkActionBuilder { protected final BuildConfiguration configuration; private final CppConfiguration cppConfiguration; private FeatureConfiguration featureConfiguration; - private CcToolchainFeatures.Variables buildVariables = - new CcToolchainFeatures.Variables.Builder().build(); // Morally equivalent with {@link Context}, except these are mutable. // Keep these in sync with {@link Context}. @@ -196,10 +242,8 @@ public class CppLinkActionBuilder { private String getActionName() { return linkType.getActionName(); } - - /** - * Returns linker inputs that are not libraries. - */ + + /** Returns linker inputs that are not libraries. */ public Set<LinkerInput> getNonLibraries() { return nonLibraries; } @@ -401,6 +445,17 @@ public class CppLinkActionBuilder { final ImmutableSet<String> features = (ruleContext == null) ? ImmutableSet.<String>of() : ruleContext.getFeatures(); + // For backwards compatibility, and for tests, we permit the link action to be + // instantiated without a feature configuration. + if (featureConfiguration == null) { + if (toolchain != null) { + featureConfiguration = + CcCommon.configureFeatures(ruleContext, toolchain, CcLibraryHelper.SourceCategory.CC); + } else { + featureConfiguration = CcCommon.configureFeatures(ruleContext); + } + } + final LibraryToLink outputLibrary = LinkerInputs.newInputLibrary(output, filteredNonLibraryArtifacts, this.ltoBitcodeFiles); final LibraryToLink interfaceOutputLibrary = @@ -436,6 +491,24 @@ public class CppLinkActionBuilder { symbolCounts); } + ImmutableList<LinkerInput> runtimeLinkerInputs = + ImmutableList.copyOf(LinkerInputs.simpleLinkerInputs(runtimeInputs)); + + // Add build variables necessary to template link args into the crosstool. + Variables.Builder buildVariablesBuilder = new Variables.Builder(); + CppLinkVariablesExtension variablesExtension = + isLTOIndexing + ? new CppLinkVariablesExtension( + linkstampMap, needWholeArchive, linkerInputs, runtimeLinkerInputs, null) + : new CppLinkVariablesExtension( + linkstampMap, + needWholeArchive, + linkerInputs, + runtimeLinkerInputs, + outputLibrary.getArtifact()); + variablesExtension.addVariables(buildVariablesBuilder); + Variables buildVariables = buildVariablesBuilder.build(); + PathFragment paramRootPath = ParameterFile.derivePath( outputLibrary.getArtifact().getRootRelativePath(), (isLTOIndexing) ? "lto" : "2"); @@ -446,28 +519,52 @@ public class CppLinkActionBuilder { ? linkArtifactFactory.create(ruleContext, configuration, paramRootPath) : null; + Preconditions.checkArgument( + linkType != LinkTargetType.INTERFACE_DYNAMIC_LIBRARY, + "you can't link an interface dynamic library directly"); + if (linkType != LinkTargetType.DYNAMIC_LIBRARY) { + Preconditions.checkArgument( + interfaceOutput == null, + "interface output may only be non-null for dynamic library links"); + } + if (linkType.isStaticLibraryLink()) { + // solib dir must be null for static links + runtimeSolibDir = null; + + Preconditions.checkArgument( + linkStaticness == LinkStaticness.FULLY_STATIC, "static library link must be static"); + Preconditions.checkArgument( + symbolCounts == null, "the symbol counts output must be null for static links"); + Preconditions.checkArgument( + !isNativeDeps, "the native deps flag must be false for static links"); + Preconditions.checkArgument( + !needWholeArchive, "the need whole archive flag must be false for static links"); + } + LinkCommandLine.Builder linkCommandLineBuilder = new LinkCommandLine.Builder(configuration, getOwner(), ruleContext) - .setActionName(getActionName()) .setLinkerInputs(linkerInputs) - .setRuntimeInputs(ImmutableList.copyOf(LinkerInputs.simpleLinkerInputs(runtimeInputs))) + .setRuntimeInputs(runtimeLinkerInputs) .setLinkTargetType(linkType) .setLinkStaticness(linkStaticness) .setFeatures(features) .setRuntimeSolibDir(linkType.isStaticLibraryLink() ? null : runtimeSolibDir) .setNativeDeps(isNativeDeps) .setUseTestOnlyFlags(useTestOnlyFlags) - .setNeedWholeArchive(needWholeArchive) .setParamFile(paramFile) - .setAllLTOArtifacts(isLTOIndexing ? null : allLTOArtifacts) .setToolchain(toolchain) + .setBuildVariables(buildVariables) .setFeatureConfiguration(featureConfiguration); + // TODO(b/30228443): Refactor noWholeArchiveInputs into action_configs, and remove this. + if (needWholeArchive) { + linkCommandLineBuilder.setNoWholeArchiveFlags(variablesExtension.getNoWholeArchiveInputs()); + } + if (!isLTOIndexing) { linkCommandLineBuilder .setOutput(outputLibrary.getArtifact()) .setInterfaceOutput(interfaceOutput) - .setSymbolCountsOutput(symbolCounts) .setBuildInfoHeaderArtifacts(buildInfoHeaderArtifacts) .setInterfaceSoBuilder(getInterfaceSoBuilder()) .setLinkstamps(linkstampMap) @@ -506,13 +603,6 @@ public class CppLinkActionBuilder { dependencyInputsBuilder.addTransitive(compilationInputs.build()); } - // For backwards compatibility, and for tests, we permit the link action to be - // instantiated without a feature configuration. In this case, an empty feature - // configuration is used. - if (featureConfiguration == null) { - this.featureConfiguration = new FeatureConfiguration(); - } - Iterable<Artifact> expandedInputs = LinkerInputs.toLibraryArtifacts( Link.mergeInputsDependencies( @@ -545,7 +635,7 @@ public class CppLinkActionBuilder { for (LTOBackendArtifacts a : allLTOArtifacts) { List<String> argv = new ArrayList<>(); argv.addAll(cppConfiguration.getLinkOptions()); - argv.addAll(featureConfiguration.getCommandLine(getActionName(), buildVariables)); + argv.addAll(featureConfiguration.getCommandLine(getActionName(), Variables.EMPTY)); argv.addAll(cppConfiguration.getCompilerOptions(features)); a.setCommandLine(argv); } @@ -684,12 +774,6 @@ public class CppLinkActionBuilder { return this; } - /** Sets the build variables that will be used to template the crosstool. */ - public CppLinkActionBuilder setBuildVariables(CcToolchainFeatures.Variables buildVariables) { - this.buildVariables = buildVariables; - return this; - } - /** * This is the LTO indexing step, rather than the real link. * @@ -936,4 +1020,439 @@ public class CppLinkActionBuilder { this.runtimeSolibDir = runtimeSolibDir; return this; } + + private static class LinkArgCollector { + String rpathRoot; + List<String> rpathEntries; + Set<String> libopts; + List<String> linkerInputParams; + List<String> wholeArchiveLinkerInputParams; + List<String> noWholeArchiveInputs; + + public void setRpathRoot(String rPathRoot) { + this.rpathRoot = rPathRoot; + } + + public void setRpathEntries(List<String> rpathEntries) { + this.rpathEntries = rpathEntries; + } + + public void setLibopts(Set<String> libopts) { + this.libopts = libopts; + } + + public void setLinkerInputParams(List<String> linkerInputParams) { + this.linkerInputParams = linkerInputParams; + } + + public void setWholeArchiveLinkerInputParams(List<String> wholeArchiveInputParams) { + this.wholeArchiveLinkerInputParams = wholeArchiveInputParams; + } + + public void setNoWholeArchiveInputs(List<String> noWholeArchiveInputs) { + this.noWholeArchiveInputs = noWholeArchiveInputs; + } + + public String getRpathRoot() { + return rpathRoot; + } + + public List<String> getRpathEntries() { + return rpathEntries; + } + + public Set<String> getLibopts() { + return libopts; + } + + public List<String> getLinkerInputParams() { + return linkerInputParams; + } + + public List<String> getWholeArchiveLinkerInputParams() { + return wholeArchiveLinkerInputParams; + } + + public List<String> getNoWholeArchiveInputs() { + return noWholeArchiveInputs; + } + } + + private class CppLinkVariablesExtension implements VariablesExtension { + + private final ImmutableMap<Artifact, Artifact> linkstampMap; + private final boolean needWholeArchive; + private final Iterable<LinkerInput> linkerInputs; + private final ImmutableList<LinkerInput> runtimeLinkerInputs; + private final Artifact outputArtifact; + + private final LinkArgCollector linkArgCollector = new LinkArgCollector(); + + public CppLinkVariablesExtension( + ImmutableMap<Artifact, Artifact> linkstampMap, + boolean needWholeArchive, + Iterable<LinkerInput> linkerInputs, + ImmutableList<LinkerInput> runtimeLinkerInputs, + Artifact output) { + this.linkstampMap = linkstampMap; + this.needWholeArchive = needWholeArchive; + this.linkerInputs = linkerInputs; + this.runtimeLinkerInputs = runtimeLinkerInputs; + this.outputArtifact = output; + + addInputFileLinkOptions(linkArgCollector); + } + + /** + * Returns linker parameters indicating libraries that should not be linked inside a + * --whole_archive block. + * + * <p>TODO(b/30228443): Refactor into action configs + */ + public List<String> getNoWholeArchiveInputs() { + return linkArgCollector.getNoWholeArchiveInputs(); + } + + @Override + public void addVariables(Variables.Builder buildVariables) { + + // symbol counting + if (symbolCounts != null) { + buildVariables.addVariable(SYMBOL_COUNTS_OUTPUT_VARIABLE, symbolCounts.getExecPathString()); + } + + // linkstamp + ImmutableSet.Builder<String> linkstampPaths = ImmutableSet.<String>builder(); + for (Artifact linkstampOutput : linkstampMap.values()) { + linkstampPaths.add(linkstampOutput.getExecPathString()); + } + + buildVariables.addSequenceVariable(LINKSTAMP_PATHS_VARIABLE, linkstampPaths.build()); + + // pic + boolean forcePic = cppConfiguration.forcePic(); + if (forcePic) { + buildVariables.addVariable(FORCE_PIC_VARIABLE, ""); + } + + // rpath + if (linkArgCollector.getRpathRoot() != null) { + buildVariables.addVariable(RUNTIME_ROOT_FLAGS_VARIABLE, linkArgCollector.getRpathRoot()); + } + + if (linkArgCollector.getRpathEntries() != null) { + buildVariables.addSequenceVariable( + RUNTIME_ROOT_ENTRIES_VARIABLE, linkArgCollector.getRpathEntries()); + } + + buildVariables.addSequenceVariable(LIBOPTS_VARIABLE, linkArgCollector.getLibopts()); + buildVariables.addSequenceVariable( + LINKER_INPUT_PARAMS_VARIABLE, linkArgCollector.getLinkerInputParams()); + buildVariables.addSequenceVariable( + WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE, + linkArgCollector.getWholeArchiveLinkerInputParams()); + + // global archive + if (needWholeArchive) { + buildVariables.addVariable(GLOBAL_WHOLE_ARCHIVE_VARIABLE, ""); + } + + // mostly static + if (linkStaticness == LinkStaticness.MOSTLY_STATIC && cppConfiguration.skipStaticOutputs()) { + buildVariables.addVariable(SKIP_MOSTLY_STATIC_VARIABLE, ""); + } + + // output exec path + if (this.outputArtifact != null) { + buildVariables.addVariable( + OUTPUT_EXECPATH_VARIABLE, this.outputArtifact.getExecPathString()); + } + + // Variables arising from the toolchain + buildVariables + .addAllVariables(CppHelper.getToolchain(ruleContext).getBuildVariables()) + .build(); + CppHelper.getFdoSupport(ruleContext).getLinkOptions(featureConfiguration, buildVariables); + } + + private boolean isDynamicLibrary(LinkerInput linkInput) { + Artifact libraryArtifact = linkInput.getArtifact(); + String name = libraryArtifact.getFilename(); + return Link.SHARED_LIBRARY_FILETYPES.matches(name) && name.startsWith("lib"); + } + + private boolean isSharedNativeLibrary() { + return isNativeDeps && cppConfiguration.shareNativeDeps(); + } + + /** + * When linking a shared library fully or mostly static then we need to link in *all* dependent + * files, not just what the shared library needs for its own code. This is done by wrapping all + * objects/libraries with -Wl,-whole-archive and -Wl,-no-whole-archive. For this case the + * globalNeedWholeArchive parameter must be set to true. Otherwise only library objects (.lo) + * need to be wrapped with -Wl,-whole-archive and -Wl,-no-whole-archive. + * + * <p>TODO: Factor out of the bazel binary into build variables for crosstool action_configs. + */ + private void addInputFileLinkOptions(LinkArgCollector linkArgCollector) { + + // Used to collect -L and -Wl,-rpath options, ensuring that each used only once. + Set<String> libOpts = new LinkedHashSet<>(); + + // List of command line parameters to link input files (either directly or using -l). + List<String> linkerInputParameters = new ArrayList<>(); + + // List of command line parameters that need to be placed *outside* of + // --whole-archive ... --no-whole-archive. + List<String> noWholeArchiveInputs = new ArrayList<>(); + + PathFragment solibDir = + configuration + .getBinDirectory() + .getExecPath() + .getRelative(cppConfiguration.getSolibDirectory()); + String runtimeSolibName = runtimeSolibDir != null ? runtimeSolibDir.getBaseName() : null; + boolean runtimeRpath = + runtimeSolibDir != null + && (linkType == LinkTargetType.DYNAMIC_LIBRARY + || (linkType == LinkTargetType.EXECUTABLE + && linkStaticness == LinkStaticness.DYNAMIC)); + + String rpathRoot = null; + List<String> runtimeRpathEntries = new ArrayList<>(); + + if (output != null) { + String origin = + useTestOnlyFlags && cppConfiguration.supportsExecOrigin() + ? "$EXEC_ORIGIN/" + : "$ORIGIN/"; + if (runtimeRpath) { + runtimeRpathEntries.add("-Wl,-rpath," + origin + runtimeSolibName + "/"); + } + + // Calculate the correct relative value for the "-rpath" link option (which sets + // the search path for finding shared libraries). + if (isSharedNativeLibrary()) { + // For shared native libraries, special symlinking is applied to ensure C++ + // runtimes are available under $ORIGIN/_solib_[arch]. So we set the RPATH to find + // them. + // + // Note that we have to do this because $ORIGIN points to different paths for + // different targets. In other words, blaze-bin/d1/d2/d3/a_shareddeps.so and + // blaze-bin/d4/b_shareddeps.so have different path depths. The first could + // reference a standard blaze-bin/_solib_[arch] via $ORIGIN/../../../_solib[arch], + // and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared + // artifact, both are symlinks to the same place, so + // there's no *one* RPATH setting that fits all targets involved in the sharing. + rpathRoot = + "-Wl,-rpath," + origin + ":" + origin + cppConfiguration.getSolibDirectory() + "/"; + if (runtimeRpath) { + runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/"); + } + } else { + // For all other links, calculate the relative path from the output file to _solib_[arch] + // (the directory where all shared libraries are stored, which resides under the blaze-bin + // directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be + // "../../_solib_[arch]". + if (runtimeRpath) { + runtimeRpathEntries.add( + "-Wl,-rpath," + + origin + + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1) + + runtimeSolibName + + "/"); + } + + rpathRoot = + "-Wl,-rpath," + + origin + + Strings.repeat("../", output.getRootRelativePath().segmentCount() - 1) + + cppConfiguration.getSolibDirectory() + + "/"; + + if (isNativeDeps) { + // We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to + // the package directory) + if (runtimeRpath) { + runtimeRpathEntries.add("-Wl,-rpath," + origin + "../" + runtimeSolibName + "/"); + } + rpathRoot += ":" + origin; + } + } + } + + boolean includeSolibDir = false; + + Map<Artifact, Artifact> ltoMap = null; + if (!isLTOIndexing && (allLTOArtifacts != null)) { + // TODO(bazel-team): The LTO final link can only work if there are individual .o files on + // the command line. Rather than crashing, this should issue a nice error. We will get + // this by + // 1) moving supports_start_end_lib to a toolchain feature + // 2) having thin_lto require start_end_lib + // As a bonus, we can rephrase --nostart_end_lib as --features=-start_end_lib and get rid + // of a command line option. + + Preconditions.checkState(cppConfiguration.useStartEndLib()); + ltoMap = new HashMap<>(); + for (LTOBackendArtifacts l : allLTOArtifacts) { + ltoMap.put(l.getBitcodeFile(), l.getObjectFile()); + } + } + + for (LinkerInput input : linkerInputs) { + if (isDynamicLibrary(input)) { + PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory(); + Preconditions.checkState( + libDir.startsWith(solibDir), + "Artifact '%s' is not under directory '%s'.", + input.getArtifact(), + solibDir); + if (libDir.equals(solibDir)) { + includeSolibDir = true; + } + addDynamicInputLinkOptions(input, linkerInputParameters, libOpts, solibDir, rpathRoot); + } else { + addStaticInputLinkOptions(input, linkerInputParameters, ltoMap); + } + } + + boolean includeRuntimeSolibDir = false; + + for (LinkerInput input : runtimeLinkerInputs) { + List<String> optionsList = needWholeArchive ? noWholeArchiveInputs : linkerInputParameters; + + if (isDynamicLibrary(input)) { + PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory(); + Preconditions.checkState( + runtimeSolibDir != null && libDir.equals(runtimeSolibDir), + "Artifact '%s' is not under directory '%s'.", + input.getArtifact(), + solibDir); + includeRuntimeSolibDir = true; + addDynamicInputLinkOptions(input, optionsList, libOpts, solibDir, rpathRoot); + } else { + addStaticInputLinkOptions(input, optionsList, ltoMap); + } + } + + // rpath ordering matters for performance; first add the one where most libraries are found. + if (includeSolibDir && rpathRoot != null) { + linkArgCollector.setRpathRoot(rpathRoot); + } + if (includeRuntimeSolibDir) { + linkArgCollector.setRpathEntries(runtimeRpathEntries); + } + + linkArgCollector.setLibopts(libOpts); + + ImmutableList.Builder<String> wholeArchiveInputParams = ImmutableList.builder(); + ImmutableList.Builder<String> standardArchiveInputParams = ImmutableList.builder(); + for (String param : linkerInputParameters) { + if (!wholeArchive && Link.LINK_LIBRARY_FILETYPES.matches(param) && !needWholeArchive) { + wholeArchiveInputParams.add(param); + } else { + standardArchiveInputParams.add(param); + } + } + + linkArgCollector.setLinkerInputParams(standardArchiveInputParams.build()); + linkArgCollector.setWholeArchiveLinkerInputParams(wholeArchiveInputParams.build()); + linkArgCollector.setNoWholeArchiveInputs(noWholeArchiveInputs); + + if (ltoMap != null) { + Preconditions.checkState(ltoMap.isEmpty(), "Still have LTO objects left: %s", ltoMap); + } + } + + /** Adds command-line options for a dynamic library input file into options and libOpts. */ + private void addDynamicInputLinkOptions( + LinkerInput input, + List<String> options, + Set<String> libOpts, + PathFragment solibDir, + String rpathRoot) { + Preconditions.checkState(isDynamicLibrary(input)); + Preconditions.checkState(!Link.useStartEndLib(input, cppConfiguration.archiveType())); + + Artifact inputArtifact = input.getArtifact(); + PathFragment libDir = inputArtifact.getExecPath().getParentDirectory(); + if (rpathRoot != null + && !libDir.equals(solibDir) + && (runtimeSolibDir == null || !runtimeSolibDir.equals(libDir))) { + String dotdots = ""; + PathFragment commonParent = solibDir; + while (!libDir.startsWith(commonParent)) { + dotdots += "../"; + commonParent = commonParent.getParentDirectory(); + } + + libOpts.add(rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString()); + } + + libOpts.add("-L" + inputArtifact.getExecPath().getParentDirectory().getPathString()); + + String name = inputArtifact.getFilename(); + if (CppFileTypes.SHARED_LIBRARY.matches(name)) { + String libName = name.replaceAll("(^lib|\\.(so|dylib)$)", ""); + options.add("-l" + libName); + } else { + // Interface shared objects have a non-standard extension + // that the linker won't be able to find. So use the + // filename directly rather than a -l option. Since the + // library has an SONAME attribute, this will work fine. + options.add(inputArtifact.getExecPathString()); + } + } + + /** + * Adds command-line options for a static library or non-library input into options. + * + * @param ltoMap is a mutable list of exec paths that should be on the command-line, which must + * be supplied for LTO final links. + */ + private void addStaticInputLinkOptions( + LinkerInput input, List<String> options, @Nullable Map<Artifact, Artifact> ltoMap) { + Preconditions.checkState(!isDynamicLibrary(input)); + + // start-lib/end-lib library: adds its input object files. + if (Link.useStartEndLib(input, cppConfiguration.archiveType())) { + Iterable<Artifact> archiveMembers = input.getObjectFiles(); + if (!Iterables.isEmpty(archiveMembers)) { + options.add("-Wl,--start-lib"); + for (Artifact member : archiveMembers) { + if (ltoMap != null) { + Artifact backend = ltoMap.remove(member); + + if (backend != null) { + // If the backend artifact is missing, we can't print a warning because this may + // happen normally, due libraries that list .o files explicitly, or generate .o + // files from assembler. + member = backend; + } + } + + options.add(member.getExecPathString()); + } + options.add("-Wl,--end-lib"); + } + } else { + // For anything else, add the input directly. + Artifact inputArtifact = input.getArtifact(); + + if (ltoMap != null) { + Artifact ltoArtifact = ltoMap.remove(inputArtifact); + if (ltoArtifact != null) { + inputArtifact = ltoArtifact; + } + } + + if (input.isFake()) { + options.add(Link.FAKE_OBJECT_PREFIX + inputArtifact.getExecPathString()); + } else { + options.add(inputArtifact.getExecPathString()); + } + } + } + } } |