aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
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
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')
-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
-rw-r--r--src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java3
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CcLibraryConfiguredTargetTest.java46
-rw-r--r--src/test/py/bazel/bazel_windows_dynamic_link_test.py103
9 files changed, 259 insertions, 30 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.
*/
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 39c4b119f5..eaa5b694d1 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
@@ -406,6 +406,9 @@ public abstract class MockCcSupport {
+ " }"
+ "}";
+ public static final String COPY_DYNAMIC_LIBRARIES_TO_BINARY_CONFIGURATION =
+ "" + "feature { " + " name: 'copy_dynamic_libraries_to_binary'" + "}";
+
public static final String STATIC_LINK_TWEAKED_CONFIGURATION =
""
+ "artifact_name_pattern {"
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 98ba0c223f..0770ead00d 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
@@ -1186,6 +1186,52 @@ public class CcLibraryConfiguredTargetTest extends BuildViewTestCase {
}
@Test
+ public void testCcLinkParamsHasExecutionDynamicLibraries() throws Exception {
+ AnalysisMock.get()
+ .ccSupport()
+ .setupCrosstool(
+ mockToolsConfig, MockCcSupport.COPY_DYNAMIC_LIBRARIES_TO_BINARY_CONFIGURATION);
+ useConfiguration("--cpu=k8", "--features=copy_dynamic_libraries_to_binary");
+ ConfiguredTarget target =
+ scratchConfiguredTarget("a", "foo", "cc_library(name = 'foo', srcs = ['foo.cc'])");
+ Iterable<Artifact> libraries =
+ target
+ .get(CcLinkParamsInfo.PROVIDER)
+ .getCcLinkParams(false, true)
+ .getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).doesNotContain("bin a/libfoo.ifso");
+ assertThat(artifactsToStrings(libraries)).contains("bin a/libfoo.so");
+ }
+
+ @Test
+ public void testCcLinkParamsHasExecutionDynamicLibrariesWithoutCopyFeature() throws Exception {
+ useConfiguration("--cpu=k8");
+ ConfiguredTarget target =
+ scratchConfiguredTarget("a", "foo", "cc_library(name = 'foo', srcs = ['foo.cc'])");
+ Iterable<Artifact> libraries =
+ target
+ .get(CcLinkParamsInfo.PROVIDER)
+ .getCcLinkParams(false, true)
+ .getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).doesNotContain("bin _solib_k8/liba_Slibfoo.ifso");
+ assertThat(artifactsToStrings(libraries)).contains("bin _solib_k8/liba_Slibfoo.so");
+ }
+
+ @Test
+ public void testCcLinkParamsDoNotHasExecutionDynamicLibraries() throws Exception {
+ useConfiguration("--cpu=k8");
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "a", "foo", "cc_library(name = 'foo', srcs = ['foo.cc'], linkstatic=1)");
+ Iterable<Artifact> libraries =
+ target
+ .get(CcLinkParamsInfo.PROVIDER)
+ .getCcLinkParams(false, true)
+ .getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).isEmpty();
+ }
+
+ @Test
public void forbidBuildingAndWrappingSameLibraryIdentifier() throws Exception {
useConfiguration("--cpu=k8");
checkError(
diff --git a/src/test/py/bazel/bazel_windows_dynamic_link_test.py b/src/test/py/bazel/bazel_windows_dynamic_link_test.py
index 33440cd033..1093037ad0 100644
--- a/src/test/py/bazel/bazel_windows_dynamic_link_test.py
+++ b/src/test/py/bazel/bazel_windows_dynamic_link_test.py
@@ -23,6 +23,7 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
self.ScratchFile('WORKSPACE')
self.ScratchFile('BUILD', [
'package(',
+ ' default_visibility = ["//visibility:public"],',
' features=["windows_export_all_symbols"]',
')',
'',
@@ -49,6 +50,7 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
' linkstatic = 0,',
')',
])
+
self.ScratchFile('a.cc', [
'#include <stdio.h>',
'#include "a.h"',
@@ -58,6 +60,7 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
' printf("Hello A, %d\\n", a);',
'}',
])
+
self.ScratchFile('b.cc', [
'#include <stdio.h>',
'#include "a.h"',
@@ -88,7 +91,7 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
self.ScratchFile('b.h',
[line.replace('%{name}', 'B') for line in header_temp])
- self.ScratchFile('c.cc', [
+ c_cc_content = [
'#include <stdio.h>',
'#include "a.h"',
'#include "b.h"',
@@ -103,7 +106,21 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
' hello_C();',
' return 0;',
'}',
+ ]
+
+ self.ScratchFile('c.cc', c_cc_content)
+
+ self.ScratchFile('lib/BUILD', [
+ 'cc_library(',
+ ' name = "A",',
+ ' srcs = ["dummy.cc"],',
+ ' features = ["windows_export_all_symbols"],',
+ ' visibility = ["//visibility:public"],',
+ ')',
])
+ self.ScratchFile('lib/dummy.cc', ['void dummy() {}'])
+
+ self.ScratchFile('main/main.cc', c_cc_content)
def getBazelInfo(self, info_key):
exit_code, stdout, stderr = self.RunBazel(['info', info_key])
@@ -188,6 +205,90 @@ class BazelWindowsDynamicLinkTest(test_base.TestBase):
# c_exe
self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'C.exe')))
+ def testBuildCcBinaryFromDifferentPackage(self):
+ self.createProjectFiles()
+ self.ScratchFile('main/BUILD', [
+ 'cc_binary(',
+ ' name = "main",',
+ ' srcs = ["main.cc"],',
+ ' deps = ["//:B"],',
+ ' linkstatic = 0,'
+ ')',
+ ])
+ bazel_bin = self.getBazelInfo('bazel-bin')
+
+ # We dynamically link to msvcrt by setting USE_DYNAMIC_CRT=1
+ exit_code, _, stderr = self.RunBazel(
+ ['build', '//main:main', '--action_env=USE_DYNAMIC_CRT=1'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ # Test if libA.so and libB.so are copied to the directory of main.exe
+ main_bin = os.path.join(bazel_bin, 'main/main.exe')
+ self.assertTrue(os.path.exists(main_bin))
+ self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'main/libA.so')))
+ self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'main/libB.so')))
+
+ # Run the binary to see if it runs successfully
+ exit_code, stdout, stderr = self.RunProgram([main_bin])
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(['Hello A, 1', 'Hello A, 2', 'Hello B', 'Hello C'], stdout)
+
+ def testBuildCcBinaryDependsOnConflictDLLs(self):
+ self.createProjectFiles()
+ self.ScratchFile(
+ 'main/BUILD',
+ [
+ 'cc_binary(',
+ ' name = "main",',
+ ' srcs = ["main.cc"],',
+ ' deps = ["//:B", "//lib:A"],', # Transitively depends on //:A
+ ' linkstatic = 0,'
+ ')',
+ ])
+
+ # //main:main depends on both //lib:A and //:A,
+ # their dlls are both called libA.so,
+ # so there should be a conflict error
+ exit_code, _, stderr = self.RunBazel(['build', '//main:main'])
+ self.AssertExitCode(exit_code, 1, stderr)
+ self.assertIn(
+ 'ERROR: file \'main/libA.so\' is generated by these conflicting '
+ 'actions:',
+ ''.join(stderr))
+
+ def testBuildDifferentCcBinariesDependOnConflictDLLs(self):
+ self.createProjectFiles()
+ self.ScratchFile(
+ 'main/BUILD',
+ [
+ 'cc_binary(',
+ ' name = "main",',
+ ' srcs = ["main.cc"],',
+ ' deps = ["//:B"],', # Transitively depends on //:A
+ ' linkstatic = 0,'
+ ')',
+ '',
+ 'cc_binary(',
+ ' name = "other_main",',
+ ' srcs = ["other_main.cc"],',
+ ' deps = ["//lib:A"],',
+ ' linkstatic = 0,'
+ ')',
+ ])
+ self.ScratchFile('main/other_main.cc', ['int main() {return 0;}'])
+
+ # Building //main:main should succeed
+ exit_code, _, stderr = self.RunBazel(['build', '//main:main'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ # Building //main:other_main after //main:main should fail
+ exit_code, _, stderr = self.RunBazel(['build', '//main:other_main'])
+ self.AssertExitCode(exit_code, 1, stderr)
+ self.assertIn(
+ 'ERROR: file \'main/libA.so\' is generated by these conflicting '
+ 'actions:',
+ ''.join(stderr))
+
if __name__ == '__main__':
unittest.main()