| // 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.XcodeProductType.LIBRARY_STATIC; |
| |
| import com.google.common.base.Optional; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSetMultimap; |
| import com.google.common.collect.Ordering; |
| import com.google.common.collect.Sets; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; |
| import com.google.devtools.build.lib.analysis.actions.FileWriteAction; |
| import com.google.devtools.build.lib.analysis.actions.SpawnAction; |
| import com.google.devtools.build.lib.analysis.config.BuildConfiguration; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; |
| 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.RuleClass.ConfiguredTargetFactory.RuleErrorException; |
| import com.google.devtools.build.lib.rules.proto.ProtoSourcesProvider; |
| import com.google.devtools.build.lib.vfs.FileSystemUtils; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.util.HashMap; |
| import java.util.Set; |
| |
| /** |
| * Support for generating Objective C proto static libraries that registers actions which generate |
| * and compile the Objective C protos by using the open source protobuf library and compiler. |
| * |
| * <p>Each group represents one proto_library target depended on by objc_proto_library targets using |
| * the portable_proto_filters attribute. This group contains all the necessary protos to satisfy its |
| * internal dependencies. |
| * |
| * <p>Grouping has a first pass in which for each proto required to be built, we find the smallest |
| * group containing it, and store that information in a map. We then reverse that map into a multi |
| * map, in which the keys are the input protos and the values are the output protos to be |
| * generated/compiled with the input group as dependencies. This minimizes the number of inputs |
| * required for each generation/compilation action and the probability of regeneration when one of |
| * the proto files change, improving cache hits. |
| */ |
| final class ProtobufSupport { |
| |
| private static final String BUNDLED_PROTOS_IDENTIFIER = "BundledProtos"; |
| |
| private static final String UNIQUE_DIRECTORY_NAME = "_generated_protos"; |
| |
| private final RuleContext ruleContext; |
| private final BuildConfiguration buildConfiguration; |
| private final ProtoAttributes attributes; |
| |
| // Each entry of this map represents a generation action and a compilation action. The input set |
| // are dependencies of the output set. The output set is always a subset of, or the same set as, |
| // the input set. For example, given a sample entry of the inputsToOutputsMap like: |
| // |
| // {A, B, C} => {B, C} |
| // |
| // this represents: |
| // 1. A generation action in which the inputs are A, B and C, and the outputs are B.pbobjc.h, |
| // B.pbobjc.m, C.pbobjc.h and C.pbobjc.m. |
| // 2. A compilation action in which the inputs are A.pbobjc.h, B.pbobjc.h, C.pbobjc.h, |
| // B.pbobjc.m and C.pbobjc.m, while the outputs are B.pbobjc.o and C.pbobjc.o. |
| // |
| // Given that each input set appears only once, by the nature of the structure, we can safely use |
| // it as an identifier of the entry. |
| private final ImmutableSetMultimap<ImmutableSet<Artifact>, Artifact> inputsToOutputsMap; |
| |
| /** |
| * Creates a new proto support for the protobuf library. This support code bundles up all the |
| * transitive protos within the groups in which they were defined. We use that information to |
| * minimize the number of inputs per generation/compilation actions by only providing what is |
| * really needed to the actions. |
| * |
| * @param ruleContext context this proto library is constructed in |
| */ |
| public ProtobufSupport(RuleContext ruleContext) throws RuleErrorException { |
| this(ruleContext, null); |
| } |
| |
| /** |
| * Creates a new proto support for the protobuf library. This support code bundles up all the |
| * transitive protos within the groups in which they were defined. We use that information to |
| * minimize the number of inputs per generation/compilation actions by only providing what is |
| * really needed to the actions. |
| * |
| * @param ruleContext context this proto library is constructed in |
| * @param buildConfiguration the configuration from which to get prerequisites when building proto |
| * targets in a split configuration |
| */ |
| public ProtobufSupport(RuleContext ruleContext, BuildConfiguration buildConfiguration) |
| throws RuleErrorException { |
| this.ruleContext = ruleContext; |
| this.buildConfiguration = buildConfiguration; |
| this.attributes = new ProtoAttributes(ruleContext); |
| this.inputsToOutputsMap = getInputsToOutputsMap(); |
| } |
| |
| /** |
| * Registers the proto generation actions. These actions generate the ObjC/CPP code to be compiled |
| * by this rule. |
| */ |
| public ProtobufSupport registerGenerationActions() { |
| int actionId = 0; |
| |
| for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) { |
| Iterable<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos); |
| registerGenerationAction(outputProtos, inputProtos, getUniqueBundledProtosSuffix(actionId)); |
| actionId++; |
| } |
| |
| if (!isLinkingTarget()) { |
| registerModuleMapGenerationAction(); |
| } |
| |
| return this; |
| } |
| |
| private void registerModuleMapGenerationAction() { |
| IntermediateArtifacts moduleMapIntermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext); |
| CompilationArtifacts.Builder moduleMapCompilationArtifacts = |
| new CompilationArtifacts.Builder() |
| .setIntermediateArtifacts(moduleMapIntermediateArtifacts) |
| .setPchFile(Optional.<Artifact>absent()) |
| .addAdditionalHdrs(getProtobufHeaders()) |
| .addAdditionalHdrs( |
| getGeneratedProtoOutputs(inputsToOutputsMap.values(), ".pbobjc.h")); |
| |
| new CompilationSupport( |
| ruleContext, |
| ObjcRuleClasses.intermediateArtifacts(ruleContext), |
| new CompilationAttributes.Builder().build()) |
| .registerGenerateModuleMapAction(Optional.of(moduleMapCompilationArtifacts.build())); |
| } |
| |
| /** Registers the actions that will compile the generated code. */ |
| public ProtobufSupport registerCompilationActions() { |
| int actionId = 0; |
| Iterable<PathFragment> userHeaderSearchPaths = |
| ImmutableList.of(getWorkspaceRelativeOutputDir()); |
| for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) { |
| ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos); |
| |
| IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId); |
| |
| CompilationArtifacts compilationArtifacts = |
| getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos); |
| |
| ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts); |
| |
| new CompilationSupport( |
| ruleContext, intermediateArtifacts, new CompilationAttributes.Builder().build()) |
| .registerCompileAndArchiveActions(common, userHeaderSearchPaths); |
| |
| actionId++; |
| } |
| return this; |
| } |
| |
| /** Adds the generated files to the set of files to be output when this rule is built. */ |
| public ProtobufSupport addFilesToBuild(NestedSetBuilder<Artifact> filesToBuild) { |
| for (ImmutableSet<Artifact> inputProtoFiles : inputsToOutputsMap.keySet()) { |
| ImmutableSet<Artifact> outputProtoFiles = inputsToOutputsMap.get(inputProtoFiles); |
| Iterable<Artifact> generatedSources = getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.m"); |
| Iterable<Artifact> generatedHeaders = getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.h"); |
| |
| filesToBuild.addAll(generatedSources).addAll(generatedHeaders); |
| } |
| |
| int actionId = 0; |
| for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) { |
| ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos); |
| IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId); |
| |
| CompilationArtifacts compilationArtifacts = |
| getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos); |
| |
| ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts); |
| filesToBuild.addAll(common.getCompiledArchive().asSet()); |
| actionId++; |
| } |
| |
| return this; |
| } |
| |
| /** |
| * Returns the ObjcProvider for this target, or Optional.absent() if there were no protos to |
| * generate. |
| */ |
| public Optional<ObjcProvider> getObjcProvider() { |
| if (inputsToOutputsMap.isEmpty()) { |
| return Optional.absent(); |
| } |
| |
| Iterable<PathFragment> userHeaderSearchPaths = |
| ImmutableList.of(getWorkspaceRelativeOutputDir()); |
| IntermediateArtifacts moduleMapIntermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext); |
| ObjcCommon.Builder commonBuilder = |
| new ObjcCommon.Builder(ruleContext) |
| .setIntermediateArtifacts(moduleMapIntermediateArtifacts) |
| .setHasModuleMap(); |
| |
| int actionId = 0; |
| for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) { |
| ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos); |
| IntermediateArtifacts intermediateArtifacts = getUniqueIntermediateArtifacts(actionId); |
| |
| CompilationArtifacts compilationArtifacts = |
| getCompilationArtifacts(intermediateArtifacts, inputProtos, outputProtos); |
| |
| ObjcCommon common = getCommon(intermediateArtifacts, compilationArtifacts); |
| commonBuilder.addDepObjcProviders(ImmutableSet.of(common.getObjcProvider())); |
| actionId++; |
| } |
| |
| if (isLinkingTarget()) { |
| commonBuilder.addUserHeaderSearchPaths(userHeaderSearchPaths); |
| } else { |
| commonBuilder.addDirectDependencyHeaderSearchPaths(userHeaderSearchPaths); |
| } |
| |
| return Optional.of(commonBuilder.build().getObjcProvider()); |
| } |
| |
| /** |
| * Returns the XcodeProvider for this target or Optional.absent() if there were no protos to |
| * generate. |
| */ |
| public Optional<XcodeProvider> getXcodeProvider() throws RuleErrorException { |
| if (inputsToOutputsMap.isEmpty()) { |
| return Optional.absent(); |
| } |
| |
| XcodeProvider.Builder xcodeProviderBuilder = new XcodeProvider.Builder(); |
| IntermediateArtifacts intermediateArtifacts = |
| ObjcRuleClasses.intermediateArtifacts(ruleContext); |
| new XcodeSupport(ruleContext, intermediateArtifacts, getXcodeLabel(getBundledProtosSuffix())) |
| .addXcodeSettings(xcodeProviderBuilder, getObjcProvider().get(), LIBRARY_STATIC); |
| |
| int actionId = 0; |
| for (ImmutableSet<Artifact> inputProtos : inputsToOutputsMap.keySet()) { |
| ImmutableSet<Artifact> outputProtos = inputsToOutputsMap.get(inputProtos); |
| IntermediateArtifacts bundleIntermediateArtifacts = getUniqueIntermediateArtifacts(actionId); |
| |
| CompilationArtifacts compilationArtifacts = |
| getCompilationArtifacts(bundleIntermediateArtifacts, inputProtos, outputProtos); |
| |
| ObjcCommon common = getCommon(bundleIntermediateArtifacts, compilationArtifacts); |
| |
| XcodeProvider bundleProvider = |
| getBundleXcodeProvider( |
| common, bundleIntermediateArtifacts, getUniqueBundledProtosSuffix(actionId)); |
| if (isLinkingTarget()) { |
| xcodeProviderBuilder.addPropagatedDependencies(ImmutableSet.of(bundleProvider)); |
| } else { |
| xcodeProviderBuilder.addPropagatedDependenciesWithStrictDependencyHeaders( |
| ImmutableSet.of(bundleProvider)); |
| } |
| actionId++; |
| } |
| |
| return Optional.of(xcodeProviderBuilder.build()); |
| } |
| |
| private NestedSet<Artifact> getPortableProtoFilters() { |
| Iterable<ObjcProtoProvider> objcProtoProviders = getObjcProtoProviders(); |
| |
| NestedSetBuilder<Artifact> portableProtoFilters = NestedSetBuilder.stableOrder(); |
| for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) { |
| portableProtoFilters.addTransitive(objcProtoProvider.getPortableProtoFilters()); |
| } |
| portableProtoFilters.addAll(attributes.getPortableProtoFilters()); |
| return portableProtoFilters.build(); |
| } |
| |
| private NestedSet<Artifact> getProtobufHeaders() { |
| Iterable<ObjcProtoProvider> objcProtoProviders = getObjcProtoProviders(); |
| |
| NestedSetBuilder<Artifact> protobufHeaders = NestedSetBuilder.stableOrder(); |
| for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) { |
| protobufHeaders.addTransitive(objcProtoProvider.getProtobufHeaders()); |
| } |
| return protobufHeaders.build(); |
| } |
| |
| private NestedSet<PathFragment> getProtobufHeaderSearchPaths() { |
| Iterable<ObjcProtoProvider> objcProtoProviders = getObjcProtoProviders(); |
| |
| NestedSetBuilder<PathFragment> protobufHeaderSearchPaths = NestedSetBuilder.stableOrder(); |
| for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) { |
| protobufHeaderSearchPaths.addTransitive(objcProtoProvider.getProtobufHeaderSearchPaths()); |
| } |
| return protobufHeaderSearchPaths.build(); |
| } |
| |
| private ImmutableSetMultimap<ImmutableSet<Artifact>, Artifact> getInputsToOutputsMap() |
| throws RuleErrorException { |
| Iterable<ObjcProtoProvider> objcProtoProviders = getObjcProtoProviders(); |
| Iterable<ProtoSourcesProvider> protoProviders = getProtoSourcesProviders(); |
| |
| ImmutableList.Builder<NestedSet<Artifact>> protoSets = |
| new ImmutableList.Builder<NestedSet<Artifact>>(); |
| |
| // Traverse all the dependencies ObjcProtoProviders and ProtoSourcesProviders to aggregate |
| // all the transitive groups of proto. |
| for (ObjcProtoProvider objcProtoProvider : objcProtoProviders) { |
| protoSets.addAll(objcProtoProvider.getProtoGroups()); |
| } |
| for (ProtoSourcesProvider protoProvider : protoProviders) { |
| protoSets.add(protoProvider.getTransitiveProtoSources()); |
| } |
| |
| HashMap<Artifact, Set<Artifact>> protoToGroupMap = new HashMap<>(); |
| |
| // For each proto in each proto group, store the smallest group in which it is contained. This |
| // group will be considered the smallest input group with which the proto can be generated. |
| for (NestedSet<Artifact> nestedProtoSet : protoSets.build()) { |
| ImmutableSet<Artifact> protoSet = ImmutableSet.copyOf(nestedProtoSet.toSet()); |
| for (Artifact proto : protoSet) { |
| // If the proto is well known, don't store it as we don't need to generate it; it comes |
| // generated with the runtime library. |
| if (attributes.isProtoWellKnown(proto)) { |
| continue; |
| } |
| if (!protoToGroupMap.containsKey(proto)) { |
| protoToGroupMap.put(proto, protoSet); |
| } else { |
| protoToGroupMap.put(proto, Sets.intersection(protoSet, protoToGroupMap.get(proto))); |
| } |
| } |
| } |
| |
| // Now that we have the smallest proto inputs groups for each proto to be generated, we reverse |
| // that map into a multimap to take advantage of the fact that multiple protos can be generated |
| // with the same inputs, to avoid having multiple generation actions with the same inputs and |
| // different ouputs. This only applies for the generation actions, as the compilation actions |
| // compile one generated file at a time. |
| // It's OK to use ImmutableSet<Artifact> as the key, since Artifact caches it's hashCode, and |
| // ImmutableSet calculates it's hashCode in O(n). |
| ImmutableSetMultimap.Builder<ImmutableSet<Artifact>, Artifact> inputsToOutputsMapBuilder = |
| ImmutableSetMultimap.builder(); |
| |
| for (Artifact proto : protoToGroupMap.keySet()) { |
| inputsToOutputsMapBuilder.put(ImmutableSet.copyOf(protoToGroupMap.get(proto)), proto); |
| } |
| return inputsToOutputsMapBuilder.build(); |
| } |
| |
| private XcodeProvider getBundleXcodeProvider( |
| ObjcCommon common, IntermediateArtifacts intermediateArtifacts, String labelSuffix) |
| throws RuleErrorException { |
| Iterable<PathFragment> userHeaderSearchPaths = |
| ImmutableList.of(getWorkspaceRelativeOutputDir()); |
| |
| XcodeProvider.Builder xcodeProviderBuilder = |
| new XcodeProvider.Builder() |
| .addUserHeaderSearchPaths(userHeaderSearchPaths) |
| .setCompilationArtifacts(common.getCompilationArtifacts().get()); |
| |
| XcodeSupport xcodeSupport = |
| new XcodeSupport(ruleContext, intermediateArtifacts, getXcodeLabel(labelSuffix)) |
| .addXcodeSettings(xcodeProviderBuilder, common.getObjcProvider(), LIBRARY_STATIC); |
| if (isLinkingTarget()) { |
| xcodeProviderBuilder |
| .addHeaders(getProtobufHeaders()) |
| .addUserHeaderSearchPaths(getProtobufHeaderSearchPaths()); |
| } else { |
| xcodeSupport.addDependencies( |
| xcodeProviderBuilder, new Attribute(ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET)); |
| } |
| |
| return xcodeProviderBuilder.build(); |
| } |
| |
| private String getBundledProtosSuffix() { |
| return "_" + BUNDLED_PROTOS_IDENTIFIER; |
| } |
| |
| private String getUniqueBundledProtosPrefix(int actionId) { |
| return BUNDLED_PROTOS_IDENTIFIER + "_" + actionId; |
| } |
| |
| private String getUniqueBundledProtosSuffix(int actionId) { |
| return getBundledProtosSuffix() + "_" + actionId; |
| } |
| |
| private Label getXcodeLabel(String suffix) throws RuleErrorException { |
| Label xcodeLabel = null; |
| try { |
| xcodeLabel = |
| ruleContext.getLabel().getLocalTargetLabel(ruleContext.getLabel().getName() + suffix); |
| } catch (LabelSyntaxException e) { |
| ruleContext.throwWithRuleError(e.getLocalizedMessage()); |
| } |
| return xcodeLabel; |
| } |
| |
| private IntermediateArtifacts getUniqueIntermediateArtifacts(int actionId) { |
| return new IntermediateArtifacts( |
| ruleContext, |
| getUniqueBundledProtosSuffix(actionId), |
| getUniqueBundledProtosPrefix(actionId), |
| ruleContext.getConfiguration()); |
| } |
| |
| private ObjcCommon getCommon( |
| IntermediateArtifacts intermediateArtifacts, CompilationArtifacts compilationArtifacts) { |
| ObjcCommon.Builder commonBuilder = |
| new ObjcCommon.Builder(ruleContext) |
| .setIntermediateArtifacts(intermediateArtifacts) |
| .setCompilationArtifacts(compilationArtifacts); |
| if (isLinkingTarget()) { |
| commonBuilder.addUserHeaderSearchPaths(getProtobufHeaderSearchPaths()); |
| } else { |
| commonBuilder.addDepObjcProviders( |
| ruleContext.getPrerequisites( |
| ObjcRuleClasses.PROTO_LIB_ATTR, Mode.TARGET, ObjcProvider.class)); |
| } |
| return commonBuilder.build(); |
| } |
| |
| private CompilationArtifacts getCompilationArtifacts( |
| IntermediateArtifacts intermediateArtifacts, |
| Iterable<Artifact> inputProtoFiles, |
| Iterable<Artifact> outputProtoFiles) { |
| // Filter the well known protos from the set of headers. We don't generate the headers for them |
| // as they are part of the runtime library. |
| Iterable<Artifact> filteredInputProtos = attributes.filterWellKnownProtos(inputProtoFiles); |
| |
| CompilationArtifacts.Builder compilationArtifacts = |
| new CompilationArtifacts.Builder() |
| .setIntermediateArtifacts(intermediateArtifacts) |
| .setPchFile(Optional.<Artifact>absent()) |
| .addAdditionalHdrs(getGeneratedProtoOutputs(filteredInputProtos, ".pbobjc.h")) |
| .addAdditionalHdrs(getProtobufHeaders()); |
| |
| if (isLinkingTarget()) { |
| compilationArtifacts.addNonArcSrcs(getGeneratedProtoOutputs(outputProtoFiles, ".pbobjc.m")); |
| } |
| |
| return compilationArtifacts.build(); |
| } |
| |
| private void registerGenerationAction( |
| Iterable<Artifact> outputProtos, Iterable<Artifact> inputProtos, String protoFileSuffix) { |
| Artifact protoInputsFile = getProtoInputsFile(protoFileSuffix); |
| |
| ruleContext.registerAction( |
| new FileWriteAction( |
| ruleContext.getActionOwner(), |
| protoInputsFile, |
| getProtoInputsFileContents(outputProtos), |
| false)); |
| |
| ruleContext.registerAction( |
| new SpawnAction.Builder() |
| .setMnemonic("GenObjcBundledProtos") |
| .addInput(attributes.getProtoCompiler()) |
| .addInputs(attributes.getProtoCompilerSupport()) |
| .addTransitiveInputs(getPortableProtoFilters()) |
| .addInput(protoInputsFile) |
| .addInputs(inputProtos) |
| .addOutputs(getGeneratedProtoOutputs(outputProtos, ".pbobjc.h")) |
| .addOutputs(getGeneratedProtoOutputs(outputProtos, ".pbobjc.m")) |
| .setExecutable(attributes.getProtoCompiler().getExecPath()) |
| .setCommandLine(getGenerationCommandLine(protoInputsFile)) |
| .build(ruleContext)); |
| } |
| |
| private Artifact getProtoInputsFile(String suffix) { |
| return ruleContext.getUniqueDirectoryArtifact( |
| "_protos", |
| "_proto_input_files" + suffix, |
| ruleContext.getConfiguration().getGenfilesDirectory()); |
| } |
| |
| private String getProtoInputsFileContents(Iterable<Artifact> outputProtos) { |
| // Sort the file names to make the remote action key independent of the precise deps structure. |
| // compile_protos.py will sort the input list anyway. |
| Iterable<Artifact> sorted = Ordering.natural().immutableSortedCopy(outputProtos); |
| return Artifact.joinRootRelativePaths("\n", sorted); |
| } |
| |
| private CustomCommandLine getGenerationCommandLine(Artifact protoInputsFile) { |
| return new CustomCommandLine.Builder() |
| .add("--input-file-list") |
| .add(protoInputsFile.getExecPathString()) |
| .add("--output-dir") |
| .add(getWorkspaceRelativeOutputDir().getSafePathString()) |
| .add("--force") |
| .add("--proto-root-dir") |
| .add(getGenfilesPathString()) |
| .add("--proto-root-dir") |
| .add(".") |
| .addBeforeEachExecPath("--config", getPortableProtoFilters()) |
| .build(); |
| } |
| |
| private String getGenfilesPathString() { |
| if (buildConfiguration != null) { |
| return buildConfiguration.getGenfilesDirectory().getExecPathString(); |
| } |
| return ruleContext.getConfiguration().getGenfilesDirectory().getExecPathString(); |
| } |
| |
| private PathFragment getWorkspaceRelativeOutputDir() { |
| // Generate sources in a package-and-rule-scoped directory; adds both the |
| // package-and-rule-scoped directory and the header-containing-directory to the include path |
| // of dependers. |
| PathFragment rootRelativeOutputDir = ruleContext.getUniqueDirectory(UNIQUE_DIRECTORY_NAME); |
| |
| return new PathFragment( |
| ruleContext.getBinOrGenfilesDirectory().getExecPath(), rootRelativeOutputDir); |
| } |
| |
| private Iterable<Artifact> getGeneratedProtoOutputs( |
| Iterable<Artifact> outputProtos, String extension) { |
| ImmutableList.Builder<Artifact> builder = new ImmutableList.Builder<>(); |
| for (Artifact protoFile : outputProtos) { |
| String protoFileName = FileSystemUtils.removeExtension(protoFile.getFilename()); |
| String generatedOutputName = attributes.getGeneratedProtoFilename(protoFileName, true); |
| |
| PathFragment generatedFilePath = |
| new PathFragment( |
| protoFile.getRootRelativePath().getParentDirectory(), |
| new PathFragment(generatedOutputName)); |
| |
| PathFragment outputFile = FileSystemUtils.appendExtension(generatedFilePath, extension); |
| |
| if (outputFile != null) { |
| builder.add( |
| ruleContext.getUniqueDirectoryArtifact( |
| UNIQUE_DIRECTORY_NAME, outputFile, ruleContext.getBinOrGenfilesDirectory())); |
| } |
| } |
| return builder.build(); |
| } |
| |
| private Iterable<ObjcProtoProvider> getObjcProtoProviders() { |
| if (buildConfiguration != null) { |
| return ruleContext |
| .getPrerequisitesByConfiguration("deps", Mode.SPLIT, ObjcProtoProvider.class) |
| .get(buildConfiguration); |
| } |
| return ruleContext.getPrerequisites("deps", Mode.TARGET, ObjcProtoProvider.class); |
| } |
| |
| private Iterable<ProtoSourcesProvider> getProtoSourcesProviders() { |
| if (buildConfiguration != null) { |
| return ruleContext |
| .getPrerequisitesByConfiguration("deps", Mode.SPLIT, ProtoSourcesProvider.class) |
| .get(buildConfiguration); |
| } |
| return ruleContext.getPrerequisites("deps", Mode.TARGET, ProtoSourcesProvider.class); |
| } |
| |
| private boolean isLinkingTarget() { |
| return !ruleContext |
| .attributes() |
| .isAttributeValueExplicitlySpecified(ObjcProtoLibraryRule.PORTABLE_PROTO_FILTERS_ATTR); |
| } |
| } |