com.google.devtools.build.lib.rules.objc.MultiArchBinarySupport.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.build.lib.rules.objc.MultiArchBinarySupport.java

Source

// 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.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
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.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
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.apple.Platform;
import com.google.devtools.build.lib.rules.objc.CompilationSupport.ExtraLinkArgs;
import com.google.devtools.build.lib.rules.objc.ObjcCommon.ResourceAttributes;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Support utility for creating multi-arch Apple binaries.
 */
public class MultiArchBinarySupport {
    private final RuleContext ruleContext;

    /**
     * @param ruleContext the current rule context
     */
    public MultiArchBinarySupport(RuleContext ruleContext) {
        this.ruleContext = ruleContext;
    }

    /**
     * Registers actions to create a multi-arch Apple binary.
     *
     * @param platform the platform for which the binary is targeted
     * @param extraLinkArgs the extra linker args to add to link actions linking single-architecture
     *     binaries together
     * @param configurationToObjcProvider a map from from dependency configuration to the
     *     {@link ObjcProvider} which comprises all information about the dependencies in that
     *     configuration. Can be obtained via {@link #objcProviderByDepConfiguration}
     * @param extraLinkInputs the extra linker inputs to be made available during link actions
     * @param configToDepsCollectionMap a multimap from dependency configuration to the
     *     list of provider collections which are propagated from the dependencies of that
     *     configuration
     * @param outputLipoBinary the artifact (lipo'ed binary) which should be output as a result of
     *     this support
     * @throws RuleErrorException if there are attribute errors in the current rule context
     */
    public void registerActions(Platform platform, ExtraLinkArgs extraLinkArgs,
            Map<BuildConfiguration, ObjcProvider> configurationToObjcProvider, Iterable<Artifact> extraLinkInputs,
            ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection> configToDepsCollectionMap,
            Artifact outputLipoBinary) throws RuleErrorException, InterruptedException {

        NestedSetBuilder<Artifact> binariesToLipo = NestedSetBuilder.<Artifact>stableOrder();
        for (BuildConfiguration childConfig : configurationToObjcProvider.keySet()) {
            IntermediateArtifacts intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext,
                    childConfig);
            ImmutableList.Builder<J2ObjcMappingFileProvider> j2ObjcMappingFileProviders = ImmutableList.builder();
            J2ObjcEntryClassProvider.Builder j2ObjcEntryClassProviderBuilder = new J2ObjcEntryClassProvider.Builder();
            for (TransitiveInfoCollection dep : configToDepsCollectionMap.get(childConfig)) {
                if (dep.getProvider(J2ObjcMappingFileProvider.class) != null) {
                    j2ObjcMappingFileProviders.add(dep.getProvider(J2ObjcMappingFileProvider.class));
                }
                if (dep.getProvider(J2ObjcEntryClassProvider.class) != null) {
                    j2ObjcEntryClassProviderBuilder.addTransitive(dep.getProvider(J2ObjcEntryClassProvider.class));
                }
            }
            J2ObjcMappingFileProvider j2ObjcMappingFileProvider = J2ObjcMappingFileProvider
                    .union(j2ObjcMappingFileProviders.build());
            J2ObjcEntryClassProvider j2ObjcEntryClassProvider = j2ObjcEntryClassProviderBuilder.build();

            binariesToLipo.add(intermediateArtifacts.strippedSingleArchitectureBinary());

            ObjcProvider objcProvider = configurationToObjcProvider.get(childConfig);
            CompilationArtifacts compilationArtifacts = CompilationSupport.compilationArtifacts(ruleContext,
                    ObjcRuleClasses.intermediateArtifacts(ruleContext, childConfig));
            CompilationSupport.createForConfig(ruleContext, childConfig)
                    .registerCompileAndArchiveActions(compilationArtifacts, objcProvider)
                    .registerLinkActions(objcProvider, j2ObjcMappingFileProvider, j2ObjcEntryClassProvider,
                            extraLinkArgs, extraLinkInputs, DsymOutputType.APP)
                    .validateAttributes();
            ruleContext.assertNoErrors();
        }

