From 2084a3df1230609a655591e438cfb97508d10347 Mon Sep 17 00:00:00 2001 From: Cal Peyser Date: Fri, 15 Apr 2016 14:45:19 +0000 Subject: Introduces experimental_objc_library. This rule builds objc code with the c++ rule implementation backend and an OSX crosstool. -- MOS_MIGRATED_REVID=119954578 --- .../lib/bazel/rules/BazelRuleClassProvider.java | 3 + .../build/lib/rules/cpp/CcLibraryHelper.java | 2 +- .../build/lib/rules/cpp/CppCompileAction.java | 14 ++++ .../devtools/build/lib/rules/cpp/CppFileTypes.java | 2 +- .../lib/rules/objc/ExperimentalObjcLibrary.java | 87 ++++++++++++++++++++++ .../rules/objc/ExperimentalObjcLibraryRule.java | 53 +++++++++++++ .../build/lib/rules/objc/ObjcCppSemantics.java | 75 +++++++++++++++++++ .../build/lib/rules/objc/ObjcRuleClasses.java | 69 ++++++++++++++++- 8 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java create mode 100644 src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibraryRule.java create mode 100644 src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java (limited to 'src/main') diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index 4c33658ed6..ef0bca705c 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -101,6 +101,7 @@ import com.google.devtools.build.lib.rules.java.ProguardLibraryRule; import com.google.devtools.build.lib.rules.objc.AppleSkylarkCommon; import com.google.devtools.build.lib.rules.objc.AppleWatch1ExtensionRule; import com.google.devtools.build.lib.rules.objc.AppleWatchExtensionBinaryRule; +import com.google.devtools.build.lib.rules.objc.ExperimentalObjcLibraryRule; import com.google.devtools.build.lib.rules.objc.IosApplicationRule; import com.google.devtools.build.lib.rules.objc.IosDeviceRule; import com.google.devtools.build.lib.rules.objc.IosExtensionBinaryRule; @@ -340,6 +341,7 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new IosTestRule()); builder.addRuleDefinition(new IosDeviceRule()); builder.addRuleDefinition(new ObjcBinaryRule()); + builder.addRuleDefinition(new ExperimentalObjcLibraryRule()); builder.addRuleDefinition(new ObjcBundleRule()); builder.addRuleDefinition(new ObjcBundleLibraryRule()); builder.addRuleDefinition(new ObjcFrameworkRule()); @@ -364,6 +366,7 @@ public class BazelRuleClassProvider { builder.addRuleDefinition(new ObjcRuleClasses.ReleaseBundlingToolsRule()); builder.addRuleDefinition(new ObjcRuleClasses.WatchExtensionBundleRule()); builder.addRuleDefinition(new ObjcRuleClasses.WatchApplicationBundleRule()); + builder.addRuleDefinition(new ObjcRuleClasses.CrosstoolRule()); builder.addRuleDefinition(new AppleToolchain.RequiresXcodeConfigRule()); builder.addRuleDefinition(new AppleWatch1ExtensionRule()); builder.addRuleDefinition(new AppleWatchExtensionBinaryRule()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java index 3b969b8d1a..9f8f98d46c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibraryHelper.java @@ -69,7 +69,7 @@ import javax.annotation.Nullable; * methods. */ public final class CcLibraryHelper { - + /** * A group of source file types for builds controlled by CcLibraryHelper. Determines what * file types CcLibraryHelper considers sources. diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java index d1dce71ebf..04b862cb3a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java @@ -126,6 +126,16 @@ public class CppCompileAction extends AbstractAction implements IncludeScannable */ public static final String CPP_COMPILE = "c++-compile"; + /** + * A string constant for the objc compilation action. + */ + public static final String OBJC_COMPILE = "objc-compile"; + + /** + * A string constant for the objc++ compile action. + */ + public static final String OBJCPP_COMPILE = "objc++-compile"; + /** * A string constant for the c++ header parsing. */ @@ -1335,6 +1345,10 @@ public class CppCompileAction extends AbstractAction implements IncludeScannable return C_COMPILE; } else if (CppFileTypes.CPP_SOURCE.matches(sourcePath)) { return CPP_COMPILE; + } else if (CppFileTypes.OBJC_SOURCE.matches(sourcePath)) { + return OBJC_COMPILE; + } else if (CppFileTypes.OBJCPP_SOURCE.matches(sourcePath)) { + return OBJCPP_COMPILE; } else if (CppFileTypes.ASSEMBLER.matches(sourcePath)) { return ASSEMBLE; } else if (CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR.matches(sourcePath)) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java index d97dbb9931..c3bd853ff6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppFileTypes.java @@ -28,7 +28,7 @@ public final class CppFileTypes { public static final FileType C_SOURCE = FileType.of(".c"); public static final FileType OBJC_SOURCE = FileType.of(".m"); public static final FileType OBJCPP_SOURCE = FileType.of(".mm"); - + // Filetypes that generate LLVM bitcode when -flto is specified. public static final FileTypeSet LTO_SOURCE = FileTypeSet.of(CppFileTypes.CPP_SOURCE, CppFileTypes.C_SOURCE); diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java new file mode 100644 index 0000000000..97335d0861 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibrary.java @@ -0,0 +1,87 @@ +// 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.Sets; +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.cpp.CcLibraryHelper; +import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; +import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; +import com.google.devtools.build.lib.rules.objc.ObjcCommon.CompilationAttributes; + +import java.util.Collection; + +/** + * Implementation for experimental_objc_library. + */ +public class ExperimentalObjcLibrary implements RuleConfiguredTargetFactory { + + @Override + public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException { + + CompilationArtifacts compilationArtifacts = + CompilationSupport.compilationArtifacts(ruleContext); + CompilationAttributes compilationAttributes = new CompilationAttributes(ruleContext); + + ObjcCommon common = common(ruleContext, compilationAttributes, compilationArtifacts); + + CcToolchainProvider toolchain = + ruleContext + .getPrerequisite(":cc_toolchain", Mode.TARGET) + .getProvider(CcToolchainProvider.class); + FeatureConfiguration featureConfiguration = toolchain.getFeatures().getFeatureConfiguration(); + + Collection sources = Sets.newHashSet(compilationArtifacts.getSrcs()); + Collection privateHdrs = Sets.newHashSet(compilationArtifacts.getPrivateHdrs()); + Collection publicHdrs = Sets.newHashSet(compilationAttributes.hdrs()); + + CcLibraryHelper helper = + new CcLibraryHelper( + ruleContext, + ObjcCppSemantics.INSTANCE, + featureConfiguration, + CcLibraryHelper.SourceCategory.CC_AND_OBJC) + .addSources(sources) + .addSources(privateHdrs) + .enableCompileProviders() + .addPublicHeaders(publicHdrs) + .addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET)); + + CcLibraryHelper.Info info = helper.build(); + + NestedSetBuilder filesToBuild = + NestedSetBuilder.stableOrder().addAll(common.getCompiledArchive().asSet()); + + return ObjcRuleClasses.ruleConfiguredTarget(ruleContext, filesToBuild.build()) + .addProviders(info.getProviders()) + .build(); + } + + private ObjcCommon common( + RuleContext ruleContext, + CompilationAttributes compilationAttributes, + CompilationArtifacts compilationArtifacts) { + return new ObjcCommon.Builder(ruleContext) + .setCompilationAttributes(compilationAttributes) + .setCompilationArtifacts(compilationArtifacts) + .addDepObjcProviders(ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProvider.class)) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibraryRule.java new file mode 100644 index 0000000000..77c70f65de --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ExperimentalObjcLibraryRule.java @@ -0,0 +1,53 @@ +// 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.devtools.build.lib.analysis.BaseRuleClasses; +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; +import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint; +import com.google.devtools.build.lib.rules.apple.AppleConfiguration; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; + +/** + * Rule definition for experimental_objc_library. + */ +public class ExperimentalObjcLibraryRule implements RuleDefinition { + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + return builder + .requiresConfigurationFragments( + ObjcConfiguration.class, AppleConfiguration.class, CppConfiguration.class) + // experimental_objc_library should only occur in bazel test code. We use the /objc + // directory for tests. + .setValidityPredicate(new PackageNameConstraint(1, "objc")) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("experimental_objc_library") + .factoryClass(ExperimentalObjcLibrary.class) + .ancestors( + BaseRuleClasses.BaseRule.class, + ObjcRuleClasses.LinkingRule.class, + ObjcRuleClasses.AlwaysLinkRule.class, + ObjcRuleClasses.CrosstoolRule.class) + .build(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java new file mode 100644 index 0000000000..b36523b181 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcCppSemantics.java @@ -0,0 +1,75 @@ +// 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.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Root; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.rules.cpp.CppCompilationContext.Builder; +import com.google.devtools.build.lib.rules.cpp.CppCompileActionBuilder; +import com.google.devtools.build.lib.rules.cpp.CppCompileActionContext; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration.HeadersCheckingMode; +import com.google.devtools.build.lib.rules.cpp.CppHelper; +import com.google.devtools.build.lib.rules.cpp.CppSemantics; +import com.google.devtools.build.lib.vfs.PathFragment; + +/** + * CppSemantics for objc builds. + */ +public class ObjcCppSemantics implements CppSemantics { + + // We make CppSemantics a singleton object for efficiency and consistency, since we expect + // any instance to be identical. + public static final CppSemantics INSTANCE = new ObjcCppSemantics(); + + @Override + public PathFragment getEffectiveSourcePath(Artifact source) { + return source.getRootRelativePath(); + } + + @Override + public void finalizeCompileActionBuilder( + RuleContext ruleContext, CppCompileActionBuilder actionBuilder) { + actionBuilder.setCppConfiguration(ruleContext.getFragment(CppConfiguration.class)); + actionBuilder.setActionContext(CppCompileActionContext.class); + // Because Bazel does not support include scanning, we need the entire crosstool filegroup, + // including header files, as opposed to just the "compile" filegroup. + actionBuilder.addTransitiveMandatoryInputs(CppHelper.getToolchain(ruleContext).getCrosstool()); + actionBuilder.setShouldScanIncludes(false); + } + + @Override + public void setupCompilationContext(RuleContext ruleContext, Builder contextBuilder) { + // For objc builds, no extra setup is required. + } + + @Override + public HeadersCheckingMode determineHeadersCheckingMode(RuleContext ruleContext) { + // Currently, objc builds do not enforce strict deps. To begin enforcing strict deps in objc, + // switch this flag to STRICT. + return HeadersCheckingMode.WARN; + } + + @Override + public boolean needsIncludeScanning(RuleContext ruleContext) { + return false; + } + + @Override + public Root getGreppedIncludesDirectory(RuleContext ruleContext) { + return null; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java index ef9e07911a..14365541c4 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcRuleClasses.java @@ -53,6 +53,7 @@ import com.google.devtools.build.lib.rules.apple.AppleConfiguration; import com.google.devtools.build.lib.rules.apple.AppleToolchain; import com.google.devtools.build.lib.rules.apple.AppleToolchain.RequiresXcodeConfigRule; import com.google.devtools.build.lib.rules.apple.Platform; +import com.google.devtools.build.lib.rules.cpp.CppConfiguration; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.util.FileType; import com.google.devtools.build.lib.util.FileTypeSet; @@ -125,11 +126,49 @@ public class ObjcRuleClasses { return !ASSEMBLY_SOURCES.matches(sourceArtifact.getFilename()); } - @VisibleForTesting static final Iterable AUTOMATIC_SDK_FRAMEWORKS = ImmutableList.of( new SdkFramework("Foundation"), new SdkFramework("UIKit")); + /** + * Label of a filegroup that contains all crosstool and grte files for all configurations, + * as specified on the command-line. + * + *

Since this is the loading-phase default for the :cc_toolchain attribute of rules + * using the crosstool, it must contain in its transitive closure the computer value + * of that attribute under the default configuration. + */ + public static final String CROSSTOOL_LABEL = "//tools/defaults:crosstool"; + + /** + * Late-bound attribute giving the CcToolchain for CROSSTOOL_LABEL. + * + * TODO(cpeyser): Use AppleCcToolchain instead of CcToolchain once released. + */ + public static final LateBoundLabel APPLE_TOOLCHAIN = + new LateBoundLabel(CROSSTOOL_LABEL, CppConfiguration.class) { + @Override + public Label getDefault( + Rule rule, AttributeMap attributes, BuildConfiguration configuration) { + return configuration.getFragment(CppConfiguration.class).getCcToolchainRuleLabel(); + } + }; + + /** + * A null value for the lipo context collector. Objc builds do not use a lipo context collector. + */ + // TODO(b/28084560): Allow :lipo_context_collector not to be set instead of having a null + // instance. + public static final LateBoundLabel NULL_LIPO_CONTEXT_COLLECTOR = + new LateBoundLabel() { + @Override + public Label getDefault( + Rule rule, AttributeMap attributes, BuildConfiguration configuration) { + return null; + } + }; + + /** * Creates a new spawn action builder with apple environment variables set that are typically * needed by the apple toolchain. This should be used to start to build spawn actions that, in @@ -509,6 +548,31 @@ public class ObjcRuleClasses { } } + /** + * Common attributes for {@code objc_*} rules that depend on a crosstool. + */ + public static class CrosstoolRule implements RuleDefinition { + + @Override + public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { + return builder + .add(attr(":cc_toolchain", LABEL).value(APPLE_TOOLCHAIN)) + .add( + attr(":lipo_context_collector", LABEL) + .value(NULL_LIPO_CONTEXT_COLLECTOR) + .skipPrereqValidatorCheck()) + .build(); + } + + @Override + public Metadata getMetadata() { + return RuleDefinition.Metadata.builder() + .name("$objc_crosstool_rule") + .type(RuleClassType.ABSTRACT) + .build(); + } + } + /** * Common attributes for {@code objc_*} rules that can be input to compilation (i.e. can be * dependencies of other compiling rules). @@ -592,7 +656,8 @@ public class ObjcRuleClasses { "cc_library", "cc_inc_library", "ios_framework", - "swift_library"); + "swift_library", + "experimental_objc_library"); @Override public RuleClass build(Builder builder, RuleDefinitionEnvironment env) { -- cgit v1.2.3