Move interface so building to action configs
This cl moves the conditional building of interface libraries from LinkCommandLine to action configs and features. It provides link_dynamic_library.sh to keep blaze backwards compatible. The script and related code can be deleted once all crosstools are updated.
RELNOTES: No.
--
MOS_MIGRATED_REVID=135799041
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index ec766a7..5ff24aa 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -56,6 +56,7 @@
* Implementation for the cc_toolchain rule.
*/
public class CcToolchain implements RuleConfiguredTargetFactory {
+
/**
* This file (found under the sysroot) may be unconditionally included in every C/C++ compilation.
*/
@@ -198,6 +199,8 @@
"FDO_DIR", cppConfiguration.getFdoInstrument().getPathString()));
}
+ Artifact linkDynamicLibraryTool = getLinkDynamicLibraryTool(ruleContext);
+
CcToolchainProvider provider =
new CcToolchainProvider(
cppConfiguration,
@@ -220,6 +223,7 @@
getBuildVariables(ruleContext),
getBuiltinIncludes(ruleContext),
coverageEnvironment.build(),
+ linkDynamicLibraryTool,
getEnvironment(ruleContext));
RuleConfiguredTargetBuilder builder =
new RuleConfiguredTargetBuilder(ruleContext)
@@ -250,6 +254,10 @@
return builder.build();
}
+ private Artifact getLinkDynamicLibraryTool(RuleContext ruleContext) {
+ return ruleContext.getPrerequisiteArtifact("$link_dynamic_library_tool", Mode.TARGET);
+ }
+
private ImmutableList<Artifact> getBuiltinIncludes(RuleContext ruleContext) {
ImmutableList.Builder<Artifact> result = ImmutableList.builder();
for (Artifact artifact : inputsForLibc(ruleContext)) {
@@ -285,6 +293,7 @@
return NestedSetBuilder.<Artifact>stableOrder()
.addTransitive(link)
.addTransitive(AnalysisUtils.getMiddlemanFor(ruleContext, ":libc_top"))
+ .add(getLinkDynamicLibraryTool(ruleContext))
.add(
ruleContext
.getAnalysisEnvironment()
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 799be8b..a5e3715 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
@@ -1149,9 +1149,12 @@
return enabledFeatureNames.contains(feature);
}
- /**
- * @return whether an action config for the blaze action with the given name is enabled.
- */
+ /** @return true if tool_path in action_config points to a real tool, not a dummy placeholder */
+ public boolean hasConfiguredLinkerPathInActionConfig() {
+ return isEnabled("has_configured_linker_path");
+ }
+
+ /** @return whether an action config for the blaze action with the given name is enabled. */
boolean actionIsConfigured(String actionName) {
return enabledActionConfigActionNames.contains(actionName);
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
index 755da53..4145ebd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
@@ -25,9 +25,7 @@
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
-
import java.util.Map;
-
import javax.annotation.Nullable;
/**
@@ -35,9 +33,7 @@
*/
@Immutable
public final class CcToolchainProvider implements TransitiveInfoProvider {
- /**
- * An empty toolchain to be returned in the error case (instead of null).
- */
+ /** An empty toolchain to be returned in the error case (instead of null). */
public static final CcToolchainProvider EMPTY_TOOLCHAIN_IS_ERROR =
new CcToolchainProvider(
null,
@@ -60,6 +56,7 @@
ImmutableMap.<String, String>of(),
ImmutableList.<Artifact>of(),
NestedSetBuilder.<Pair<String, String>>emptySet(Order.COMPILE_ORDER),
+ null,
ImmutableMap.<String, String>of());
@Nullable private final CppConfiguration cppConfiguration;
@@ -82,6 +79,7 @@
private final ImmutableMap<String, String> buildVariables;
private final ImmutableList<Artifact> builtinIncludeFiles;
private final NestedSet<Pair<String, String>> coverageEnvironment;
+ @Nullable private final Artifact linkDynamicLibraryTool;
private final ImmutableMap<String, String> environment;
public CcToolchainProvider(
@@ -105,6 +103,7 @@
Map<String, String> buildVariables,
ImmutableList<Artifact> builtinIncludeFiles,
NestedSet<Pair<String, String>> coverageEnvironment,
+ Artifact linkDynamicLibraryTool,
ImmutableMap<String, String> environment) {
this.cppConfiguration = cppConfiguration;
this.crosstool = Preconditions.checkNotNull(crosstool);
@@ -126,6 +125,7 @@
this.buildVariables = ImmutableMap.copyOf(buildVariables);
this.builtinIncludeFiles = builtinIncludeFiles;
this.coverageEnvironment = coverageEnvironment;
+ this.linkDynamicLibraryTool = linkDynamicLibraryTool;
this.environment = environment;
}
@@ -283,4 +283,12 @@
public ImmutableMap<String, String> getEnvironment() {
return environment;
}
+
+ /**
+ * Returns the tool which should be used for linking dynamic libraries, or in case it's not
+ * specified by the crosstool this will be @tools_repository/tools/cpp:link_dynamic_library
+ */
+ public Artifact getLinkDynamicLibraryTool() {
+ return linkDynamicLibraryTool;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
index 9ee4481..786add8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainRule.java
@@ -75,12 +75,16 @@
.add(attr("module_map", LABEL).legacyAllowAnyFileType().cfg(HOST))
.add(attr("supports_param_files", BOOLEAN).value(true))
.add(attr("supports_header_parsing", BOOLEAN).value(false))
+ .add(
+ attr("$link_dynamic_library_tool", LABEL)
+ .value(env.getToolsLabel("//tools/cpp:link_dynamic_library")))
// TODO(bazel-team): Should be using the TARGET configuration.
.add(attr(":libc_top", LABEL).cfg(HOST).value(LIBC_TOP))
- .add(attr(":lipo_context_collector", LABEL)
- .cfg(LipoTransition.LIPO_COLLECTOR)
- .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR)
- .skipPrereqValidatorCheck())
+ .add(
+ attr(":lipo_context_collector", LABEL)
+ .cfg(LipoTransition.LIPO_COLLECTOR)
+ .value(CppRuleClasses.LIPO_CONTEXT_COLLECTOR)
+ .skipPrereqValidatorCheck())
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
index 95f37e7..7231f64 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java
@@ -51,6 +51,7 @@
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.CToolchain.ArtifactNamePattern;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LinkingModeFlags;
import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LipoMode;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.ToolPath;
import com.google.devtools.common.options.OptionsParsingException;
import com.google.protobuf.TextFormat;
import com.google.protobuf.TextFormat.ParseException;
@@ -693,7 +694,6 @@
// feature configuration, and all crosstools have been converted.
private CToolchain addLegacyFeatures(CToolchain toolchain) {
CToolchain.Builder toolchainBuilder = CToolchain.newBuilder();
- toolchainBuilder.mergeFrom(toolchain);
Set<ArtifactCategory> definedCategories = new HashSet<>();
for (ArtifactNamePattern pattern : toolchainBuilder.getArtifactNamePatternList()) {
@@ -719,292 +719,302 @@
featuresBuilder.add(feature.getName());
}
Set<String> features = featuresBuilder.build();
- if (features.contains(CppRuleClasses.NO_LEGACY_FEATURES)) {
- // The toolchain requested to not get any legacy features enabled.
- return toolchainBuilder.build();
- }
+ if (!features.contains(CppRuleClasses.NO_LEGACY_FEATURES)) {
+ try {
+ if (!linkActionsAreConfigured(toolchain)) {
+ String linkerToolPath = "DUMMY_LINKER_TOOL";
+ for (ToolPath tool : toolchain.getToolPathList()) {
+ if (tool.getName().equals(Tool.GCC.getNamePart())) {
+ linkerToolPath =
+ crosstoolTopPathFragment
+ .getRelative(new PathFragment(tool.getPath()))
+ .getPathString();
+ }
+ }
+ if (getTargetLibc().equals("macosx")) {
+ TextFormat.merge(
+ CppLinkActionConfigs.getCppLinkActionConfigs(
+ CppLinkPlatform.MAC, features, linkerToolPath),
+ toolchainBuilder);
+ } else {
+ TextFormat.merge(
+ CppLinkActionConfigs.getCppLinkActionConfigs(
+ CppLinkPlatform.LINUX, features, linkerToolPath),
+ toolchainBuilder);
+ }
+ }
- try {
-
- if (!linkActionsAreConfigured(toolchain)) {
- if (getTargetLibc().equals("macosx")) {
+ if (!features.contains("dependency_file")) {
+ // Gcc options:
+ // -MD turns on .d file output as a side-effect (doesn't imply -E)
+ // -MM[D] enables user includes only, not system includes
+ // -MF <name> specifies the dotd file name
+ // Issues:
+ // -M[M] alone subverts actual .o output (implies -E)
+ // -M[M]D alone breaks some of the .d naming assumptions
+ // This combination gets user and system includes with specified name:
+ // -MD -MF <name>
TextFormat.merge(
- CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.MAC), toolchainBuilder);
- } else {
- TextFormat.merge(
- CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.LINUX),
+ ""
+ + "feature {"
+ + " name: 'dependency_file'"
+ + " flag_set {"
+ + " action: 'assemble'"
+ + " action: 'preprocess-assemble'"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-module-compile'"
+ + " action: 'objc-compile'"
+ + " action: 'objc++-compile'"
+ + " action: 'c++-header-preprocessing'"
+ + " action: 'c++-header-parsing'"
+ + " expand_if_all_available: 'dependency_file'"
+ + " flag_group {"
+ + " flag: '-MD'"
+ + " flag: '-MF'"
+ + " flag: '%{dependency_file}'"
+ + " }"
+ + " }"
+ + "}",
toolchainBuilder);
}
- }
- if (!features.contains("dependency_file")) {
- // Gcc options:
- // -MD turns on .d file output as a side-effect (doesn't imply -E)
- // -MM[D] enables user includes only, not system includes
- // -MF <name> specifies the dotd file name
- // Issues:
- // -M[M] alone subverts actual .o output (implies -E)
- // -M[M]D alone breaks some of the .d naming assumptions
- // This combination gets user and system includes with specified name:
- // -MD -MF <name>
- TextFormat.merge(""
- + "feature {"
- + " name: 'dependency_file'"
- + " flag_set {"
- + " action: 'assemble'"
- + " action: 'preprocess-assemble'"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-module-compile'"
- + " action: 'objc-compile'"
- + " action: 'objc++-compile'"
- + " action: 'c++-header-preprocessing'"
- + " action: 'c++-header-parsing'"
- + " expand_if_all_available: 'dependency_file'"
- + " flag_group {"
- + " flag: '-MD'"
- + " flag: '-MF'"
- + " flag: '%{dependency_file}'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("random_seed")) {
- // GCC and Clang give randomized names to symbols which are defined in
- // an anonymous namespace but have external linkage. To make
- // computation of these deterministic, we want to override the
- // default seed for the random number generator. It's safe to use
- // any value which differs for all translation units; we use the
- // path to the object file.
- TextFormat.merge(""
- + "feature {"
- + " name: 'random_seed'"
- + " flag_set {"
- + " action: 'c++-compile'"
- + " action: 'c++-module-compile'"
- + " flag_group {"
- + " flag: '-frandom-seed=%{output_file}'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
-
- if (!features.contains("pic")) {
- TextFormat.merge(""
- + "feature {"
- + " name: 'pic'"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-module-compile'"
- + " action: 'preprocess-assemble'"
- + " expand_if_all_available: 'pic'"
- + " flag_group {"
- + " flag: '-fPIC'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
-
- if (!features.contains("per_object_debug_info")) {
- TextFormat.merge(""
- + "feature {"
- + " name: 'per_object_debug_info'"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'assemble'"
- + " action: 'preprocess-assemble'"
- + " expand_if_all_available: 'per_object_debug_info_file'"
- + " flag_group {"
- + " flag: '-gsplit-dwarf'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
-
- if (!features.contains("preprocessor_defines")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'preprocessor_defines'"
- + " flag_set {"
- + " action: 'preprocess-assemble'"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-header-parsing'"
- + " action: 'c++-header-preprocessing'"
- + " action: 'c++-module-compile'"
- + " action: 'clif-match'"
- + " flag_group {"
- + " flag: '-D%{preprocessor_defines}'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("include_paths")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'include_paths'"
- + " flag_set {"
- + " action: 'preprocess-assemble'"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-header-parsing'"
- + " action: 'c++-header-preprocessing'"
- + " action: 'c++-module-compile'"
- + " action: 'clif-match'"
- + " action: 'objc-compile'"
- + " action: 'objc++-compile'"
- + " flag_group {"
- + " flag: '-iquote'"
- + " flag: '%{quote_include_paths}'"
- + " }"
- + " flag_group {"
- + " flag: '-I%{include_paths}'"
- + " }"
- + " flag_group {"
- + " flag: '-isystem'"
- + " flag: '%{system_include_paths}'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("fdo_instrument")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'fdo_instrument'"
- + " provides: 'profile'"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-link-interface-dynamic-library'"
- + " action: 'c++-link-dynamic-library'"
- + " action: 'c++-link-executable'"
- + " flag_group {"
- + " flag: '-fprofile-generate=%{fdo_instrument_path}'"
- + " flag: '-fno-data-sections'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("fdo_optimize")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'fdo_optimize'"
- + " provides: 'profile'"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " expand_if_all_available: 'fdo_profile_path'"
- + " flag_group {"
- + " flag: '-fprofile-use=%{fdo_profile_path}'"
- + " flag: '-Xclang-only=-Wno-profile-instr-unprofiled'"
- + " flag: '-Xclang-only=-Wno-profile-instr-out-of-date'"
- + " flag: '-fprofile-correction'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("autofdo")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'autofdo'"
- + " provides: 'profile'"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " expand_if_all_available: 'fdo_profile_path'"
- + " flag_group {"
- + " flag: '-fauto-profile=%{fdo_profile_path}'"
- + " flag: '-fprofile-correction'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("lipo")) {
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'lipo'"
- + " requires { feature: 'autofdo' }"
- + " requires { feature: 'fdo_optimize' }"
- + " requires { feature: 'fdo_instrument' }"
- + " flag_set {"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " flag_group {"
- + " flag: '-fripa'"
- + " }"
- + " }"
- + "}",
- toolchainBuilder);
- }
- if (!features.contains("coverage")) {
- String compileFlags;
- String linkerFlags;
- if (useLLVMCoverageMap) {
- compileFlags =
- "flag_group {"
- + " flag: '-fprofile-instr-generate'"
- + " flag: '-fcoverage-mapping'"
- + "}";
- linkerFlags =
- " flag_group {"
- + " flag: '-fprofile-instr-generate'"
- + "}";
- } else {
- compileFlags =
- " expand_if_all_available: 'gcov_gcno_file'"
- + "flag_group {"
- + " flag: '-fprofile-arcs'"
- + " flag: '-ftest-coverage'"
- + "}";
- linkerFlags =
- " flag_group {"
- + " flag: '-lgcov'"
- + "}";
+ if (!features.contains("random_seed")) {
+ // GCC and Clang give randomized names to symbols which are defined in
+ // an anonymous namespace but have external linkage. To make
+ // computation of these deterministic, we want to override the
+ // default seed for the random number generator. It's safe to use
+ // any value which differs for all translation units; we use the
+ // path to the object file.
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'random_seed'"
+ + " flag_set {"
+ + " action: 'c++-compile'"
+ + " action: 'c++-module-compile'"
+ + " flag_group {"
+ + " flag: '-frandom-seed=%{output_file}'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
}
- TextFormat.merge(
- ""
- + "feature {"
- + " name: 'coverage'"
- + " provides: 'profile'"
- + " flag_set {"
- + " action: 'preprocess-assemble'"
- + " action: 'c-compile'"
- + " action: 'c++-compile'"
- + " action: 'c++-header-parsing'"
- + " action: 'c++-header-preprocessing'"
- + " action: 'c++-module-compile'"
- + compileFlags
- + " }"
- + " flag_set {"
- + " action: 'c++-link-interface-dynamic-library'"
- + " action: 'c++-link-dynamic-library'"
- + " action: 'c++-link-executable'"
- + linkerFlags
- + " }"
- + "}",
- toolchainBuilder);
+
+ if (!features.contains("pic")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'pic'"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-module-compile'"
+ + " action: 'preprocess-assemble'"
+ + " expand_if_all_available: 'pic'"
+ + " flag_group {"
+ + " flag: '-fPIC'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+
+ if (!features.contains("per_object_debug_info")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'per_object_debug_info'"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'assemble'"
+ + " action: 'preprocess-assemble'"
+ + " expand_if_all_available: 'per_object_debug_info_file'"
+ + " flag_group {"
+ + " flag: '-gsplit-dwarf'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+
+ if (!features.contains("preprocessor_defines")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'preprocessor_defines'"
+ + " flag_set {"
+ + " action: 'preprocess-assemble'"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-header-parsing'"
+ + " action: 'c++-header-preprocessing'"
+ + " action: 'c++-module-compile'"
+ + " action: 'clif-match'"
+ + " flag_group {"
+ + " flag: '-D%{preprocessor_defines}'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("include_paths")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'include_paths'"
+ + " flag_set {"
+ + " action: 'preprocess-assemble'"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-header-parsing'"
+ + " action: 'c++-header-preprocessing'"
+ + " action: 'c++-module-compile'"
+ + " action: 'clif-match'"
+ + " action: 'objc-compile'"
+ + " action: 'objc++-compile'"
+ + " flag_group {"
+ + " flag: '-iquote'"
+ + " flag: '%{quote_include_paths}'"
+ + " }"
+ + " flag_group {"
+ + " flag: '-I%{include_paths}'"
+ + " }"
+ + " flag_group {"
+ + " flag: '-isystem'"
+ + " flag: '%{system_include_paths}'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("fdo_instrument")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'fdo_instrument'"
+ + " provides: 'profile'"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-link-interface-dynamic-library'"
+ + " action: 'c++-link-dynamic-library'"
+ + " action: 'c++-link-executable'"
+ + " flag_group {"
+ + " flag: '-fprofile-generate=%{fdo_instrument_path}'"
+ + " flag: '-fno-data-sections'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("fdo_optimize")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'fdo_optimize'"
+ + " provides: 'profile'"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " expand_if_all_available: 'fdo_profile_path'"
+ + " flag_group {"
+ + " flag: '-fprofile-use=%{fdo_profile_path}'"
+ + " flag: '-Xclang-only=-Wno-profile-instr-unprofiled'"
+ + " flag: '-Xclang-only=-Wno-profile-instr-out-of-date'"
+ + " flag: '-fprofile-correction'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("autofdo")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'autofdo'"
+ + " provides: 'profile'"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " expand_if_all_available: 'fdo_profile_path'"
+ + " flag_group {"
+ + " flag: '-fauto-profile=%{fdo_profile_path}'"
+ + " flag: '-fprofile-correction'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("lipo")) {
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'lipo'"
+ + " requires { feature: 'autofdo' }"
+ + " requires { feature: 'fdo_optimize' }"
+ + " requires { feature: 'fdo_instrument' }"
+ + " flag_set {"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " flag_group {"
+ + " flag: '-fripa'"
+ + " }"
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ if (!features.contains("coverage")) {
+ String compileFlags;
+ String linkerFlags;
+ if (useLLVMCoverageMap) {
+ compileFlags =
+ "flag_group {"
+ + " flag: '-fprofile-instr-generate'"
+ + " flag: '-fcoverage-mapping'"
+ + "}";
+ linkerFlags = " flag_group {" + " flag: '-fprofile-instr-generate'" + "}";
+ } else {
+ compileFlags =
+ " expand_if_all_available: 'gcov_gcno_file'"
+ + "flag_group {"
+ + " flag: '-fprofile-arcs'"
+ + " flag: '-ftest-coverage'"
+ + "}";
+ linkerFlags = " flag_group {" + " flag: '-lgcov'" + "}";
+ }
+ TextFormat.merge(
+ ""
+ + "feature {"
+ + " name: 'coverage'"
+ + " provides: 'profile'"
+ + " flag_set {"
+ + " action: 'preprocess-assemble'"
+ + " action: 'c-compile'"
+ + " action: 'c++-compile'"
+ + " action: 'c++-header-parsing'"
+ + " action: 'c++-header-preprocessing'"
+ + " action: 'c++-module-compile'"
+ + compileFlags
+ + " }"
+ + " flag_set {"
+ + " action: 'c++-link-interface-dynamic-library'"
+ + " action: 'c++-link-dynamic-library'"
+ + " action: 'c++-link-executable'"
+ + linkerFlags
+ + " }"
+ + "}",
+ toolchainBuilder);
+ }
+ } catch (ParseException e) {
+ // Can only happen if we change the proto definition without changing our
+ // configuration above.
+ throw new RuntimeException(e);
}
- } catch (ParseException e) {
- // Can only happen if we change the proto definition without changing our configuration above.
- throw new RuntimeException(e);
}
+
+ toolchainBuilder.mergeFrom(toolchain);
return toolchainBuilder.build();
}
@@ -1026,7 +1036,8 @@
private static final String SYSROOT_START = "%sysroot%/";
private static final String WORKSPACE_START = "%workspace%/";
private static final String CROSSTOOL_START = "%crosstool_top%/";
- private static final String PACKAGE_START = "%package(", PACKAGE_END = ")%";
+ private static final String PACKAGE_START = "%package(";
+ private static final String PACKAGE_END = ")%";
/**
* Resolve the given include directory.
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 178d068..d6b2c62 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
@@ -100,6 +100,18 @@
/** A build variable for the execpath of the output of the linker. */
public static final String OUTPUT_EXECPATH_VARIABLE = "output_execpath";
+ /** A build variable setting if interface library should be generated. */
+ public static final String GENERATE_INTERFACE_LIBRARY_VARIABLE = "generate_interface_library";
+
+ /** A build variable for the path to the interface library builder tool. */
+ public static final String INTERFACE_LIBRARY_BUILDER_VARIABLE = "interface_library_builder_path";
+
+ /** A build variable for the input for the interface library builder tool. */
+ public static final String INTERFACE_LIBRARY_INPUT_VARIABLE = "interface_library_input_path";
+
+ /** A build variable for the path where to generate interface library using the builder tool. */
+ public static final String INTERFACE_LIBRARY_OUTPUT_VARIABLE = "interface_library_output_path";
+
/**
* A build variable that is set to indicate a mostly static linking for which the linked binary
* should be piped to /dev/null.
@@ -320,6 +332,10 @@
public List<String> getLinkstampOptions() {
return this.linkstampOptions;
}
+
+ protected Artifact getInterfaceSoBuilder() {
+ return analysisEnvironment.getEmbeddedToolArtifact(CppRuleClasses.BUILD_INTERFACE_SO);
+ }
/**
* Returns command line options for this link action.
@@ -552,7 +568,9 @@
runtimeLinkerInputs,
null,
linkerParamsFile,
- ltoOutputRootPrefix)
+ ltoOutputRootPrefix,
+ null,
+ null)
: new CppLinkVariablesExtension(
configuration,
linkstampMap,
@@ -561,7 +579,9 @@
runtimeLinkerInputs,
output,
linkerParamsFile,
- PathFragment.EMPTY_FRAGMENT);
+ PathFragment.EMPTY_FRAGMENT,
+ getInterfaceSoBuilder(),
+ interfaceOutput);
variablesExtension.addVariables(buildVariablesBuilder);
for (VariablesExtension extraVariablesExtension : variablesExtensions) {
extraVariablesExtension.addVariables(buildVariablesBuilder);
@@ -612,6 +632,7 @@
.setParamFile(paramFile)
.setToolchain(toolchain)
.setBuildVariables(buildVariables)
+ .setToolPath(getToolPath())
.setFeatureConfiguration(featureConfiguration);
// TODO(b/30228443): Refactor noWholeArchiveInputs into action_configs, and remove this.
@@ -622,9 +643,7 @@
if (!isLTOIndexing) {
linkCommandLineBuilder
.setOutput(output)
- .setInterfaceOutput(interfaceOutput)
.setBuildInfoHeaderArtifacts(buildInfoHeaderArtifacts)
- .setInterfaceSoBuilder(getInterfaceSoBuilder())
.setLinkstamps(linkstampMap)
.setLinkopts(ImmutableList.copyOf(linkopts))
.addLinkstampCompileOptions(linkstampOptions);
@@ -639,6 +658,7 @@
// Compute the set of inputs - we only need stable order here.
NestedSetBuilder<Artifact> dependencyInputsBuilder = NestedSetBuilder.stableOrder();
dependencyInputsBuilder.addTransitive(crosstoolInputs);
+ dependencyInputsBuilder.add(toolchain.getLinkDynamicLibraryTool());
dependencyInputsBuilder.addAll(linkActionInputs);
if (runtimeMiddleman != null) {
dependencyInputsBuilder.add(runtimeMiddleman);
@@ -739,6 +759,26 @@
executionRequirements.build());
}
+ /**
+ * Returns the tool path from feature configuration, if the tool in the configuration is sane, or
+ * builtin tool, if configuration has a dummy value.
+ */
+ private String getToolPath() {
+ if (!featureConfiguration.actionIsConfigured(linkType.getActionName())) {
+ return null;
+ }
+ String toolPath =
+ featureConfiguration
+ .getToolForAction(linkType.getActionName())
+ .getToolPath(cppConfiguration.getCrosstoolTopPathFragment())
+ .getPathString();
+ if (linkType.equals(LinkTargetType.DYNAMIC_LIBRARY)
+ && !featureConfiguration.hasConfiguredLinkerPathInActionConfig()) {
+ toolPath = toolchain.getLinkDynamicLibraryTool().getExecPathString();
+ }
+ return toolPath;
+ }
+
/** The default heuristic on whether we need to use whole-archive for the link. */
private static boolean needWholeArchive(
LinkStaticness staticness,
@@ -809,10 +849,6 @@
return ruleContext.getActionOwner();
}
- protected Artifact getInterfaceSoBuilder() {
- return analysisEnvironment.getEmbeddedToolArtifact(CppRuleClasses.BUILD_INTERFACE_SO);
- }
-
/** Set the crosstool inputs required for the action. */
public CppLinkActionBuilder setCrosstoolInputs(NestedSet<Artifact> inputs) {
this.crosstoolInputs = inputs;
@@ -1196,6 +1232,8 @@
private final Iterable<LinkerInput> linkerInputs;
private final ImmutableList<LinkerInput> runtimeLinkerInputs;
private final Artifact outputArtifact;
+ private final Artifact interfaceLibraryBuilder;
+ private final Artifact interfaceLibraryOutput;
private final Artifact linkerParamsFile;
private final PathFragment ltoOutputRootPrefix;
@@ -1209,13 +1247,17 @@
ImmutableList<LinkerInput> runtimeLinkerInputs,
Artifact output,
Artifact linkerParamsFile,
- PathFragment ltoOutputRootPrefix) {
+ PathFragment ltoOutputRootPrefix,
+ Artifact interfaceLibraryBuilder,
+ Artifact interfaceLibraryOutput) {
this.configuration = configuration;
this.linkstampMap = linkstampMap;
this.needWholeArchive = needWholeArchive;
this.linkerInputs = linkerInputs;
this.runtimeLinkerInputs = runtimeLinkerInputs;
this.outputArtifact = output;
+ this.interfaceLibraryBuilder = interfaceLibraryBuilder;
+ this.interfaceLibraryOutput = interfaceLibraryOutput;
this.linkerParamsFile = linkerParamsFile;
this.ltoOutputRootPrefix = ltoOutputRootPrefix;
@@ -1285,9 +1327,8 @@
}
// output exec path
- if (this.outputArtifact != null) {
- buildVariables.addVariable(
- OUTPUT_EXECPATH_VARIABLE, this.outputArtifact.getExecPathString());
+ if (outputArtifact != null) {
+ buildVariables.addVariable(OUTPUT_EXECPATH_VARIABLE, outputArtifact.getExecPathString());
}
if (!ltoOutputRootPrefix.equals(PathFragment.EMPTY_FRAGMENT)) {
@@ -1303,6 +1344,21 @@
+ ";"
+ configuration.getBinDirectory().getExecPath().getRelative(ltoOutputRootPrefix));
}
+ boolean shouldGenerateInterfaceLibrary =
+ outputArtifact != null
+ && interfaceLibraryBuilder != null
+ && interfaceLibraryOutput != null;
+ buildVariables.addVariable(
+ GENERATE_INTERFACE_LIBRARY_VARIABLE, shouldGenerateInterfaceLibrary ? "yes" : "no");
+ buildVariables.addVariable(
+ INTERFACE_LIBRARY_BUILDER_VARIABLE,
+ shouldGenerateInterfaceLibrary ? interfaceLibraryBuilder.getExecPathString() : "ignored");
+ buildVariables.addVariable(
+ INTERFACE_LIBRARY_INPUT_VARIABLE,
+ shouldGenerateInterfaceLibrary ? outputArtifact.getExecPathString() : "ignored");
+ buildVariables.addVariable(
+ INTERFACE_LIBRARY_OUTPUT_VARIABLE,
+ shouldGenerateInterfaceLibrary ? interfaceLibraryOutput.getExecPathString() : "ignored");
// Variables arising from the toolchain
buildVariables
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 a359350..dc7b250 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
@@ -15,6 +15,7 @@
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
+import java.util.Set;
/**
* A helper class for creating action_configs for the c++ link action.
@@ -30,7 +31,25 @@
MAC
}
- public static String getCppLinkActionConfigs(CppLinkPlatform platform) {
+ public static String getCppLinkActionConfigs(
+ CppLinkPlatform platform, Set<String> features, String cppLinkDynamicLibraryToolPath) {
+ String cppDynamicLibraryLinkerTool = "";
+ if (!features.contains("dynamic_library_linker_tool")) {
+ cppDynamicLibraryLinkerTool =
+ ""
+ + "feature {"
+ + " name: 'dynamic_library_linker_tool'"
+ + " flag_set {"
+ + " action: 'c++-link-dynamic-library'"
+ + " flag_group {"
+ + " flag: '"
+ + cppLinkDynamicLibraryToolPath
+ + "'"
+ + " }"
+ + " }"
+ + "}";
+ }
+
return Joiner.on("\n")
.join(
ImmutableList.of(
@@ -55,6 +74,8 @@
" tool {",
" tool_path: 'DUMMY_TOOL'",
" }",
+ " implies: 'build_interface_libraries'",
+ " implies: 'dynamic_library_linker_tool'",
" implies: 'symbol_counts'",
" implies: 'shared_flag'",
" implies: 'linkstamps'",
@@ -109,6 +130,22 @@
" implies: 'global_whole_archive_close'",
"}",
"feature {",
+ " name: 'build_interface_libraries'",
+ " flag_set {",
+ " expand_if_all_available: 'generate_interface_library'",
+ " action: 'c++-link-dynamic-library'",
+ " flag_group {",
+ " flag: '%{generate_interface_library}'",
+ " flag: '%{interface_library_builder_path}'",
+ " flag: '%{interface_library_input_path}'",
+ " flag: '%{interface_library_output_path}'",
+ " }",
+ " }",
+ "}",
+ // Order of feature declaration matters, cppDynamicLibraryLinkerTool has to follow
+ // right after build_interface_libraries.
+ cppDynamicLibraryLinkerTool,
+ "feature {",
" name: 'symbol_counts'",
" flag_set {",
" expand_if_all_available: 'symbol_counts_output'",
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 db3ab65..27e3e4d 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
@@ -53,14 +53,13 @@
@Immutable
public final class LinkCommandLine extends CommandLine {
private final String actionName;
- private final BuildConfiguration configuration;
+ private final String toolPath;
private final CppConfiguration cppConfiguration;
private final ActionOwner owner;
private final CcToolchainFeatures.Variables variables;
// The feature config can be null for tests.
@Nullable private final FeatureConfiguration featureConfiguration;
@Nullable private final Artifact output;
- @Nullable private final Artifact interfaceOutput;
private final ImmutableList<Artifact> buildInfoHeaderArtifacts;
private final Iterable<? extends LinkerInput> linkerInputs;
private final Iterable<? extends LinkerInput> runtimeInputs;
@@ -77,14 +76,13 @@
private final List<String> noWholeArchiveFlags;
@Nullable private final Artifact paramFile;
- @Nullable private final Artifact interfaceSoBuilder;
private LinkCommandLine(
String actionName,
+ String toolPath,
BuildConfiguration configuration,
ActionOwner owner,
Artifact output,
- @Nullable Artifact interfaceOutput,
ImmutableList<Artifact> buildInfoHeaderArtifacts,
Iterable<? extends LinkerInput> linkerInputs,
Iterable<? extends LinkerInput> runtimeInputs,
@@ -100,23 +98,17 @@
boolean useTestOnlyFlags,
boolean needWholeArchive,
@Nullable Artifact paramFile,
- Artifact interfaceSoBuilder,
List<String> noWholeArchiveFlags,
CcToolchainFeatures.Variables variables,
@Nullable FeatureConfiguration featureConfiguration) {
this.actionName = actionName;
- this.configuration = Preconditions.checkNotNull(configuration);
+ this.toolPath = toolPath;
this.cppConfiguration = configuration.getFragment(CppConfiguration.class);
this.variables = variables;
this.featureConfiguration = featureConfiguration;
this.owner = Preconditions.checkNotNull(owner);
this.output = output;
- this.interfaceOutput = interfaceOutput;
- if (interfaceOutput != null) {
- Preconditions.checkNotNull(this.output);
- }
-
this.buildInfoHeaderArtifacts = Preconditions.checkNotNull(buildInfoHeaderArtifacts);
this.linkerInputs = Preconditions.checkNotNull(linkerInputs);
this.runtimeInputs = Preconditions.checkNotNull(runtimeInputs);
@@ -135,23 +127,6 @@
this.useTestOnlyFlags = useTestOnlyFlags;
this.paramFile = paramFile;
this.noWholeArchiveFlags = noWholeArchiveFlags;
-
- // For now, silently ignore interfaceSoBuilder if we don't build an interface dynamic library.
- this.interfaceSoBuilder =
- ((linkTargetType == LinkTargetType.DYNAMIC_LIBRARY) && (interfaceOutput != null))
- ? Preconditions.checkNotNull(
- interfaceSoBuilder, "cannot build interface dynamic library without builder")
- : null;
- }
-
- /**
- * Returns an interface shared object output artifact produced during linking. This only returns
- * non-null if {@link #getLinkTargetType} is {@code DYNAMIC_LIBRARY} and an interface shared
- * object was requested.
- */
- @Nullable
- public Artifact getInterfaceOutput() {
- return interfaceOutput;
}
@Nullable
@@ -410,17 +385,7 @@
break;
case DYNAMIC_LIBRARY:
- if (interfaceOutput != null) {
- argv.add(configuration.getShellExecutable().getPathString());
- argv.add("-c");
- argv.add(
- "build_iface_so=\"$0\"; impl=\"$1\"; iface=\"$2\"; cmd=\"$3\"; shift 3; "
- + "\"$cmd\" \"$@\" && \"$build_iface_so\" \"$impl\" \"$iface\"");
- argv.add(interfaceSoBuilder.getExecPathString());
- argv.add(output.getExecPathString());
- argv.add(interfaceOutput.getExecPathString());
- }
- argv.add(cppConfiguration.getCppExecutable().getPathString());
+ argv.add(toolPath);
argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
argv.addAll(noWholeArchiveFlags);
addToolchainFlags(argv);
@@ -443,11 +408,7 @@
// TODO(b/30109612): make this pattern the case for all link variants.
case OBJC_ARCHIVE:
case OBJC_FULLY_LINKED_ARCHIVE:
- argv.add(
- featureConfiguration
- .getToolForAction(actionName)
- .getToolPath(cppConfiguration.getCrosstoolTopPathFragment())
- .getPathString());
+ argv.add(toolPath);
argv.addAll(featureConfiguration.getCommandLine(actionName, variables));
break;
@@ -664,8 +625,8 @@
private final ActionOwner owner;
@Nullable private final RuleContext ruleContext;
+ @Nullable private String toolPath;
@Nullable private Artifact output;
- @Nullable private Artifact interfaceOutput;
private ImmutableList<Artifact> buildInfoHeaderArtifacts = ImmutableList.of();
private Iterable<? extends LinkerInput> linkerInputs = ImmutableList.of();
private Iterable<? extends LinkerInput> runtimeInputs = ImmutableList.of();
@@ -680,7 +641,6 @@
private boolean useTestOnlyFlags;
private boolean needWholeArchive;
@Nullable private Artifact paramFile;
- @Nullable private Artifact interfaceSoBuilder;
@Nullable private CcToolchainProvider toolchain;
private Variables variables;
private FeatureConfiguration featureConfiguration;
@@ -740,10 +700,10 @@
return new LinkCommandLine(
actionName,
+ toolPath,
configuration,
owner,
output,
- interfaceOutput,
buildInfoHeaderArtifacts,
linkerInputs,
runtimeInputs,
@@ -759,7 +719,6 @@
useTestOnlyFlags,
needWholeArchive,
paramFile,
- interfaceSoBuilder,
noWholeArchiveFlags,
variables,
featureConfiguration);
@@ -774,9 +733,13 @@
return this;
}
- /**
- * Sets the feature configuration for this link action.
- */
+ /** Sets the tool path, with tool being the first thing on the command line */
+ public Builder setToolPath(String toolPath) {
+ this.toolPath = toolPath;
+ return this;
+ }
+
+ /** Sets the feature configuration for this link action. */
public Builder setFeatureConfiguration(FeatureConfiguration featureConfiguration) {
this.featureConfiguration = featureConfiguration;
return this;
@@ -818,16 +781,6 @@
}
/**
- * Sets the additional interface output artifact, which is only used for dynamic libraries. The
- * {@link #build} method throws an exception if the target type is not {@link
- * LinkTargetType#DYNAMIC_LIBRARY}.
- */
- public Builder setInterfaceOutput(Artifact interfaceOutput) {
- this.interfaceOutput = interfaceOutput;
- return this;
- }
-
- /**
* Sets the linker options. These are passed to the linker in addition to the other linker
* options like linker inputs, symbol count options, etc. The {@link #build} method throws an
* exception if the linker options are non-empty for a static link (see {@link
@@ -850,16 +803,6 @@
}
/**
- * Sets the binary that should be used to create the interface output for a dynamic library.
- * This is ignored unless the target type is {@link LinkTargetType#DYNAMIC_LIBRARY} and an
- * interface output artifact is specified.
- */
- public Builder setInterfaceSoBuilder(Artifact interfaceSoBuilder) {
- this.interfaceSoBuilder = interfaceSoBuilder;
- return this;
- }
-
- /**
* Sets the linkstamps. Linkstamps are additional C++ source files that are compiled as part of
* the link command. The {@link #build} method throws an exception if the linkstamps are
* non-empty for a static link (see {@link LinkTargetType#staticness()}}).
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
index 4ecc1c0..521d56a 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/BazelMockCcSupport.java
@@ -32,7 +32,8 @@
new Predicate<String>() {
@Override
public boolean apply(String label) {
- return !label.startsWith("@blaze_tools//tools/cpp/stl");
+ return !label.startsWith("@blaze_tools//tools/cpp/stl")
+ && !label.startsWith("@blaze_tools//tools/cpp/link_dynamic_library");
}
};
@@ -75,6 +76,7 @@
public void setup(MockToolsConfig config) throws IOException {
config.create(
"/bazel_tools_workspace/tools/cpp/BUILD",
+ "package(default_visibility=['//visibility:public'])",
"cc_library(name = 'stl')",
"cc_library(name = 'malloc')",
"cc_toolchain_suite(",
@@ -119,11 +121,20 @@
" linker_files = ':empty',",
" module_map = 'crosstool.cppmap', supports_header_parsing = 1,",
" objcopy_files = ':empty', static_runtime_libs = [':empty'], strip_files = ':empty',",
+ ")",
+ "filegroup(",
+ " name = 'link_dynamic_library',",
+ " srcs = ['link_dynamic_library.sh'],",
")");
config.create(
"/bazel_tools_workspace/tools/cpp/CROSSTOOL",
readCrosstoolFile());
+ if (config.isRealFileSystem()) {
+ config.linkTool("tools/cpp/link_dynamic_library.sh");
+ } else {
+ config.create("tools/cpp/link_dynamic_library.sh", "");
+ }
config.create(
"/bazel_tools_workspace/tools/objc/BUILD",
"xcode_config(name = 'host_xcodes')");
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
index 0a7c700..5901ace 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java
@@ -35,10 +35,7 @@
*/
public abstract class MockCcSupport {
- /**
- * Filter to remove implicit crosstool artifact and module map inputs
- * of C/C++ rules.
- */
+ /** Filter to remove implicit crosstool artifact and module map inputs of C/C++ rules. */
public static final Predicate<Artifact> CC_ARTIFACT_FILTER =
new Predicate<Artifact>() {
@Override
@@ -46,6 +43,7 @@
String basename = artifact.getExecPath().getBaseName();
String pathString = artifact.getExecPathString();
return !pathString.startsWith("third_party/crosstool/")
+ && !pathString.startsWith("tools/cpp/link_dynamic_library")
&& !(pathString.contains("/internal/_middlemen") && basename.contains("crosstool"))
&& !pathString.startsWith("_bin/build_interface_so")
&& !pathString.endsWith(".cppmap");
@@ -502,7 +500,16 @@
"package(default_visibility = ['//visibility:public'])",
"cc_library(name = 'stl')",
"alias(name='toolchain', actual='//third_party/crosstool')",
- "cc_library(name = 'malloc')");
+ "cc_library(name = 'malloc')",
+ "filegroup(",
+ " name = 'link_dynamic_library',",
+ " srcs = ['link_dynamic_library.sh'],",
+ ")");
+ if (config.isRealFileSystem()) {
+ config.linkTool("tools/cpp/link_dynamic_library.sh");
+ } else {
+ config.create("tools/cpp/link_dynamic_library.sh", "");
+ }
}
protected void createCrosstoolPackage(MockToolsConfig config, boolean addEmbeddedRuntimes)
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
index 2099df6..c8de88c 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java
@@ -262,8 +262,6 @@
LinkerInputs.toLibraryArtifacts(action.getLinkCommandLine().getLinkerInputs()));
assertThat(cppLinkInfo.getInputFileList()).containsExactlyElementsIn(inputs);
assertEquals(action.getPrimaryOutput().getExecPathString(), cppLinkInfo.getOutputFile());
- Artifact interfaceOutput = action.getLinkCommandLine().getInterfaceOutput();
- assertEquals(interfaceOutput.getExecPathString(), cppLinkInfo.getInterfaceOutputFile());
assertEquals(action.getLinkCommandLine().getLinkTargetType().name(),
cppLinkInfo.getLinkTargetType());
assertEquals(action.getLinkCommandLine().getLinkStaticness().name(),
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 eda2715..cd92b39 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
@@ -21,6 +21,7 @@
import com.google.common.base.Joiner;
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.Action;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
@@ -54,10 +55,13 @@
@RunWith(JUnit4.class)
public class CppLinkActionTest extends BuildViewTestCase {
private RuleContext createDummyRuleContext() throws Exception {
- return view.getRuleContextForTesting(reporter, scratchConfiguredTarget(
- "dummyRuleContext", "dummyRuleContext",
- // CppLinkAction creation requires a CcToolchainProvider.
- "cc_library(name = 'dummyRuleContext')"),
+ return view.getRuleContextForTesting(
+ reporter,
+ scratchConfiguredTarget(
+ "dummyRuleContext",
+ "dummyRuleContext",
+ // CppLinkAction creation requires a CcToolchainProvider.
+ "cc_library(name = 'dummyRuleContext')"),
new StubAnalysisEnvironment() {
@Override
public void registerAction(ActionAnalysisMetadata... action) {
@@ -65,16 +69,23 @@
}
@Override
+ public Artifact getEmbeddedToolArtifact(String embeddedPath) {
+ return scratchArtifact("tools/interface_so_builder");
+ }
+
+ @Override
public Artifact getDerivedArtifact(PathFragment rootRelativePath, Root root) {
return CppLinkActionTest.this.getDerivedArtifact(
rootRelativePath, root, ActionsTestUtil.NULL_ARTIFACT_OWNER);
}
- }, masterConfig);
+ },
+ masterConfig);
}
private final FeatureConfiguration getMockFeatureConfiguration() throws Exception {
return CcToolchainFeaturesTest.buildFeatures(
- CppLinkActionConfigs.getCppLinkActionConfigs(CppLinkPlatform.LINUX))
+ CppLinkActionConfigs.getCppLinkActionConfigs(
+ CppLinkPlatform.LINUX, ImmutableSet.<String>of(), "dynamic_library_linker_tool"))
.getFeatureConfiguration(
Link.LinkTargetType.EXECUTABLE.getActionName(),
Link.LinkTargetType.DYNAMIC_LIBRARY.getActionName(),
@@ -107,11 +118,10 @@
CppLinkAction linkAction =
createLinkBuilder(
Link.LinkTargetType.EXECUTABLE,
- "out",
+ "dummyRuleContext/out",
ImmutableList.<Artifact>of(),
ImmutableList.<LibraryToLink>of(),
- featureConfiguration,
- false)
+ featureConfiguration)
.build();
assertThat(linkAction.getArgv()).contains("some_flag");
}
@@ -160,11 +170,10 @@
CppLinkAction linkAction =
createLinkBuilder(
Link.LinkTargetType.EXECUTABLE,
- "out",
+ "dummyRuleContext/out",
ImmutableList.<Artifact>of(),
ImmutableList.<LibraryToLink>of(),
- featureConfiguration,
- false)
+ featureConfiguration)
.build();
assertThat(linkAction.getEnvironment()).containsEntry("foo", "bar");
}
@@ -315,11 +324,10 @@
CppLinkAction linkAction =
createLinkBuilder(
Link.LinkTargetType.EXECUTABLE,
- "binary2",
+ "dummyRuleContext/binary2",
objects.build(),
ImmutableList.<LibraryToLink>of(),
- new FeatureConfiguration(),
- false)
+ new FeatureConfiguration())
.setFake(true)
.build();
@@ -350,8 +358,7 @@
String outputPath,
Iterable<Artifact> nonLibraryInputs,
ImmutableList<LibraryToLink> libraryInputs,
- FeatureConfiguration featureConfiguration,
- boolean shouldIncludeToolchain)
+ FeatureConfiguration featureConfiguration)
throws Exception {
RuleContext ruleContext = createDummyRuleContext();
CppLinkActionBuilder builder =
@@ -359,10 +366,10 @@
ruleContext,
new Artifact(
new PathFragment(outputPath),
- getTargetConfiguration().getBinDirectory(
- ruleContext.getRule().getRepository())),
+ getTargetConfiguration()
+ .getBinDirectory(ruleContext.getRule().getRepository())),
ruleContext.getConfiguration(),
- shouldIncludeToolchain ? CppHelper.getToolchain(ruleContext) : null)
+ CppHelper.getToolchain(ruleContext))
.addObjectFiles(nonLibraryInputs)
.addLibraries(NestedSetBuilder.wrap(Order.LINK_ORDER, libraryInputs))
.setLinkType(type)
@@ -382,8 +389,7 @@
output.getPathString(),
ImmutableList.<Artifact>of(),
ImmutableList.<LibraryToLink>of(),
- new FeatureConfiguration(),
- true);
+ new FeatureConfiguration());
}
public Artifact getOutputArtifact(String relpath) {
@@ -424,6 +430,68 @@
}
@Test
+ public void testInterfaceOutputForDynamicLibrary() throws Exception {
+ FeatureConfiguration featureConfiguration =
+ CcToolchainFeaturesTest.buildFeatures(
+ "feature {",
+ " name: 'build_interface_libraries'",
+ " flag_set {",
+ " action: '" + LinkTargetType.DYNAMIC_LIBRARY.getActionName() + "',",
+ " flag_group {",
+ " flag: '%{generate_interface_library}'",
+ " flag: '%{interface_library_builder_path}'",
+ " flag: '%{interface_library_input_path}'",
+ " flag: '%{interface_library_output_path}'",
+ " }",
+ " }",
+ "}",
+ "feature {",
+ " name: 'dynamic_library_linker_tool'",
+ " flag_set {",
+ " action: 'c++-link-dynamic-library'",
+ " flag_group {",
+ " flag: 'dynamic_library_linker_tool'",
+ " }",
+ " }",
+ "}",
+ "feature {",
+ " name: 'has_configured_linker_path'",
+ "}",
+ "action_config {",
+ " config_name: '" + LinkTargetType.DYNAMIC_LIBRARY.getActionName() + "'",
+ " action_name: '" + LinkTargetType.DYNAMIC_LIBRARY.getActionName() + "'",
+ " tool {",
+ " tool_path: 'custom/crosstool/scripts/link_dynamic_library.sh'",
+ " }",
+ " implies: 'has_configured_linker_path'",
+ " implies: 'build_interface_libraries'",
+ " implies: 'dynamic_library_linker_tool'",
+ "}")
+ .getFeatureConfiguration(
+ "build_interface_libraries",
+ "dynamic_library_linker_tool",
+ LinkTargetType.DYNAMIC_LIBRARY.getActionName());
+ CppLinkActionBuilder builder =
+ createLinkBuilder(
+ LinkTargetType.DYNAMIC_LIBRARY,
+ "foo.so",
+ ImmutableList.<Artifact>of(),
+ ImmutableList.<LibraryToLink>of(),
+ featureConfiguration)
+ .setLibraryIdentifier("foo")
+ .setInterfaceOutput(scratchArtifact("FakeInterfaceOutput.ifso"));
+
+ List<String> commandLine = builder.build().getCommandLine();
+ assertThat(commandLine.size()).isGreaterThan(6);
+ assertThat(commandLine.get(0)).endsWith("custom/crosstool/scripts/link_dynamic_library.sh");
+ assertThat(commandLine.get(1)).isEqualTo("yes");
+ assertThat(commandLine.get(2)).isEqualTo("tools/interface_so_builder");
+ assertThat(commandLine.get(3)).endsWith("foo.so");
+ assertThat(commandLine.get(4)).isEqualTo("FakeInterfaceOutput.ifso");
+ assertThat(commandLine.get(5)).isEqualTo("dynamic_library_linker_tool");
+ }
+
+ @Test
public void testStaticLinkWithDynamicIsError() throws Exception {
CppLinkActionBuilder builder =
createLinkBuilder(LinkTargetType.STATIC_LIBRARY)
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/LibraryLinkingTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/LibraryLinkingTest.java
index 3adb69e..30adaf6 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/LibraryLinkingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/LibraryLinkingTest.java
@@ -21,13 +21,11 @@
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
-
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
-import java.util.List;
-
/**
* Test for shared library linking {@link CppLinkAction}.
*/
@@ -35,8 +33,9 @@
public final class LibraryLinkingTest extends BuildViewTestCase {
private List<String> getLinkOpts(CppLinkAction linkAction, String... optionPatterns)
throws Exception {
- // Strip the first parameter from the argv, which is the gcc command.
- return linkAction.getRawLinkArgv().subList(1, optionPatterns.length + 3);
+ // Strip the first parameters from the argv, which are the dynamic library script
+ // (usually tools/cpp/link_dynamic_library.sh), and its arguments.
+ return linkAction.getRawLinkArgv().subList(6, optionPatterns.length + 6);
}
private void assertLinkopts(CppLinkAction linkAction, String... optionPatterns) throws Exception {
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 7e9a9dc..5cd2ce3 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
@@ -22,6 +22,7 @@
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.Link.LinkTargetType;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -162,7 +163,60 @@
}
/**
- * TODO(pcloudy): Add test for testing that necessary build variables are populated
- * when alwayslink=1.
+ * TODO(pcloudy): Add test for testing that necessary build variables are populated when
+ * alwayslink=1.
*/
+ @Test
+ public void testInterfaceLibraryBuildingVariablesWhenGenerationPossible() throws Exception {
+ scratch.file("x/BUILD", "cc_library(", " name = 'foo',", " srcs = ['a.cc'],", ")");
+ scratch.file("x/a.cc");
+
+ ConfiguredTarget target = getConfiguredTarget("//x:foo");
+ Variables variables = getLinkBuildVariables(target, LinkTargetType.DYNAMIC_LIBRARY);
+
+ String interfaceLibraryBuilder =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_BUILDER_VARIABLE));
+ String interfaceLibraryInput =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_INPUT_VARIABLE));
+ String interfaceLibraryOutput =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_OUTPUT_VARIABLE));
+ String generateInterfaceLibrary =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.GENERATE_INTERFACE_LIBRARY_VARIABLE));
+
+ assertThat(generateInterfaceLibrary).isEqualTo("yes");
+ assertThat(interfaceLibraryInput).endsWith("libfoo.so");
+ assertThat(interfaceLibraryOutput).endsWith("libfoo.ifso");
+ assertThat(interfaceLibraryBuilder).endsWith("build_interface_so");
+ }
+
+ @Test
+ public void testInterfaceLibraryBuildingVariablesWhenGenerationNotAllowed() throws Exception {
+ scratch.file("x/BUILD", "cc_library(", " name = 'foo',", " srcs = ['a.cc'],", ")");
+ scratch.file("x/a.cc");
+
+ ConfiguredTarget target = getConfiguredTarget("//x:foo");
+ Variables variables = getLinkBuildVariables(target, LinkTargetType.STATIC_LIBRARY);
+
+ String interfaceLibraryBuilder =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_BUILDER_VARIABLE));
+ String interfaceLibraryInput =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_INPUT_VARIABLE));
+ String interfaceLibraryOutput =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.INTERFACE_LIBRARY_OUTPUT_VARIABLE));
+ String generateInterfaceLibrary =
+ Iterables.getOnlyElement(
+ getVariableValue(variables, CppLinkActionBuilder.GENERATE_INTERFACE_LIBRARY_VARIABLE));
+
+ assertThat(generateInterfaceLibrary).isEqualTo("no");
+ assertThat(interfaceLibraryInput).endsWith("ignored");
+ assertThat(interfaceLibraryOutput).endsWith("ignored");
+ assertThat(interfaceLibraryBuilder).endsWith("ignored");
+ }
}
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index 50d19a8..a3c8cbe 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -158,3 +158,8 @@
name = "srcs",
srcs = glob(["**"]) + ["//tools/cpp/test:srcs"],
)
+
+filegroup(
+ name = "link_dynamic_library",
+ srcs = ["link_dynamic_library.sh"],
+)
diff --git a/tools/cpp/BUILD.static b/tools/cpp/BUILD.static
index 32a323a..6f52c9d 100644
--- a/tools/cpp/BUILD.static
+++ b/tools/cpp/BUILD.static
@@ -94,3 +94,8 @@
"wrapper/bin/pydir/msvc*",
]),
)
+
+filegroup(
+ name = "link_dynamic_library",
+ srcs = ["link_dynamic_library.sh"],
+)
diff --git a/tools/cpp/link_dynamic_library.sh b/tools/cpp/link_dynamic_library.sh
new file mode 100755
index 0000000..ae79a80
--- /dev/null
+++ b/tools/cpp/link_dynamic_library.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+# This script handles interface library generation for dynamic library
+# link action.
+#
+# Bazel can be configured to generate external interface library script
+# to generate interface libraries in CppLinkAction for dynamic libraries.
+# This is not needed on Windows (as the "interface" libraries are
+# generated by default). This script therefore handles the cases when
+# external script is provided, or when no script should be used.
+
+set -eu
+
+E_LINKER_COMMAND_NOT_FOUND=12
+E_INTERFACE_BUILDER_NOT_FOUND=13
+
+# Should generate interface library switch (<yes|no>); if the value is "no",
+# following 3 args are ignored (but must be present)
+GENERATE_INTERFACE_LIBRARY="$1"
+# Tool which can generate interface library from dynamic library file
+INTERFACE_LIBRARY_BUILDER="$2"
+# Dynamic library from which we want to generate interface library
+DYNAMIC_LIBRARY="$3"
+# Resulting interface library
+INTERFACE_LIBRARY="$4"
+# The command used to generate the dynamic library
+LINKER_COMMAND="$5"
+
+shift 5
+
+if [ ! -e "$LINKER_COMMAND" ]; then
+ echo "Linker command ($LINKER_COMMAND) not found." 1>&2;
+ exit "$E_LINKER_COMMAND_NOT_FOUND"
+fi
+
+if [ "no" == "$GENERATE_INTERFACE_LIBRARY" ]; then
+ INTERFACE_GENERATION=:
+else
+ if [ ! -e "$INTERFACE_LIBRARY_BUILDER" ]; then
+ echo "Interface library builder ($INTERFACE_LIBRARY_BUILDER) not found." 1>&2;
+ exit "$E_INTERFACE_BUILDER_NOT_FOUND"
+ fi
+ INTERFACE_GENERATION="${INTERFACE_LIBRARY_BUILDER} ${DYNAMIC_LIBRARY} ${INTERFACE_LIBRARY}"
+fi
+
+${LINKER_COMMAND} "$@" && ${INTERFACE_GENERATION}