aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2017-09-20 10:25:48 +0200
committerGravatar László Csomor <laszlocsomor@google.com>2017-09-20 11:59:04 +0200
commit481657d6149b3c68b893ad8221ac1bccccf1060d (patch)
treedb33e89dbfd5f9df16143de5553cbaf1ab638159 /src/main/java/com/google/devtools/build/lib/rules
parente28b772d85a463e4fe154767d0d82c0fb9e63c3d (diff)
Windows: Make dynamic libraries available to binary at runtime
When copy_dynamic_libraries_to_binary is enabled, we copy the shared libraries required by the binary to the binary's directory. Bazel will throw errors if there are confilct actions generating the same artifacts. Change-Id: I09a5a599ca0ec7a67efd49d5aa89481450fa4e90 PiperOrigin-RevId: 169364498
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java52
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java54
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppRuleClasses.java3
6 files changed, 108 insertions, 29 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index 20b8ae5780..14eeb3bbe8 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -36,6 +36,7 @@ import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.ParamFileInfo;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.test.ExecutionInfo;
import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider;
@@ -236,6 +237,14 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
ruleContext.attributeError("linkshared", "'linkshared' used in non-shared library");
return null;
}
+
+ CcLinkParams linkParams =
+ collectCcLinkParams(
+ ruleContext,
+ linkStaticness != LinkStaticness.DYNAMIC,
+ isLinkShared(ruleContext),
+ linkopts);
+
CppLinkActionBuilder linkActionBuilder =
determineLinkerArguments(
ruleContext,
@@ -248,8 +257,7 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
cppCompilationContext.getTransitiveCompilationPrerequisites(),
fake,
binary,
- linkStaticness,
- linkopts,
+ linkParams,
linkCompileOutputSeparately);
linkActionBuilder.setUseTestOnlyFlags(ruleContext.isTestTarget());
if (linkStaticness == LinkStaticness.DYNAMIC) {
@@ -363,6 +371,17 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
}
}
+ // If the binary is linked dynamically and COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, collect
+ // all the dynamic libraries we need at runtime. Then copy these libraries next to the binary.
+ if (featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
+ filesToBuild =
+ NestedSetBuilder.fromNestedSet(filesToBuild)
+ .addAll(
+ createDynamicLibrariesCopyActions(
+ ruleContext, linkParams.getExecutionDynamicLibraries()))
+ .build();
+ }
+
// TODO(bazel-team): Do we need to put original shared libraries (along with
// mangled symlinks) into the RunfilesSupport object? It does not seem
// logical since all symlinked libraries will be linked anyway and would
@@ -462,8 +481,7 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
ImmutableSet<Artifact> compilationPrerequisites,
boolean fake,
Artifact binary,
- LinkStaticness linkStaticness,
- List<String> linkopts,
+ CcLinkParams linkParams,
boolean linkCompileOutputSeparately)
throws InterruptedException {
CppLinkActionBuilder builder =
@@ -512,9 +530,8 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
}
// Then the link params from the closure of deps.
- CcLinkParams linkParams = collectCcLinkParams(
- context, linkStaticness != LinkStaticness.DYNAMIC, isLinkShared(context), linkopts);
builder.addLinkParams(linkParams, context);
+
return builder;
}
@@ -689,6 +706,29 @@ public abstract class CcBinary implements RuleConfiguredTargetFactory {
}
/**
+ * Create the actions to symlink/copy execution dynamic libraries to binary directory so that they
+ * are available at runtime.
+ *
+ * @param executionDynamicLibraries The libraries to be copied.
+ * @return The result artifacts of the copies.
+ */
+ private static ImmutableList<Artifact> createDynamicLibrariesCopyActions(
+ RuleContext ruleContext, NestedSet<Artifact> executionDynamicLibraries) {
+ ImmutableList.Builder<Artifact> result = ImmutableList.builder();
+ for (Artifact target : executionDynamicLibraries) {
+ if (!ruleContext.getLabel().getPackageName().equals(target.getOwner().getPackageName())) {
+ // SymlinkAction on file is actually copy on Windows.
+ Artifact copy = ruleContext.getBinArtifact(target.getFilename());
+ ruleContext.registerAction(
+ new SymlinkAction(
+ ruleContext.getActionOwner(), target, copy, "Copying Execution Dynamic Library"));
+ result.add(copy);
+ }
+ }
+ return result.build();
+ }
+
+ /**
* Returns a new SpawnAction builder for generating dwp files, pre-initialized with standard
* settings.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
index 4fe0b4bebd..fd7a3cbb0a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java
@@ -1558,13 +1558,15 @@ public final class CcLibraryHelper {
CcLinkParams.Builder builder, boolean linkingStatically, boolean linkShared) {
builder.addLinkstamps(linkstamps.build(), cppCompilationContext);
builder.addTransitiveTargets(
- deps,
- CcLinkParamsInfo.TO_LINK_PARAMS,
- CcSpecificLinkParamsProvider.TO_LINK_PARAMS);
+ deps, CcLinkParamsInfo.TO_LINK_PARAMS, CcSpecificLinkParamsProvider.TO_LINK_PARAMS);
if (!neverlink) {
builder.addLibraries(
ccLinkingOutputs.getPreferredLibraries(
linkingStatically, /*preferPic=*/ linkShared || forcePic));
+ if (!linkingStatically) {
+ builder.addExecutionDynamicLibraries(
+ LinkerInputs.toLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries()));
+ }
builder.addLinkOpts(linkopts);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java
index 75b5662b1e..afb863101c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkParams.java
@@ -69,15 +69,19 @@ public final class CcLinkParams {
private final NestedSet<LinkOptions> linkOpts;
private final NestedSet<Linkstamp> linkstamps;
private final NestedSet<LibraryToLink> libraries;
+ private final NestedSet<Artifact> executionDynamicLibraries;
private final ExtraLinkTimeLibraries extraLinkTimeLibraries;
- private CcLinkParams(NestedSet<LinkOptions> linkOpts,
- NestedSet<Linkstamp> linkstamps,
- NestedSet<LibraryToLink> libraries,
- ExtraLinkTimeLibraries extraLinkTimeLibraries) {
+ private CcLinkParams(
+ NestedSet<LinkOptions> linkOpts,
+ NestedSet<Linkstamp> linkstamps,
+ NestedSet<LibraryToLink> libraries,
+ NestedSet<Artifact> executionDynamicLibraries,
+ ExtraLinkTimeLibraries extraLinkTimeLibraries) {
this.linkOpts = linkOpts;
this.linkstamps = linkstamps;
this.libraries = libraries;
+ this.executionDynamicLibraries = executionDynamicLibraries;
this.extraLinkTimeLibraries = extraLinkTimeLibraries;
}
@@ -106,6 +110,11 @@ public final class CcLinkParams {
return libraries;
}
+ /** @return the executionDynamicLibraries */
+ public NestedSet<Artifact> getExecutionDynamicLibraries() {
+ return executionDynamicLibraries;
+ }
+
/**
* The extra link time libraries; will be null if there are no such libraries.
*/
@@ -146,6 +155,8 @@ public final class CcLinkParams {
NestedSetBuilder.compileOrder();
private final NestedSetBuilder<LibraryToLink> librariesBuilder =
NestedSetBuilder.linkOrder();
+ private final NestedSetBuilder<Artifact> executionDynamicLibrariesBuilder =
+ NestedSetBuilder.stableOrder();
/**
* A builder for the list of link time libraries. Most builds
@@ -176,8 +187,12 @@ public final class CcLinkParams {
if (extraLinkTimeLibrariesBuilder != null) {
extraLinkTimeLibraries = extraLinkTimeLibrariesBuilder.build();
}
- return new CcLinkParams(linkOptsBuilder.build(), linkstampsBuilder.build(),
- librariesBuilder.build(), extraLinkTimeLibraries);
+ return new CcLinkParams(
+ linkOptsBuilder.build(),
+ linkstampsBuilder.build(),
+ librariesBuilder.build(),
+ executionDynamicLibrariesBuilder.build(),
+ extraLinkTimeLibraries);
}
public boolean add(CcLinkParamsStore store) {
@@ -263,6 +278,7 @@ public final class CcLinkParams {
linkOptsBuilder.addTransitive(args.getLinkopts());
linkstampsBuilder.addTransitive(args.getLinkstamps());
librariesBuilder.addTransitive(args.getLibraries());
+ executionDynamicLibrariesBuilder.addTransitive(args.getExecutionDynamicLibraries());
if (args.getExtraLinkTimeLibraries() != null) {
if (extraLinkTimeLibrariesBuilder == null) {
extraLinkTimeLibrariesBuilder = ExtraLinkTimeLibraries.builder();
@@ -306,6 +322,12 @@ public final class CcLinkParams {
return this;
}
+ /** Adds a collection of library artifacts. */
+ public Builder addExecutionDynamicLibraries(Iterable<Artifact> libraries) {
+ executionDynamicLibrariesBuilder.addAll(libraries);
+ return this;
+ }
+
/**
* Adds an extra link time library, a library that is actually
* built at link time.
@@ -334,6 +356,10 @@ public final class CcLinkParams {
if (!neverlink) {
addLibraries(linkingOutputs.getPreferredLibraries(linkingStatically,
linkShared || context.getFragment(CppConfiguration.class).forcePic()));
+ if (!linkingStatically) {
+ addExecutionDynamicLibraries(
+ LinkerInputs.toLibraryArtifacts(linkingOutputs.getExecutionDynamicLibraries()));
+ }
addLinkOpts(linkopts);
}
return this;
@@ -388,12 +414,12 @@ public final class CcLinkParams {
}
}
- /**
- * Empty CcLinkParams.
- */
- public static final CcLinkParams EMPTY = new CcLinkParams(
- NestedSetBuilder.<LinkOptions>emptySet(Order.LINK_ORDER),
- NestedSetBuilder.<Linkstamp>emptySet(Order.COMPILE_ORDER),
- NestedSetBuilder.<LibraryToLink>emptySet(Order.LINK_ORDER),
- null);
+ /** Empty CcLinkParams. */
+ public static final CcLinkParams EMPTY =
+ new CcLinkParams(
+ NestedSetBuilder.<LinkOptions>emptySet(Order.LINK_ORDER),
+ NestedSetBuilder.<Linkstamp>emptySet(Order.COMPILE_ORDER),
+ NestedSetBuilder.<LibraryToLink>emptySet(Order.LINK_ORDER),
+ NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER),
+ null);
}
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 194bb00484..2df7719e49 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
@@ -1736,11 +1736,15 @@ public class CppLinkActionBuilder {
for (LinkerInput input : linkerInputs) {
if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY) {
PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
- Preconditions.checkState(
- libDir.startsWith(solibDir),
- "Artifact '%s' is not under directory '%s'.",
- input.getArtifact(),
- solibDir);
+ // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, dynamic libraries are not symlinked
+ // under solibDir, so don't check it.
+ if (!featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
+ Preconditions.checkState(
+ libDir.startsWith(solibDir),
+ "Artifact '%s' is not under directory '%s'.",
+ input.getArtifact(),
+ solibDir);
+ }
if (libDir.equals(solibDir)) {
includeSolibDir = true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
index 10b3aea37a..42a596c992 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppModel.java
@@ -1543,7 +1543,11 @@ public final class CppModel {
// If shared library has neverlink=1, then leave it untouched. Otherwise,
// create a mangled symlink for it and from now on reference it through
// mangled name only.
- if (neverLink) {
+ //
+ // When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, we don't need to create the special
+ // solibDir, instead we use the original interface library and dynamic library.
+ if (neverLink
+ || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
result.addDynamicLibrary(interfaceLibrary);
result.addExecutionDynamicLibrary(dynamicLibrary);
} else {
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 a4ad59ec05..97ad0f391e 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
@@ -300,6 +300,9 @@ public class CppRuleClasses {
/** A string constant for a feature to disable WINDOWS_EXPORT_ALL_SYMBOLS. */
public static final String NO_WINDOWS_EXPORT_ALL_SYMBOLS = "no_windows_export_all_symbols";
+ /** A string constant for a feature to copy dynamic libraries to the binary's directory. */
+ public static final String COPY_DYNAMIC_LIBRARIES_TO_BINARY = "copy_dynamic_libraries_to_binary";
+
/**
* A string constant for a feature that indicates we are using a toolchain building for Windows.
*/