From 146ecf9883883a97cf9c25b0b8e478fc3e5e2c22 Mon Sep 17 00:00:00 2001 From: Sergio Campama Date: Mon, 6 Jun 2016 15:12:55 +0000 Subject: Separates the proto compilation action from the other linking sources, to isolate them from the linking target's defines and copts flags. Refactors CompilationAttributes into its own class with the Builder pattern. -- MOS_MIGRATED_REVID=124137672 --- .../lib/rules/objc/CompilationAttributes.java | 480 +++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 src/main/java/com/google/devtools/build/lib/rules/objc/CompilationAttributes.java (limited to 'src/main/java/com/google/devtools/build/lib/rules/objc/CompilationAttributes.java') diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationAttributes.java b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationAttributes.java new file mode 100644 index 0000000000..f41b101c2f --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/objc/CompilationAttributes.java @@ -0,0 +1,480 @@ +// 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.devtools.build.lib.rules.objc.ObjcProvider.TOP_LEVEL_MODULE_MAP; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicates; +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.PrerequisiteArtifacts; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.cmdline.Label; +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.BuildType; +import com.google.devtools.build.lib.rules.cpp.CcCommon; +import com.google.devtools.build.lib.rules.cpp.CppModuleMap; +import com.google.devtools.build.lib.syntax.Type; +import com.google.devtools.build.lib.util.Pair; +import com.google.devtools.build.lib.vfs.PathFragment; + +import java.util.List; + +/** + * Provides a way to access attributes that are common to all compilation rules. + */ +// TODO(bazel-team): Delete and move into support-specific attributes classes once ObjcCommon is +// gone. +final class CompilationAttributes { + static class Builder { + private final NestedSetBuilder hdrs = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder textualHdrs = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder includes = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder sdkIncludes = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder copts = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder linkopts = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder moduleMapsForDirectDeps = + NestedSetBuilder.stableOrder(); + private final NestedSetBuilder sdkFrameworks = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder weakSdkFrameworks = NestedSetBuilder.stableOrder(); + private final NestedSetBuilder sdkDylibs = NestedSetBuilder.stableOrder(); + private Optional bridgingHeader = Optional.absent(); + private Optional packageFragment = Optional.absent(); + private boolean enableModules; + + /** + * Adds the default values available through the rule's context. + */ + static Builder fromRuleContext(RuleContext ruleContext) { + Builder builder = new Builder(); + + addHeadersFromRuleContext(builder, ruleContext); + addIncludesFromRuleContext(builder, ruleContext); + addSdkAttributesFromRuleContext(builder, ruleContext); + addCompileOptionsFromRuleContext(builder, ruleContext); + addModuleOptionsFromRuleContext(builder, ruleContext); + + return builder; + } + + /** + * Adds headers to be made available for dependents. + */ + public Builder addHdrs(NestedSet hdrs) { + this.hdrs.addTransitive(hdrs); + return this; + } + + /** + * Adds headers that cannot be compiled individually. + */ + public Builder addTextualHdrs(NestedSet textualHdrs) { + this.textualHdrs.addTransitive(textualHdrs); + return this; + } + + /** + * Adds include paths to be made available for compilation. + */ + public Builder addIncludes(NestedSet includes) { + this.includes.addTransitive(includes); + return this; + } + + /** + * Adds paths for SDK includes. + */ + public Builder addSdkIncludes(NestedSet sdkIncludes) { + this.sdkIncludes.addTransitive(sdkIncludes); + return this; + } + + /** + * Adds compile-time options. + */ + public Builder addCopts(NestedSet copts) { + this.copts.addTransitive(copts); + return this; + } + + /** + * Adds link-time options. + */ + public Builder addLinkopts(NestedSet linkopts) { + this.linkopts.addTransitive(linkopts); + return this; + } + + /** + * Adds clang module maps for direct dependencies of the rule. These are needed to generate + * module maps. + */ + public Builder addModuleMapsForDirectDeps(NestedSet moduleMapsForDirectDeps) { + this.moduleMapsForDirectDeps.addTransitive(moduleMapsForDirectDeps); + return this; + } + + /** + * Adds SDK frameworks to link against. + */ + public Builder addSdkFrameworks(NestedSet sdkFrameworks) { + this.sdkFrameworks.addTransitive(sdkFrameworks); + return this; + } + + /** + * Adds SDK frameworks to be linked weakly. + */ + public Builder addWeakSdkFrameworks(NestedSet weakSdkFrameworks) { + this.weakSdkFrameworks.addTransitive(weakSdkFrameworks); + return this; + } + + /** + * Adds SDK Dylibs to link against. + */ + public Builder addSdkDylibs(NestedSet sdkDylibs) { + this.sdkDylibs.addTransitive(sdkDylibs); + return this; + } + + /** + * Sets the bridging header to be used when compiling Swift sources. + */ + public Builder setBridgingHeader(Artifact bridgingHeader) { + Preconditions.checkState( + !this.bridgingHeader.isPresent(), + "bridgingHeader is already set to %s", + this.bridgingHeader); + this.bridgingHeader = Optional.of(bridgingHeader); + return this; + } + + /** + * Sets the package path from which to base the header search paths. + */ + public Builder setPackageFragment(PathFragment packageFragment) { + Preconditions.checkState( + !this.packageFragment.isPresent(), + "packageFragment is already set to %s", + this.packageFragment); + this.packageFragment = Optional.of(packageFragment); + return this; + } + + /** + * Enables the usage of clang modules maps during compilation. + */ + public Builder enableModules() { + this.enableModules = true; + return this; + } + + /** + * Builds a {@code CompilationAttributes} object. + */ + public CompilationAttributes build() { + return new CompilationAttributes( + this.hdrs.build(), + this.textualHdrs.build(), + this.bridgingHeader, + this.includes.build(), + this.sdkIncludes.build(), + this.sdkFrameworks.build(), + this.weakSdkFrameworks.build(), + this.sdkDylibs.build(), + this.packageFragment, + this.copts.build(), + this.linkopts.build(), + this.moduleMapsForDirectDeps.build(), + this.enableModules); + } + + private static void addHeadersFromRuleContext(Builder builder, RuleContext ruleContext) { + if (ruleContext.attributes().has("hdrs", BuildType.LABEL_LIST)) { + NestedSetBuilder headers = NestedSetBuilder.stableOrder(); + for (Pair header : CcCommon.getHeaders(ruleContext)) { + headers.add(header.first); + } + builder.addHdrs(headers.build()); + } + + if (ruleContext.attributes().has("textual_hdrs", BuildType.LABEL_LIST)) { + builder.addTextualHdrs( + PrerequisiteArtifacts.nestedSet(ruleContext, "textual_hdrs", Mode.TARGET)); + } + + if (ruleContext.attributes().has("bridging_header", BuildType.LABEL)) { + Artifact header = ruleContext.getPrerequisiteArtifact("bridging_header", Mode.TARGET); + if (header != null) { + builder.setBridgingHeader(header); + } + } + } + + private static void addIncludesFromRuleContext(Builder builder, RuleContext ruleContext) { + if (ruleContext.attributes().has("includes", Type.STRING_LIST)) { + NestedSetBuilder includes = NestedSetBuilder.stableOrder(); + includes.addAll( + Iterables.transform( + ruleContext.attributes().get("includes", Type.STRING_LIST), + PathFragment.TO_PATH_FRAGMENT)); + builder.addIncludes(includes.build()); + } + + if (ruleContext.attributes().has("sdk_includes", Type.STRING_LIST)) { + NestedSetBuilder sdkIncludes = NestedSetBuilder.stableOrder(); + sdkIncludes.addAll( + Iterables.transform( + ruleContext.attributes().get("sdk_includes", Type.STRING_LIST), + PathFragment.TO_PATH_FRAGMENT)); + builder.addSdkIncludes(sdkIncludes.build()); + } + } + + private static void addSdkAttributesFromRuleContext(Builder builder, RuleContext ruleContext) { + if (ruleContext.attributes().has("sdk_frameworks", Type.STRING_LIST)) { + NestedSetBuilder frameworks = NestedSetBuilder.stableOrder(); + // TODO(bazel-team): Move the inclusion of the default frameworks to CompilationSupport. + frameworks.addAll(ObjcRuleClasses.AUTOMATIC_SDK_FRAMEWORKS); + for (String explicit : ruleContext.attributes().get("sdk_frameworks", Type.STRING_LIST)) { + frameworks.add(new SdkFramework(explicit)); + } + builder.addSdkFrameworks(frameworks.build()); + } + + if (ruleContext.attributes().has("weak_sdk_frameworks", Type.STRING_LIST)) { + NestedSetBuilder weakFrameworks = NestedSetBuilder.stableOrder(); + for (String frameworkName : + ruleContext.attributes().get("weak_sdk_frameworks", Type.STRING_LIST)) { + weakFrameworks.add(new SdkFramework(frameworkName)); + } + builder.addWeakSdkFrameworks(weakFrameworks.build()); + } + + if (ruleContext.attributes().has("sdk_dylibs", Type.STRING_LIST)) { + NestedSetBuilder sdkDylibs = NestedSetBuilder.stableOrder(); + sdkDylibs.addAll(ruleContext.attributes().get("sdk_dylibs", Type.STRING_LIST)); + builder.addSdkDylibs(sdkDylibs.build()); + } + } + + private static void addCompileOptionsFromRuleContext(Builder builder, RuleContext ruleContext) { + if (ruleContext.attributes().has("copts", Type.STRING_LIST)) { + NestedSetBuilder copts = NestedSetBuilder.stableOrder(); + copts.addAll(ruleContext.getTokenizedStringListAttr("copts")); + builder.addCopts(copts.build()); + } + + if (ruleContext.attributes().has("linkopts", Type.STRING_LIST)) { + NestedSetBuilder linkopts = NestedSetBuilder.stableOrder(); + linkopts.addAll(ruleContext.getTokenizedStringListAttr("linkopts")); + builder.addLinkopts(linkopts.build()); + } + } + + private static void addModuleOptionsFromRuleContext(Builder builder, RuleContext ruleContext) { + NestedSetBuilder moduleMaps = NestedSetBuilder.stableOrder(); + ObjcConfiguration objcConfiguration = ObjcRuleClasses.objcConfiguration(ruleContext); + if (objcConfiguration.moduleMapsEnabled()) { + // Make sure all dependencies that have headers are included here. If a module map is + // missing, its private headers will be treated as public! + if (ruleContext.attributes().has("deps", BuildType.LABEL_LIST)) { + Iterable providers = + ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProvider.class); + for (ObjcProvider provider : providers) { + moduleMaps.addTransitive(provider.get(TOP_LEVEL_MODULE_MAP)); + } + } + if (ruleContext.attributes().has("non_propagated_deps", BuildType.LABEL_LIST)) { + Iterable providers = + ruleContext.getPrerequisites("non_propagated_deps", Mode.TARGET, ObjcProvider.class); + for (ObjcProvider provider : providers) { + moduleMaps.addTransitive(provider.get(TOP_LEVEL_MODULE_MAP)); + } + } + } + + builder.addModuleMapsForDirectDeps(moduleMaps.build()); + + PathFragment packageFragment = + ruleContext.getLabel().getPackageIdentifier().getPathFragment(); + if (packageFragment != null) { + builder.setPackageFragment(packageFragment); + } + + if (ruleContext.attributes().has("enable_modules", Type.BOOLEAN) + && ruleContext.attributes().get("enable_modules", Type.BOOLEAN)) { + builder.enableModules(); + } + } + } + + private final NestedSet hdrs; + private final NestedSet textualHdrs; + private final Optional bridgingHeader; + private final NestedSet includes; + private final NestedSet sdkIncludes; + private final NestedSet sdkFrameworks; + private final NestedSet weakSdkFrameworks; + private final NestedSet sdkDylibs; + private final Optional packageFragment; + private final NestedSet copts; + private final NestedSet linkopts; + private final NestedSet moduleMapsForDirectDeps; + private final boolean enableModules; + + private CompilationAttributes( + NestedSet hdrs, + NestedSet textualHdrs, + Optional bridgingHeader, + NestedSet includes, + NestedSet sdkIncludes, + NestedSet sdkFrameworks, + NestedSet weakSdkFrameworks, + NestedSet sdkDylibs, + Optional packageFragment, + NestedSet copts, + NestedSet linkopts, + NestedSet moduleMapsForDirectDeps, + boolean enableModules) { + this.hdrs = hdrs; + this.textualHdrs = textualHdrs; + this.bridgingHeader = bridgingHeader; + this.includes = includes; + this.sdkIncludes = sdkIncludes; + this.sdkFrameworks = sdkFrameworks; + this.weakSdkFrameworks = weakSdkFrameworks; + this.sdkDylibs = sdkDylibs; + this.packageFragment = packageFragment; + this.copts = copts; + this.linkopts = linkopts; + this.moduleMapsForDirectDeps = moduleMapsForDirectDeps; + this.enableModules = enableModules; + } + + /** + * Returns the headers to be made available for dependents. + */ + public NestedSet hdrs() { + return this.hdrs; + } + + /** + * Returns the headers that cannot be compiled individually. + */ + public NestedSet textualHdrs() { + return this.textualHdrs; + } + + /** + * Returns the bridging header to be used when compiling Swift sources. + */ + public Optional bridgingHeader() { + return this.bridgingHeader; + } + + /** + * Returns the include paths to be made available for compilation. + */ + public NestedSet includes() { + return this.includes; + } + + /** + * Returns the paths for SDK includes. + */ + public NestedSet sdkIncludes() { + return this.sdkIncludes; + } + + /** + * Returns the SDK frameworks to link against. + */ + public NestedSet sdkFrameworks() { + return this.sdkFrameworks; + } + + /** + * Returns the SDK frameworks to be linked weakly. + */ + public NestedSet weakSdkFrameworks() { + return this.weakSdkFrameworks; + } + + /** + * Returns the SDK Dylibs to link against. + */ + public NestedSet sdkDylibs() { + return this.sdkDylibs; + } + + /** + * Returns the exec paths of all header search paths that should be added to this target and + * dependers on this target, obtained from the {@code includes} attribute. + */ + public NestedSet headerSearchPaths(PathFragment genfilesFragment) { + NestedSetBuilder paths = NestedSetBuilder.stableOrder(); + if (packageFragment.isPresent()) { + List rootFragments = + ImmutableList.of( + packageFragment.get(), genfilesFragment.getRelative(packageFragment.get())); + + Iterable relativeIncludes = + Iterables.filter(includes(), Predicates.not(PathFragment.IS_ABSOLUTE)); + for (PathFragment include : relativeIncludes) { + for (PathFragment rootFragment : rootFragments) { + paths.add(rootFragment.getRelative(include).normalize()); + } + } + } + return paths.build(); + } + + /** + * Returns the compile-time options. + */ + public NestedSet copts() { + return this.copts; + } + + /** + * Returns the link-time options. + */ + public NestedSet linkopts() { + return this.linkopts; + } + + /** + * Returns the clang module maps of direct dependencies of this rule. These are needed to generate + * this rule's module map. + */ + public NestedSet moduleMapsForDirectDeps() { + return this.moduleMapsForDirectDeps; + } + + /** + * Returns whether this target uses language features that require clang modules, such as + * {@literal @}import. + */ + public boolean enableModules() { + return this.enableModules; + } +} -- cgit v1.2.3