| // 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.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableListMultimap; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Iterables; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; |
| import com.google.devtools.build.lib.analysis.config.BuildConfiguration; |
| 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.Platform; |
| import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider; |
| import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs; |
| import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes; |
| |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Support utility for creating multi-arch Apple binaries. |
| */ |
| public class MultiArchBinarySupport { |
| private final RuleContext ruleContext; |
| |
| /** |
| * @param ruleContext the current rule context |
| */ |
| public MultiArchBinarySupport(RuleContext ruleContext) { |
| this.ruleContext = ruleContext; |
| } |
| |
| /** |
| * Registers actions to create a multi-arch Apple binary. |
| * |
| * @param platform the platform for which the binary is targeted |
| * @param extraLinkArgs the extra linker args to add to link actions linking single-architecture |
| * binaries together |
| * @param configurationToObjcProvider a map from from dependency configuration to the |
| * {@link ObjcProvider} which comprises all information about the dependencies in that |
| * configuration. Can be obtained via {@link #objcProviderByDepConfiguration} |
| * @param extraLinkInputs the extra linker inputs to be made available during link actions |
| * @param configToDepsCollectionMap a multimap from dependency configuration to the |
| * list of provider collections which are propagated from the dependencies of that |
| * configuration |
| * @param outputLipoBinary the artifact (lipo'ed binary) which should be output as a result of |
| * this support |
| * @throws RuleErrorException if there are attribute errors in the current rule context |
| */ |
| public void registerActions( |
| Platform platform, |
| ExtraLinkArgs extraLinkArgs, |
| Map<BuildConfiguration, ObjcProvider> configurationToObjcProvider, |
| Iterable<Artifact> extraLinkInputs, |
| ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection> configToDepsCollectionMap, |
| Artifact outputLipoBinary) |
| throws RuleErrorException, InterruptedException { |
| |
| NestedSetBuilder<Artifact> binariesToLipo = |
| NestedSetBuilder.<Artifact>stableOrder(); |
| for (BuildConfiguration childConfig : configurationToObjcProvider.keySet()) { |
| IntermediateArtifacts intermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig); |
| ImmutableList.Builder<J2ObjcMappingFileProvider> j2ObjcMappingFileProviders = |
| ImmutableList.builder(); |
| J2ObjcEntryClassProvider.Builder j2ObjcEntryClassProviderBuilder = |
| new J2ObjcEntryClassProvider.Builder(); |
| for (TransitiveInfoCollection dep : configToDepsCollectionMap.get(childConfig)) { |
| if (dep.getProvider(J2ObjcMappingFileProvider.class) != null) { |
| j2ObjcMappingFileProviders.add(dep.getProvider(J2ObjcMappingFileProvider.class)); |
| } |
| if (dep.getProvider(J2ObjcEntryClassProvider.class) != null) { |
| j2ObjcEntryClassProviderBuilder.addTransitive( |
| dep.getProvider(J2ObjcEntryClassProvider.class)); |
| } |
| } |
| J2ObjcMappingFileProvider j2ObjcMappingFileProvider = |
| J2ObjcMappingFileProvider.union(j2ObjcMappingFileProviders.build()); |
| J2ObjcEntryClassProvider j2ObjcEntryClassProvider = j2ObjcEntryClassProviderBuilder.build(); |
| |
| binariesToLipo.add(intermediateArtifacts.strippedSingleArchitectureBinary()); |
| |
| ObjcProvider objcProvider = configurationToObjcProvider.get(childConfig); |
| CompilationArtifacts compilationArtifacts = |
| CompilationSupport.compilationArtifacts( |
| ruleContext, ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig)); |
| CompilationSupport.createForConfig(ruleContext, childConfig) |
| .registerCompileAndArchiveActions(compilationArtifacts, objcProvider) |
| .registerLinkActions( |
| objcProvider, |
| j2ObjcMappingFileProvider, |
| j2ObjcEntryClassProvider, |
| extraLinkArgs, |
| extraLinkInputs, |
| DsymOutputType.APP) |
| .validateAttributes(); |
| ruleContext.assertNoErrors(); |
| } |
| |
| new LipoSupport(ruleContext) |
| .registerCombineArchitecturesAction( |
| binariesToLipo.build(), |
| outputLipoBinary, |
| platform); |
| } |
| |
| /** |
| * Returns a map from from dependency configuration to the {@link ObjcCommon} which comprises all |
| * information about the dependencies in that configuration. This can be used both to register |
| * actions in {@link #registerActions} and collect provider information to be propagated upstream. |
| * |
| * @param childConfigurations the set of configurations in which dependencies of the current rule |
| * are built |
| * @param configToDepsCollectionMap a map from child configuration to providers that "deps" of the |
| * current rule have propagated in that configuration |
| * @param configurationToNonPropagatedObjcMap a map from child configuration to providers that |
| * "non_propagated_deps" of the current rule have propagated in that configuration |
| * @param dylibObjcProviders {@link ObjcProvider}s that dynamic library dependencies of the |
| * current rule have propagated |
| * @param dylibProtoProviders {@link ObjcProtoProvider} providers that dynamic library |
| * dependencies of the current rule have propagated |
| * @param bundleLoaderObjcProvider Optional ObjcProvider containing artifacts and paths to be |
| * included in this binary's compilation actions |
| * @throws RuleErrorException if there are attribute errors in the current rule context |
| */ |
| public Map<BuildConfiguration, ObjcProvider> objcProviderByDepConfiguration( |
| Set<BuildConfiguration> childConfigurations, |
| ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection> configToDepsCollectionMap, |
| ImmutableListMultimap<BuildConfiguration, ObjcProvider> configurationToNonPropagatedObjcMap, |
| Iterable<ObjcProvider> dylibObjcProviders, |
| Iterable<ObjcProtoProvider> dylibProtoProviders) |
| throws RuleErrorException, InterruptedException { |
| ImmutableMap.Builder<BuildConfiguration, ObjcProvider> configurationToObjcProviderBuilder = |
| ImmutableMap.builder(); |
| |
| for (BuildConfiguration childConfig : childConfigurations) { |
| Optional<ObjcProvider> protosObjcProvider; |
| if (ObjcRuleClasses.objcConfiguration(ruleContext).enableAppleBinaryNativeProtos()) { |
| ProtobufSupport protoSupport = |
| new ProtobufSupport(ruleContext, childConfig, |
| protoArtifactsToAvoid(dylibProtoProviders)) |
| .registerGenerationActions() |
| .registerCompilationActions(); |
| protosObjcProvider = protoSupport.getObjcProvider(); |
| } else { |
| protosObjcProvider = Optional.absent(); |
| } |
| |
| IntermediateArtifacts intermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig); |
| |
| Iterable<ObjcProvider> additionalDepProviders = |
| Iterables.concat( |
| dylibObjcProviders, |
| ruleContext.getPrerequisites("bundles", Mode.TARGET, ObjcProvider.class), |
| protosObjcProvider.asSet()); |
| |
| ObjcCommon common = |
| common( |
| ruleContext, |
| childConfig, |
| intermediateArtifacts, |
| nullToEmptyList(configToDepsCollectionMap.get(childConfig)), |
| nullToEmptyList(configurationToNonPropagatedObjcMap.get(childConfig)), |
| additionalDepProviders); |
| ObjcProvider objcProvider = common.getObjcProvider().subtractSubtrees(dylibObjcProviders, |
| ImmutableList.<CcLinkParamsProvider>of()); |
| |
| configurationToObjcProviderBuilder.put(childConfig, objcProvider); |
| } |
| |
| return configurationToObjcProviderBuilder.build(); |
| } |
| |
| private ObjcCommon common( |
| RuleContext ruleContext, |
| BuildConfiguration buildConfiguration, |
| IntermediateArtifacts intermediateArtifacts, |
| List<TransitiveInfoCollection> propagatedDeps, |
| List<ObjcProvider> nonPropagatedObjcDeps, |
| Iterable<ObjcProvider> additionalDepProviders) { |
| |
| CompilationArtifacts compilationArtifacts = |
| CompilationSupport.compilationArtifacts(ruleContext, intermediateArtifacts); |
| |
| ObjcCommon.Builder commonBuilder = new ObjcCommon.Builder(ruleContext, buildConfiguration) |
| .setCompilationAttributes( |
| CompilationAttributes.Builder.fromRuleContext(ruleContext).build()) |
| .setCompilationArtifacts(compilationArtifacts) |
| .setResourceAttributes(new ResourceAttributes(ruleContext)) |
| .addDefines(ruleContext.getTokenizedStringListAttr("defines")) |
| .addDeps(propagatedDeps) |
| .addDepObjcProviders(additionalDepProviders) |
| .addNonPropagatedDepObjcProviders(nonPropagatedObjcDeps) |
| .setIntermediateArtifacts(intermediateArtifacts) |
| .setAlwayslink(false) |
| // TODO(b/29152500): Enable module map generation. |
| .setLinkedBinary(intermediateArtifacts.strippedSingleArchitectureBinary()); |
| |
| if (ObjcRuleClasses.objcConfiguration(ruleContext).generateDsym()) { |
| commonBuilder.addDebugArtifacts(DsymOutputType.APP); |
| } |
| return commonBuilder.build(); |
| } |
| |
| private <T> List<T> nullToEmptyList(List<T> inputList) { |
| return inputList != null ? inputList : ImmutableList.<T>of(); |
| } |
| |
| private static NestedSet<Artifact> protoArtifactsToAvoid( |
| Iterable<ObjcProtoProvider> avoidedProviders) { |
| NestedSetBuilder<Artifact> avoidArtifacts = NestedSetBuilder.stableOrder(); |
| for (ObjcProtoProvider avoidProvider : avoidedProviders) { |
| for (NestedSet<Artifact> avoidProviderOutputGroup : avoidProvider.getProtoGroups()) { |
| avoidArtifacts.addTransitive(avoidProviderOutputGroup); |
| } |
| } |
| return avoidArtifacts.build(); |
| } |
| } |