aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java131
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcImportRule.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java23
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkActionBuilder.java32
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java26
-rw-r--r--src/test/java/com/google/devtools/build/lib/packages/util/MockCcSupport.java8
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportConfiguredTargetTest.java250
-rw-r--r--src/test/py/bazel/BUILD7
-rw-r--r--src/test/py/bazel/cc_import_test.py257
-rw-r--r--src/test/py/bazel/test_base.py5
13 files changed, 727 insertions, 39 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
index 08e70cfbbc..6ed5a96106 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -112,10 +112,7 @@ public class BazelCppRuleClasses {
static final String[] DEPS_ALLOWED_RULES =
new String[] {
- "cc_inc_library",
- "cc_library",
- "objc_library",
- "cc_proto_library",
+ "cc_inc_library", "cc_library", "objc_library", "cc_proto_library", "cc_import",
};
/**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
index abfe81ce26..b9173e71b9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
@@ -14,13 +14,20 @@
package com.google.devtools.build.lib.rules.cpp;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode;
+import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
+import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.vfs.PathFragment;
/**
* A ConfiguredTarget for <code>cc_import</code> rule.
@@ -35,9 +42,125 @@ public abstract class CcImport implements RuleConfiguredTargetFactory {
@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws RuleErrorException, InterruptedException {
+ Artifact staticLibrary = ruleContext.getPrerequisiteArtifact("static_library", Mode.TARGET);
+ Artifact sharedLibrary = ruleContext.getPrerequisiteArtifact("shared_library", Mode.TARGET);
+ Artifact interfaceLibrary =
+ ruleContext.getPrerequisiteArtifact("interface_library", Mode.TARGET);
+
+ boolean systemProvided = ruleContext.attributes().get("system_provided", Type.BOOLEAN);
+ // If the shared library will be provided by system during runtime, users are not supposed to
+ // specify shared_library.
+ if (systemProvided && sharedLibrary != null) {
+ ruleContext.ruleError(
+ "'shared_library' shouldn't be specified when 'system_provided' is true");
+ }
+ // If a shared library won't be provided by system during runtime and we are linking the shared
+ // library through interface library, the shared library must be specified.
+ if (!systemProvided && sharedLibrary == null && interfaceLibrary != null) {
+ ruleContext.ruleError(
+ "'shared_library' should be specified when 'system_provided' is false");
+ }
+
+ // Create CcLibraryHelper
+ CcToolchainProvider ccToolchain =
+ CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext);
+ FeatureConfiguration featureConfiguration =
+ CcCommon.configureFeatures(ruleContext, ccToolchain);
+ FdoSupportProvider fdoSupport =
+ CppHelper.getFdoSupportUsingDefaultCcToolchainAttribute(ruleContext);
+ CcLibraryHelper helper =
+ new CcLibraryHelper(ruleContext, semantics, featureConfiguration, ccToolchain, fdoSupport);
+
+ // Add headers
+ final CcCommon common = new CcCommon(ruleContext);
+ helper.addPublicHeaders(common.getHeaders());
+ helper.setHeadersCheckingMode(HeadersCheckingMode.STRICT);
+
+ // Get alwayslink attribute
+ boolean alwayslink = ruleContext.attributes().get("alwayslink", Type.BOOLEAN);
+ ArtifactCategory staticLibraryCategory =
+ alwayslink ? ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY : ArtifactCategory.STATIC_LIBRARY;
+
+ PathFragment labelName = PathFragment.create(ruleContext.getLabel().getName());
+ String libraryIdentifier =
+ ruleContext
+ .getPackageDirectory()
+ .getRelative(labelName.replaceName("lib" + labelName.getBaseName()))
+ .getPathString();
+
+ if (staticLibrary != null) {
+ if (CppFileTypes.PIC_ARCHIVE.matches(staticLibrary.getPath())) {
+ helper.addPicStaticLibraries(
+ ImmutableList.of(
+ LinkerInputs.opaqueLibraryToLink(
+ staticLibrary, staticLibraryCategory, libraryIdentifier, alwayslink)));
+ } else {
+ helper.addStaticLibraries(
+ ImmutableList.of(
+ LinkerInputs.opaqueLibraryToLink(
+ staticLibrary, staticLibraryCategory, libraryIdentifier, alwayslink)));
+ }
+ }
+
+ // Now we are going to have some platform dependent behaviors
+ boolean targetWindows = featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS);
+
+ Iterable<LibraryToLink> dynamicLibraryList = null;
+ Iterable<LibraryToLink> executionDynamicLibraryList = null;
+ if (sharedLibrary != null) {
+ if (targetWindows) {
+ executionDynamicLibraryList =
+ ImmutableList.of(
+ LinkerInputs.opaqueLibraryToLink(
+ sharedLibrary, ArtifactCategory.DYNAMIC_LIBRARY, libraryIdentifier));
+ } else {
+ executionDynamicLibraryList =
+ ImmutableList.of(
+ LinkerInputs.solibLibraryToLink(
+ common.getDynamicLibrarySymlink(sharedLibrary, true),
+ sharedLibrary,
+ libraryIdentifier));
+ }
+ helper.addExecutionDynamicLibraries(executionDynamicLibraryList);
+ }
+
+ if (interfaceLibrary != null) {
+ if (targetWindows) {
+ dynamicLibraryList =
+ ImmutableList.of(
+ LinkerInputs.opaqueLibraryToLink(
+ interfaceLibrary, ArtifactCategory.INTERFACE_LIBRARY, libraryIdentifier));
+ } else {
+ dynamicLibraryList =
+ ImmutableList.of(
+ LinkerInputs.solibLibraryToLink(
+ common.getDynamicLibrarySymlink(interfaceLibrary, true),
+ interfaceLibrary,
+ libraryIdentifier));
+ }
+ } else {
+ // If interface_library is not specified and we are not building for Windows, then the dynamic
+ // library required at linking time is the same as the one required at execution time.
+ if (!targetWindows) {
+ dynamicLibraryList = executionDynamicLibraryList;
+ } else if (staticLibrary == null) {
+ ruleContext.ruleError(
+ "'interface library' must be specified when using cc_import for shared library on"
+ + " Windows");
+ }
+ }
+
+ if (dynamicLibraryList != null) {
+ helper.addDynamicLibraries(dynamicLibraryList);
+ }
+
+ CcLibraryHelper.Info info = helper.build();
+
return new RuleConfiguredTargetBuilder(ruleContext)
- .setFilesToBuild(NestedSetBuilder.emptySet(Order.STABLE_ORDER))
- .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
+ .addProviders(info.getProviders())
+ .addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider())
+ .addOutputGroups(info.getOutputGroups())
+ .addProvider(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY))
.build();
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImportRule.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImportRule.java
index 298908bce1..262e4cc2ad 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImportRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImportRule.java
@@ -34,23 +34,29 @@ public final class CcImportRule implements RuleDefinition {
public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
return builder
/*<!-- #BLAZE_RULE($cc_import).ATTRIBUTE(static_library) -->
- A single precompiled static library
+ A single precompiled static library.
+ Permited file types: <code>.a</code>, <code>.pic.a</code> or <code>.lib</code>
<!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
.add(
attr("static_library", LABEL)
- .allowedFileTypes(CppFileTypes.ARCHIVE)
+ .allowedFileTypes(CppFileTypes.ARCHIVE, CppFileTypes.PIC_ARCHIVE)
)
/*<!-- #BLAZE_RULE($cc_import).ATTRIBUTE(shared_library) -->
A single precompiled shared library
+ Permited file types: <code>.so</code>, <code>.dll</code> or <code>.dylib</code>
<!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
.add(attr("shared_library", LABEL)
.allowedFileTypes(CppFileTypes.SHARED_LIBRARY)
)
/*<!-- #BLAZE_RULE($cc_import).ATTRIBUTE(shared_library) -->
A single interface library for linking the shared library
+ Permited file types: <code>.ifso</code>, <code>.tbd</code>, <code>.so</code> or
+ <code>.dylib</code>
<!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
.add(attr("interface_library", LABEL)
- .allowedFileTypes(CppFileTypes.INTERFACE_SHARED_LIBRARY))
+ .allowedFileTypes(
+ CppFileTypes.INTERFACE_SHARED_LIBRARY,
+ CppFileTypes.UNIX_SHARED_LIBRARY))
/*<!-- #BLAZE_RULE($cc_import).ATTRIBUTE(hdrs) -->
The list of header files published by
this precompiled library to be directly included by sources in dependent rules.
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 4500ab109c..461ed4d11c 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
@@ -256,14 +256,16 @@ public abstract class CcLibrary implements RuleConfiguredTargetFactory {
helper.addStaticLibraries(alwayslinkLibrariesFromSrcs);
helper.addPicStaticLibraries(picStaticLibrariesFromSrcs);
helper.addPicStaticLibraries(picAlwayslinkLibrariesFromSrcs);
- helper.addDynamicLibraries(
+ Iterable<LibraryToLink> dynamicLibraries =
Iterables.transform(
precompiledFiles.getSharedLibraries(),
library ->
LinkerInputs.solibLibraryToLink(
common.getDynamicLibrarySymlink(library, true),
library,
- CcLinkingOutputs.libraryIdentifierOf(library))));
+ CcLinkingOutputs.libraryIdentifierOf(library)));
+ helper.addDynamicLibraries(dynamicLibraries);
+ helper.addExecutionDynamicLibraries(dynamicLibraries);
CcLibraryHelper.Info info = helper.build();
/*
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 ee2d8bc680..fbd1322b71 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
@@ -303,6 +303,7 @@ public final class CcLibraryHelper {
private final List<LibraryToLink> staticLibraries = new ArrayList<>();
private final List<LibraryToLink> picStaticLibraries = new ArrayList<>();
private final List<LibraryToLink> dynamicLibraries = new ArrayList<>();
+ private final List<LibraryToLink> executionDynamicLibraries = new ArrayList<>();
private boolean emitLinkActions = true;
private boolean emitLinkActionsIfEmpty;
@@ -653,6 +654,12 @@ public final class CcLibraryHelper {
return this;
}
+ /** Add the corresponding files as dynamic libraries required at runtime */
+ public CcLibraryHelper addExecutionDynamicLibraries(Iterable<LibraryToLink> libraries) {
+ Iterables.addAll(executionDynamicLibraries, libraries);
+ return this;
+ }
+
public CcLibraryHelper setCopts(ImmutableList<String> copts) {
this.copts = Preconditions.checkNotNull(copts);
return this;
@@ -988,8 +995,10 @@ public final class CcLibraryHelper {
}
}
CcLinkingOutputs originalLinkingOutputs = ccLinkingOutputs;
- if (!(
- staticLibraries.isEmpty() && picStaticLibraries.isEmpty() && dynamicLibraries.isEmpty())) {
+ if (!(staticLibraries.isEmpty()
+ && picStaticLibraries.isEmpty()
+ && dynamicLibraries.isEmpty()
+ && executionDynamicLibraries.isEmpty())) {
CcLinkingOutputs.Builder newOutputsBuilder = new CcLinkingOutputs.Builder();
if (!ccOutputs.isEmpty()) {
@@ -998,7 +1007,9 @@ public final class CcLibraryHelper {
newOutputsBuilder.merge(originalLinkingOutputs);
ImmutableSetMultimap<String, LibraryToLink> precompiledLibraryMap =
CcLinkingOutputs.getLibrariesByIdentifier(
- Iterables.concat(staticLibraries, picStaticLibraries, dynamicLibraries));
+ Iterables.concat(
+ staticLibraries, picStaticLibraries,
+ dynamicLibraries, executionDynamicLibraries));
ImmutableSetMultimap<String, LibraryToLink> linkedLibraryMap =
originalLinkingOutputs.getLibrariesByIdentifier();
for (String matchingIdentifier :
@@ -1031,7 +1042,7 @@ public final class CcLibraryHelper {
.addStaticLibraries(staticLibraries)
.addPicStaticLibraries(picStaticLibraries)
.addDynamicLibraries(dynamicLibraries)
- .addExecutionDynamicLibraries(dynamicLibraries)
+ .addExecutionDynamicLibraries(executionDynamicLibraries)
.build();
}
@@ -1567,7 +1578,9 @@ public final class CcLibraryHelper {
builder.addLibraries(
ccLinkingOutputs.getPreferredLibraries(
linkingStatically, /*preferPic=*/ linkShared || forcePic));
- if (!linkingStatically) {
+ if (!linkingStatically
+ || (ccLinkingOutputs.getStaticLibraries().isEmpty()
+ && ccLinkingOutputs.getPicStaticLibraries().isEmpty())) {
builder.addExecutionDynamicLibraries(
LinkerInputs.toLibraryArtifacts(ccLinkingOutputs.getExecutionDynamicLibraries()));
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java
index d92add9ee6..fd2c60fcc9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java
@@ -132,7 +132,9 @@ public final class CppFileTypes {
public static final FileType LTO_INDEXING_OBJECT_FILE = FileType.of(".indexing.o");
public static final FileType SHARED_LIBRARY = FileType.of(".so", ".dylib", ".dll");
- public static final FileType INTERFACE_SHARED_LIBRARY = FileType.of(".ifso");
+ // Unix shared libraries can be passed to linker, but not .dll on Windows
+ public static final FileType UNIX_SHARED_LIBRARY = FileType.of(".so", ".dylib");
+ public static final FileType INTERFACE_SHARED_LIBRARY = FileType.of(".ifso", ".tbd");
public static final FileType LINKER_SCRIPT = FileType.of(".ld", ".lds", ".ldscript");
// Windows DEF file: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
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 52fdab4b83..1777257632 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
@@ -1856,14 +1856,17 @@ public class CppLinkActionBuilder {
Map<Artifact, Artifact> ltoMap) {
boolean includeRuntimeSolibDir = false;
for (LinkerInput input : runtimeLinkerInputs) {
- if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY) {
+ if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY
+ || input.getArtifactCategory() == ArtifactCategory.INTERFACE_LIBRARY) {
PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
- Preconditions.checkState(
- runtimeSolibDir != null && libDir.equals(runtimeSolibDir),
- "Artifact '%s' is not under directory '%s'.",
- input.getArtifact(),
- solibDir);
- includeRuntimeSolibDir = true;
+ if (!featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) {
+ Preconditions.checkState(
+ runtimeSolibDir != null && libDir.equals(runtimeSolibDir),
+ "Artifact '%s' is not under directory '%s'.",
+ input.getArtifact(),
+ solibDir);
+ includeRuntimeSolibDir = true;
+ }
addDynamicInputLinkOptions(
input,
librariesToLink,
@@ -1887,19 +1890,20 @@ public class CppLinkActionBuilder {
Map<Artifact, Artifact> ltoMap) {
boolean includeSolibDir = false;
for (LinkerInput input : linkerInputs) {
- if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY) {
+ if (input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY
+ || input.getArtifactCategory() == ArtifactCategory.INTERFACE_LIBRARY) {
PathFragment libDir = input.getArtifact().getExecPath().getParentDirectory();
// When COPY_DYNAMIC_LIBRARIES_TO_BINARY is enabled, dynamic libraries are not symlinked
- // under solibDir, so don't check it.
+ // under solibDir, so don't check it and don't include solibDir.
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;
+ if (libDir.equals(solibDir)) {
+ includeSolibDir = true;
+ }
}
addDynamicInputLinkOptions(
input,
@@ -1927,7 +1931,9 @@ public class CppLinkActionBuilder {
ImmutableSet.Builder<String> rpathRootsForExplicitSoDeps,
PathFragment solibDir,
String rpathRoot) {
- Preconditions.checkState(input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY);
+ Preconditions.checkState(
+ input.getArtifactCategory() == ArtifactCategory.DYNAMIC_LIBRARY
+ || input.getArtifactCategory() == ArtifactCategory.INTERFACE_LIBRARY);
Preconditions.checkState(
!Link.useStartEndLib(input, CppHelper.getArchiveType(cppConfiguration, toolchain)));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
index 3dbbd3c722..469d424da5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LinkerInputs.java
@@ -267,17 +267,21 @@ public abstract class LinkerInputs {
String libraryIdentifier,
Iterable<Artifact> objectFiles,
ImmutableMap<Artifact, Artifact> ltoBitcodeFiles,
- ImmutableMap<Artifact, LtoBackendArtifacts> sharedNonLtoBackends) {
+ ImmutableMap<Artifact, LtoBackendArtifacts> sharedNonLtoBackends,
+ boolean allowArchiveTypeInAlwayslink) {
String basename = libraryArtifact.getFilename();
switch (category) {
case ALWAYSLINK_STATIC_LIBRARY:
- Preconditions.checkState(Link.LINK_LIBRARY_FILETYPES.matches(basename));
+ Preconditions.checkState(
+ Link.LINK_LIBRARY_FILETYPES.matches(basename)
+ || (allowArchiveTypeInAlwayslink && Link.ARCHIVE_FILETYPES.matches(basename)));
break;
case STATIC_LIBRARY:
Preconditions.checkState(Link.ARCHIVE_FILETYPES.matches(basename));
break;
+ case INTERFACE_LIBRARY:
case DYNAMIC_LIBRARY:
Preconditions.checkState(Link.SHARED_LIBRARY_FILETYPES.matches(basename));
break;
@@ -427,7 +431,8 @@ public abstract class LinkerInputs {
CcLinkingOutputs.libraryIdentifierOf(artifact),
/* objectFiles= */ null,
/* ltoBitcodeFiles= */ null,
- /* sharedNonLtoBackends= */ null);
+ /* sharedNonLtoBackends= */ null,
+ /* allowArchiveTypeInAlwayslink= */ false);
}
public static LibraryToLink opaqueLibraryToLink(
@@ -438,7 +443,17 @@ public abstract class LinkerInputs {
libraryIdentifier,
/* objectFiles= */ null,
/* ltoBitcodeFiles= */ null,
- /* sharedNonLtoBackends= */ null);
+ /* sharedNonLtoBackends= */ null,
+ /* allowArchiveTypeInAlwayslink= */ false);
+ }
+
+ public static LibraryToLink opaqueLibraryToLink(
+ Artifact artifact,
+ ArtifactCategory category,
+ String libraryIdentifier,
+ boolean allowArchiveTypeInAlwayslink) {
+ return new CompoundLibraryToLink(
+ artifact, category, libraryIdentifier, null, null, null, allowArchiveTypeInAlwayslink);
}
/** Creates a library to link with the specified object files. */
@@ -450,7 +465,8 @@ public abstract class LinkerInputs {
ImmutableMap<Artifact, Artifact> ltoBitcodeFiles,
ImmutableMap<Artifact, LtoBackendArtifacts> sharedNonLtoBackends) {
return new CompoundLibraryToLink(
- library, category, libraryIdentifier, objectFiles, ltoBitcodeFiles, sharedNonLtoBackends);
+ library, category, libraryIdentifier, objectFiles, ltoBitcodeFiles, sharedNonLtoBackends,
+ /* allowArchiveTypeInAlwayslink= */ false);
}
public static Iterable<Artifact> toNonSolibArtifacts(Iterable<LibraryToLink> libraries) {
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 326539f231..c7a78d4fe3 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
@@ -414,6 +414,14 @@ 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 TARGETS_WINDOWS_CONFIGURATION =
+ ""
+ + "feature {"
+ + " name: 'targets_windows'"
+ + " implies: 'copy_dynamic_libraries_to_binary'"
+ + " enabled: true"
+ + "}";
+
public static final String STATIC_LINK_TWEAKED_CONFIGURATION =
""
+ "artifact_name_pattern {"
diff --git a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportConfiguredTargetTest.java
index e7fa1657cd..b11b104a45 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportConfiguredTargetTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/cpp/CcImportConfiguredTargetTest.java
@@ -15,8 +15,14 @@
package com.google.devtools.build.lib.rules.cpp;
-import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import static com.google.common.truth.Truth.assertThat;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.util.AnalysisMock;
+import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import com.google.devtools.build.lib.packages.util.MockCcSupport;
+import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -29,7 +35,8 @@ public class CcImportConfiguredTargetTest extends BuildViewTestCase {
@Test
public void testCcImportRule() throws Exception {
- scratch.file("third_party/BUILD",
+ scratch.file(
+ "third_party/BUILD",
"cc_import(",
" name = 'a_import',",
" static_library = 'A.a',",
@@ -37,7 +44,246 @@ public class CcImportConfiguredTargetTest extends BuildViewTestCase {
" interface_library = 'A.ifso',",
" hdrs = ['a.h'],",
" alwayslink = 1,",
+ " system_provided = 0,",
")");
getConfiguredTarget("//third_party:a_import");
}
+
+ @Test
+ public void testWrongCcImportDefinitions() throws Exception {
+ checkError("a", "foo",
+ "'//a:libfoo.so' does not produce any cc_import static_library files "
+ + "(expected .a, .lib or .pic.a)",
+ "cc_import(",
+ " name = 'foo',",
+ " static_library = 'libfoo.so',",
+ ")"
+ );
+ checkError("b", "foo",
+ "'//b:libfoo.a' does not produce any cc_import shared_library files "
+ + "(expected .so, .dylib or .dll)",
+ "cc_import(",
+ " name = 'foo',",
+ " shared_library = 'libfoo.a',",
+ ")"
+ );
+ checkError("c", "foo",
+ "'//c:libfoo.a' does not produce any cc_import interface_library files "
+ + "(expected .ifso, .tbd, .so or .dylib)",
+ "cc_import(",
+ " name = 'foo',",
+ " shared_library = 'libfoo.dll',",
+ " interface_library = 'libfoo.a',",
+ ")"
+ );
+ checkError("d", "foo",
+ "'shared_library' shouldn't be specified when 'system_provided' is true",
+ "cc_import(",
+ " name = 'foo',",
+ " shared_library = 'libfoo.so',",
+ " system_provided = 1,",
+ ")"
+ );
+ checkError("e", "foo",
+ "'shared_library' should be specified when 'system_provided' is false",
+ "cc_import(",
+ " name = 'foo',",
+ " interface_library = 'libfoo.ifso',",
+ " system_provided = 0,",
+ ")"
+ );
+ }
+
+ @Test
+ public void testWrongCcImportDefinitionsOnWindows() throws Exception {
+ AnalysisMock.get()
+ .ccSupport()
+ .setupCrosstool(
+ mockToolsConfig,
+ MockCcSupport.COPY_DYNAMIC_LIBRARIES_TO_BINARY_CONFIGURATION,
+ MockCcSupport.TARGETS_WINDOWS_CONFIGURATION);
+ useConfiguration();
+ checkError("a", "foo",
+ "'interface library' must be specified when using cc_import for shared library on Windows",
+ "cc_import(",
+ " name = 'foo',",
+ " shared_library = 'libfoo.dll',",
+ ")"
+ );
+ }
+
+ @Test
+ public void testCcImportWithStaticLibrary() throws Exception {
+ ConfiguredTarget target =
+ scratchConfiguredTarget("a", "foo", "cc_import(name = 'foo', static_library = 'libfoo.a')");
+ Iterable<Artifact> libraries =
+ LinkerInputs.toNonSolibArtifacts(
+ target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, false).getLibraries());
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+
+ libraries =
+ LinkerInputs.toNonSolibArtifacts(
+ target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, true).getLibraries());
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+
+ libraries =
+ LinkerInputs.toNonSolibArtifacts(
+ target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, false).getLibraries());
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+
+ libraries =
+ LinkerInputs.toNonSolibArtifacts(
+ target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, true).getLibraries());
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+ }
+
+ @Test
+ public void testCcImportWithSharedLibrary() throws Exception {
+ useConfiguration("--cpu=k8");
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "a", "foo", "cc_import(name = 'foo', shared_library = 'libfoo.so')");
+ CcLinkParams ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, false);
+ Iterable<Artifact> libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ Iterable<Artifact> executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, false);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+ }
+
+ @Test
+ public void testCcImportWithInterfaceSharedLibrary() throws Exception {
+ useConfiguration("--cpu=k8");
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "b",
+ "foo",
+ "cc_import(name = 'foo', shared_library = 'libfoo.so',"
+ + " interface_library = 'libfoo.ifso')");
+ CcLinkParams ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, false);
+ Iterable<Artifact> libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ Iterable<Artifact> executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src b/libfoo.ifso");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sb_Cfoo___Ub/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src b/libfoo.ifso");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sb_Cfoo___Ub/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, false);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src b/libfoo.ifso");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sb_Cfoo___Ub/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src b/libfoo.ifso");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sb_Cfoo___Ub/libfoo.so");
+ }
+
+ @Test
+ public void testCcImportWithBothStaticAndSharedLibraries() throws Exception {
+ useConfiguration("--cpu=k8");
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "a",
+ "foo",
+ "cc_import(name = 'foo', static_library = 'libfoo.a', shared_library = 'libfoo.so')");
+ CcLinkParams ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, false);
+ Iterable<Artifact> libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ Iterable<Artifact> executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.so");
+ assertThat(artifactsToStrings(executionDynamicLibraries))
+ .containsExactly("bin _solib_k8/_U_S_Sa_Cfoo___Ua/libfoo.so");
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, false);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+ assertThat(artifactsToStrings(executionDynamicLibraries)).isEmpty();
+
+ ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(true, true);
+ libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.a");
+ assertThat(artifactsToStrings(executionDynamicLibraries)).isEmpty();
+ }
+
+ @Test
+ public void testCcImportWithAlwaysLinkStaticLibrary() throws Exception {
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "a", "foo", "cc_import(name = 'foo', static_library = 'libfoo.a', alwayslink = 1)");
+ LibraryToLink libraryToLink =
+ target
+ .get(CcLinkParamsInfo.PROVIDER)
+ .getCcLinkParams(false, false)
+ .getLibraries()
+ .toList()
+ .get(0);
+ assertThat(libraryToLink.getArtifactCategory())
+ .isEqualTo(ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY);
+ }
+
+ @Test
+ public void testCcImportSystemProvidedIsTrue() throws Exception {
+ ConfiguredTarget target =
+ scratchConfiguredTarget(
+ "a",
+ "foo",
+ "cc_import(name = 'foo', interface_library = 'libfoo.ifso', system_provided = 1)");
+ CcLinkParams ccLinkParams = target.get(CcLinkParamsInfo.PROVIDER).getCcLinkParams(false, false);
+ Iterable<Artifact> libraries = LinkerInputs.toNonSolibArtifacts(ccLinkParams.getLibraries());
+ Iterable<Artifact> executionDynamicLibraries = ccLinkParams.getExecutionDynamicLibraries();
+ assertThat(artifactsToStrings(libraries)).containsExactly("src a/libfoo.ifso");
+ assertThat(artifactsToStrings(executionDynamicLibraries)).isEmpty();
+ }
+
+ @Test
+ public void testCcImportProvideHeaderFiles() throws Exception {
+ Iterable<Artifact> headers =
+ scratchConfiguredTarget(
+ "a",
+ "foo",
+ "cc_import(name = 'foo', static_library = 'libfoo.a', hdrs = ['foo.h'])")
+ .getProvider(CppCompilationContext.class)
+ .getDeclaredIncludeSrcs();
+ assertThat(artifactsToStrings(headers)).containsExactly("src a/foo.h");
+ }
}
diff --git a/src/test/py/bazel/BUILD b/src/test/py/bazel/BUILD
index afec10a9f1..4198b90f44 100644
--- a/src/test/py/bazel/BUILD
+++ b/src/test/py/bazel/BUILD
@@ -32,6 +32,13 @@ py_test(
)
py_test(
+ name = "cc_import_test",
+ size = "medium",
+ srcs = ["cc_import_test.py"],
+ deps = [":test_base"],
+)
+
+py_test(
name = "bazel_server_mode_test",
size = "medium",
srcs = ["bazel_server_mode_test.py"],
diff --git a/src/test/py/bazel/cc_import_test.py b/src/test/py/bazel/cc_import_test.py
new file mode 100644
index 0000000000..1563957495
--- /dev/null
+++ b/src/test/py/bazel/cc_import_test.py
@@ -0,0 +1,257 @@
+# Copyright 2017 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.
+
+import os
+import shutil
+import stat
+import unittest
+from src.test.py.bazel import test_base
+
+
+class CcImportTest(test_base.TestBase):
+
+ def createProjectFiles(self,
+ alwayslink=0,
+ system_provided=0,
+ linkstatic=1,
+ provide_header=True):
+ self.ScratchFile('WORKSPACE')
+
+ # We use the outputs of cc_binary and cc_library as precompiled
+ # libraries for cc_import
+ self.ScratchFile(
+ 'lib/BUILD',
+ [
+ 'package(default_visibility = ["//visibility:public"])',
+ '',
+ 'cc_binary(',
+ ' name = "libA.so",',
+ ' srcs = ["a.cc"],',
+ ' linkshared = 1,',
+ ')',
+ '',
+ 'filegroup(',
+ ' name = "libA_ifso",',
+ ' srcs = [":libA.so"],',
+ ' output_group = "interface_library",',
+ ')',
+ '',
+ 'cc_library(',
+ ' name = "libA",',
+ ' srcs = ["a.cc", "a_al.cc"],',
+ ')',
+ '',
+ 'filegroup(',
+ ' name = "libA_archive",',
+ ' srcs = [":libA"],',
+ ' output_group = "archive",',
+ ')',
+ '',
+ 'cc_import(',
+ ' name = "A",',
+ ' static_library = "//lib:libA_archive",',
+ ' shared_library = "//lib:libA.so",'
+ if not system_provided else '',
+ # On Windows, we always need the interface library
+ ' interface_library = "//lib:libA_ifso",'
+ if self.IsWindows() else (
+ # On Unix, we use .so file as interface library
+ # if system_provided is true
+ ' interface_library = "//lib:libA.so",'
+ if system_provided else ''),
+ ' hdrs = ["a.h"],' if provide_header else '',
+ ' alwayslink = %s,' % str(alwayslink),
+ ' system_provided = %s,' % str(system_provided),
+ ')',
+ ])
+
+ self.ScratchFile('lib/a.cc', [
+ '#include <stdio.h>',
+ '',
+ '#ifdef COMPILER_MSVC',
+ ' #define DLLEXPORT __declspec(dllexport)',
+ '#else',
+ ' #define DLLEXPORT',
+ '#endif',
+ '',
+ 'DLLEXPORT void HelloWorld() {',
+ ' printf("HelloWorld\\n");',
+ '}',
+ ])
+
+ # For testing alwayslink=1
+ self.ScratchFile('lib/a_al.cc', [
+ 'extern int global_variable;',
+ 'int init() {',
+ ' ++global_variable;',
+ ' return global_variable;',
+ '}',
+ 'int x = init();',
+ 'int y = init();',
+ ])
+
+ self.ScratchFile('lib/a.h', [
+ 'void HelloWorld();',
+ ])
+
+ self.ScratchFile('main/BUILD', [
+ 'cc_binary(',
+ ' name = "B",',
+ ' srcs = ["b.cc"],',
+ ' deps = ["//lib:A",],',
+ ' linkstatic = %s,' % str(linkstatic),
+ ')',
+ ])
+
+ self.ScratchFile('main/b.cc', [
+ '#include <stdio.h>',
+ '#include "lib/a.h"',
+ 'int global_variable = 0;',
+ 'int main() {',
+ ' HelloWorld();',
+ ' printf("global : %d\\n", global_variable);',
+ ' return 0;',
+ '}',
+ ])
+
+ def getBazelInfo(self, info_key):
+ exit_code, stdout, stderr = self.RunBazel(['info', info_key])
+ self.AssertExitCode(exit_code, 0, stderr)
+ return stdout[0]
+
+ def testLinkStaticLibrary(self):
+ self.createProjectFiles(alwayslink=0, linkstatic=1)
+ bazel_bin = self.getBazelInfo('bazel-bin')
+ suffix = '.exe' if self.IsWindows() else ''
+
+ exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
+ self.assertTrue(os.path.exists(b_bin))
+ exit_code, stdout, stderr = self.RunProgram([b_bin])
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout[0], 'HelloWorld')
+ self.assertEqual(stdout[1], 'global : 0')
+
+ def testAlwayslinkStaticLibrary(self):
+ self.createProjectFiles(alwayslink=1, linkstatic=1)
+ bazel_bin = self.getBazelInfo('bazel-bin')
+ suffix = '.exe' if self.IsWindows() else ''
+
+ exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
+ self.assertTrue(os.path.exists(b_bin))
+ exit_code, stdout, stderr = self.RunProgram([b_bin])
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout[0], 'HelloWorld')
+ self.assertEqual(stdout[1], 'global : 2')
+
+ def testLinkSharedLibrary(self):
+ self.createProjectFiles(linkstatic=0)
+ bazel_bin = self.getBazelInfo('bazel-bin')
+ suffix = '.exe' if self.IsWindows() else ''
+
+ exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
+ self.assertTrue(os.path.exists(b_bin))
+ if self.IsWindows():
+ self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'main/libA.so')))
+ exit_code, stdout, stderr = self.RunProgram([b_bin])
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout[0], 'HelloWorld')
+
+ def testSystemProvidedSharedLibraryOnWinodws(self):
+ if not self.IsWindows():
+ return
+ self.createProjectFiles(system_provided=1, linkstatic=0)
+ bazel_bin = self.getBazelInfo('bazel-bin')
+
+ exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ b_bin = os.path.join(bazel_bin, 'main/B.exe')
+ exit_code, stdout, stderr = self.RunProgram([b_bin])
+ # Should fail because missing libA.so
+ self.assertFalse(exit_code == 0)
+
+ # Let's build libA.so and add it into PATH
+ exit_code, stdout, stderr = self.RunBazel(['build', '//lib:libA.so'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ exit_code, stdout, stderr = self.RunProgram(
+ [b_bin], env_add={
+ 'PATH': str(os.path.join(bazel_bin, 'lib'))
+ })
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout[0], 'HelloWorld')
+
+ def testSystemProvidedSharedLibraryOnUnix(self):
+ if not self.IsUnix():
+ return
+ self.createProjectFiles(system_provided=1, linkstatic=0)
+ bazel_bin = self.getBazelInfo('bazel-bin')
+
+ exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ b_bin = os.path.join(bazel_bin, 'main/B')
+ tmp_dir = self.ScratchDir('temp_dir_for_run_b_bin')
+ b_bin_tmp = os.path.join(tmp_dir, 'B')
+ # Copy the binary to a temp directory to make sure it cannot find
+ # libA.so
+ shutil.copyfile(b_bin, b_bin_tmp)
+ os.chmod(b_bin_tmp, stat.S_IRWXU)
+ exit_code, stdout, stderr = self.RunProgram([b_bin_tmp])
+ # Should fail because missing libA.so
+ self.assertFalse(exit_code == 0)
+
+ # Let's build libA.so and add it into PATH
+ exit_code, stdout, stderr = self.RunBazel(['build', '//lib:libA.so'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ exit_code, stdout, stderr = self.RunProgram(
+ [b_bin_tmp], env_add={
+ # For Linux
+ 'LD_LIBRARY_PATH': str(os.path.join(bazel_bin, 'lib')),
+ # For Mac
+ 'DYLD_LIBRARY_PATH': str(os.path.join(bazel_bin, 'lib')),
+ })
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout[0], 'HelloWorld')
+
+ def testCcImportHeaderCheck(self):
+ self.createProjectFiles(provide_header=False)
+ # Build should fail, because lib/a.h is not declared in BUILD file, disable
+ # sandbox so that bazel produces same error across different platforms.
+ exit_code, _, stderr = self.RunBazel(
+ ['build', '//main:B', '--spawn_strategy=standalone'])
+ self.AssertExitCode(exit_code, 1, stderr)
+ self.assertIn('this rule is missing dependency declarations for the'
+ ' following files included by \'main/b.cc\':',
+ ''.join(stderr))
+
+ def AssertFileContentContains(self, file_path, entry):
+ f = open(file_path, 'r')
+ if entry not in f.read():
+ self.fail('File "%s" does not contain "%s"' % (file_path, entry))
+ f.close()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/src/test/py/bazel/test_base.py b/src/test/py/bazel/test_base.py
index 695aef9882..9eb763dd77 100644
--- a/src/test/py/bazel/test_base.py
+++ b/src/test/py/bazel/test_base.py
@@ -94,6 +94,11 @@ class TestBase(unittest.TestCase):
"""Returns true if the current platform is Windows."""
return os.name == 'nt'
+ @staticmethod
+ def IsUnix():
+ """Returns true if the current platform is Unix platform."""
+ return os.name == 'posix'
+
def Path(self, path):
"""Returns the absolute path of `path` relative to self._test_cwd.