| // Copyright 2016 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. |
| |
| package com.google.devtools.build.lib.rules.objc; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableListMultimap; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; |
| import com.google.devtools.build.lib.analysis.OutputGroupInfo; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; |
| import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
| import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; |
| import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode; |
| import com.google.devtools.build.lib.rules.apple.AppleConfiguration; |
| import com.google.devtools.build.lib.rules.apple.ApplePlatform; |
| import com.google.devtools.build.lib.rules.cpp.CcInfo; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; |
| import com.google.devtools.build.lib.rules.cpp.CppConfiguration; |
| import com.google.devtools.build.lib.rules.cpp.CppSemantics; |
| import com.google.devtools.build.lib.rules.objc.AppleDebugOutputsInfo.OutputType; |
| import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs; |
| import com.google.devtools.build.lib.rules.objc.MultiArchBinarySupport.DependencySpecificConfiguration; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| /** Native support for Apple binary rules. */ |
| public class AppleBinary { |
| private AppleBinary() {} |
| |
| /** |
| * Links a (potentially multi-architecture) binary targeting Apple platforms. |
| * |
| * <p>This method comprises a bulk of the logic of the {@code apple_binary} rule, and is |
| * statically available so that it may be referenced by Starlark APIs that replicate its |
| * functionality. |
| * |
| * @param ruleContext the current rule context |
| * @param cppSemantics the cpp semantics to use |
| * @param avoidDeps a list of {@code TransitiveInfoColllection} that contain information about |
| * dependencies whose symbols are used by the linked binary but should not be linked into the |
| * binary itself |
| * @param extraLinkopts extra linkopts to pass to the linker actions |
| * @param extraLinkInputs extra input files to pass to the linker action |
| * @param isStampingEnabled whether linkstamping is enabled |
| * @return a tuple containing all necessary information about the linked binary |
| */ |
| public static AppleLinkingOutputs linkMultiArchBinary( |
| RuleContext ruleContext, |
| CppSemantics cppSemantics, |
| ImmutableList<TransitiveInfoCollection> avoidDeps, |
| Iterable<String> extraLinkopts, |
| Iterable<Artifact> extraLinkInputs, |
| boolean isStampingEnabled) |
| throws InterruptedException, RuleErrorException, ActionConflictException { |
| ImmutableListMultimap<String, TransitiveInfoCollection> cpuToDepsCollectionMap = |
| MultiArchBinarySupport.transformMap(ruleContext.getPrerequisitesByConfiguration("deps")); |
| |
| ImmutableMap<BuildConfigurationValue, CcToolchainProvider> childConfigurationsAndToolchains = |
| MultiArchBinarySupport.getChildConfigurationsAndToolchains(ruleContext); |
| MultiArchBinarySupport multiArchBinarySupport = |
| new MultiArchBinarySupport(ruleContext, cppSemantics); |
| |
| ImmutableSet<DependencySpecificConfiguration> dependencySpecificConfigurations = |
| multiArchBinarySupport.getDependencySpecificConfigurations( |
| childConfigurationsAndToolchains, cpuToDepsCollectionMap, avoidDeps); |
| |
| Map<String, NestedSet<Artifact>> outputGroupCollector = new TreeMap<>(); |
| |
| ImmutableList.Builder<Artifact> allLinkInputs = ImmutableList.builder(); |
| ImmutableList.Builder<String> allLinkopts = ImmutableList.builder(); |
| allLinkInputs.addAll(extraLinkInputs); |
| allLinkopts.addAll(extraLinkopts); |
| |
| ImmutableListMultimap<BuildConfigurationValue, CcInfo> buildConfigToCcInfoMap = |
| ruleContext.getPrerequisitesByConfiguration("deps", CcInfo.PROVIDER); |
| NestedSetBuilder<Artifact> headerTokens = NestedSetBuilder.stableOrder(); |
| for (Map.Entry<BuildConfigurationValue, CcInfo> entry : buildConfigToCcInfoMap.entries()) { |
| CcInfo dep = entry.getValue(); |
| headerTokens.addTransitive(dep.getCcCompilationContext().getHeaderTokens()); |
| } |
| outputGroupCollector.put(OutputGroupInfo.VALIDATION, headerTokens.build()); |
| |
| ObjcProvider.Builder objcProviderBuilder = |
| new ObjcProvider.Builder(ruleContext.getAnalysisEnvironment().getStarlarkSemantics()); |
| for (DependencySpecificConfiguration dependencySpecificConfiguration : |
| dependencySpecificConfigurations) { |
| objcProviderBuilder.addTransitiveAndPropagate( |
| dependencySpecificConfiguration.objcProviderWithDylibSymbols()); |
| } |
| |
| AppleDebugOutputsInfo.Builder legacyDebugOutputsBuilder = |
| AppleDebugOutputsInfo.Builder.create(); |
| AppleLinkingOutputs.Builder builder = |
| new AppleLinkingOutputs.Builder().addOutputGroups(outputGroupCollector); |
| |
| for (DependencySpecificConfiguration dependencySpecificConfiguration : |
| dependencySpecificConfigurations) { |
| BuildConfigurationValue childConfig = dependencySpecificConfiguration.config(); |
| String configCpu = childConfig.getCpu(); |
| AppleConfiguration childAppleConfig = childConfig.getFragment(AppleConfiguration.class); |
| CppConfiguration childCppConfig = childConfig.getFragment(CppConfiguration.class); |
| ObjcConfiguration childObjcConfig = childConfig.getFragment(ObjcConfiguration.class); |
| IntermediateArtifacts intermediateArtifacts = |
| new IntermediateArtifacts( |
| ruleContext, /*archiveFileNameSuffix*/ "", /*outputPrefix*/ "", childConfig); |
| String arch = childAppleConfig.getSingleArchitecture(); |
| |
| Artifact binaryArtifact = |
| multiArchBinarySupport.registerConfigurationSpecificLinkActions( |
| dependencySpecificConfiguration, |
| new ExtraLinkArgs(allLinkopts.build()), |
| allLinkInputs.build(), |
| isStampingEnabled, |
| cpuToDepsCollectionMap.get(configCpu), |
| outputGroupCollector); |
| |
| // TODO(b/177442911): Use the target platform from platform info coming from split |
| // transition outputs instead of inferring this based on the target CPU. |
| ApplePlatform cpuPlatform = ApplePlatform.forTargetCpu(configCpu); |
| |
| AppleLinkingOutputs.LinkingOutput.Builder outputBuilder = |
| AppleLinkingOutputs.LinkingOutput.builder() |
| .setPlatform(cpuPlatform.getTargetPlatform()) |
| .setArchitecture(arch) |
| .setEnvironment(cpuPlatform.getTargetEnvironment()) |
| .setBinary(binaryArtifact); |
| |
| if (childCppConfig.getAppleBitcodeMode() == AppleBitcodeMode.EMBEDDED) { |
| Artifact bitcodeSymbols = intermediateArtifacts.bitcodeSymbolMap(); |
| outputBuilder.setBitcodeSymbols(bitcodeSymbols); |
| legacyDebugOutputsBuilder.addOutput(arch, OutputType.BITCODE_SYMBOLS, bitcodeSymbols); |
| } |
| if (childCppConfig.appleGenerateDsym()) { |
| Artifact dsymBinary = |
| childObjcConfig.shouldStripBinary() |
| ? intermediateArtifacts.dsymSymbolForUnstrippedBinary() |
| : intermediateArtifacts.dsymSymbolForStrippedBinary(); |
| outputBuilder.setDsymBinary(dsymBinary); |
| legacyDebugOutputsBuilder.addOutput(arch, OutputType.DSYM_BINARY, dsymBinary); |
| } |
| if (childObjcConfig.generateLinkmap()) { |
| Artifact linkmap = intermediateArtifacts.linkmap(); |
| outputBuilder.setLinkmap(linkmap); |
| legacyDebugOutputsBuilder.addOutput(arch, OutputType.LINKMAP, linkmap); |
| } |
| |
| builder.addOutput(outputBuilder.build()); |
| } |
| |
| return builder |
| .setDepsObjcProvider(objcProviderBuilder.build()) |
| .setLegacyDebugOutputsProvider(legacyDebugOutputsBuilder.build()) |
| .build(); |
| } |
| } |