diff options
author | Matthew DeVore <matvore@google.com> | 2015-02-06 18:26:23 +0000 |
---|---|---|
committer | Han-Wen Nienhuys <hanwen@google.com> | 2015-02-06 18:26:23 +0000 |
commit | 25bdc33f14a7781f5ffeca018f8dc0f5575f0979 (patch) | |
tree | b30c9ffd3a38f3602ed9913bd3c3d558ba8cb8dd /src/main/java/com/google/devtools/build/lib/rules/objc | |
parent | 50a1194557959501ef36a44eaf782be6acb531f1 (diff) |
Implement ios_extension_binary rule, which is similar to objc_binary, but only links and does not bundle, and creates a binary for an iOS app extension.
ios_extension_binary is minimialistic, not allow infoplist, entitlements, and other attributes, and generate different artifacts, which how objc_binary will also work for iOS applications in the new world when we have ios_application.
--
MOS_MIGRATED_REVID=85728076
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/objc')
5 files changed, 274 insertions, 121 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java new file mode 100644 index 0000000000..2c0d336f56 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/BinaryLinkingTargetFactory.java @@ -0,0 +1,181 @@ +// Copyright 2014 Google Inc. 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.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; +import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; +import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.objc.ApplicationSupport.LinkedBinary; +import com.google.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraLinkArgs; +import com.google.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraLinkInputs; +import com.google.devtools.build.lib.rules.objc.ObjcCommon.CompilationAttributes; +import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes; + +/** + * Implementation for rules that link binaries. + */ +abstract class BinaryLinkingTargetFactory implements RuleConfiguredTargetFactory { + /** + * Indicates whether this binary generates an application bundle. If so, it causes the + * {@code infoplist} attribute to be read and a bundle to be added to the files-to-build. + */ + enum HasApplicationSupport { + YES, NO; + } + + private final HasApplicationSupport hasApplicationSupport; + private final ExtraLinkArgs extraLinkArgs; + private final XcodeProductType productType; + + protected BinaryLinkingTargetFactory(HasApplicationSupport hasApplicationSupport, + ExtraLinkArgs extraLinkArgs, XcodeProductType productType) { + this.hasApplicationSupport = hasApplicationSupport; + this.extraLinkArgs = extraLinkArgs; + this.productType = productType; + } + + @VisibleForTesting + static final String REQUIRES_AT_LEAST_ONE_LIBRARY_OR_SOURCE_FILE = + "At least one library dependency or source file is required."; + + @Override + public final ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { + ObjcCommon common = common(ruleContext); + OptionsProvider optionsProvider = optionsProvider(ruleContext); + + ObjcProvider objcProvider = common.getObjcProvider(); + if (!hasLibraryOrSources(objcProvider)) { + ruleContext.ruleError(REQUIRES_AT_LEAST_ONE_LIBRARY_OR_SOURCE_FILE); + return null; + } + + XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder(); + NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.<Artifact>stableOrder() + .add(ObjcRuleClasses.intermediateArtifacts(ruleContext).singleArchitectureBinary()); + + new CompilationSupport(ruleContext) + .registerJ2ObjcCompileAndArchiveActions(optionsProvider, common.getObjcProvider()) + .registerCompileAndArchiveActions(common, optionsProvider) + .addXcodeSettings(xcodeProviderBuilder, common, optionsProvider) + .registerLinkActions(common.getObjcProvider(), extraLinkArgs, new ExtraLinkInputs()) + .validateAttributes(); + + Optional<XcTestAppProvider> xcTestAppProvider; + switch (hasApplicationSupport) { + case YES: + // TODO(bazel-team): Remove once all bundle users are migrated to ios_application. + ApplicationSupport applicationSupport = new ApplicationSupport( + ruleContext, common.getObjcProvider(), optionsProvider, + LinkedBinary.LOCAL_AND_DEPENDENCIES); + applicationSupport + .registerActions() + .addXcodeSettings(xcodeProviderBuilder) + .addFilesToBuild(filesToBuild) + .validateAttributes(); + xcTestAppProvider = Optional.of(applicationSupport.xcTestAppProvider()); + break; + case NO: + xcTestAppProvider = Optional.absent(); + break; + default: + throw new AssertionError(); + } + + new ResourceSupport(ruleContext) + .registerActions(common.getStoryboards()) + .validateAttributes() + .addXcodeSettings(xcodeProviderBuilder); + + XcodeSupport xcodeSupport = new XcodeSupport(ruleContext) + // TODO(bazel-team): Use LIBRARY_STATIC as parameter instead of APPLICATION once objc_binary + // no longer creates an application bundle + .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), productType) + .addDependencies(xcodeProviderBuilder) + .addFilesToBuild(filesToBuild); + XcodeProvider xcodeProvider = xcodeProviderBuilder.build(); + xcodeSupport.registerActions(xcodeProvider); + + // TODO(bazel-team): Stop exporting an XcTestAppProvider once objc_binary no longer creates an + // application bundle. + return common.configuredTarget( + filesToBuild.build(), + Optional.of(xcodeProvider), + Optional.<ObjcProvider>absent(), + xcTestAppProvider, + Optional.<J2ObjcSrcsProvider>absent()); + } + + private OptionsProvider optionsProvider(RuleContext ruleContext) { + OptionsProvider.Builder provider = new OptionsProvider.Builder() + .addCopts(ruleContext.getTokenizedStringListAttr("copts")) + .addTransitive(Optional.fromNullable( + ruleContext.getPrerequisite("options", Mode.TARGET, OptionsProvider.class))); + if (hasApplicationSupport == HasApplicationSupport.YES) { + provider + .addInfoplists(ruleContext.getPrerequisiteArtifacts("infoplist", Mode.TARGET).list()); + } + return provider.build(); + } + + private boolean hasLibraryOrSources(ObjcProvider objcProvider) { + return !Iterables.isEmpty(objcProvider.get(LIBRARY)) // Includes sources from this target. + || !Iterables.isEmpty(objcProvider.get(IMPORTED_LIBRARY)); + } + + private ObjcCommon common(RuleContext ruleContext) { + IntermediateArtifacts intermediateArtifacts = + ObjcRuleClasses.intermediateArtifacts(ruleContext); + CompilationArtifacts compilationArtifacts = + CompilationSupport.compilationArtifacts(ruleContext); + + return new ObjcCommon.Builder(ruleContext) + .setCompilationAttributes(new CompilationAttributes(ruleContext)) + .setResourceAttributes(new ResourceAttributes(ruleContext)) + .setCompilationArtifacts(compilationArtifacts) + .addDepObjcProviders(ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProvider.class)) + .addDepObjcProviders( + ruleContext.getPrerequisites("bundles", Mode.TARGET, ObjcProvider.class)) + .addNonPropagatedDepObjcProviders( + ruleContext.getPrerequisites("non_propagated_deps", Mode.TARGET, ObjcProvider.class)) + .setIntermediateArtifacts(intermediateArtifacts) + .setAlwayslink(false) + .addExtraImportLibraries(j2ObjcLibraries(ruleContext)) + .setLinkedBinary(intermediateArtifacts.singleArchitectureBinary()) + .build(); + } + + private Iterable<Artifact> j2ObjcLibraries(RuleContext ruleContext) { + J2ObjcSrcsProvider j2ObjcSrcsProvider = ObjcRuleClasses.j2ObjcSrcsProvider(ruleContext); + ImmutableList.Builder<Artifact> j2objcLibraries = ImmutableList.builder(); + + // TODO(bazel-team): Refactor the code to stop flattening the nested set here. + for (J2ObjcSource j2ObjcSource : j2ObjcSrcsProvider.getSrcs()) { + j2objcLibraries.add( + ObjcRuleClasses.j2objcIntermediateArtifacts(ruleContext, j2ObjcSource).archive()); + } + + return j2objcLibraries.build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinary.java new file mode 100644 index 0000000000..c930a84005 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinary.java @@ -0,0 +1,28 @@ +// Copyright 2015 Google Inc. 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.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraLinkArgs; + +/** + * Implementation for the "ios_extension_binary" rule. + */ +public class IosExtensionBinary extends BinaryLinkingTargetFactory { + public IosExtensionBinary() { + super(HasApplicationSupport.NO, + new ExtraLinkArgs("-e", "_NSExtensionMain", "-fapplication-extension"), + XcodeProductType.LIBRARY_STATIC); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java new file mode 100644 index 0000000000..716758bb05 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosExtensionBinaryRule.java @@ -0,0 +1,56 @@ +// Copyright 2015 Google Inc. 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.devtools.build.lib.analysis.BlazeRule; +import com.google.devtools.build.lib.analysis.RuleDefinition; +import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.packages.RuleClass; +import com.google.devtools.build.lib.packages.RuleClass.Builder; + +/** + * Rule definition for ios_extension_binary. + */ +@BlazeRule(name = "ios_extension_binary", + factoryClass = IosExtensionBinary.class, + ancestors = { ObjcLibraryRule.class }) +public class IosExtensionBinaryRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) { + return builder + /*<!-- #BLAZE_RULE(ios_extension_binary).IMPLICIT_OUTPUTS --> + <ul> + <li><code><var>name</var>.xcodeproj/project.pbxproj</code>: An Xcode project file which + can be used to develop or build on a Mac.</li> + </ul> + <!-- #END_BLAZE_RULE.IMPLICIT_OUTPUTS -->*/ + .setImplicitOutputsFunction(XcodeSupport.PBXPROJ) + .removeAttribute("alwayslink") + .build(); + } +} + +/*<!-- #BLAZE_RULE (NAME = ios_extension_binary, TYPE = BINARY, FAMILY = Objective-C) --> + +${ATTRIBUTE_SIGNATURE} + +<p>This rule produces a binary for an iOS app extension by linking one or more +Objective-C libraries.</p> + +${IMPLICIT_OUTPUTS} + +${ATTRIBUTE_DEFINITION} + +<!-- #END_BLAZE_RULE -->*/ diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinary.java index 52c897fe23..23bd8ea515 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBinary.java @@ -14,134 +14,21 @@ package com.google.devtools.build.lib.rules.objc; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.IMPORTED_LIBRARY; -import static com.google.devtools.build.lib.rules.objc.ObjcProvider.LIBRARY; -import static com.google.devtools.build.lib.rules.objc.XcodeProductType.APPLICATION; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; -import com.google.devtools.build.lib.rules.objc.ApplicationSupport.LinkedBinary; import com.google.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraLinkArgs; -import com.google.devtools.build.lib.rules.objc.ObjcActionsBuilder.ExtraLinkInputs; -import com.google.devtools.build.lib.rules.objc.ObjcCommon.CompilationAttributes; -import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes; /** * Implementation for the "objc_binary" rule. */ -public class ObjcBinary implements RuleConfiguredTargetFactory { - - @VisibleForTesting - static final String REQUIRES_AT_LEAST_ONE_LIBRARY_OR_SOURCE_FILE = - "At least one library dependency or source file is required."; - - @Override - public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { - ObjcCommon common = common(ruleContext); - OptionsProvider optionsProvider = optionsProvider(ruleContext); - - ObjcProvider objcProvider = common.getObjcProvider(); - if (!hasLibraryOrSources(objcProvider)) { - ruleContext.ruleError(REQUIRES_AT_LEAST_ONE_LIBRARY_OR_SOURCE_FILE); - return null; - } - - XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder(); - NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder(); +public class ObjcBinary extends BinaryLinkingTargetFactory { + public ObjcBinary() { + super( + // TODO(bazel-team): Remove the enum and delete all code depending on YES case once all + // bundle users are migrated to ios_application. + HasApplicationSupport.YES, + new ExtraLinkArgs(), - new CompilationSupport(ruleContext) - .registerJ2ObjcCompileAndArchiveActions(optionsProvider, common.getObjcProvider()) - .registerCompileAndArchiveActions(common, optionsProvider) - .addXcodeSettings(xcodeProviderBuilder, common, optionsProvider) - .registerLinkActions(common.getObjcProvider(), new ExtraLinkArgs(), new ExtraLinkInputs()) - .validateAttributes(); - - // TODO(bazel-team): Remove once all bundle users are migrated to ios_application. - ApplicationSupport applicationSupport = new ApplicationSupport( - ruleContext, common.getObjcProvider(), optionsProvider, LinkedBinary.LOCAL_AND_DEPENDENCIES) - .registerActions() - .addXcodeSettings(xcodeProviderBuilder) - .addFilesToBuild(filesToBuild) - .validateAttributes(); - - new ResourceSupport(ruleContext) - .registerActions(common.getStoryboards()) - .validateAttributes() - .addXcodeSettings(xcodeProviderBuilder); - - XcodeSupport xcodeSupport = new XcodeSupport(ruleContext) // TODO(bazel-team): Use LIBRARY_STATIC as parameter instead of APPLICATION once objc_binary // no longer creates an application bundle - .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), APPLICATION) - .addDependencies(xcodeProviderBuilder) - .addFilesToBuild(filesToBuild); - XcodeProvider xcodeProvider = xcodeProviderBuilder.build(); - xcodeSupport.registerActions(xcodeProvider); - - // TODO(bazel-team): Stop exporting an XcTestAppProvider once objc_binary no longer creates an - // application bundle. - return common.configuredTarget( - filesToBuild.build(), - Optional.of(xcodeProvider), - Optional.<ObjcProvider>absent(), - Optional.of(applicationSupport.xcTestAppProvider()), - Optional.<J2ObjcSrcsProvider>absent()); - } - - private OptionsProvider optionsProvider(RuleContext ruleContext) { - return new OptionsProvider.Builder() - .addCopts(ruleContext.getTokenizedStringListAttr("copts")) - .addInfoplists(ruleContext.getPrerequisiteArtifacts("infoplist", Mode.TARGET).list()) - .addTransitive(Optional.fromNullable( - ruleContext.getPrerequisite("options", Mode.TARGET, OptionsProvider.class))) - .build(); - } - - private boolean hasLibraryOrSources(ObjcProvider objcProvider) { - return !Iterables.isEmpty(objcProvider.get(LIBRARY)) // Includes sources from this target. - || !Iterables.isEmpty(objcProvider.get(IMPORTED_LIBRARY)); - } - - private ObjcCommon common(RuleContext ruleContext) { - IntermediateArtifacts intermediateArtifacts = - ObjcRuleClasses.intermediateArtifacts(ruleContext); - CompilationArtifacts compilationArtifacts = - CompilationSupport.compilationArtifacts(ruleContext); - - return new ObjcCommon.Builder(ruleContext) - .setCompilationAttributes(new CompilationAttributes(ruleContext)) - .setResourceAttributes(new ResourceAttributes(ruleContext)) - .setCompilationArtifacts(compilationArtifacts) - .addDepObjcProviders(ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProvider.class)) - .addDepObjcProviders( - ruleContext.getPrerequisites("bundles", Mode.TARGET, ObjcProvider.class)) - .addNonPropagatedDepObjcProviders( - ruleContext.getPrerequisites("non_propagated_deps", Mode.TARGET, ObjcProvider.class)) - .setIntermediateArtifacts(intermediateArtifacts) - .setAlwayslink(false) - .addExtraImportLibraries(j2ObjcLibraries(ruleContext)) - .setLinkedBinary(intermediateArtifacts.singleArchitectureBinary()) - .build(); - } - - private Iterable<Artifact> j2ObjcLibraries(RuleContext ruleContext) { - J2ObjcSrcsProvider j2ObjcSrcsProvider = ObjcRuleClasses.j2ObjcSrcsProvider(ruleContext); - ImmutableList.Builder<Artifact> j2objcLibraries = ImmutableList.builder(); - - // TODO(bazel-team): Refactor the code to stop flattening the nested set here. - for (J2ObjcSource j2ObjcSource : j2ObjcSrcsProvider.getSrcs()) { - j2objcLibraries.add( - ObjcRuleClasses.j2objcIntermediateArtifacts(ruleContext, j2ObjcSource).archive()); - } - - return j2objcLibraries.build(); + XcodeProductType.APPLICATION); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java index 0a6c4baf97..ecfff3952c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcXcodeprojRule.java @@ -51,6 +51,7 @@ public class ObjcXcodeprojRule implements RuleDefinition { .nonEmpty() .allowedRuleClasses( "objc_binary", + "ios_extension_binary", "ios_test", "objc_bundle_library", "objc_import", |