Skip to content

Commit

Permalink
Introduces experimental_objc_library. This rule builds objc code with…
Browse files Browse the repository at this point in the history
… the c++ rule implementation backend and an OSX crosstool.

--
MOS_MIGRATED_REVID=119660101
  • Loading branch information
calpeyser authored and lberki committed Apr 13, 2016
1 parent 3231e78 commit bbf59ed
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
import com.google.devtools.build.lib.rules.java.ProguardLibraryRule;
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;
Expand Down Expand Up @@ -340,6 +341,7 @@ public static void setup(ConfiguredRuleClassProvider.Builder builder) {
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());
Expand All @@ -364,6 +366,7 @@ public static void setup(ConfiguredRuleClassProvider.Builder builder) {
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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,20 @@
* methods.
*/
public final class CcLibraryHelper {

/**
* Candidate source types for the CcLibraryHelper.
*
* <p>This is distinct from the set of candidate "srcs" for cc_* targets, which cannot, for
* example, contain objective-c sources.
*/
static final FileTypeSet SOURCE_TYPES =
FileTypeSet.of(
CppFileTypes.CPP_SOURCE,
CppFileTypes.CPP_HEADER,
CppFileTypes.C_SOURCE,
CppFileTypes.OBJC_SOURCE,
CppFileTypes.OBJCPP_SOURCE,
CppFileTypes.ASSEMBLER,
CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ public Collection<Artifact> getInputsForIncludedFile(
*/
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.
*/
Expand Down Expand Up @@ -1336,6 +1346,10 @@ private String getActionName() {
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)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
public final class CppFileTypes {
public static final FileType CPP_SOURCE = FileType.of(".cc", ".cpp", ".cxx", ".c++", ".C");
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 =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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<Artifact> sources = Sets.newHashSet(compilationArtifacts.getSrcs());
Collection<Artifact> privateHdrs = Sets.newHashSet(compilationArtifacts.getPrivateHdrs());
Collection<Artifact> publicHdrs = Sets.newHashSet(compilationAttributes.hdrs());

CcLibraryHelper helper =
new CcLibraryHelper(ruleContext, ObjcCppSemantics.INSTANCE, featureConfiguration)
.addSources(sources)
.addSources(privateHdrs)
.enableCompileProviders()
.addPublicHeaders(publicHdrs)
.addDeps(ruleContext.getPrerequisites("deps", Mode.TARGET));

CcLibraryHelper.Info info = helper.build();

NestedSetBuilder<Artifact> filesToBuild =
NestedSetBuilder.<Artifact>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();
}
}
Original file line number Diff line number Diff line change
@@ -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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
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;
Expand Down Expand Up @@ -125,11 +126,49 @@ public static boolean isInstrumentable(Artifact sourceArtifact) {
return !ASSEMBLY_SOURCES.matches(sourceArtifact.getFilename());
}


@VisibleForTesting
static final Iterable<SdkFramework> 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.
*
* <p> 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<BuildConfiguration> APPLE_TOOLCHAIN =
new LateBoundLabel<BuildConfiguration>(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 colletor. 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<BuildConfiguration> NULL_LIPO_CONTEXT_COLLECTOR =
new LateBoundLabel<BuildConfiguration>() {
@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
Expand Down Expand Up @@ -509,6 +548,31 @@ public Metadata getMetadata() {
}
}

/**
* 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).
Expand Down Expand Up @@ -592,7 +656,8 @@ public static class CompilingRule implements RuleDefinition {
"cc_library",
"cc_inc_library",
"ios_framework",
"swift_library");
"swift_library",
"experimental_objc_library");

@Override
public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
Expand Down

0 comments on commit bbf59ed

Please sign in to comment.