| // 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 static com.google.common.collect.ImmutableList.toImmutableList; |
| import static com.google.common.collect.Streams.stream; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSortedSet; |
| import com.google.common.collect.Iterables; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.analysis.PlatformOptions; |
| 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.analysis.config.BuildOptions; |
| import com.google.devtools.build.lib.analysis.config.BuildOptionsView; |
| import com.google.devtools.build.lib.analysis.config.CoreOptions; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.packages.BuiltinProvider; |
| import com.google.devtools.build.lib.packages.Info; |
| import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; |
| import com.google.devtools.build.lib.packages.StructImpl; |
| import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions; |
| import com.google.devtools.build.lib.rules.apple.AppleConfiguration; |
| import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher; |
| import com.google.devtools.build.lib.rules.apple.ApplePlatform; |
| import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType; |
| import com.google.devtools.build.lib.rules.apple.DottedVersion; |
| import com.google.devtools.build.lib.rules.cpp.CcInfo; |
| import com.google.devtools.build.lib.rules.cpp.CcLinkingContext; |
| import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; |
| import com.google.devtools.build.lib.rules.cpp.CppSemantics; |
| import com.google.devtools.build.lib.rules.objc.AppleLinkingOutputs.TargetTriplet; |
| import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs; |
| import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.stream.Collectors; |
| import net.starlark.java.eval.Dict; |
| |
| /** Support utility for creating multi-arch Apple binaries. */ |
| public class MultiArchBinarySupport { |
| private final RuleContext ruleContext; |
| private final CppSemantics cppSemantics; |
| |
| /** A tuple of values about dependency trees in a specific child configuration. */ |
| @AutoValue |
| abstract static class DependencySpecificConfiguration { |
| static DependencySpecificConfiguration create( |
| BuildConfigurationValue config, |
| CcToolchainProvider toolchain, |
| ObjcProvider objcLinkProvider, |
| ObjcProvider objcProviderWithAvoidDepsSymbols, |
| CcInfo ccInfoWithAvoidDepsSymbols) { |
| return new AutoValue_MultiArchBinarySupport_DependencySpecificConfiguration( |
| config, |
| toolchain, |
| objcLinkProvider, |
| objcProviderWithAvoidDepsSymbols, |
| ccInfoWithAvoidDepsSymbols); |
| } |
| |
| /** Returns the child configuration for this tuple. */ |
| abstract BuildConfigurationValue config(); |
| |
| /** Returns the cc toolchain for this configuration. */ |
| abstract CcToolchainProvider toolchain(); |
| |
| /** |
| * Returns the {@link ObjcProvider} to use as input to the support controlling link actions; |
| * avoid deps symbols should be subtracted from this provider. |
| */ |
| abstract ObjcProvider objcLinkProvider(); |
| |
| /** |
| * Returns the {@link ObjcProvider} to propagate up to dependers; this will not have avoid deps |
| * symbols subtracted, thus signaling that this target is still responsible for those symbols. |
| */ |
| abstract ObjcProvider objcProviderWithAvoidDepsSymbols(); |
| |
| /** |
| * Returns the {@link CcInfo} to propagate up to dependers; this will not have avoid deps |
| * symbols subtracted, thus signaling that this target is still responsible for those symbols. |
| */ |
| abstract CcInfo ccInfoWithAvoidDepsSymbols(); |
| } |
| |
| /** @param ruleContext the current rule context */ |
| public MultiArchBinarySupport(RuleContext ruleContext, CppSemantics cppSemantics) { |
| this.ruleContext = ruleContext; |
| this.cppSemantics = cppSemantics; |
| } |
| |
| /** |
| * Registers actions to link a single-platform/architecture Apple binary in a specific |
| * configuration. |
| * |
| * @param dependencySpecificConfiguration a single {@link DependencySpecificConfiguration} that |
| * corresponds to the child configuration to link for this target. Can be obtained via {@link |
| * #getDependencySpecificConfigurations} |
| * @param extraLinkArgs the extra linker args to add to link actions linking single-architecture |
| * binaries together |
| * @param extraLinkInputs the extra linker inputs to be made available during link actions |
| * @param isStampingEnabled whether linkstamping is enabled |
| * @param infoCollections a list of provider collections which are propagated from the |
| * dependencies in the requested configuration |
| * @param outputMapCollector a map to which output groups created by compile action generation are |
| * added |
| * @return an {@link Artifact} representing the single-architecture binary linked from this call |
| * @throws RuleErrorException if there are attribute errors in the current rule context |
| */ |
| public Artifact registerConfigurationSpecificLinkActions( |
| DependencySpecificConfiguration dependencySpecificConfiguration, |
| ExtraLinkArgs extraLinkArgs, |
| Iterable<Artifact> extraLinkInputs, |
| boolean isStampingEnabled, |
| Iterable<? extends TransitiveInfoCollection> infoCollections, |
| Map<String, NestedSet<Artifact>> outputMapCollector) |
| throws RuleErrorException, InterruptedException { |
| IntermediateArtifacts intermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts( |
| ruleContext, dependencySpecificConfiguration.config()); |
| J2ObjcMappingFileProvider j2ObjcMappingFileProvider = |
| J2ObjcMappingFileProvider.union( |
| getTypedProviders(infoCollections, J2ObjcMappingFileProvider.PROVIDER)); |
| J2ObjcEntryClassProvider j2ObjcEntryClassProvider = |
| new J2ObjcEntryClassProvider.Builder() |
| .addTransitive(getTypedProviders(infoCollections, J2ObjcEntryClassProvider.PROVIDER)) |
| .build(); |
| ImmutableList<CcLinkingContext> ccLinkingContexts = |
| getTypedProviders(infoCollections, CcInfo.PROVIDER).stream() |
| .map(CcInfo::getCcLinkingContext) |
| .collect(toImmutableList()); |
| |
| ObjcProvider objcProvider = dependencySpecificConfiguration.objcLinkProvider(); |
| |
| CompilationSupport compilationSupport = |
| new CompilationSupport.Builder(ruleContext, cppSemantics) |
| .setConfig(dependencySpecificConfiguration.config()) |
| .setToolchainProvider(dependencySpecificConfiguration.toolchain()) |
| .build(); |
| |
| compilationSupport |
| .registerLinkActions( |
| objcProvider, |
| ccLinkingContexts, |
| j2ObjcMappingFileProvider, |
| j2ObjcEntryClassProvider, |
| extraLinkArgs, |
| extraLinkInputs, |
| isStampingEnabled) |
| .validateAttributes(); |
| ruleContext.assertNoErrors(); |
| |
| return intermediateArtifacts.strippedSingleArchitectureBinary(); |
| } |
| |
| /** |
| * Returns a map of {@link DependencySpecificConfiguration} instances keyed by their split |
| * transition key. Each dependency specific configuration comprise all information about the |
| * dependencies for each child configuration. This can be used both to register actions in {@link |
| * #registerConfigurationSpecificLinkActions} and collect provider information to be propagated |
| * upstream. |
| * |
| * @param splitToolchains a map from split toolchains for which dependencies of the current rule |
| * are built |
| * @param splitDeps a map from split "deps" of the current rule. |
| * @param avoidDepsProviders {@link TransitiveInfoCollection}s that dependencies of the current |
| * rule have propagated which should not be linked into the binary |
| * @throws RuleErrorException if there are attribute errors in the current rule context |
| */ |
| public ImmutableMap<Optional<String>, DependencySpecificConfiguration> |
| getDependencySpecificConfigurations( |
| Map<Optional<String>, List<ConfiguredTargetAndData>> splitToolchains, |
| Map<Optional<String>, List<ConfiguredTargetAndData>> splitDeps, |
| ImmutableList<TransitiveInfoCollection> avoidDepsProviders) |
| throws RuleErrorException, InterruptedException { |
| Iterable<ObjcProvider> avoidDepsObjcProviders = getAvoidDepsObjcProviders(avoidDepsProviders); |
| ImmutableList<CcLinkingContext> avoidDepsCcLinkingContexts = |
| getTypedProviders(avoidDepsProviders, CcInfo.PROVIDER).stream() |
| .map(CcInfo::getCcLinkingContext) |
| .collect(toImmutableList()); |
| |
| ImmutableMap.Builder<Optional<String>, DependencySpecificConfiguration> childInfoBuilder = |
| ImmutableMap.builder(); |
| for (Optional<String> splitTransitionKey : splitToolchains.keySet()) { |
| ConfiguredTargetAndData ctad = |
| Iterables.getOnlyElement(splitToolchains.get(splitTransitionKey)); |
| BuildConfigurationValue childToolchainConfig = ctad.getConfiguration(); |
| IntermediateArtifacts intermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext, childToolchainConfig); |
| |
| List<? extends TransitiveInfoCollection> propagatedDeps = |
| getProvidersFromCtads(splitDeps.get(splitTransitionKey)); |
| |
| ObjcCommon common = |
| common( |
| ruleContext, |
| childToolchainConfig, |
| intermediateArtifacts, |
| propagatedDeps, |
| avoidDepsObjcProviders); |
| ObjcProvider objcProviderWithAvoidDepsSymbols = common.getObjcProvider(); |
| ObjcProvider objcProvider = |
| objcProviderWithAvoidDepsSymbols.subtractSubtrees( |
| avoidDepsObjcProviders, avoidDepsCcLinkingContexts); |
| |
| CcInfo ccInfoWithAvoidDepsSymbols = common.createCcInfo(); |
| |
| CcToolchainProvider toolchainProvider = |
| ctad.getConfiguredTarget().get(CcToolchainProvider.PROVIDER); |
| |
| childInfoBuilder.put( |
| splitTransitionKey, |
| DependencySpecificConfiguration.create( |
| childToolchainConfig, |
| toolchainProvider, |
| objcProvider, |
| objcProviderWithAvoidDepsSymbols, |
| ccInfoWithAvoidDepsSymbols)); |
| } |
| |
| return childInfoBuilder.buildOrThrow(); |
| } |
| |
| /** |
| * Returns the ConfigurationDistinguisher that maps directly to the given PlatformType. |
| * |
| * @throws IllegalArgumentException if the platform type attribute is an unsupported value |
| */ |
| private static ConfigurationDistinguisher configurationDistinguisher(PlatformType platformType) { |
| switch (platformType) { |
| case IOS: |
| return ConfigurationDistinguisher.APPLEBIN_IOS; |
| case CATALYST: |
| return ConfigurationDistinguisher.APPLEBIN_CATALYST; |
| case WATCHOS: |
| return ConfigurationDistinguisher.APPLEBIN_WATCHOS; |
| case TVOS: |
| return ConfigurationDistinguisher.APPLEBIN_TVOS; |
| case MACOS: |
| return ConfigurationDistinguisher.APPLEBIN_MACOS; |
| } |
| throw new IllegalArgumentException("Unsupported platform type " + platformType); |
| } |
| |
| /** |
| * Returns the preferred minimum OS version based on information found from inputs. |
| * |
| * @param buildOptions the build's top-level options |
| * @param platformType the platform type attribute found from the given rule being built |
| * @param minimumOsVersion a minimum OS version represented to override command line options, if |
| * one has been found |
| * @return an {@link DottedVersion.Option} representing the preferred minimum OS version if found, |
| * or null |
| * @throws IllegalArgumentException if the platform type attribute is an unsupported value and the |
| * optional minimumOsVersion is not present |
| */ |
| private static DottedVersion.Option minimumOsVersionOption( |
| BuildOptionsView buildOptions, |
| PlatformType platformType, |
| Optional<DottedVersion> minimumOsVersion) { |
| if (minimumOsVersion.isPresent()) { |
| return DottedVersion.option(minimumOsVersion.get()); |
| } |
| DottedVersion.Option option; |
| switch (platformType) { |
| case IOS: |
| case CATALYST: |
| option = buildOptions.get(AppleCommandLineOptions.class).iosMinimumOs; |
| break; |
| case WATCHOS: |
| option = buildOptions.get(AppleCommandLineOptions.class).watchosMinimumOs; |
| break; |
| case TVOS: |
| option = buildOptions.get(AppleCommandLineOptions.class).tvosMinimumOs; |
| break; |
| case MACOS: |
| option = buildOptions.get(AppleCommandLineOptions.class).macosMinimumOs; |
| break; |
| default: |
| throw new IllegalArgumentException("Unsupported platform type " + platformType); |
| } |
| return option; |
| } |
| |
| /** |
| * Creates a derivative set of build options for the given split transition with default options. |
| * |
| * @param buildOptions the build's top-level options |
| * @param platformType the platform type attribute found from the given rule being built |
| * @param minimumOsVersionOption a minimum OS version option for this given split |
| * @return an {@link BuildOptionsView} to be used as a basis for a given multi arch binary split |
| * transition |
| */ |
| private static BuildOptionsView defaultBuildOptionsForSplit( |
| BuildOptionsView buildOptions, |
| PlatformType platformType, |
| DottedVersion.Option minimumOsVersionOption) { |
| BuildOptionsView splitOptions = buildOptions.clone(); |
| |
| AppleCommandLineOptions appleCommandLineOptions = |
| splitOptions.get(AppleCommandLineOptions.class); |
| appleCommandLineOptions.applePlatformType = platformType; |
| switch (platformType) { |
| case IOS: |
| case CATALYST: |
| appleCommandLineOptions.iosMinimumOs = minimumOsVersionOption; |
| break; |
| case WATCHOS: |
| appleCommandLineOptions.watchosMinimumOs = minimumOsVersionOption; |
| break; |
| case TVOS: |
| appleCommandLineOptions.tvosMinimumOs = minimumOsVersionOption; |
| break; |
| case MACOS: |
| appleCommandLineOptions.macosMinimumOs = minimumOsVersionOption; |
| break; |
| } |
| return splitOptions; |
| } |
| |
| /** |
| * Creates a split transition mapping based on --apple_platforms and --platforms. |
| * |
| * @param buildOptions the build's top-level options |
| * @param platformType the platform type attribute found from the given rule being built |
| * @param minimumOsVersion a minimum OS version represented to override command line options, if |
| * one has been found |
| * @param applePlatforms the {@link List} of {@link Label}s representing Apple platforms to split |
| * on |
| * @return an {@link ImmutableMap<String, BuildOptions>} representing the split transition for all |
| * platforms found |
| */ |
| public static ImmutableMap<String, BuildOptions> handleApplePlatforms( |
| BuildOptionsView buildOptions, |
| PlatformType platformType, |
| Optional<DottedVersion> minimumOsVersion, |
| List<Label> applePlatforms) { |
| ImmutableMap.Builder<String, BuildOptions> splitBuildOptions = ImmutableMap.builder(); |
| |
| ConfigurationDistinguisher configurationDistinguisher = |
| configurationDistinguisher(platformType); |
| DottedVersion.Option minimumOsVersionOption = |
| minimumOsVersionOption(buildOptions, platformType, minimumOsVersion); |
| |
| for (Label platform : ImmutableSortedSet.copyOf(applePlatforms)) { |
| BuildOptionsView splitOptions = |
| defaultBuildOptionsForSplit(buildOptions, platformType, minimumOsVersionOption); |
| |
| // Disable multi-platform options for child configurations. |
| splitOptions.get(AppleCommandLineOptions.class).applePlatforms = ImmutableList.of(); |
| |
| // The cpu flag will be set by platform mapping if a mapping exists. |
| splitOptions.get(PlatformOptions.class).platforms = ImmutableList.of(platform); |
| if (splitOptions.get(ObjcCommandLineOptions.class).enableCcDeps) { |
| // Only set the (CC-compilation) configs for dependencies if explicitly required by the |
| // user. |
| // This helps users of the iOS rules who do not depend on CC rules as these config values |
| // require additional flags to work (e.g. a custom crosstool) which now only need to be |
| // set if this feature is explicitly requested. |
| AppleCrosstoolTransition.setAppleCrosstoolTransitionPlatformConfiguration( |
| buildOptions, splitOptions, platform); |
| } |
| AppleCommandLineOptions appleCommandLineOptions = |
| splitOptions.get(AppleCommandLineOptions.class); |
| // Set the configuration distinguisher last, as the method |
| // setAppleCrosstoolTransitionPlatformConfiguration will set this value to the Apple CROSSTOOL |
| // configuration distinguisher, and we want to make sure it's set for the right platform |
| // instead in this split transition. |
| appleCommandLineOptions.configurationDistinguisher = configurationDistinguisher; |
| |
| splitBuildOptions.put(platform.getCanonicalForm(), splitOptions.underlying()); |
| } |
| |
| return splitBuildOptions.buildOrThrow(); |
| } |
| |
| /** |
| * Returns a list of supported Apple CPUs given the minimum OS for the target platform. |
| * |
| * @param minimumOsVersionOption a minimum OS version represented to override command line |
| * options, if one has been found |
| * @param cpus list of Apple CPUs requested by the build invocation |
| * @param platformType the platform type attribute found from the given rule being built |
| * @return a {@link List<String>} representing the supported list of Apple CPUs |
| */ |
| private static List<String> supportedAppleCpusFromMinimumOs( |
| DottedVersion.Option minimumOsVersionOption, List<String> cpus, PlatformType platformType) { |
| List<String> supportedCpus = cpus; |
| DottedVersion actualMinimumOsVersion = DottedVersion.maybeUnwrap(minimumOsVersionOption); |
| DottedVersion unsupported32BitMinimumOs; |
| switch (platformType) { |
| case IOS: |
| unsupported32BitMinimumOs = DottedVersion.fromStringUnchecked("11.0"); |
| break; |
| case WATCHOS: |
| unsupported32BitMinimumOs = DottedVersion.fromStringUnchecked("9.0"); |
| break; |
| default: |
| return supportedCpus; |
| } |
| |
| if (actualMinimumOsVersion != null |
| && actualMinimumOsVersion.compareTo(unsupported32BitMinimumOs) >= 0) { |
| ImmutableList<String> non32BitCpus = |
| cpus.stream() |
| .filter(cpu -> !ApplePlatform.is32Bit(platformType, cpu)) |
| .collect(toImmutableList()); |
| if (!non32BitCpus.isEmpty()) { |
| supportedCpus = non32BitCpus; |
| } |
| } |
| return supportedCpus; |
| } |
| |
| /** |
| * Creates a split transition mapping based on Apple cpu options. |
| * |
| * @param buildOptions the build's top-level options |
| * @param platformType the platform type attribute found from the given rule being built |
| * @param minimumOsVersion a minimum OS version represented to override command line options, if |
| * one has been found |
| * @return an {@link ImmutableMap<String, BuildOptions>} representing the split transition for all |
| * architectures found from cpu flags |
| */ |
| public static ImmutableMap<String, BuildOptions> handleAppleCpus( |
| BuildOptionsView buildOptions, |
| PlatformType platformType, |
| Optional<DottedVersion> minimumOsVersion) { |
| List<String> cpus; |
| ConfigurationDistinguisher configurationDistinguisher = |
| configurationDistinguisher(platformType); |
| DottedVersion.Option minimumOsVersionOption = |
| minimumOsVersionOption(buildOptions, platformType, minimumOsVersion); |
| |
| switch (platformType) { |
| case IOS: |
| cpus = buildOptions.get(AppleCommandLineOptions.class).iosMultiCpus; |
| if (cpus.isEmpty()) { |
| cpus = |
| ImmutableList.of( |
| AppleConfiguration.iosCpuFromCpu(buildOptions.get(CoreOptions.class).cpu)); |
| } |
| cpus = supportedAppleCpusFromMinimumOs(minimumOsVersionOption, cpus, platformType); |
| break; |
| case WATCHOS: |
| cpus = buildOptions.get(AppleCommandLineOptions.class).watchosCpus; |
| if (cpus.isEmpty()) { |
| cpus = ImmutableList.of(AppleCommandLineOptions.DEFAULT_WATCHOS_CPU); |
| } |
| cpus = supportedAppleCpusFromMinimumOs(minimumOsVersionOption, cpus, platformType); |
| break; |
| case TVOS: |
| cpus = buildOptions.get(AppleCommandLineOptions.class).tvosCpus; |
| if (cpus.isEmpty()) { |
| cpus = ImmutableList.of(AppleCommandLineOptions.DEFAULT_TVOS_CPU); |
| } |
| break; |
| case MACOS: |
| cpus = buildOptions.get(AppleCommandLineOptions.class).macosCpus; |
| if (cpus.isEmpty()) { |
| cpus = ImmutableList.of(AppleCommandLineOptions.DEFAULT_MACOS_CPU); |
| } |
| break; |
| case CATALYST: |
| cpus = buildOptions.get(AppleCommandLineOptions.class).catalystCpus; |
| if (cpus.isEmpty()) { |
| cpus = ImmutableList.of(AppleCommandLineOptions.DEFAULT_CATALYST_CPU); |
| } |
| break; |
| default: |
| throw new IllegalArgumentException("Unsupported platform type " + platformType); |
| } |
| |
| // There may be some duplicate flag values. |
| cpus = ImmutableSortedSet.copyOf(cpus).asList(); |
| ImmutableMap.Builder<String, BuildOptions> splitBuildOptions = ImmutableMap.builder(); |
| for (String cpu : cpus) { |
| BuildOptionsView splitOptions = |
| defaultBuildOptionsForSplit(buildOptions, platformType, minimumOsVersionOption); |
| |
| AppleCommandLineOptions appleCommandLineOptions = |
| splitOptions.get(AppleCommandLineOptions.class); |
| |
| appleCommandLineOptions.appleSplitCpu = cpu; |
| |
| String platformCpu = ApplePlatform.cpuStringForTarget(platformType, cpu); |
| if (splitOptions.get(ObjcCommandLineOptions.class).enableCcDeps) { |
| // Only set the (CC-compilation) CPU for dependencies if explicitly required by the user. |
| // This helps users of the iOS rules who do not depend on CC rules as these CPU values |
| // require additional flags to work (e.g. a custom crosstool) which now only need to be |
| // set if this feature is explicitly requested. |
| AppleCrosstoolTransition.setAppleCrosstoolTransitionCpuConfiguration( |
| buildOptions, splitOptions, platformCpu); |
| } |
| // Set the configuration distinguisher last, as setAppleCrosstoolTransitionCpuConfiguration |
| // will set this value to the Apple CROSSTOOL configuration distinguisher, and we want to make |
| // sure it's set for the right platform instead in this split transition. |
| appleCommandLineOptions.configurationDistinguisher = configurationDistinguisher; |
| |
| splitBuildOptions.put(platformCpu, splitOptions.underlying()); |
| } |
| return splitBuildOptions.buildOrThrow(); |
| } |
| |
| private static Iterable<ObjcProvider> getAvoidDepsObjcProviders( |
| ImmutableList<TransitiveInfoCollection> transitiveInfoCollections) { |
| // Dylibs. |
| ImmutableList<ObjcProvider> frameworkObjcProviders = |
| getTypedProviders(transitiveInfoCollections, AppleDynamicFrameworkInfo.STARLARK_CONSTRUCTOR) |
| .stream() |
| .map(frameworkProvider -> frameworkProvider.getDepsObjcProvider()) |
| .collect(toImmutableList()); |
| // Bundle Loaders. |
| ImmutableList<ObjcProvider> executableObjcProviders = |
| getTypedProviders(transitiveInfoCollections, AppleExecutableBinaryInfo.STARLARK_CONSTRUCTOR) |
| .stream() |
| .map(frameworkProvider -> frameworkProvider.getDepsObjcProvider()) |
| .collect(toImmutableList()); |
| |
| return Iterables.concat( |
| frameworkObjcProviders, |
| executableObjcProviders, |
| getTypedProviders(transitiveInfoCollections, ObjcProvider.STARLARK_CONSTRUCTOR)); |
| } |
| |
| private ObjcCommon common( |
| RuleContext ruleContext, |
| BuildConfigurationValue buildConfiguration, |
| IntermediateArtifacts intermediateArtifacts, |
| List<? extends TransitiveInfoCollection> propagatedDeps, |
| Iterable<ObjcProvider> additionalDepProviders) |
| throws InterruptedException { |
| |
| ObjcCommon.Builder commonBuilder = |
| new ObjcCommon.Builder(ObjcCommon.Purpose.LINK_ONLY, ruleContext, buildConfiguration) |
| .setCompilationAttributes( |
| CompilationAttributes.Builder.fromRuleContext(ruleContext).build()) |
| .addDeps(propagatedDeps) |
| .addObjcProviders(additionalDepProviders) |
| .setIntermediateArtifacts(intermediateArtifacts) |
| .setAlwayslink(false); |
| |
| return commonBuilder.build(); |
| } |
| |
| private static <T extends Info> ImmutableList<T> getTypedProviders( |
| Iterable<? extends TransitiveInfoCollection> infoCollections, |
| BuiltinProvider<T> providerClass) { |
| return stream(infoCollections) |
| .filter(infoCollection -> infoCollection.get(providerClass) != null) |
| .map(infoCollection -> infoCollection.get(providerClass)) |
| .collect(toImmutableList()); |
| } |
| |
| /** Returns providers from a list of {@link ConfiguredTargetAndData} */ |
| public static List<? extends TransitiveInfoCollection> getProvidersFromCtads( |
| List<ConfiguredTargetAndData> ctads) { |
| if (ctads == null) { |
| return ImmutableList.<TransitiveInfoCollection>of(); |
| } |
| return ctads.stream() |
| .map(ConfiguredTargetAndData::getConfiguredTarget) |
| .collect(Collectors.toList()); |
| } |
| |
| /** |
| * Returns an Apple target triplet (arch, platform, environment) for a given {@link |
| * BuildConfigurationValue}. |
| * |
| * @param config {@link BuildConfigurationValue} from rule context |
| * @return {@link AppleLinkingOutputs.TargetTriplet} |
| */ |
| public static AppleLinkingOutputs.TargetTriplet getTargetTriplet(BuildConfigurationValue config) { |
| // 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(config.getCpu()); |
| AppleConfiguration appleConfig = config.getFragment(AppleConfiguration.class); |
| |
| return TargetTriplet.create( |
| appleConfig.getSingleArchitecture(), |
| cpuPlatform.getTargetPlatform(), |
| cpuPlatform.getTargetEnvironment()); |
| } |
| |
| /** |
| * Transforms a {@link Map<Optional<String>, List<ConfiguredTargetAndData>>}, to a Starlark Dict |
| * keyed by split transition keys with {@link AppleLinkingOutputs.TargetTriplet} Starlark struct |
| * definition. |
| * |
| * @param ctads a {@link Map<Optional<String>, List<ConfiguredTargetAndData>>} from rule context |
| * @return a Starlark {@link Dict<String, StructImpl>} representing split transition keys with |
| * their target triplet (architecture, platform, environment) |
| */ |
| public static Dict<String, StructImpl> getSplitTargetTripletFromCtads( |
| Map<Optional<String>, List<ConfiguredTargetAndData>> ctads) { |
| Dict.Builder<String, StructImpl> result = Dict.builder(); |
| for (Optional<String> splitTransitionKey : ctads.keySet()) { |
| TargetTriplet targetTriplet = |
| getTargetTriplet( |
| Iterables.getOnlyElement(ctads.get(splitTransitionKey)).getConfiguration()); |
| result.put(splitTransitionKey.get(), targetTriplet.toStarlarkStruct()); |
| } |
| return result.buildImmutable(); |
| } |
| } |