From 5a7d2575d3527a35b8ac541ae09591b6a040f67b Mon Sep 17 00:00:00 2001 From: cparsons Date: Mon, 8 Jan 2018 14:04:50 -0800 Subject: Expose apple_common.link_multi_arch_binary to Skylark. This API mimics the linking logic of apple_binary, and is a step to migrating apple_binary to skylark. This API is *highly experimental* and subject to change. RELNOTES: None. PiperOrigin-RevId: 181215275 --- .../build/lib/rules/cpp/CppConfiguration.java | 7 + .../devtools/build/lib/rules/objc/AppleBinary.java | 166 +++++++++++++++++---- .../build/lib/rules/objc/AppleSkylarkCommon.java | 29 +++- .../lib/rules/objc/MultiArchBinarySupport.java | 13 +- 4 files changed, 174 insertions(+), 41 deletions(-) (limited to 'src/main/java/com/google/devtools/build/lib') diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java index b1099467b1..bf53bd53c4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppConfiguration.java @@ -32,6 +32,7 @@ import com.google.devtools.build.lib.analysis.config.CompilationMode; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.config.PerLabelOptions; import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition; +import com.google.devtools.build.lib.analysis.skylark.SkylarkConfigurationField; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.events.Event; @@ -466,6 +467,12 @@ public class CppConfiguration extends BuildConfiguration.Fragment { /** * Returns the label of the cc_compiler rule for the C++ configuration. */ + @SkylarkConfigurationField( + name = "cc_toolchain", + doc = "The label of the target describing the C++ toolchain", + defaultLabel = "//tools/defaults:crosstool", + defaultInToolRepository = false + ) public Label getCcToolchainRuleLabel() { return ccToolchainLabel; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java index cf2fc9109d..8a6215bbb6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java @@ -38,6 +38,7 @@ import com.google.devtools.build.lib.analysis.test.InstrumentedFilesCollector; import com.google.devtools.build.lib.analysis.test.InstrumentedFilesProvider; 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.NativeInfo; 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; @@ -46,7 +47,6 @@ import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; import com.google.devtools.build.lib.rules.objc.AppleDebugOutputsProvider.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; @@ -114,6 +114,23 @@ public class AppleBinary implements RuleConfiguredTargetFactory { @Override public final ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException, RuleErrorException { + AppleBinaryOutput appleBinaryOutput = linkMultiArchBinary(ruleContext); + + return ruleConfiguredTargetFromProvider(ruleContext, appleBinaryOutput); + } + + /** + * Links a (potentially multi-architecture) binary targeting Apple platforms. + * + *

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 Skylark APIs that replicate its + * functionality. + * + * @param ruleContext the current rule context + * @return a tuple containing all necessary information about the linked binary + */ + public static AppleBinaryOutput linkMultiArchBinary(RuleContext ruleContext) + throws InterruptedException, RuleErrorException { MultiArchSplitTransitionProvider.validateMinimumOs(ruleContext); PlatformType platformType = MultiArchSplitTransitionProvider.getPlatformType(ruleContext); @@ -141,19 +158,20 @@ public class AppleBinary implements RuleConfiguredTargetFactory { getDylibProviderTargets(ruleContext)); Map> outputGroupCollector = new TreeMap<>(); - multiArchBinarySupport.registerActions( - platform, - getExtraLinkArgs(ruleContext), - dependencySpecificConfigurations, - getExtraLinkInputs(ruleContext), - configToDepsCollectionMap, - outputArtifact, - outputGroupCollector); + NestedSet binariesToLipo = + multiArchBinarySupport.registerActions( + platform, + getExtraLinkArgs(ruleContext), + dependencySpecificConfigurations, + getExtraLinkInputs(ruleContext), + configToDepsCollectionMap, + outputGroupCollector); - NestedSetBuilder filesToBuild = - NestedSetBuilder.stableOrder().add(outputArtifact); - RuleConfiguredTargetBuilder targetBuilder = - ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build()); + new LipoSupport(ruleContext) + .registerCombineArchitecturesAction( + binariesToLipo, + outputArtifact, + platform); ObjcProvider.Builder objcProviderBuilder = new ObjcProvider.Builder(); for (DependencySpecificConfiguration dependencySpecificConfiguration : @@ -164,24 +182,24 @@ public class AppleBinary implements RuleConfiguredTargetFactory { objcProviderBuilder.add(MULTI_ARCH_LINKED_BINARIES, outputArtifact); ObjcProvider objcProvider = objcProviderBuilder.build(); - - if (appleConfiguration.shouldLinkingRulesPropagateObjc()) { - targetBuilder.addNativeDeclaredProvider(objcProvider); - } + NativeInfo binaryInfoProvider; switch (getBinaryType(ruleContext)) { case EXECUTABLE: - targetBuilder.addNativeDeclaredProvider( - new AppleExecutableBinaryProvider(outputArtifact, objcProvider)); + binaryInfoProvider = + new AppleExecutableBinaryProvider(outputArtifact, objcProvider); break; case DYLIB: - targetBuilder.addNativeDeclaredProvider( - new AppleDylibBinaryProvider(outputArtifact, objcProvider)); + binaryInfoProvider = + new AppleDylibBinaryProvider(outputArtifact, objcProvider); break; case LOADABLE_BUNDLE: - targetBuilder.addNativeDeclaredProvider( - new AppleLoadableBundleBinaryProvider(outputArtifact, objcProvider)); + binaryInfoProvider = + new AppleLoadableBundleBinaryProvider(outputArtifact, objcProvider); break; + default: + ruleContext.ruleError("Unhandled binary type " + getBinaryType(ruleContext)); + throw new RuleErrorException(); } AppleDebugOutputsProvider.Builder builder = AppleDebugOutputsProvider.Builder.create(); @@ -214,13 +232,7 @@ public class AppleBinary implements RuleConfiguredTargetFactory { } } - targetBuilder.addNativeDeclaredProvider(builder.build()).addOutputGroups(outputGroupCollector); - - InstrumentedFilesProvider instrumentedFilesProvider = - InstrumentedFilesCollector.forward(ruleContext, "deps", "bundle_loader"); - targetBuilder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider); - - return targetBuilder.build(); + return new AppleBinaryOutput(binaryInfoProvider, builder.build(), outputGroupCollector); } private static ExtraLinkArgs getExtraLinkArgs(RuleContext ruleContext) throws RuleErrorException { @@ -282,4 +294,98 @@ public class AppleBinary implements RuleConfiguredTargetFactory { ruleContext.attributes().get(AppleBinaryRule.BINARY_TYPE_ATTR, STRING); return BinaryType.fromString(binaryTypeString); } + + private static ConfiguredTarget ruleConfiguredTargetFromProvider( + RuleContext ruleContext, AppleBinaryOutput appleBinaryOutput) throws RuleErrorException { + NativeInfo nativeInfo = appleBinaryOutput.getBinaryInfoProvider(); + AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class); + + ObjcProvider objcProvider = null; + Artifact outputArtifact; + + switch (getBinaryType(ruleContext)) { + case EXECUTABLE: + AppleExecutableBinaryProvider executableProvider = + (AppleExecutableBinaryProvider) nativeInfo; + objcProvider = executableProvider.getDepsObjcProvider(); + outputArtifact = executableProvider.getAppleExecutableBinary(); + break; + case DYLIB: + AppleDylibBinaryProvider dylibProvider = (AppleDylibBinaryProvider) nativeInfo; + objcProvider = dylibProvider.getDepsObjcProvider(); + outputArtifact = dylibProvider.getAppleDylibBinary(); + break; + case LOADABLE_BUNDLE: + AppleLoadableBundleBinaryProvider loadableBundleProvider = + (AppleLoadableBundleBinaryProvider) nativeInfo; + outputArtifact = loadableBundleProvider.getAppleLoadableBundleBinary(); + break; + default: + ruleContext.ruleError("Unhandled binary type " + getBinaryType(ruleContext)); + throw new RuleErrorException(); + } + + NestedSetBuilder filesToBuild = + NestedSetBuilder.stableOrder().add(outputArtifact); + + RuleConfiguredTargetBuilder targetBuilder = + ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build()); + + if (appleConfiguration.shouldLinkingRulesPropagateObjc() && objcProvider != null) { + targetBuilder.addNativeDeclaredProvider(objcProvider); + } + + InstrumentedFilesProvider instrumentedFilesProvider = + InstrumentedFilesCollector.forward(ruleContext, "deps", "bundle_loader"); + + return targetBuilder.addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider) + .addNativeDeclaredProvider(nativeInfo) + .addNativeDeclaredProvider(appleBinaryOutput.getDebugOutputsProvider()) + .addOutputGroups(appleBinaryOutput.getOutputGroups()) + .build(); + + } + + /** + * The set of rule outputs propagated by the {@code apple_binary} rule. + */ + public static class AppleBinaryOutput { + private final NativeInfo binaryInfoProvider; + private final AppleDebugOutputsProvider debugOutputsProvider; + private final Map> outputGroups; + + private AppleBinaryOutput(NativeInfo binaryInfoProvider, + AppleDebugOutputsProvider debugOutputsProvider, + Map> outputGroups) { + this.binaryInfoProvider = binaryInfoProvider; + this.debugOutputsProvider = debugOutputsProvider; + this.outputGroups = outputGroups; + } + + /** + * Returns a {@link NativeInfo} possessing information about the linked binary. Depending + * on the type of binary, this may be either a {@link AppleExecutableBinaryProvider}, a + * {@link AppleDylibBinaryProvider}, or a {@link AppleLoadableBundleBinaryProvider}. + */ + public NativeInfo getBinaryInfoProvider() { + return binaryInfoProvider; + } + + /** + * Returns a {@link AppleDebugOutputsProvider} containing debug information about the linked + * binary. + */ + public AppleDebugOutputsProvider getDebugOutputsProvider() { + return debugOutputsProvider; + } + + /** + * Returns a map from output group name to set of artifacts belonging to this output group. + * This should be added to configured target information using + * {@link RuleConfiguredTargetBuilder#addOutputGroups(Map)}. + */ + public Map> getOutputGroups() { + return outputGroups; + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java index b679558aae..6dec5fe3d2 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java @@ -18,12 +18,16 @@ import com.google.common.annotations.VisibleForTesting; 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.RuleContext; +import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.Attribute.SplitTransitionProvider; import com.google.devtools.build.lib.packages.Info; +import com.google.devtools.build.lib.packages.NativeInfo; import com.google.devtools.build.lib.packages.Provider; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.SkylarkAspect; import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.ApplePlatform; @@ -32,12 +36,14 @@ import com.google.devtools.build.lib.rules.apple.AppleToolchain; import com.google.devtools.build.lib.rules.apple.DottedVersion; import com.google.devtools.build.lib.rules.apple.XcodeConfigProvider; import com.google.devtools.build.lib.rules.apple.XcodeVersionProperties; +import com.google.devtools.build.lib.rules.objc.AppleBinary.AppleBinaryOutput; import com.google.devtools.build.lib.rules.objc.ObjcProvider.Key; import com.google.devtools.build.lib.skylarkinterface.Param; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature; import com.google.devtools.build.lib.syntax.BuiltinFunction; +import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.Runtime; import com.google.devtools.build.lib.syntax.SkylarkDict; import com.google.devtools.build.lib.syntax.SkylarkNestedSet; @@ -54,7 +60,7 @@ import javax.annotation.Nullable; doc = "Functions for skylark to access internals of the apple rule implementations." ) public class AppleSkylarkCommon { - + @VisibleForTesting public static final String BAD_KEY_ERROR = "Argument %s not a recognized key, 'providers'," + " or 'direct_dep_providers'."; @@ -519,6 +525,27 @@ public class AppleSkylarkCommon { } }; + @SkylarkCallable( + name = "link_multi_arch_binary", + doc = "Links a (potentially multi-architecture) binary targeting Apple platforms. This " + + "method comprises a bulk of the logic of the apple_binary rule, and is " + + "exposed as an API to iterate on migration of apple_binary to skylark.\n" + + "

This API is highly experimental and subject to change at any time. Do not " + + "depend on the stability of this function at this time.", + mandatoryPositionals = 1 // The SkylarkRuleContext. + ) + // TODO(b/70937317): Iterate on, improve, and solidify this API. + public NativeInfo linkMultiArchBinary(SkylarkRuleContext skylarkRuleContext) + throws EvalException, InterruptedException { + try { + RuleContext ruleContext = skylarkRuleContext.getRuleContext(); + AppleBinaryOutput appleBinaryOutput = AppleBinary.linkMultiArchBinary(ruleContext); + return appleBinaryOutput.getBinaryInfoProvider(); + } catch (RuleErrorException exception) { + throw new EvalException(null, exception); + } + } + @SkylarkSignature( name = "dotted_version", objectType = AppleSkylarkCommon.class, diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java index 71a8a7fb6f..dc5eb4f9d1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/MultiArchBinarySupport.java @@ -127,19 +127,17 @@ public class MultiArchBinarySupport { * @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 * @param outputMapCollector a map to which output groups created by compile action generation are * added + * @return a set containing all single-architecture binaries that are linked from this call * @throws RuleErrorException if there are attribute errors in the current rule context */ - public void registerActions( + public NestedSet registerActions( ApplePlatform platform, ExtraLinkArgs extraLinkArgs, Set dependencySpecificConfigurations, Iterable extraLinkInputs, ImmutableListMultimap configToDepsCollectionMap, - Artifact outputLipoBinary, Map> outputMapCollector) throws RuleErrorException, InterruptedException { @@ -190,12 +188,7 @@ public class MultiArchBinarySupport { .validateAttributes(); ruleContext.assertNoErrors(); } - - new LipoSupport(ruleContext) - .registerCombineArchitecturesAction( - binariesToLipo.build(), - outputLipoBinary, - platform); + return binariesToLipo.build(); } /** -- cgit v1.2.3