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 860bccce3d1727..8ea59c06c08264 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 @@ -283,7 +283,7 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont ruleContext.getConfiguration()) .fromCommon(common) .addDeps(ImmutableList.of(CppHelper.mallocForTarget(ruleContext))) - .enableInterfaceSharedObjects() + .emitInterfaceSharedObjects(true) .setAlwayslink(false); ccLinkingOutputs = linkingHelper.link(ccCompilationOutputs); } @@ -294,58 +294,10 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont linkingMode != Link.LinkingMode.DYNAMIC, isLinkShared(ruleContext), common.getLinkopts()); - CppLinkActionBuilder linkActionBuilder = - determineLinkerArguments( - ruleContext, - ccToolchain, - featureConfiguration, - fdoProvider, - common, - precompiledFiles, - ccCompilationOutputs, - ccLinkingOutputs, - ccCompilationContext.getTransitiveCompilationPrerequisites(), - fake, - binary, - linkParams, - linkCompileOutputSeparately, - semantics); - linkActionBuilder.setUseTestOnlyFlags(ruleContext.isTestTarget()); - if (linkingMode == Link.LinkingMode.DYNAMIC) { - linkActionBuilder.setRuntimeInputs( - ArtifactCategory.DYNAMIC_LIBRARY, - ccToolchain.getDynamicRuntimeLinkMiddleman(featureConfiguration), - ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration)); - } else { - linkActionBuilder.setRuntimeInputs( - ArtifactCategory.STATIC_LIBRARY, - ccToolchain.getStaticRuntimeLinkMiddleman(featureConfiguration), - ccToolchain.getStaticRuntimeLinkInputs(featureConfiguration)); - if (!cppConfiguration.disableEmittingStaticLibgcc()) { - // Only force a static link of libgcc if static runtime linking is enabled (which - // can't be true if runtimeInputs is empty). - // TODO(bazel-team): Move this to CcToolchain. - if (!ccToolchain.getStaticRuntimeLinkInputs(featureConfiguration).isEmpty()) { - linkActionBuilder.addLinkopt("-static-libgcc"); - } - } - } - - linkActionBuilder.setLinkType(linkType); - linkActionBuilder.setLinkingMode(linkingMode); - linkActionBuilder.setFake(fake); - - if (CppLinkAction.enableSymbolsCounts( - cppConfiguration, ccToolchain.supportsGoldLinker(), fake, linkType)) { - linkActionBuilder.setSymbolCountsOutput(ruleContext.getBinArtifact( - CppLinkAction.symbolCountsFileName(binaryPath))); - } Artifact generatedDefFile = null; - Artifact interfaceLibrary = null; + Artifact customDefFile = null; if (isLinkShared(ruleContext)) { - linkActionBuilder.setLibraryIdentifier(CcLinkingOutputs.libraryIdentifierOf(binary)); - if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) { ImmutableList.Builder objectFiles = ImmutableList.builder(); objectFiles.addAll(ccCompilationOutputs.getObjectFiles(false)); @@ -362,62 +314,56 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST), objectFiles.build(), binary.getFilename()); - - if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) { - linkActionBuilder.setDefFile(generatedDefFile); - } - - Artifact customDefFile = common.getWinDefFile(); - if (customDefFile != null) { - linkActionBuilder.setDefFile(customDefFile); - } - - // If we are using a toolchain supporting interface library and targeting Windows, we build - // the interface library with the link action and add it to `interface_output` output group. - if (CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)) { - interfaceLibrary = CppHelper.getLinkedArtifact( - ruleContext, - ccToolchain, - ruleContext.getConfiguration(), - LinkTargetType.INTERFACE_DYNAMIC_LIBRARY); - linkActionBuilder.setInterfaceOutput(interfaceLibrary); - } + customDefFile = common.getWinDefFile(); } } - // Store immutable context for use in other *_binary rules that are implemented by - // linking the interpreter (Java, Python, etc.) together with native deps. - CppLinkAction.Context linkContext = new CppLinkAction.Context(linkActionBuilder); boolean usePic = usePic(ruleContext, ccToolchain); - if (linkActionBuilder.hasLtoBitcodeInputs() - && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) { - linkActionBuilder.setLtoIndexing(true); - linkActionBuilder.setUsePicForLtoBackendActions(usePic); - CppLinkAction indexAction = linkActionBuilder.build(); - if (indexAction != null) { - ruleContext.registerAction(indexAction); - } - - linkActionBuilder.setLtoIndexing(false); - } - // On Windows, if GENERATE_PDB_FILE feature is enabled // then a pdb file will be built along with the executable. Artifact pdbFile = null; if (featureConfiguration.isEnabled(CppRuleClasses.GENERATE_PDB_FILE)) { pdbFile = ruleContext.getRelatedArtifact(binary.getRootRelativePath(), ".pdb"); - linkActionBuilder.addActionOutput(pdbFile); } - CppLinkAction linkAction = linkActionBuilder.build(); - Iterable ltoBackendArtifacts = - linkActionBuilder.getAllLtoBackendArtifacts(); - ruleContext.registerAction(linkAction); - LibraryToLink outputLibrary = linkAction.getOutputLibrary(); + CcLinkingOutputs ccLinkingOutputsBinary = + createTransitiveLinkingActions( + ruleContext, + ccToolchain, + featureConfiguration, + fdoProvider, + common, + precompiledFiles, + ccCompilationOutputs, + ccLinkingOutputs, + ccCompilationContext, + fake, + binary, + linkParams, + linkCompileOutputSeparately, + semantics, + linkingMode, + cppConfiguration, + linkType, + binaryPath, + pdbFile, + generatedDefFile, + customDefFile); + + // Store immutable context for use in other *_binary rules that are implemented by + // linking the interpreter (Java, Python, etc.) together with native deps. + CppLinkAction.Context linkContext = ccLinkingOutputsBinary.getCppLinkActionContext(); + + LibraryToLink outputLibrary = null; + List dynamicLibrariesForRuntime = + ccLinkingOutputsBinary.getDynamicLibrariesForRuntime(); + if (!dynamicLibrariesForRuntime.isEmpty()) { + Preconditions.checkState(dynamicLibrariesForRuntime.size() == 1); + outputLibrary = dynamicLibrariesForRuntime.get(0); + } Iterable fakeLinkerInputs = - fake ? linkAction.getInputs() : ImmutableList.of(); - Artifact executable = linkAction.getLinkOutput(); + fake ? ccLinkingOutputsBinary.getLinkActionInputs() : ImmutableList.of(); CcLinkingOutputs.Builder linkingOutputsBuilder = new CcLinkingOutputs.Builder(); if (isLinkShared(ruleContext)) { linkingOutputsBuilder.addDynamicLibraryForLinking(outputLibrary); @@ -432,13 +378,13 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont linkingOutputsBuilder.addDynamicLibraryForRuntime(symlinkLibrary); } CcLinkingOutputs linkingOutputs = linkingOutputsBuilder.build(); - NestedSet filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, executable); + NestedSet filesToBuild = NestedSetBuilder.create(Order.STABLE_ORDER, binary); // Create the stripped binary, but don't add it to filesToBuild; it's only built when requested. Artifact strippedFile = ruleContext.getImplicitOutputArtifact( CppRuleClasses.CC_BINARY_STRIPPED); CppHelper.createStripAction( - ruleContext, ccToolchain, cppConfiguration, executable, strippedFile, featureConfiguration); + ruleContext, ccToolchain, cppConfiguration, binary, strippedFile, featureConfiguration); DwoArtifactsCollector dwoArtifacts = collectTransitiveDwoArtifacts( @@ -447,7 +393,7 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont linkingMode, ccToolchain.useFission(), usePic, - ltoBackendArtifacts); + ccLinkingOutputsBinary.getAllLtoArtifacts()); Artifact dwpFile = ruleContext.getImplicitOutputArtifact(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE); createDebugPackagerActions(ruleContext, ccToolchain, dwpFile, dwoArtifacts); @@ -497,8 +443,7 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont fake, compilationHelper.getCompilationUnitSources(), linkCompileOutputSeparately); - RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable( - ruleContext, runfiles, executable); + RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable(ruleContext, runfiles, binary); RuleConfiguredTargetBuilder ruleBuilder = new RuleConfiguredTargetBuilder(ruleContext); addTransitiveInfoProviders( @@ -530,92 +475,131 @@ public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleCont ruleBuilder.addOutputGroup("def_file", generatedDefFile); } - if (interfaceLibrary != null) { - ruleBuilder.addOutputGroup("interface_library", interfaceLibrary); + List dynamicLibraryForLinking = + ccLinkingOutputsBinary.getDynamicLibrariesForLinking(); + if (!dynamicLibraryForLinking.isEmpty()) { + Preconditions.checkState(dynamicLibraryForLinking.size() == 1); + ruleBuilder.addOutputGroup( + "interface_library", dynamicLibraryForLinking.get(0).getOriginalLibraryArtifact()); } return ruleBuilder .addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles)) .addProvider( DebugPackageProvider.class, - new DebugPackageProvider( - ruleContext.getLabel(), strippedFile, executable, explicitDwpFile)) - .setRunfilesSupport(runfilesSupport, executable) + new DebugPackageProvider(ruleContext.getLabel(), strippedFile, binary, explicitDwpFile)) + .setRunfilesSupport(runfilesSupport, binary) .addProvider(CppLinkAction.Context.class, linkContext) .addSkylarkTransitiveInfo(CcSkylarkApiProvider.NAME, new CcSkylarkApiProvider()) .build(); } - /** - * Given 'temps', traverse this target and its dependencies and collect up all the object files, - * libraries, linker options, linkstamps attributes and linker scripts. - */ - private static CppLinkActionBuilder determineLinkerArguments( - RuleContext context, - CcToolchainProvider toolchain, + public static CcLinkingOutputs createTransitiveLinkingActions( + RuleContext ruleContext, + CcToolchainProvider ccToolchain, FeatureConfiguration featureConfiguration, FdoProvider fdoProvider, CcCommon common, PrecompiledFiles precompiledFiles, - CcCompilationOutputs compilationOutputs, - CcLinkingOutputs linkingOutputs, - ImmutableSet compilationPrerequisites, + CcCompilationOutputs ccCompilationOutputs, + CcLinkingOutputs ccLinkingOutputs, + CcCompilationContext ccCompilationContext, boolean fake, Artifact binary, CcLinkParams linkParams, boolean linkCompileOutputSeparately, - CppSemantics cppSemantics) + CppSemantics cppSemantics, + LinkingMode linkingMode, + CppConfiguration cppConfiguration, + LinkTargetType linkType, + PathFragment binaryPath, + Artifact pdbFile, + Artifact generatedDefFile, + Artifact customDefFile) throws InterruptedException, RuleErrorException { - CppLinkActionBuilder builder = - new CppLinkActionBuilder( - context, binary, toolchain, fdoProvider, featureConfiguration, cppSemantics) - .setCrosstoolInputs(toolchain.getLink()) - .addNonCodeInputs(compilationPrerequisites); - - // Either link in the .o files generated for the sources of this target or link in the - // generated dynamic library they are compiled into. - if (linkCompileOutputSeparately) { - for (LibraryToLink library : linkingOutputs.getDynamicLibrariesForLinking()) { - builder.addLibrary(library); - } - } else { - boolean usePic = usePic(context, toolchain); - Iterable objectFiles = compilationOutputs.getObjectFiles(usePic); + CcLinkingHelper ccLinkingHelper = + new CcLinkingHelper( + ruleContext, + cppSemantics, + featureConfiguration, + ccToolchain, + fdoProvider, + ruleContext.getConfiguration()) + .addNonCodeLinkerInputs(ccCompilationContext.getTransitiveCompilationPrerequisites()) + .addNonCodeLinkerInputs(common.getLinkerScripts()); - if (fake) { - builder.addFakeObjectFiles(objectFiles); - } else { - builder.addObjectFiles(objectFiles); + CcLinkParams.Builder ccLinkParamsBuilder = CcLinkParams.builder(); + ccLinkParamsBuilder.addTransitiveArgs(linkParams); + + if (linkCompileOutputSeparately) { + for (LibraryToLink library : ccLinkingOutputs.getDynamicLibrariesForLinking()) { + ccLinkParamsBuilder.addLibrary(library); } + ccCompilationOutputs = new CcCompilationOutputs.Builder().build(); } - builder.addLtoBitcodeFiles(compilationOutputs.getLtoBitcodeFiles()); - builder.addNonCodeInputs(common.getLinkerScripts()); - // Determine the libraries to link in. // First libraries from srcs. Shared library artifacts here are substituted with mangled symlink // artifacts generated by getDynamicLibraryLink(). This is done to minimize number of -rpath // entries during linking process. for (Artifact library : precompiledFiles.getLibraries()) { if (Link.SHARED_LIBRARY_FILETYPES.matches(library.getFilename())) { - builder.addLibrary(LinkerInputs.solibLibraryToLink( - common.getDynamicLibrarySymlink(library, true), library, - CcLinkingOutputs.libraryIdentifierOf(library))); + ccLinkParamsBuilder.addLibrary( + LinkerInputs.solibLibraryToLink( + common.getDynamicLibrarySymlink(library, true), + library, + CcLinkingOutputs.libraryIdentifierOf(library))); } else if (Link.LINK_LIBRARY_FILETYPES.matches(library.getFilename())) { - builder.addLibrary(LinkerInputs.precompiledLibraryToLink( - library, ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY)); + ccLinkParamsBuilder.addLibrary( + LinkerInputs.precompiledLibraryToLink( + library, ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY)); } else if (Link.ARCHIVE_FILETYPES.matches(library.getFilename())) { - builder.addLibrary(LinkerInputs.precompiledLibraryToLink( - library, ArtifactCategory.STATIC_LIBRARY)); + ccLinkParamsBuilder.addLibrary( + LinkerInputs.precompiledLibraryToLink(library, ArtifactCategory.STATIC_LIBRARY)); } else { throw new IllegalStateException(); } } - // Then the link params from the closure of deps. - builder.addLinkParams(linkParams, context); + CcLinkParams ccLinkParams = ccLinkParamsBuilder.build(); + CcLinkingInfo.Builder ccLinkingInfo = CcLinkingInfo.Builder.create(); + ccLinkingInfo.setStaticModeParamsForDynamicLibrary(ccLinkParams); + ccLinkingInfo.setStaticModeParamsForExecutable(ccLinkParams); + ccLinkingInfo.setDynamicModeParamsForDynamicLibrary(ccLinkParams); + ccLinkingInfo.setDynamicModeParamsForExecutable(ccLinkParams); + + ccLinkingHelper + .addCcLinkingInfos(ImmutableList.of(ccLinkingInfo.build())) + .setUseTestOnlyFlags(ruleContext.isTestTarget()) + .setShouldCreateStaticLibraries(false) + .setLinkingMode(linkingMode) + .setDynamicLinkType(linkType) + .setDynamicLibrary(binary) + .setNeverLink(true) + .emitInterfaceSharedObjects( + isLinkShared(ruleContext) + && featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS) + && CppHelper.useInterfaceSharedObjects(cppConfiguration, ccToolchain)) + .setPdbFile(pdbFile) + .setFake(fake); + + if (customDefFile != null) { + ccLinkingHelper.setDefFile(customDefFile); + } else if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) { + ccLinkingHelper.setDefFile(generatedDefFile); + } + + if (linkingMode != Link.LinkingMode.DYNAMIC + && !cppConfiguration.disableEmittingStaticLibgcc()) { + // Only force a static link of libgcc if static runtime linking is enabled (which + // can't be true if runtimeInputs is empty). + // TODO(bazel-team): Move this to CcToolchain. + if (!ccToolchain.getStaticRuntimeLinkInputs(featureConfiguration).isEmpty()) { + ccLinkingHelper.addLinkopts(ImmutableList.of("-static-libgcc")); + } + } - return builder; + return ccLinkingHelper.link(/* ccOutputs */ ccCompilationOutputs); } /** 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 ef3cb53d1e5640..28d44cb2c34261 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 @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.rules.cpp; +import static com.google.devtools.build.lib.packages.BuildType.LABEL; import static java.util.stream.Collectors.joining; import com.google.common.collect.ImmutableList; @@ -35,6 +36,7 @@ import com.google.devtools.build.lib.analysis.Runfiles; import com.google.devtools.build.lib.analysis.RunfilesProvider; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; +import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider; import com.google.devtools.build.lib.cmdline.Label; @@ -153,7 +155,7 @@ public static void init( ruleContext.getConfiguration()) .fromCommon(common) .addLinkopts(common.getLinkopts()) - .enableInterfaceSharedObjects() + .emitInterfaceSharedObjects(true) .setAlwayslink(alwaysLink) .setNeverLink(neverLink) .addLinkstamps(ruleContext.getPrerequisites("linkstamp", Mode.TARGET)); @@ -258,6 +260,37 @@ public static void init( CcLinkingOutputs ccLinkingOutputs = CcLinkingOutputs.EMPTY; if (ruleContext.getRule().getImplicitOutputsFunction() != ImplicitOutputsFunction.NONE || !ccCompilationOutputs.isEmpty()) { + if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) { + // If windows_export_all_symbols feature is enabled, bazel parses object files to generate + // DEF file and use it to export symbols. The generated DEF file won't be used if a custom + // DEF file is specified by win_def_file attribute. + if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) { + try { + Artifact generatedDefFile = + CppHelper.createDefFileActions( + ruleContext, + ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST), + ccCompilationOutputs.getObjectFiles(false), + ccToolchain + .getFeatures() + .getArtifactNameForCategory( + ArtifactCategory.DYNAMIC_LIBRARY, ruleContext.getLabel().getName())); + linkingHelper.setDefFile(generatedDefFile); + } catch (InvalidConfigurationException e) { + ruleContext.throwWithRuleError(e.getMessage()); + throw new IllegalStateException("Should not be reached"); + } + } + + // If user specifies a custom DEF file, then we use this one instead of the generated one. + Artifact customDefFile = null; + if (ruleContext.isAttrDefined("win_def_file", LABEL)) { + customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET); + if (customDefFile != null) { + linkingHelper.setDefFile(customDefFile); + } + } + } ccLinkingOutputs = linkingHelper.link(ccCompilationOutputs); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java index 15650214065961..0b4ee03370d263 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingHelper.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.rules.cpp; -import static com.google.devtools.build.lib.packages.BuildType.LABEL; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -36,6 +35,7 @@ import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.ExpansionException; import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; import com.google.devtools.build.lib.rules.cpp.CcToolchainVariables.VariablesExtension; +import com.google.devtools.build.lib.rules.cpp.CppLinkAction.Context; import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType; import com.google.devtools.build.lib.rules.cpp.Link.LinkerOrArchiver; import com.google.devtools.build.lib.rules.cpp.Link.LinkingMode; @@ -101,7 +101,8 @@ public CcLinkingOutputs getCcLinkingOutputs() { private final List linkActionInputs = new ArrayList<>(); @Nullable private Artifact dynamicLibrary; - private LinkTargetType linkType = LinkTargetType.STATIC_LIBRARY; + private LinkTargetType staticLinkType = LinkTargetType.STATIC_LIBRARY; + private LinkTargetType dynamicLinkType = LinkTargetType.NODEPS_DYNAMIC_LIBRARY; private boolean neverlink; private boolean checkDepsGenerateCpp = true; @@ -110,6 +111,11 @@ public CcLinkingOutputs getCcLinkingOutputs() { private boolean shouldCreateStaticLibraries = true; private boolean willOnlyBeLinkedIntoDynamicLibraries; private final List variablesExtensions = new ArrayList<>(); + private boolean useTestOnlyFlags; + private Artifact pdbFile; + private Artifact defFile; + private LinkingMode linkingMode = LinkingMode.DYNAMIC; + private boolean fake; private final FeatureConfiguration featureConfiguration; private final CcToolchainProvider ccToolchain; @@ -151,7 +157,7 @@ public CcLinkingHelper fromCommon(CcCommon common) { } /** Adds the corresponding non-code files as linker inputs. */ - public void addNonCodeLinkerInputs(Iterable nonCodeLinkerInputs) { + public CcLinkingHelper addNonCodeLinkerInputs(Iterable nonCodeLinkerInputs) { for (Artifact nonCodeLinkerInput : nonCodeLinkerInputs) { String basename = nonCodeLinkerInput.getFilename(); Preconditions.checkArgument(!Link.OBJECT_FILETYPES.matches(basename)); @@ -159,6 +165,7 @@ public void addNonCodeLinkerInputs(Iterable nonCodeLinkerInputs) { Preconditions.checkArgument(!Link.SHARED_LIBRARY_FILETYPES.matches(basename)); this.nonCodeLinkerInputs.add(nonCodeLinkerInput); } + return this; } /** Adds the given options as linker options to the link command. */ @@ -231,7 +238,7 @@ public CcLinkingHelper setDynamicLibrary(@Nullable Artifact dynamicLibrary) { * downstream code). */ public CcLinkingHelper setAlwayslink(boolean alwayslink) { - linkType = + staticLinkType = alwayslink ? LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY : LinkTargetType.STATIC_LIBRARY; return this; } @@ -245,7 +252,7 @@ public CcLinkingHelper setAlwayslink(boolean alwayslink) { public CcLinkingHelper setStaticLinkType(LinkTargetType linkType) { Preconditions.checkNotNull(linkType); Preconditions.checkState(linkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER); - this.linkType = linkType; + this.staticLinkType = linkType; return this; } @@ -285,8 +292,8 @@ public CcLinkingHelper setLinkedArtifactNameSuffix(String suffix) { * linker generates a dynamic library, and only if the crosstool supports it. The default is not * to generate interface dynamic libraries. */ - public CcLinkingHelper enableInterfaceSharedObjects() { - this.emitInterfaceSharedObjects = true; + public CcLinkingHelper emitInterfaceSharedObjects(boolean emitInterfaceSharedObjects) { + this.emitInterfaceSharedObjects = emitInterfaceSharedObjects; return this; } @@ -338,7 +345,7 @@ public CcLinkingOutputs link(CcCompilationOutputs ccOutputs) // // An additional pre-existing issue is that the header check tokens are dropped if we don't // generate any link actions, effectively disabling header checking in some cases. - if (linkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER) { + if (staticLinkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER) { // TODO(bazel-team): This can't create the link action for a cc_binary yet. ccLinkingOutputs = createCcLinkActions(ccOutputs); } @@ -396,7 +403,6 @@ public CcLinkingInfo buildCcLinkingInfo( return ccLinkingInfoBuilder.build(); } - /** * Constructs the C++ linker actions. It generally generates two actions, one for a static library * and one for a dynamic library. If PIC is required for shared libraries, but not for binaries, @@ -405,17 +411,19 @@ public CcLinkingInfo buildCcLinkingInfo( * *

For dynamic libraries, this method can additionally create an interface shared library that * can be used for linking, but doesn't contain any executable code. This increases the number of - * cache hits for link actions. Call {@link #enableInterfaceSharedObjects()} to enable this + * cache hits for link actions. Call {@link #emitInterfaceSharedObjects(boolean)} to enable this * behavior. * * @throws RuleErrorException */ private CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs) throws RuleErrorException, InterruptedException { - // For now only handle static links. Note that the dynamic library link below ignores linkType. + // For now only handle static links. Note that the dynamic library link below ignores + // staticLinkType. // TODO(bazel-team): Either support non-static links or move this check to setStaticLinkType(). Preconditions.checkState( - linkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER, "can only handle static links"); + staticLinkType.linkerOrArchiver() == LinkerOrArchiver.ARCHIVER, + "can only handle static links"); CcLinkingOutputs.Builder result = new CcLinkingOutputs.Builder(); AnalysisEnvironment env = ruleContext.getAnalysisEnvironment(); @@ -442,7 +450,10 @@ private CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs) } if (shouldCreateDynamicLibrary) { - createDynamicLibrary(result, env, usePicForDynamicLibs, libraryIdentifier, ccOutputs); + boolean usePic = + (!dynamicLinkType.isExecutable() && usePicForDynamicLibs) + || (dynamicLinkType.isExecutable() && usePicForBinaries); + createDynamicLibrary(result, env, usePic, libraryIdentifier, ccOutputs); } return result.build(); @@ -454,6 +465,36 @@ public CcLinkingHelper setWillOnlyBeLinkedIntoDynamicLibraries( return this; } + public CcLinkingHelper setUseTestOnlyFlags(boolean useTestOnlyFlags) { + this.useTestOnlyFlags = useTestOnlyFlags; + return this; + } + + public CcLinkingHelper setLinkingMode(LinkingMode linkingMode) { + this.linkingMode = linkingMode; + return this; + } + + public CcLinkingHelper setDynamicLinkType(LinkTargetType dynamicLinkType) { + this.dynamicLinkType = dynamicLinkType; + return this; + } + + public CcLinkingHelper setFake(boolean fake) { + this.fake = fake; + return this; + } + + public CcLinkingHelper setPdbFile(Artifact pdbFile) { + this.pdbFile = pdbFile; + return this; + } + + public CcLinkingHelper setDefFile(Artifact defFile) { + this.defFile = defFile; + return this; + } + private Pair createNoPicAndPicStaticLibraries( AnalysisEnvironment env, boolean usePicForBinaries, @@ -463,8 +504,9 @@ private Pair createNoPicAndPicStaticLibraries( throws RuleErrorException, InterruptedException { LibraryToLink staticLibrary = null; LibraryToLink picStaticLibrary = null; - // Create static library (.a). The linkType only reflects whether the library is alwayslink or - // not. The PIC-ness is determined by whether we need to use PIC or not. There are four cases + // Create static library (.a). The staticLinkType only reflects whether the library is + // alwayslink or not. The PIC-ness is determined by whether we need to use PIC or not. There + // are four cases: // for (usePicForDynamicLibs usePicForBinaries): // // (1) (false false) -> no pic code is when toolchain and cppOptions don't need pic code for @@ -495,7 +537,7 @@ private Pair createNoPicAndPicStaticLibraries( if (createNoPicAction) { staticLibrary = registerActionForStaticLibrary( - linkType, ccOutputs, /* usePic= */ false, libraryIdentifier, env) + staticLinkType, ccOutputs, /* usePic= */ false, libraryIdentifier, env) .getOutputLibrary(); } @@ -503,10 +545,10 @@ private Pair createNoPicAndPicStaticLibraries( LinkTargetType linkTargetTypeUsedForNaming; if (!createNoPicAction) { // Only PIC library created, name does not match content. - linkTargetTypeUsedForNaming = linkType; + linkTargetTypeUsedForNaming = staticLinkType; } else { linkTargetTypeUsedForNaming = - (linkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY) + (staticLinkType == LinkTargetType.ALWAYS_LINK_STATIC_LIBRARY) ? LinkTargetType.ALWAYS_LINK_PIC_STATIC_LIBRARY : LinkTargetType.PIC_STATIC_LIBRARY; } @@ -549,7 +591,7 @@ private CppLinkAction registerActionForStaticLibrary( private void createDynamicLibrary( CcLinkingOutputs.Builder result, AnalysisEnvironment env, - boolean usePicForDynamicLibs, + boolean usePic, String libraryIdentifier, CcCompilationOutputs ccOutputs) throws RuleErrorException, InterruptedException { @@ -595,57 +637,79 @@ private void createDynamicLibrary( CppLinkActionBuilder dynamicLinkActionBuilder = newLinkActionBuilder(soImpl) .setInterfaceOutput(soInterface) - .addObjectFiles(ccOutputs.getObjectFiles(usePicForDynamicLibs)) .addNonCodeInputs(ccOutputs.getHeaderTokenFiles()) .addLtoBitcodeFiles(ccOutputs.getLtoBitcodeFiles()) - .setLinkType(LinkTargetType.NODEPS_DYNAMIC_LIBRARY) - .setLinkingMode(LinkingMode.DYNAMIC) + .setLinkType(dynamicLinkType) + .setLinkingMode(linkingMode) + .setFake(fake) .addActionInputs(linkActionInputs) - .setLibraryIdentifier(mainLibraryIdentifier) .addLinkopts(linkopts) .addLinkopts(sonameLinkopts) - .setRuntimeInputs( - ArtifactCategory.DYNAMIC_LIBRARY, - ccToolchain.getDynamicRuntimeLinkMiddleman(featureConfiguration), - ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration)) + .addNonCodeInputs(nonCodeLinkerInputs) .addVariablesExtensions(variablesExtensions); - if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS)) { - // On Windows, we cannot build a shared library with symbols unresolved, so here we - // dynamically - // link to all it's dependencies. - CcLinkParams.Builder ccLinkParamsBuilder = - CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true); - ccLinkParamsBuilder.addCcLibrary(ruleContext); - dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext); - - // If windows_export_all_symbols feature is enabled, bazel parses object files to generate - // DEF file and use it to export symbols. The generated DEF file won't be used if a custom - // DEF file is specified by win_def_file attribute. - if (CppHelper.shouldUseGeneratedDefFile(ruleContext, featureConfiguration)) { - Artifact generatedDefFile = - CppHelper.createDefFileActions( - ruleContext, - ruleContext.getPrerequisiteArtifact("$def_parser", Mode.HOST), - ccOutputs.getObjectFiles(false), - SolibSymlinkAction.getDynamicLibrarySoname(soImpl.getRootRelativePath(), true)); - dynamicLinkActionBuilder.setDefFile(generatedDefFile); - } + if (fake) { + dynamicLinkActionBuilder.addFakeObjectFiles(ccOutputs.getObjectFiles(usePic)); + } else { + dynamicLinkActionBuilder.addObjectFiles(ccOutputs.getObjectFiles(usePic)); + } - // If user specifies a custom DEF file, then we use this one instead of the generated one. - Artifact customDefFile = null; - if (ruleContext.isAttrDefined("win_def_file", LABEL)) { - customDefFile = ruleContext.getPrerequisiteArtifact("win_def_file", Mode.TARGET); - } - if (customDefFile != null) { - dynamicLinkActionBuilder.setDefFile(customDefFile); + if (!dynamicLinkType.isExecutable()) { + dynamicLinkActionBuilder.setLibraryIdentifier(mainLibraryIdentifier); + } + + if (linkingMode == LinkingMode.DYNAMIC) { + dynamicLinkActionBuilder.setRuntimeInputs( + ArtifactCategory.DYNAMIC_LIBRARY, + ccToolchain.getDynamicRuntimeLinkMiddleman(featureConfiguration), + ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration)); + } else { + dynamicLinkActionBuilder.setRuntimeInputs( + ArtifactCategory.STATIC_LIBRARY, + ccToolchain.getStaticRuntimeLinkMiddleman(featureConfiguration), + ccToolchain.getStaticRuntimeLinkInputs(featureConfiguration)); + } + + if (CppLinkAction.enableSymbolsCounts( + cppConfiguration, ccToolchain.supportsGoldLinker(), fake, staticLinkType)) { + dynamicLinkActionBuilder.setSymbolCountsOutput( + ruleContext.getBinArtifact( + CppLinkAction.symbolCountsFileName( + PathFragment.create(ruleContext.getTarget().getName())))); + } + + if (featureConfiguration.isEnabled(CppRuleClasses.TARGETS_WINDOWS) + || dynamicLinkType != LinkTargetType.NODEPS_DYNAMIC_LIBRARY) { + if (dynamicLinkType != LinkTargetType.NODEPS_DYNAMIC_LIBRARY) { + for (CcLinkingInfo ccLinkingInfo : ccLinkingInfos) { + dynamicLinkActionBuilder.addLinkParams( + ccLinkingInfo.getCcLinkParams( + linkingMode == LinkingMode.STATIC, dynamicLinkType.isDynamicLibrary()), + ruleContext); + } + } else { + // On Windows, we cannot build a shared library with symbols unresolved, so here we + // dynamically + // link to all it's dependencies. + CcLinkParams.Builder ccLinkParamsBuilder = + CcLinkParams.builder(/* linkingStatically= */ false, /* linkShared= */ true); + ccLinkParamsBuilder.addCcLibrary(ruleContext); + dynamicLinkActionBuilder.addLinkParams(ccLinkParamsBuilder.build(), ruleContext); } } - if (!ccOutputs.getLtoBitcodeFiles().isEmpty() + if (pdbFile != null) { + dynamicLinkActionBuilder.addActionOutput(pdbFile); + } + + if (defFile != null) { + dynamicLinkActionBuilder.setDefFile(defFile); + } + + if (dynamicLinkActionBuilder.hasLtoBitcodeInputs() && featureConfiguration.isEnabled(CppRuleClasses.THIN_LTO)) { dynamicLinkActionBuilder.setLtoIndexing(true); - dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePicForDynamicLibs); + dynamicLinkActionBuilder.setUsePicForLtoBackendActions(usePic); CppLinkAction indexAction = dynamicLinkActionBuilder.build(); if (indexAction != null) { env.registerAction(indexAction); @@ -654,7 +718,12 @@ private void createDynamicLibrary( dynamicLinkActionBuilder.setLtoIndexing(false); } + if (dynamicLinkActionBuilder.getAllLtoBackendArtifacts() != null) { + result.addAllLtoArtifacts(dynamicLinkActionBuilder.getAllLtoBackendArtifacts()); + } CppLinkAction dynamicLinkAction = dynamicLinkActionBuilder.build(); + result.setCppLinkActionContext(new Context(dynamicLinkActionBuilder)); + result.addLinkActionInputs(dynamicLinkAction.getInputs()); env.registerAction(dynamicLinkAction); LibraryToLink dynamicLibrary = dynamicLinkAction.getOutputLibrary(); @@ -666,49 +735,52 @@ private void createDynamicLibrary( // // 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.addDynamicLibraryForLinking( - interfaceLibrary == null ? dynamicLibrary : interfaceLibrary); - result.addDynamicLibraryForRuntime(dynamicLibrary); - } else { - Artifact implLibraryLinkArtifact = - SolibSymlinkAction.getDynamicLibrarySymlink( - ruleContext, - ccToolchain.getSolibDirectory(), - dynamicLibrary.getArtifact(), - /* preserveName= */ false, - /* prefixConsumer= */ false, - ruleContext.getConfiguration()); - LibraryToLink implLibraryLink = - LinkerInputs.solibLibraryToLink( - implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier); - result.addDynamicLibraryForRuntime(implLibraryLink); - - LibraryToLink libraryLink; - if (interfaceLibrary == null) { - libraryLink = implLibraryLink; + if (dynamicLibrary != null) { + if (neverlink + || featureConfiguration.isEnabled(CppRuleClasses.COPY_DYNAMIC_LIBRARIES_TO_BINARY)) { + result.addDynamicLibraryForLinking( + interfaceLibrary == null ? dynamicLibrary : interfaceLibrary); + result.addDynamicLibraryForRuntime(dynamicLibrary); } else { - Artifact libraryLinkArtifact = + Artifact implLibraryLinkArtifact = SolibSymlinkAction.getDynamicLibrarySymlink( ruleContext, ccToolchain.getSolibDirectory(), - interfaceLibrary.getArtifact(), + dynamicLibrary.getArtifact(), /* preserveName= */ false, /* prefixConsumer= */ false, ruleContext.getConfiguration()); - libraryLink = + LibraryToLink implLibraryLink = LinkerInputs.solibLibraryToLink( - libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier); + implLibraryLinkArtifact, dynamicLibrary.getArtifact(), libraryIdentifier); + result.addDynamicLibraryForRuntime(implLibraryLink); + + LibraryToLink libraryLink; + if (interfaceLibrary == null) { + libraryLink = implLibraryLink; + } else { + Artifact libraryLinkArtifact = + SolibSymlinkAction.getDynamicLibrarySymlink( + ruleContext, + ccToolchain.getSolibDirectory(), + interfaceLibrary.getArtifact(), + /* preserveName= */ false, + /* prefixConsumer= */ false, + ruleContext.getConfiguration()); + libraryLink = + LinkerInputs.solibLibraryToLink( + libraryLinkArtifact, interfaceLibrary.getArtifact(), libraryIdentifier); + } + result.addDynamicLibraryForLinking(libraryLink); } - result.addDynamicLibraryForLinking(libraryLink); } } private CppLinkActionBuilder newLinkActionBuilder(Artifact outputArtifact) { return new CppLinkActionBuilder( ruleContext, outputArtifact, ccToolchain, fdoProvider, featureConfiguration, semantics) - .setCrosstoolInputs(ccToolchain.getLink()); + .setCrosstoolInputs(ccToolchain.getLink()) + .setUseTestOnlyFlags(useTestOnlyFlags); } /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java index ca42099aa36b5f..bcf795fcfd41e7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLinkingOutputs.java @@ -56,15 +56,25 @@ public class CcLinkingOutputs implements CcLinkingOutputsApi { */ private final ImmutableList dynamicLibrariesForRuntime; + private final ImmutableList allLtoArtifacts; + private final ImmutableList linkActionInputs; + private final CppLinkAction.Context cppLinkActionContext; + private CcLinkingOutputs( ImmutableList staticLibraries, ImmutableList picStaticLibraries, ImmutableList dynamicLibrariesForLinking, - ImmutableList dynamicLibrariesForRuntime) { + ImmutableList dynamicLibrariesForRuntime, + ImmutableList allLtoArtifacts, + ImmutableList linkActionInputs, + CppLinkAction.Context cppLinkActionContext) { this.staticLibraries = staticLibraries; this.picStaticLibraries = picStaticLibraries; this.dynamicLibrariesForLinking = dynamicLibrariesForLinking; this.dynamicLibrariesForRuntime = dynamicLibrariesForRuntime; + this.allLtoArtifacts = allLtoArtifacts; + this.linkActionInputs = linkActionInputs; + this.cppLinkActionContext = cppLinkActionContext; } @Override @@ -98,6 +108,18 @@ public ImmutableList getDynamicLibrariesForRuntime() { return dynamicLibrariesForRuntime; } + public ImmutableList getAllLtoArtifacts() { + return allLtoArtifacts; + } + + public ImmutableList getLinkActionInputs() { + return linkActionInputs; + } + + public CppLinkAction.Context getCppLinkActionContext() { + return cppLinkActionContext; + } + public boolean isEmpty() { return staticLibraries.isEmpty() && picStaticLibraries.isEmpty() @@ -250,13 +272,23 @@ public static final class Builder { private final Set picStaticLibraries = new LinkedHashSet<>(); private final Set dynamicLibrariesForLinking = new LinkedHashSet<>(); private final Set dynamicLibrariesForRuntime = new LinkedHashSet<>(); + // TODO(plf): Return a list of debug artifacts instead of lto back end artifacts and in that + // same list return the .pdb file for Windows. + private final ImmutableList.Builder allLtoArtifacts = + ImmutableList.builder(); + private final ImmutableList.Builder linkActionInputs = ImmutableList.builder(); + // TODO(plf): Try to remove this by refactoring native deps and the way they build the launcher. + private CppLinkAction.Context cppLinkActionContext; public CcLinkingOutputs build() { return new CcLinkingOutputs( ImmutableList.copyOf(staticLibraries), ImmutableList.copyOf(picStaticLibraries), ImmutableList.copyOf(dynamicLibrariesForLinking), - ImmutableList.copyOf(dynamicLibrariesForRuntime)); + ImmutableList.copyOf(dynamicLibrariesForRuntime), + allLtoArtifacts.build(), + linkActionInputs.build(), + cppLinkActionContext); } public Builder merge(CcLinkingOutputs outputs) { @@ -264,6 +296,8 @@ public Builder merge(CcLinkingOutputs outputs) { picStaticLibraries.addAll(outputs.getPicStaticLibraries()); dynamicLibrariesForLinking.addAll(outputs.getDynamicLibrariesForLinking()); dynamicLibrariesForRuntime.addAll(outputs.getDynamicLibrariesForRuntime()); + allLtoArtifacts.addAll(outputs.getAllLtoArtifacts()); + linkActionInputs.addAll(outputs.getLinkActionInputs()); return this; } @@ -306,5 +340,21 @@ public Builder addDynamicLibrariesForRuntime(Iterable libraries) Iterables.addAll(dynamicLibrariesForRuntime, libraries); return this; } + + public Builder addAllLtoArtifacts(Iterable allLtoArtifacts) { + this.allLtoArtifacts.addAll(allLtoArtifacts); + return this; + } + + public Builder addLinkActionInputs(Iterable linkActionInputs) { + this.linkActionInputs.addAll(linkActionInputs); + return this; + } + + public Builder setCppLinkActionContext(CppLinkAction.Context cppLinkActionContext) { + Preconditions.checkState(this.cppLinkActionContext == null); + this.cppLinkActionContext = cppLinkActionContext; + return this; + } } } diff --git a/src/test/py/bazel/bazel_windows_cpp_test.py b/src/test/py/bazel/bazel_windows_cpp_test.py index b4dc5a4d21940a..108bd3b94f6ae9 100644 --- a/src/test/py/bazel/bazel_windows_cpp_test.py +++ b/src/test/py/bazel/bazel_windows_cpp_test.py @@ -474,6 +474,7 @@ def testWinDefFileAttribute(self): 'build', '//:lib', '-s', '--output_groups=dynamic_library', '--features=windows_export_all_symbols' ]) + self.AssertExitCode(exit_code, 0, stderr) bazel_bin = self.getBazelInfo('bazel-bin') lib_if = os.path.join(bazel_bin, 'lib.if.lib')