diff --git a/site/docs/crosstool-reference.md b/site/docs/crosstool-reference.md
index cb2d71c48ae8ca..ea2504d358439c 100644
--- a/site/docs/crosstool-reference.md
+++ b/site/docs/crosstool-reference.md
@@ -1035,4 +1035,11 @@ conditions.
libraries. This makes incremental relinking faster.
+
+ supports_dynamic_linker
+ |
+ If enabled, C++ rules will know the toolchain can produce shared
+ libraries.
+ |
+
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index de63cc9cc46bc1..176889ad03934b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -163,7 +163,7 @@ public static void init(
.addLinkstamps(ruleContext.getPrerequisites("linkstamp", Mode.TARGET));
Artifact soImplArtifact = null;
- boolean supportsDynamicLinker = ccToolchain.supportsDynamicLinker();
+ boolean supportsDynamicLinker = ccToolchain.supportsDynamicLinker(featureConfiguration);
// TODO(djasper): This is hacky. We should actually try to figure out whether we generate
// ccOutputs.
boolean createDynamicLibrary =
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 29748451c85a70..c5773d9eb7ea00 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
@@ -553,11 +553,10 @@ public boolean supportsGoldLinker() {
return toolchainInfo.supportsGoldLinker();
}
- /**
- * Returns whether the toolchain supports dynamic linking.
- */
- public boolean supportsDynamicLinker() {
- return toolchainInfo.supportsDynamicLinker();
+ /** Returns whether the toolchain supports dynamic linking. */
+ public boolean supportsDynamicLinker(FeatureConfiguration featureConfiguration) {
+ return toolchainInfo.supportsDynamicLinker()
+ || featureConfiguration.isEnabled(CppRuleClasses.SUPPORTS_DYNAMIC_LINKER);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
index f1e1ed75326d2a..6fd1c2eefcb79c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java
@@ -391,6 +391,11 @@ public static Label ccToolchainTypeAttribute(RuleDefinitionEnvironment env) {
/** A feature marking that the toolchain can use --start-lib/--end-lib flags */
public static final String SUPPORTS_START_END_LIB = "supports_start_end_lib";
+ /**
+ * A feature marking that the toolchain can produce binaries that load shared libraries at
+ * runtime.
+ */
+ public static final String SUPPORTS_DYNAMIC_LINKER = "supports_dynamic_linker";
/** Ancestor for all rules that do include scanning. */
public static final class CcIncludeScanningRule implements RuleDefinition {
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java
index 691600aea7901e..d4a996fd648c27 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppToolchainInfo.java
@@ -332,11 +332,7 @@ public static CppToolchainInfo create(
this.supportsFission = supportsFission;
this.supportsStartEndLib = supportsStartEndLib;
this.supportsEmbeddedRuntimes = supportsEmbeddedRuntimes;
- this.supportsDynamicLinker =
- supportsDynamicLinker
- || toolchainFeatures
- .getActivatableNames()
- .contains(CppRuleClasses.DYNAMIC_LINKING_MODE);
+ this.supportsDynamicLinker = supportsDynamicLinker;
this.supportsInterfaceSharedLibraries = supportsInterfaceSharedLibraries;
this.supportsGoldLinker = supportsGoldLinker;
this.toolchainNeedsPic = toolchainNeedsPic;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
index 016e9e1fa9f68d..fe1c57b8bfab0b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
@@ -308,7 +308,7 @@ private CcLinkingHelper initializeLinkingHelper(
helper.addDeps(deps);
// TODO(dougk): Configure output artifact with action_config
// once proto compile action is configurable from the crosstool.
- if (!toolchain.supportsDynamicLinker()) {
+ if (!toolchain.supportsDynamicLinker(featureConfiguration)) {
helper.setShouldCreateDynamicLibrary(false);
}
return helper;
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 41e07358748c1c..8c2baf013920d2 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
@@ -62,6 +62,9 @@ public boolean apply(Artifact artifact) {
public static final String DYNAMIC_LINKING_MODE_FEATURE =
"feature { name: '" + CppRuleClasses.DYNAMIC_LINKING_MODE + "'}";
+ public static final String SUPPORTS_DYNAMIC_LINKER_FEATURE =
+ "feature { name: '" + CppRuleClasses.SUPPORTS_DYNAMIC_LINKER + " enabled: true'}";
+
/** Feature expected by the C++ rules when pic build is requested */
public static final String PIC_FEATURE =
""
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
index d03c7a3fdb449e..586fefa9dbee8d 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcToolchainTest.java
@@ -774,7 +774,7 @@ private void writeStarlarkRule() throws IOException {
}
@Test
- public void testSupportsDynamicLinkerCheckFeatures() throws Exception {
+ public void testSupportsDynamicLinkerIsFalseWhenFeatureNotSet() throws Exception {
scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
getAnalysisMock()
@@ -789,7 +789,29 @@ public void testSupportsDynamicLinkerCheckFeatures() throws Exception {
CcToolchainProvider toolchainProvider =
(CcToolchainProvider) target.get(ToolchainInfo.PROVIDER);
- assertThat(toolchainProvider.supportsDynamicLinker()).isTrue();
+ assertThat(toolchainProvider.supportsDynamicLinker(FeatureConfiguration.EMPTY)).isFalse();
+ }
+
+ @Test
+ public void testSupportsDynamicLinkerIsTrueWhenFeatureSet() throws Exception {
+ scratch.file("a/BUILD", "cc_toolchain_alias(name = 'b')");
+
+ getAnalysisMock()
+ .ccSupport()
+ .setupCrosstool(
+ mockToolsConfig,
+ MockCcSupport.DYNAMIC_LINKING_MODE_FEATURE,
+ MockCcSupport.SUPPORTS_DYNAMIC_LINKER_FEATURE);
+
+ // To make sure the toolchain doesn't define linking_mode_flags { mode: DYNAMIC } as that would
+ // also result in supportsDynamicLinker returning true
+ useConfiguration("--compiler=compiler_no_dyn_linker");
+
+ ConfiguredTarget target = getConfiguredTarget("//a:b");
+ CcToolchainProvider toolchainProvider =
+ (CcToolchainProvider) target.get(ToolchainInfo.PROVIDER);
+
+ assertThat(toolchainProvider.supportsDynamicLinker(FeatureConfiguration.EMPTY)).isFalse();
}
// Tests CcCommon::enableStaticLinkCppRuntimesFeature when supports_embedded_runtimes is not