diff options
7 files changed, 247 insertions, 298 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java index 8c15eb7d0e..be01fd4fa5 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainFeatures.java @@ -953,6 +953,85 @@ public class CcToolchainFeatures implements Serializable { * significantly reduces memory overhead. */ @Immutable + public static final class LibraryToLinkValue implements VariableValue { + + public static final String NAMES_FIELD_NAME = "names"; + public static final String IS_WHOLE_ARCHIVE_FIELD_NAME = "is_whole_archive"; + public static final String IS_LIB_GROUP_FIELD_NAME = "is_lib_group"; + + private final ImmutableList<String> names; + private final boolean isWholeArchive; + private final boolean isLibGroup; + + public LibraryToLinkValue(String name, boolean isWholeArchive) { + this(ImmutableList.of(name), isWholeArchive, false); + } + + public LibraryToLinkValue( + ImmutableList<String> names, boolean isWholeArchive, boolean isLibGroup) { + this.names = names; + this.isWholeArchive = isWholeArchive; + this.isLibGroup = isLibGroup; + } + + @Override + public Iterable<? extends VariableValue> getSequenceValue(String variableName) { + throw new ExpansionException( + String.format( + "Invalid toolchain configuration: Cannot expand variable '%s': expected sequence, " + + "found structure (LibraryToLink)", + variableName)); + } + + @Override + public boolean isSequence() { + return false; + } + + @Override + public VariableValue getFieldValue(String variableName, String field) { + Preconditions.checkNotNull(field); + if (NAMES_FIELD_NAME.equals(field)) { + return new StringSequence(names); + } else if (IS_WHOLE_ARCHIVE_FIELD_NAME.equals(field)) { + return new IntegerValue(isWholeArchive ? 1 : 0); + } else if (IS_LIB_GROUP_FIELD_NAME.equals(field)) { + return new IntegerValue(isLibGroup ? 1 : 0); + } else if ("whole_archive_presence".equals(field)) { + // TODO(b/33403458): Cleanup this workaround once bazel >=0.4.3 is released. + return isWholeArchive ? new IntegerValue(0) : null; + } else if ("no_whole_archive_presence".equals(field)) { + // TODO(b/33403458): Cleanup this workaround once bazel >=0.4.3 is released. + return !isWholeArchive ? new IntegerValue(0) : null; + } else if ("lib_group_presence".equals(field)) { + // TODO(b/33403458): Cleanup this workaround once bazel >=0.4.3 is released. + return names.size() > 1 ? new IntegerValue(0) : null; + } else { + return null; + } + } + + @Override + public String getStringValue(String variableName) { + throw new ExpansionException( + String.format( + "Invalid toolchain configuration: Cannot expand variable '%s': expected string, " + + "found structure (LibraryToLink)", + variableName)); + } + + @Override + public boolean isTruthy() { + return true; + } + } + + /** + * A sequence of structure values. Exists as a memory optimization - a typical build can contain + * millions of feature values, so getting rid of the overhead of {@code StructureValue} objects + * significantly reduces memory overhead. + */ + @Immutable private static final class StructureSequence implements VariableValue { private final ImmutableList<ImmutableMap<String, VariableValue>> values; 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 4b32f11dd0..35f16bfbbc 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 @@ -39,6 +39,8 @@ 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.LibraryToLinkValue; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.SequenceBuilder; 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; @@ -73,21 +75,8 @@ public class CppLinkActionBuilder { */ 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 flags providing files to link as inputs in the linker invocation */ + public static final String LIBRARIES_TO_LINK_VARIABLE = "libraries_to_link"; /** A build variable for the execpath of the output of the linker. */ public static final String OUTPUT_EXECPATH_VARIABLE = "output_execpath"; @@ -631,11 +620,6 @@ public class CppLinkActionBuilder { .setToolPath(getToolPath()) .setFeatureConfiguration(featureConfiguration); - // TODO(b/30228443): Refactor noWholeArchiveInputs into action_configs, and remove this. - if (needWholeArchive) { - linkCommandLineBuilder.setNoWholeArchiveFlags(variablesExtension.getNoWholeArchiveInputs()); - } - if (!isLTOIndexing) { linkCommandLineBuilder .setOutput(output) @@ -1184,9 +1168,7 @@ public class CppLinkActionBuilder { String rpathRoot; ImmutableList<String> rpathEntries; ImmutableSet<String> libopts; - ImmutableList<String> linkerInputParams; - ImmutableList<String> wholeArchiveLinkerInputParams; - ImmutableList<String> noWholeArchiveInputs; + SequenceBuilder librariesToLink; public void setRpathRoot(String rPathRoot) { this.rpathRoot = rPathRoot; @@ -1200,16 +1182,8 @@ public class CppLinkActionBuilder { this.libopts = libopts; } - public void setLinkerInputParams(ImmutableList<String> linkerInputParams) { - this.linkerInputParams = linkerInputParams; - } - - public void setWholeArchiveLinkerInputParams(ImmutableList<String> wholeArchiveInputParams) { - this.wholeArchiveLinkerInputParams = wholeArchiveInputParams; - } - - public void setNoWholeArchiveInputs(ImmutableList<String> noWholeArchiveInputs) { - this.noWholeArchiveInputs = noWholeArchiveInputs; + public void setLibrariesToLink(SequenceBuilder librariesToLink) { + this.librariesToLink = librariesToLink; } public String getRpathRoot() { @@ -1224,16 +1198,8 @@ public class CppLinkActionBuilder { return libopts; } - public ImmutableList<String> getLinkerInputParams() { - return linkerInputParams; - } - - public ImmutableList<String> getWholeArchiveLinkerInputParams() { - return wholeArchiveLinkerInputParams; - } - - public ImmutableList<String> getNoWholeArchiveInputs() { - return noWholeArchiveInputs; + public SequenceBuilder getLibrariesToLink() { + return librariesToLink; } } @@ -1277,16 +1243,6 @@ public class CppLinkActionBuilder { 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) { @@ -1323,16 +1279,9 @@ public class CppLinkActionBuilder { } buildVariables.addStringSequenceVariable(LIBOPTS_VARIABLE, linkArgCollector.getLibopts()); - buildVariables.addStringSequenceVariable( - LINKER_INPUT_PARAMS_VARIABLE, linkArgCollector.getLinkerInputParams()); - buildVariables.addStringSequenceVariable( - WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE, - linkArgCollector.getWholeArchiveLinkerInputParams()); - // global archive - if (needWholeArchive) { - buildVariables.addStringVariable(GLOBAL_WHOLE_ARCHIVE_VARIABLE, ""); - } + buildVariables.addCustomBuiltVariable( + LIBRARIES_TO_LINK_VARIABLE, linkArgCollector.getLibrariesToLink()); // mostly static if (linkStaticness == LinkStaticness.MOSTLY_STATIC && cppConfiguration.skipStaticOutputs()) { @@ -1385,15 +1334,6 @@ public class CppLinkActionBuilder { return isNativeDeps && cppConfiguration.shareNativeDeps(); } - private boolean inputNeedsWholeArchive(LinkerInput input) { - if (Link.useStartEndLib(input, cppConfiguration.archiveType())) { - return false; - } - - return input.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY - && !wholeArchive && !needWholeArchive; - } - /** * 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 @@ -1410,7 +1350,7 @@ public class CppLinkActionBuilder { // List of command line parameters that need to be placed *outside* of // --whole-archive ... --no-whole-archive. - ImmutableList.Builder<String> noWholeArchiveInputs = ImmutableList.builder(); + SequenceBuilder librariesToLink = new SequenceBuilder(); PathFragment solibDir = configuration @@ -1506,9 +1446,6 @@ public class CppLinkActionBuilder { } } - ImmutableList.Builder<String> wholeArchiveInputParams = ImmutableList.builder(); - ImmutableList.Builder<String> standardArchiveInputParams = ImmutableList.builder(); - for (LinkerInput input : linkerInputs) { if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY) { PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory(); @@ -1520,20 +1457,15 @@ public class CppLinkActionBuilder { if (libDir.equals(solibDir)) { includeSolibDir = true; } - addDynamicInputLinkOptions( - input, standardArchiveInputParams, libOpts, solibDir, rpathRoot); + addDynamicInputLinkOptions(input, librariesToLink, false, libOpts, solibDir, rpathRoot); } else { - addStaticInputLinkOptions( - input, wholeArchiveInputParams, standardArchiveInputParams, ltoMap); + addStaticInputLinkOptions(input, librariesToLink, false, ltoMap); } } boolean includeRuntimeSolibDir = false; for (LinkerInput input : runtimeLinkerInputs) { - ImmutableList.Builder<String> optionsList = - needWholeArchive ? noWholeArchiveInputs : standardArchiveInputParams; - if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY) { PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory(); Preconditions.checkState( @@ -1542,16 +1474,15 @@ public class CppLinkActionBuilder { input.getArtifact(), solibDir); includeRuntimeSolibDir = true; - addDynamicInputLinkOptions(input, optionsList, libOpts, solibDir, rpathRoot); + addDynamicInputLinkOptions(input, librariesToLink, true, libOpts, solibDir, rpathRoot); } else { - addStaticInputLinkOptions(input, - needWholeArchive ? noWholeArchiveInputs : wholeArchiveInputParams, - needWholeArchive ? noWholeArchiveInputs : standardArchiveInputParams, - ltoMap); + addStaticInputLinkOptions(input, librariesToLink, true, ltoMap); } } if (linkerParamsFile != null && ltoOutputRootPrefix.equals(PathFragment.EMPTY_FRAGMENT)) { - standardArchiveInputParams.add("-Wl,@" + linkerParamsFile.getExecPathString()); + librariesToLink.addValue( + new LibraryToLinkValue( + "-Wl,@" + linkerParamsFile.getExecPathString(), needWholeArchive)); } // rpath ordering matters for performance; first add the one where most libraries are found. @@ -1564,19 +1495,22 @@ public class CppLinkActionBuilder { linkArgCollector.setLibopts(libOpts.build()); - linkArgCollector.setLinkerInputParams(standardArchiveInputParams.build()); - linkArgCollector.setWholeArchiveLinkerInputParams(wholeArchiveInputParams.build()); - linkArgCollector.setNoWholeArchiveInputs(noWholeArchiveInputs.build()); + linkArgCollector.setLibrariesToLink(librariesToLink); 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. */ + /** + * Adds command-line options for a dynamic library input file into options and libOpts. + * + * @param librariesToLink - a collection that will be exposed as a build variable. + */ private void addDynamicInputLinkOptions( LinkerInput input, - ImmutableList.Builder<String> options, + SequenceBuilder librariesToLink, + boolean isRuntimeLinkerInput, ImmutableSet.Builder<String> libOpts, PathFragment solibDir, String rpathRoot) { @@ -1601,28 +1535,30 @@ public class CppLinkActionBuilder { libOpts.add("-L" + inputArtifact.getExecPath().getParentDirectory().getPathString()); String name = inputArtifact.getFilename(); + boolean inputIsWholeArchive = !isRuntimeLinkerInput && needWholeArchive; if (CppFileTypes.SHARED_LIBRARY.matches(name)) { String libName = name.replaceAll("(^lib|\\.(so|dylib)$)", ""); - options.add("-l" + libName); + librariesToLink.addValue(new LibraryToLinkValue("-l" + libName, inputIsWholeArchive)); } 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()); + librariesToLink.addValue( + new LibraryToLinkValue(inputArtifact.getExecPathString(), inputIsWholeArchive)); } } /** * Adds command-line options for a static library or non-library input into options. * + * @param librariesToLink - a collection that will be exposed as a build variable. * @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, - ImmutableList.Builder<String> wholeArchiveOptions, - ImmutableList.Builder<String> standardOptions, + SequenceBuilder librariesToLink, + boolean isRuntimeLinkerInput, @Nullable Map<Artifact, Artifact> ltoMap) { Preconditions.checkState(!(input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY)); // If we had any LTO artifacts, ltoMap whould be non-null. In that case, @@ -1638,7 +1574,7 @@ public class CppLinkActionBuilder { if (Link.useStartEndLib(input, cppConfiguration.archiveType())) { Iterable<Artifact> archiveMembers = input.getObjectFiles(); if (!Iterables.isEmpty(archiveMembers)) { - List<String> nonLTOArchiveMembers = new ArrayList<>(); + ImmutableList.Builder<String> nonLTOArchiveMembersBuilder = ImmutableList.builder(); for (Artifact member : archiveMembers) { if (ltoMap != null && ltoMap.remove(member) != null) { // The LTO artifacts that should be included in the final link @@ -1647,19 +1583,23 @@ public class CppLinkActionBuilder { // files explicitly, or generate .o files from assembler. continue; } - nonLTOArchiveMembers.add(member.getExecPathString()); + nonLTOArchiveMembersBuilder.add(member.getExecPathString()); } + ImmutableList<String> nonLTOArchiveMembers = nonLTOArchiveMembersBuilder.build(); if (!nonLTOArchiveMembers.isEmpty()) { - standardOptions.add("-Wl,--start-lib"); - standardOptions.addAll(nonLTOArchiveMembers); - standardOptions.add("-Wl,--end-lib"); + boolean inputIsWholeArchive = !isRuntimeLinkerInput && needWholeArchive; + librariesToLink.addValue( + new LibraryToLinkValue(nonLTOArchiveMembers, inputIsWholeArchive, true)); } } } else { - ImmutableList.Builder<String> options = - inputNeedsWholeArchive(input) ? wholeArchiveOptions : standardOptions; + boolean isAlwaysLinkStaticLibrary = + input.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY; // For anything else, add the input directly. Artifact inputArtifact = input.getArtifact(); + boolean inputIsWholeArchive = + (!isRuntimeLinkerInput && (isAlwaysLinkStaticLibrary || needWholeArchive)) + || (isRuntimeLinkerInput && isAlwaysLinkStaticLibrary && !needWholeArchive); if (ltoMap != null && ltoMap.remove(inputArtifact) != null) { // The LTO artifacts that should be included in the final link @@ -1668,9 +1608,13 @@ public class CppLinkActionBuilder { } if (input.isFake()) { - options.add(Link.FAKE_OBJECT_PREFIX + inputArtifact.getExecPathString()); + librariesToLink.addValue( + new LibraryToLinkValue( + Link.FAKE_OBJECT_PREFIX + inputArtifact.getExecPathString(), + inputIsWholeArchive)); } else { - options.add(inputArtifact.getExecPathString()); + librariesToLink.addValue( + new LibraryToLinkValue(inputArtifact.getExecPathString(), inputIsWholeArchive)); } } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java index dc7b250c0a..6eba06d0f7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionConfigs.java @@ -62,10 +62,9 @@ public class CppLinkActionConfigs { " implies: 'symbol_counts'", " implies: 'linkstamps'", " implies: 'output_execpath_flags_executable'", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", " implies: 'force_pic_flags'", "}", "action_config {", @@ -80,10 +79,9 @@ public class CppLinkActionConfigs { " implies: 'shared_flag'", " implies: 'linkstamps'", " implies: 'output_execpath_flags'", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", "}", "action_config {", " config_name: 'c++-link-static-library'", @@ -91,10 +89,9 @@ public class CppLinkActionConfigs { " tool {", " tool_path: 'DUMMY_TOOL'", " }", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", "}", "action_config {", " config_name: 'c++-link-alwayslink-static-library'", @@ -102,10 +99,9 @@ public class CppLinkActionConfigs { " tool {", " tool_path: 'DUMMY_TOOL'", " }", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", "}", "action_config {", " config_name: 'c++-link-pic-static-library'", @@ -113,10 +109,9 @@ public class CppLinkActionConfigs { " tool {", " tool_path: 'DUMMY_TOOL'", " }", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", "}", "action_config {", " config_name: 'c++-link-alwayslink-pic-static-library'", @@ -124,10 +119,9 @@ public class CppLinkActionConfigs { " tool {", " tool_path: 'DUMMY_TOOL'", " }", - " implies: 'global_whole_archive_open'", " implies: 'runtime_root_flags'", " implies: 'input_param_flags'", - " implies: 'global_whole_archive_close'", + " implies: 'libraries_to_link'", "}", "feature {", " name: 'build_interface_libraries'", @@ -215,24 +209,6 @@ public class CppLinkActionConfigs { " }", "}", "feature {", - " name: 'global_whole_archive_open'", - " flag_set {", - " expand_if_all_available: 'global_whole_archive'", - " action: 'c++-link-executable'", - " action: 'c++-link-dynamic-library'", - " action: 'c++-link-static-library'", - " action: 'c++-link-alwayslink-static-library'", - " action: 'c++-link-pic-static-library'", - " action: 'c++-link-alwayslink-pic-static-library'", - " flag_group {", - // TODO: Factor platform difference into respective linux and OSX crosstools. - String.format( - " flag:'%s'", - platform == CppLinkPlatform.LINUX ? "-Wl,-whole-archive" : "-Wl,-all_load"), - " }", - " }", - "}", - "feature {", " name: 'runtime_root_flags',", " flag_set {", " expand_if_all_available: 'runtime_root_flags'", @@ -273,39 +249,11 @@ public class CppLinkActionConfigs { " flag: '%{libopts}'", " }", " }", - " flag_set {", - " expand_if_all_available: 'whole_archive_linker_params'", - " action: 'c++-link-executable'", - " action: 'c++-link-dynamic-library'", - " action: 'c++-link-static-library'", - " action: 'c++-link-alwayslink-static-library'", - " action: 'c++-link-pic-static-library'", - " action: 'c++-link-alwayslink-pic-static-library'", - " flag_group {", - platform == CppLinkPlatform.LINUX - ? " flag: '-Wl,-whole-archive'\n" - + " flag: '%{whole_archive_linker_params}'\n" - + " flag: '-Wl,-no-whole-archive'" - : " flag: '-Wl,-force_load,%{whole_archive_linker_params}'", - " }", - " }", - " flag_set {", - " expand_if_all_available: 'linker_input_params'", - " action: 'c++-link-executable'", - " action: 'c++-link-dynamic-library'", - " action: 'c++-link-static-library'", - " action: 'c++-link-alwayslink-static-library'", - " action: 'c++-link-pic-static-library'", - " action: 'c++-link-alwayslink-pic-static-library'", - " flag_group {", - " flag: '%{linker_input_params}'", - " }", - " }", "}", "feature {", - " name: 'global_whole_archive_close'", + " name: 'libraries_to_link'", " flag_set {", - " expand_if_all_available: 'global_whole_archive'", + " expand_if_all_available: 'libraries_to_link'", " action: 'c++-link-executable'", " action: 'c++-link-dynamic-library'", " action: 'c++-link-static-library'", @@ -313,10 +261,41 @@ public class CppLinkActionConfigs { " action: 'c++-link-pic-static-library'", " action: 'c++-link-alwayslink-pic-static-library'", " flag_group {", - // TODO: Factor platform difference into respective linux and OSX crosstools. - String.format( - " flag: '%s'", - platform == CppLinkPlatform.LINUX ? "-Wl,-no-whole-archive" : ""), + " iterate_over: 'libraries_to_link'", + " flag_group {", + " expand_if_true: 'libraries_to_link.is_lib_group'", + " flag: '-Wl,--start-lib'", + " }", + ifLinux( + platform, + " flag_group {", + " expand_if_true: 'libraries_to_link.is_whole_archive'", + " flag: '-Wl,-whole-archive'", + " }", + " flag_group {", + " iterate_over: 'libraries_to_link.names'", + " flag: '%{libraries_to_link.names}'", + " }", + " flag_group {", + " expand_if_true: 'libraries_to_link.is_whole_archive'", + " flag: '-Wl,-no-whole-archive'", + " }"), + ifMac( + platform, + " flag_group {", + " expand_if_true: 'libraries_to_link.is_whole_archive'", + " iterate_over: 'libraries_to_link.names'", + " flag: '-Wl,-force_load,%{libraries_to_link.names}'", + " }", + " flag_group {", + " expand_if_false: 'libraries_to_link.is_whole_archive'", + " iterate_over: 'libraries_to_link.names'", + " flag: '%{libraries_to_link.names}'", + " }"), + " flag_group {", + " expand_if_true: 'libraries_to_link.is_lib_group'", + " flag: '-Wl,--end-lib'", + " }", " }", " }", "}", @@ -331,4 +310,20 @@ public class CppLinkActionConfigs { " }", "}")); } + + private static String ifLinux(CppLinkPlatform platform, String... lines) { + if (platform == CppLinkPlatform.LINUX) { + return Joiner.on("\n").join(lines); + } else { + return ""; + } + } + + private static String ifMac(CppLinkPlatform platform, String... lines) { + if (platform == CppLinkPlatform.MAC) { + return Joiner.on("\n").join(lines); + } else { + return ""; + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java index 0cb237e113..145088e321 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkCommandLine.java @@ -73,7 +73,6 @@ public final class LinkCommandLine extends CommandLine { @Nullable private final PathFragment runtimeSolibDir; private final boolean nativeDeps; private final boolean useTestOnlyFlags; - private final List<String> noWholeArchiveFlags; @Nullable private final Artifact paramFile; @@ -96,9 +95,7 @@ public final class LinkCommandLine extends CommandLine { @Nullable PathFragment runtimeSolibDir, boolean nativeDeps, boolean useTestOnlyFlags, - boolean needWholeArchive, @Nullable Artifact paramFile, - List<String> noWholeArchiveFlags, CcToolchainFeatures.Variables variables, @Nullable FeatureConfiguration featureConfiguration) { @@ -126,7 +123,6 @@ public final class LinkCommandLine extends CommandLine { this.nativeDeps = nativeDeps; this.useTestOnlyFlags = useTestOnlyFlags; this.paramFile = paramFile; - this.noWholeArchiveFlags = noWholeArchiveFlags; } @Nullable @@ -380,14 +376,12 @@ public final class LinkCommandLine extends CommandLine { case EXECUTABLE: argv.add(cppConfiguration.getCppExecutable().getPathString()); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); - argv.addAll(noWholeArchiveFlags); addToolchainFlags(argv); break; case DYNAMIC_LIBRARY: argv.add(toolPath); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); - argv.addAll(noWholeArchiveFlags); addToolchainFlags(argv); break; @@ -401,7 +395,6 @@ public final class LinkCommandLine extends CommandLine { argv.addAll(cppConfiguration.getArFlags()); argv.add(output.getExecPathString()); argv.addAll(featureConfiguration.getCommandLine(actionName, variables)); - argv.addAll(noWholeArchiveFlags); break; // Since the objc case is not hardcoded in CppConfiguration, we can use the actual tool. @@ -417,7 +410,6 @@ public final class LinkCommandLine extends CommandLine { default: throw new IllegalArgumentException(); } - return argv; } @@ -641,12 +633,10 @@ public final class LinkCommandLine extends CommandLine { @Nullable private PathFragment runtimeSolibDir; private boolean nativeDeps; private boolean useTestOnlyFlags; - private boolean needWholeArchive; @Nullable private Artifact paramFile; @Nullable private CcToolchainProvider toolchain; private Variables variables; private FeatureConfiguration featureConfiguration; - private List<String> noWholeArchiveFlags = ImmutableList.of(); // This interface is needed to support tests that don't create a // ruleContext, in which case the configuration and action owner @@ -719,9 +709,7 @@ public final class LinkCommandLine extends CommandLine { runtimeSolibDir, nativeDeps, useTestOnlyFlags, - needWholeArchive, paramFile, - noWholeArchiveFlags, variables, featureConfiguration); } @@ -874,15 +862,5 @@ public final class LinkCommandLine extends CommandLine { this.runtimeSolibDir = runtimeSolibDir; return this; } - - /** - * Set flags that should not be in a --whole_archive block. - * - * <p>TODO(b/30228443): Refactor into action_configs. - */ - public Builder setNoWholeArchiveFlags(List<String> noWholeArchiveFlags) { - this.noWholeArchiveFlags = noWholeArchiveFlags; - return this; - } } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java index cd92b39d1a..03750a40e2 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionTest.java @@ -195,7 +195,7 @@ public class CppLinkActionTest extends BuildViewTestCase { final FeatureConfiguration featureConfiguration = getMockFeatureConfiguration(); ActionTester.runTest( - 128, + 64, new ActionCombinationFactory() { @Override @@ -219,9 +219,8 @@ public class CppLinkActionTest extends BuildViewTestCase { builder.setLinkStaticness(LinkStaticness.DYNAMIC); builder.setNativeDeps((i & 4) == 0); builder.setUseTestOnlyFlags((i & 8) == 0); - builder.setWholeArchive((i & 16) == 0); - builder.setFake((i & 32) == 0); - builder.setRuntimeSolibDir((i & 64) == 0 ? null : new PathFragment("so1")); + builder.setFake((i & 16) == 0); + builder.setRuntimeSolibDir((i & 32) == 0 ? null : new PathFragment("so1")); builder.setFeatureConfiguration(featureConfiguration); return builder.build(); diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java index c5a5629eec..9089051b1f 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/LinkBuildVariablesTest.java @@ -23,6 +23,8 @@ import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; 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.LibraryToLinkValue; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.Variables.VariableValue; import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; import java.util.List; import org.junit.Test; @@ -118,51 +120,27 @@ public class LinkBuildVariablesTest extends BuildViewTestCase { } @Test - public void testWholeArchiveBuildVariables() throws Exception { - scratch.file( - "x/BUILD", - "cc_binary(", - " name = 'bin.so',", - " srcs = ['a.cc'],", - " linkopts = ['-shared'],", - " linkstatic = 1", - ")"); - scratch.file("x/a.cc"); - - ConfiguredTarget target = getConfiguredTarget("//x:bin.so"); - Variables variables = getLinkBuildVariables(target, Link.LinkTargetType.EXECUTABLE); - List<String> variableValue = - getVariableValue(variables, CppLinkActionBuilder.GLOBAL_WHOLE_ARCHIVE_VARIABLE); - assertThat(variableValue).contains(""); - } + public void testLibrariesToLinkAreExported() throws Exception { + AnalysisMock.get().ccSupport().setupCrosstool(mockToolsConfig); + useConfiguration(); - /** - * Tests that "--whole_archive" is not propagated twice through whole archive inputs and global - * whole archive. - */ - @Test - public void testGlobalWholeArchiveOrWholeArchiveBuildVariables() throws Exception { - scratch.file( - "x/BUILD", - "cc_binary(", - " name = 'bin',", - " srcs = ['a.cc', 'b.lo'],", - " linkopts = ['-shared'],", - " linkstatic = 1,", - ")"); + scratch.file("x/BUILD", "cc_library(", " name = 'foo',", " srcs = ['a.cc'],", ")"); scratch.file("x/a.cc"); - scratch.file("x/b.lo"); - ConfiguredTarget target = getConfiguredTarget("//x:bin"); - Variables variables = getLinkBuildVariables(target, Link.LinkTargetType.EXECUTABLE); - List<String> globalWholeArchiveVariableValue = - getVariableValue(variables, CppLinkActionBuilder.GLOBAL_WHOLE_ARCHIVE_VARIABLE); - List<String> wholeArchiveInputVariableValue = - getVariableValue( - variables, CppLinkActionBuilder.WHOLE_ARCHIVE_LINKER_INPUT_PARAMS_VARIABLE); - assertThat(globalWholeArchiveVariableValue).contains(""); - assertThat(wholeArchiveInputVariableValue).isEmpty(); - ; + ConfiguredTarget target = getConfiguredTarget("//x:foo"); + Variables variables = getLinkBuildVariables(target, LinkTargetType.DYNAMIC_LIBRARY); + VariableValue librariesToLinkSequence = variables.getVariable("libraries_to_link"); + assertThat(librariesToLinkSequence).isNotNull(); + Iterable<? extends VariableValue> librariesToLink = + librariesToLinkSequence.getSequenceValue("libraries_to_link"); + assertThat(librariesToLink).hasSize(1); + VariableValue nameValue = librariesToLink.iterator().next().getFieldValue( + "librariesToLink", LibraryToLinkValue.NAMES_FIELD_NAME); + assertThat(nameValue).isNotNull(); + Iterable<? extends VariableValue> names = nameValue.getSequenceValue("names"); + assertThat(names).isNotNull(); + assertThat(names).hasSize(1); + assertThat(names.iterator().next().getStringValue("names")).matches(".*a\\..*o"); } @Test diff --git a/tools/cpp/CROSSTOOL.tpl b/tools/cpp/CROSSTOOL.tpl index 2ede35de28..3728f11bea 100644 --- a/tools/cpp/CROSSTOOL.tpl +++ b/tools/cpp/CROSSTOOL.tpl @@ -302,7 +302,6 @@ toolchain { implies: 'linkstamps' implies: 'output_execpath_flags' implies: 'input_param_flags' - implies: 'global_whole_archive' } action_config { @@ -315,7 +314,6 @@ toolchain { implies: 'linkstamps' implies: 'output_execpath_flags' implies: 'input_param_flags' - implies: 'global_whole_archive' implies: 'has_configured_linker_path' } @@ -326,7 +324,6 @@ toolchain { tool_path: 'wrapper/bin/msvc_link.bat' } implies: 'input_param_flags' - implies: 'global_whole_archive' } action_config { @@ -336,7 +333,6 @@ toolchain { tool_path: 'wrapper/bin/msvc_link.bat' } implies: 'input_param_flags' - implies: 'global_whole_archive' } # TODO(pcloudy): The following action_config is listed in MANDATORY_LINK_TARGET_TYPES. @@ -348,7 +344,6 @@ toolchain { tool_path: 'wrapper/bin/msvc_link.bat' } implies: 'input_param_flags' - implies: 'global_whole_archive' } action_config { @@ -358,7 +353,6 @@ toolchain { tool_path: 'wrapper/bin/msvc_link.bat' } implies: 'input_param_flags' - implies: 'global_whole_archive' } action_config { @@ -408,61 +402,43 @@ toolchain { } feature { - name: 'input_param_flags' - flag_set { - expand_if_all_available: 'libopts' - action: 'c++-link-executable' - action: 'c++-link-dynamic-library' - action: 'c++-link-static-library' - action: 'c++-link-alwayslink-static-library' - action: 'c++-link-pic-static-library' - action: 'c++-link-alwayslink-pic-static-library' - flag_group { - flag: '%{libopts}' - } - } - flag_set { - expand_if_all_available: 'whole_archive_linker_params' - action: 'c++-link-executable' - action: 'c++-link-dynamic-library' - action: 'c++-link-static-library' - action: 'c++-link-alwayslink-static-library' - action: 'c++-link-pic-static-library' - action: 'c++-link-alwayslink-pic-static-library' - flag_group { - flag: '/WHOLEARCHIVE:%{whole_archive_linker_params}' - } - } - flag_set { - expand_if_all_available: 'linker_input_params' - action: 'c++-link-executable' - action: 'c++-link-dynamic-library' - action: 'c++-link-static-library' - action: 'c++-link-alwayslink-static-library' - action: 'c++-link-pic-static-library' - action: 'c++-link-alwayslink-pic-static-library' - flag_group { - flag: '%{linker_input_params}' - } - } + name: 'input_param_flags' + flag_set { + expand_if_all_available: 'libopts' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + flag: '%{libopts}' + } + } + flag_set { + expand_if_all_available: 'libraries_to_link' + action: 'c++-link-executable' + action: 'c++-link-dynamic-library' + action: 'c++-link-static-library' + action: 'c++-link-alwayslink-static-library' + action: 'c++-link-pic-static-library' + action: 'c++-link-alwayslink-pic-static-library' + flag_group { + iterate_over: 'libraries_to_link' + flag_group { + expand_if_true: 'libraries_to_link.is_whole_archive' + iterate_over: 'libraries_to_link.names' + flag: '/WHOLEARCHIVE:%{libraries_to_link.names}' + } + flag_group { + expand_if_false: 'libraries_to_link.is_whole_archive' + iterate_over: 'libraries_to_link.names' + flag: '%{libraries_to_link.names}' + } + } + } } - feature { - name: 'global_whole_archive' - flag_set { - expand_if_all_available: 'global_whole_archive' - action: 'c++-link-executable' - action: 'c++-link-dynamic-library' - action: 'c++-link-static-library' - action: 'c++-link-alwayslink-static-library' - action: 'c++-link-pic-static-library' - action: 'c++-link-alwayslink-pic-static-library' - flag_group { - flag: '/WHOLEARCHIVE' - } - } -} - compilation_mode_flags { mode: DBG compiler_flag: "/DDEBUG=1" |