        new LipoSupport(ruleContext).registerCombineArchitecturesAction(binariesToLipo.build(), outputLipoBinary,
                platform);
    }

    /**
     * Returns a map from from dependency configuration to the {@link ObjcCommon} which comprises all
     * information about the dependencies in that configuration. This can be used both to register
     * actions in {@link #registerActions} and collect provider information to be propagated upstream.
     *
     * @param childConfigurations the set of configurations in which dependencies of the current rule
     *     are built
     * @param configToDepsCollectionMap a map from child configuration to providers that "deps" of the
     *     current rule have propagated in that configuration
     * @param configurationToNonPropagatedObjcMap a map from child configuration to providers that
     *     "non_propagated_deps" of the current rule have propagated in that configuration
     * @param dylibObjcProviders {@link ObjcProvider}s that dynamic library dependencies of the
     *     current rule have propagated
     * @param dylibProtoProviders {@link ObjcProtoProvider} providers that dynamic library
     *     dependencies of the current rule have propagated
     * @param bundleLoaderObjcProvider Optional ObjcProvider containing artifacts and paths to be
     *     included in this binary's compilation actions
     * @throws RuleErrorException if there are attribute errors in the current rule context
     */
    public Map<BuildConfiguration, ObjcProvider> objcProviderByDepConfiguration(
            Set<BuildConfiguration> childConfigurations,
            ImmutableListMultimap<BuildConfiguration, TransitiveInfoCollection> configToDepsCollectionMap,
            ImmutableListMultimap<BuildConfiguration, ObjcProvider> configurationToNonPropagatedObjcMap,
            Iterable<ObjcProvider> dylibObjcProviders, Iterable<ObjcProtoProvider> dylibProtoProviders)
            throws RuleErrorException, InterruptedException {
        ImmutableMap.Builder<BuildConfiguration, ObjcProvider> configurationToObjcProviderBuilder = ImmutableMap
                .builder();

        for (BuildConfiguration childConfig : childConfigurations) {
            Optional<ObjcProvider> protosObjcProvider;
            if (ObjcRuleClasses.objcConfiguration(ruleContext).enableAppleBinaryNativeProtos()) {
                ProtobufSupport protoSupport = new ProtobufSupport(ruleContext, childConfig,
                        protoArtifactsToAvoid(dylibProtoProviders)).registerGenerationActions()
                                .registerCompilationActions();
                protosObjcProvider = protoSupport.getObjcProvider();
            } else {
                protosObjcProvider = Optional.absent();
            }

            IntermediateArtifacts intermediateArtifacts = ObjcRuleClasses.intermediateArtifacts(ruleContext,
                    childConfig);

            Iterable<ObjcProvider> additionalDepProviders = Iterables.concat(dylibObjcProviders,
                    ruleContext.getPrerequisites("bundles", Mode.TARGET, ObjcProvider.class),
                    protosObjcProvider.asSet());

            ObjcCommon common = common(ruleContext, childConfig, intermediateArtifacts,
                    nullToEmptyList(configToDepsCollectionMap.get(childConfig)),
                    nullToEmptyList(configurationToNonPropagatedObjcMap.get(childConfig)), additionalDepProviders);
            ObjcProvider objcProvider = common.getObjcProvider().subtractSubtrees(dylibObjcProviders);

            configurationToObjcProviderBuilder.put(childConfig, objcProvider);
        }

        return configurationToObjcProviderBuilder.build();
    }

    private ObjcCommon common(RuleContext ruleContext, BuildConfiguration buildConfiguration,
            IntermediateArtifacts intermediateArtifacts, List<TransitiveInfoCollection> propagatedDeps,
            List<ObjcProvider> nonPropagatedObjcDeps, Iterable<ObjcProvider> additionalDepProviders) {

        CompilationArtifacts compilationArtifacts = CompilationSupport.compilationArtifacts(ruleContext,
                intermediateArtifacts);

        ObjcCommon.Builder commonBuilder = new ObjcCommon.Builder(ruleContext, buildConfiguration)
                .setCompilationAttributes(CompilationAttributes.Builder.fromRuleContext(ruleContext).build())
                .setCompilationArtifacts(compilationArtifacts)
                .setResourceAttributes(new ResourceAttributes(ruleContext))
                .addDefines(ruleContext.getTokenizedStringListAttr("defines")).addDeps(propagatedDeps)
                .addDepObjcProviders(additionalDepProviders).addNonPropagatedDepObjcProviders(nonPropagatedObjcDeps)
                .setIntermediateArtifacts(intermediateArtifacts).setAlwayslink(false)
                // TODO(b/29152500): Enable module map generation.
                .setLinkedBinary(intermediateArtifacts.strippedSingleArchitectureBinary());

        if (ObjcRuleClasses.objcConfiguration(ruleContext).generateDsym()) {
            commonBuilder.addDebugArtifacts(DsymOutputType.APP);
        }
        return commonBuilder.build();
    }

    private <T> List<T> nullToEmptyList(List<T> inputList) {
        return inputList != null ? inputList : ImmutableList.<T>of();
    }

    private static NestedSet<Artifact> protoArtifactsToAvoid(Iterable<ObjcProtoProvider> avoidedProviders) {
        NestedSetBuilder<Artifact> avoidArtifacts = NestedSetBuilder.stableOrder();
        for (ObjcProtoProvider avoidProvider : avoidedProviders) {
            for (NestedSet<Artifact> avoidProviderOutputGroup : avoidProvider.getProtoGroups()) {
                avoidArtifacts.addTransitive(avoidProviderOutputGroup);
            }
        }
        return avoidArtifacts.build();
    }
}