diff options
author | 2017-12-07 07:32:09 -0800 | |
---|---|---|
committer | 2017-12-07 07:34:22 -0800 | |
commit | 40bc935f033412f8564c57a2bd7ec99f493538c3 (patch) | |
tree | d7e3182f0060296705cba2be13a3660b6e550f3b /src/main/java/com/google/devtools/build | |
parent | 7c8cd9c402b3ca4f7b50074d249ef8e1dc52086a (diff) |
Implement cc_import rule
Designed here:
https://docs.google.com/document/d/1hK2mWl3TYNL9oJYX_S020TKkXZvBw1aBoYERvTHVyfg/edit
Fix https://github.com/bazelbuild/bazel/issues/3402
Change-Id: I9beff94d8b85ffeb4e46e0959c8f5ed4ef9c6268
PiperOrigin-RevId: 178238408
Diffstat (limited to 'src/main/java/com/google/devtools/build')
8 files changed, 202 insertions, 37 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) { |