com.facebook.buck.features.lua.CxxLuaExtensionDescription.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.features.lua.CxxLuaExtensionDescription.java

Source

/*
 * Copyright 2015-present Facebook, Inc.
 *
 * 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.facebook.buck.features.lua;

import com.facebook.buck.core.cell.CellPathResolver;
import com.facebook.buck.core.description.attr.ImplicitDepsInferringDescription;
import com.facebook.buck.core.model.BuildTarget;
import com.facebook.buck.core.model.Flavor;
import com.facebook.buck.core.model.FlavorDomain;
import com.facebook.buck.core.model.Flavored;
import com.facebook.buck.core.model.impl.BuildTargetPaths;
import com.facebook.buck.core.model.targetgraph.BuildRuleCreationContextWithTargetGraph;
import com.facebook.buck.core.model.targetgraph.DescriptionWithTargetGraph;
import com.facebook.buck.core.rules.ActionGraphBuilder;
import com.facebook.buck.core.rules.BuildRule;
import com.facebook.buck.core.rules.BuildRuleParams;
import com.facebook.buck.core.rules.SourcePathRuleFinder;
import com.facebook.buck.core.sourcepath.SourcePath;
import com.facebook.buck.core.sourcepath.resolver.SourcePathResolver;
import com.facebook.buck.core.sourcepath.resolver.impl.DefaultSourcePathResolver;
import com.facebook.buck.core.toolchain.ToolchainProvider;
import com.facebook.buck.core.util.immutables.BuckStyleImmutable;
import com.facebook.buck.cxx.CxxConstructorArg;
import com.facebook.buck.cxx.CxxDescriptionEnhancer;
import com.facebook.buck.cxx.CxxFlags;
import com.facebook.buck.cxx.CxxLinkOptions;
import com.facebook.buck.cxx.CxxLinkableEnhancer;
import com.facebook.buck.cxx.CxxPreprocessAndCompile;
import com.facebook.buck.cxx.CxxPreprocessables;
import com.facebook.buck.cxx.CxxPreprocessorInput;
import com.facebook.buck.cxx.CxxSource;
import com.facebook.buck.cxx.CxxSourceRuleFactory;
import com.facebook.buck.cxx.toolchain.CxxBuckConfig;
import com.facebook.buck.cxx.toolchain.CxxPlatform;
import com.facebook.buck.cxx.toolchain.CxxPlatforms;
import com.facebook.buck.cxx.toolchain.HeaderSymlinkTree;
import com.facebook.buck.cxx.toolchain.HeaderVisibility;
import com.facebook.buck.cxx.toolchain.LinkerMapMode;
import com.facebook.buck.cxx.toolchain.PicType;
import com.facebook.buck.cxx.toolchain.linker.Linker;
import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkTargetMode;
import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkable;
import com.facebook.buck.cxx.toolchain.nativelink.NativeLinkableInput;
import com.facebook.buck.io.filesystem.ProjectFilesystem;
import com.facebook.buck.rules.args.Arg;
import com.facebook.buck.rules.args.SourcePathArg;
import com.facebook.buck.util.Optionals;
import com.facebook.buck.util.RichStream;
import com.facebook.buck.versions.VersionPropagator;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimaps;
import java.io.File;
import java.nio.file.Path;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import org.immutables.value.Value;

public class CxxLuaExtensionDescription implements DescriptionWithTargetGraph<CxxLuaExtensionDescriptionArg>,
        ImplicitDepsInferringDescription<CxxLuaExtensionDescription.AbstractCxxLuaExtensionDescriptionArg>,
        VersionPropagator<CxxLuaExtensionDescriptionArg>, Flavored {

    private final ToolchainProvider toolchainProvider;
    private final CxxBuckConfig cxxBuckConfig;

    public CxxLuaExtensionDescription(ToolchainProvider toolchainProvider, CxxBuckConfig cxxBuckConfig) {
        this.toolchainProvider = toolchainProvider;
        this.cxxBuckConfig = cxxBuckConfig;
    }

    private String getExtensionName(BuildTarget target, CxxPlatform cxxPlatform) {
        return String.format("%s.%s", target.getShortName(), cxxPlatform.getSharedLibraryExtension());
    }

    private BuildTarget getExtensionTarget(BuildTarget target, Flavor platform) {
        return target.withAppendedFlavors(platform);
    }

    private Path getExtensionPath(ProjectFilesystem filesystem, BuildTarget target, CxxPlatform cxxPlatform) {
        return BuildTargetPaths.getGenPath(filesystem, getExtensionTarget(target, cxxPlatform.getFlavor()), "%s")
                .resolve(getExtensionName(target, cxxPlatform));
    }

    private ImmutableList<Arg> getExtensionArgs(BuildTarget buildTarget, ProjectFilesystem projectFilesystem,
            ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver, SourcePathRuleFinder ruleFinder,
            CellPathResolver cellRoots, LuaPlatform luaPlatform, CxxLuaExtensionDescriptionArg args) {

        CxxPlatform cxxPlatform = luaPlatform.getCxxPlatform();

        // Extract all C/C++ sources from the constructor arg.
        ImmutableMap<String, CxxSource> srcs = CxxDescriptionEnhancer.parseCxxSources(buildTarget, graphBuilder,
                ruleFinder, pathResolver, cxxPlatform, args);
        ImmutableMap<Path, SourcePath> headers = CxxDescriptionEnhancer.parseHeaders(buildTarget, graphBuilder,
                ruleFinder, pathResolver, Optional.of(cxxPlatform), args);

        // Setup the header symlink tree and combine all the preprocessor input from this rule
        // and all dependencies.
        HeaderSymlinkTree headerSymlinkTree = CxxDescriptionEnhancer.requireHeaderSymlinkTree(buildTarget,
                projectFilesystem, ruleFinder, graphBuilder, cxxPlatform, headers, HeaderVisibility.PRIVATE, true);
        ImmutableSet<BuildRule> deps = args.getCxxDeps().get(graphBuilder, cxxPlatform);
        ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput = ImmutableList.<CxxPreprocessorInput>builder()
                .add(luaPlatform.getLuaCxxLibrary(graphBuilder).getCxxPreprocessorInput(cxxPlatform, graphBuilder))
                .addAll(CxxDescriptionEnhancer.collectCxxPreprocessorInput(buildTarget, cxxPlatform, graphBuilder,
                        deps,
                        ImmutableListMultimap.copyOf(Multimaps.transformValues(
                                CxxFlags.getLanguageFlagsWithMacros(args.getPreprocessorFlags(),
                                        args.getPlatformPreprocessorFlags(), args.getLangPreprocessorFlags(),
                                        args.getLangPlatformPreprocessorFlags(), cxxPlatform),
                                f -> CxxDescriptionEnhancer.toStringWithMacrosArgs(buildTarget, cellRoots,
                                        graphBuilder, cxxPlatform, f))),
                        ImmutableList.of(headerSymlinkTree), ImmutableSet.of(),
                        CxxPreprocessables.getTransitiveCxxPreprocessorInput(cxxPlatform, graphBuilder, deps),
                        args.getRawHeaders()))
                .build();

        // Generate rule to build the object files.
        ImmutableMultimap<CxxSource.Type, Arg> compilerFlags = ImmutableListMultimap
                .copyOf(Multimaps.transformValues(
                        CxxFlags.getLanguageFlagsWithMacros(args.getCompilerFlags(),
                                args.getPlatformCompilerFlags(), args.getLangCompilerFlags(),
                                args.getLangPlatformCompilerFlags(), cxxPlatform),
                        f -> CxxDescriptionEnhancer.toStringWithMacrosArgs(buildTarget, cellRoots, graphBuilder,
                                cxxPlatform, f)));
        ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects = CxxSourceRuleFactory
                .of(projectFilesystem, buildTarget, graphBuilder, pathResolver, ruleFinder, cxxBuckConfig,
                        cxxPlatform, cxxPreprocessorInput, compilerFlags, args.getPrefixHeader(),
                        args.getPrecompiledHeader(), PicType.PIC)
                .requirePreprocessAndCompileRules(srcs);

        ImmutableList.Builder<Arg> argsBuilder = ImmutableList.builder();
        CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(args.getLinkerFlags(), args.getPlatformLinkerFlags(),
                cxxPlatform).stream()
                .map(f -> CxxDescriptionEnhancer.toStringWithMacrosArgs(buildTarget, cellRoots, graphBuilder,
                        cxxPlatform, f))
                .forEach(argsBuilder::add);

        // Add object files into the args.
        argsBuilder.addAll(SourcePathArg.from(picObjects.values()));

        return argsBuilder.build();
    }

    private BuildRule createExtensionBuildRule(BuildTarget buildTarget, ProjectFilesystem projectFilesystem,
            ActionGraphBuilder graphBuilder, CellPathResolver cellRoots, LuaPlatform luaPlatform,
            CxxLuaExtensionDescriptionArg args) {
        CxxPlatform cxxPlatform = luaPlatform.getCxxPlatform();
        SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(graphBuilder);
        SourcePathResolver pathResolver = DefaultSourcePathResolver.from(ruleFinder);
        String extensionName = getExtensionName(buildTarget, cxxPlatform);
        Path extensionPath = getExtensionPath(projectFilesystem, buildTarget, cxxPlatform);
        return CxxLinkableEnhancer.createCxxLinkableBuildRule(cxxBuckConfig, cxxPlatform, projectFilesystem,
                graphBuilder, pathResolver, ruleFinder, getExtensionTarget(buildTarget, cxxPlatform.getFlavor()),
                Linker.LinkType.SHARED, Optional.of(extensionName), extensionPath, args.getLinkerExtraOutputs(),
                Linker.LinkableDepType.SHARED, CxxLinkOptions.of(),
                RichStream.from(args.getCxxDeps().get(graphBuilder, cxxPlatform)).filter(NativeLinkable.class)
                        .concat(Stream.of(luaPlatform.getLuaCxxLibrary(graphBuilder))).toImmutableList(),
                args.getCxxRuntimeType(), Optional.empty(), ImmutableSet.of(), ImmutableSet.of(),
                NativeLinkableInput.builder()
                        .setArgs(getExtensionArgs(
                                buildTarget.withoutFlavors(LinkerMapMode.NO_LINKER_MAP.getFlavor()),
                                projectFilesystem, graphBuilder, pathResolver, ruleFinder, cellRoots, luaPlatform,
                                args))
                        .build(),
                Optional.empty(), cellRoots);
    }

    @Override
    public Class<CxxLuaExtensionDescriptionArg> getConstructorArgType() {
        return CxxLuaExtensionDescriptionArg.class;
    }

    @Override
    public BuildRule createBuildRule(BuildRuleCreationContextWithTargetGraph context, BuildTarget buildTarget,
            BuildRuleParams params, CxxLuaExtensionDescriptionArg args) {
        ActionGraphBuilder graphBuilder = context.getActionGraphBuilder();
        FlavorDomain<LuaPlatform> luaPlatforms = getLuaPlatformsProvider().getLuaPlatforms();
        ProjectFilesystem projectFilesystem = context.getProjectFilesystem();
        CellPathResolver cellRoots = context.getCellPathResolver();

        // See if we're building a particular "type" of this library, and if so, extract
        // it as an enum.
        Optional<Map.Entry<Flavor, LuaPlatform>> platform = luaPlatforms.getFlavorAndValue(buildTarget);

        // If a C/C++ platform is specified, then build an extension with it.
        if (platform.isPresent()) {
            return createExtensionBuildRule(buildTarget, projectFilesystem, graphBuilder, cellRoots,
                    platform.get().getValue(), args);
        }

        // Otherwise, we return the generic placeholder of this library, that dependents can use
        // get the real build rules via querying the action graph.
        return new CxxLuaExtension(buildTarget, projectFilesystem, params) {

            @Override
            public String getModule(CxxPlatform cxxPlatform) {
                String baseModule = LuaUtil.getBaseModule(buildTarget, args.getBaseModule());
                String name = getExtensionName(buildTarget, cxxPlatform);
                return baseModule.isEmpty() ? name : baseModule + File.separator + name;
            }

            @Override
            public SourcePath getExtension(CxxPlatform cxxPlatform) {
                BuildRule rule = graphBuilder
                        .requireRule(getBuildTarget().withAppendedFlavors(cxxPlatform.getFlavor()));
                return Objects.requireNonNull(rule.getSourcePathToOutput());
            }

            @Override
            public NativeLinkTargetMode getNativeLinkTargetMode(CxxPlatform cxxPlatform) {
                return NativeLinkTargetMode.library();
            }

            @Override
            public Iterable<? extends NativeLinkable> getNativeLinkTargetDeps(CxxPlatform cxxPlatform,
                    ActionGraphBuilder graphBuilder) {
                return RichStream.from(args.getCxxDeps().get(graphBuilder, cxxPlatform))
                        .filter(NativeLinkable.class).toImmutableList();
            }

            @Override
            public NativeLinkableInput getNativeLinkTargetInput(CxxPlatform cxxPlatform,
                    ActionGraphBuilder graphBuilder, SourcePathResolver pathResolver,
                    SourcePathRuleFinder ruleFinder) {
                return NativeLinkableInput.builder()
                        .addAllArgs(getExtensionArgs(buildTarget, projectFilesystem, graphBuilder, pathResolver,
                                ruleFinder, cellRoots, luaPlatforms.getValue(cxxPlatform.getFlavor()), args))
                        .addAllFrameworks(args.getFrameworks()).build();
            }

            @Override
            public Optional<Path> getNativeLinkTargetOutputPath(CxxPlatform cxxPlatform) {
                return Optional.empty();
            }
        };
    }

    @Override
    public void findDepsForTargetFromConstructorArgs(BuildTarget buildTarget, CellPathResolver cellRoots,
            AbstractCxxLuaExtensionDescriptionArg constructorArg,
            ImmutableCollection.Builder<BuildTarget> extraDepsBuilder,
            ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) {

        for (LuaPlatform luaPlatform : getLuaPlatformsProvider().getLuaPlatforms().getValues()) {

            // Add deps from lua C/C++ library.
            Optionals.addIfPresent(luaPlatform.getLuaCxxLibraryTarget(), extraDepsBuilder);

            // Get any parse time deps from the C/C++ platforms.
            targetGraphOnlyDepsBuilder.addAll(CxxPlatforms.getParseTimeDeps(luaPlatform.getCxxPlatform()));
        }
    }

    @Override
    public Optional<ImmutableSet<FlavorDomain<?>>> flavorDomains() {
        return Optional.of(ImmutableSet.of(getLuaPlatformsProvider().getLuaPlatforms()));
    }

    private LuaPlatformsProvider getLuaPlatformsProvider() {
        return toolchainProvider.getByName(LuaPlatformsProvider.DEFAULT_NAME, LuaPlatformsProvider.class);
    }

    @BuckStyleImmutable
    @Value.Immutable
    interface AbstractCxxLuaExtensionDescriptionArg extends CxxConstructorArg {
        Optional<String> getBaseModule();
    }
}