com.facebook.buck.d.DDescriptionUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.d.DDescriptionUtils.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.d;

import com.facebook.buck.cxx.CxxBuckConfig;
import com.facebook.buck.cxx.CxxLink;
import com.facebook.buck.cxx.CxxLinkableEnhancer;
import com.facebook.buck.cxx.CxxPlatform;
import com.facebook.buck.cxx.Linker;
import com.facebook.buck.cxx.NativeLinkable;
import com.facebook.buck.cxx.NativeLinkableInput;
import com.facebook.buck.graph.AbstractBreadthFirstTraversal;
import com.facebook.buck.io.MorePaths;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.ImmutableFlavor;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildTargetSourcePath;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.SymlinkTree;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.rules.args.SourcePathArg;
import com.facebook.buck.rules.args.StringArg;
import com.facebook.buck.rules.coercer.SourceList;
import com.facebook.buck.util.MoreMaps;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;

import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;

/**
 * Utility functions for use in D Descriptions.
 */
abstract class DDescriptionUtils {

    public static final Flavor SOURCE_LINK_TREE = ImmutableFlavor.of("source-link-tree");

    /**
     * Creates a BuildTarget, based on an existing build target, but flavored with a CxxPlatform
     * and an additional flavor created by combining a prefix and an output file name.
     *
     * @param existingTarget the existing target
     * @param flavorPrefix prefix to be used for added flavor
     * @param fileName filename to be used for added flavor
     * @param cxxPlatform the C++ platform to compile for
     * @return the new BuildTarget
     */
    public static BuildTarget createBuildTargetForFile(BuildTarget existingTarget, String flavorPrefix,
            String fileName, CxxPlatform cxxPlatform) {
        return BuildTarget.builder(existingTarget).addFlavors(cxxPlatform.getFlavor(),
                ImmutableFlavor.of(flavorPrefix + Flavor.replaceInvalidCharacters(fileName))).build();
    }

    /**
     * Creates a new BuildTarget, based on an existing target, for a file to be compiled.
     * @param existingTarget the existing target
     * @param src the source file to be compiled
     * @param cxxPlatform the C++ platform to compile the file for
     * @return a BuildTarget to compile a D source file to an object file
     */
    public static BuildTarget createDCompileBuildTarget(BuildTarget existingTarget, String src,
            CxxPlatform cxxPlatform) {
        return createBuildTargetForFile(existingTarget, "compile-", DCompileStep.getObjectNameForSourceName(src),
                cxxPlatform);
    }

    /**
     * Creates a {@link com.facebook.buck.cxx.NativeLinkable} using sources compiled by
     * the D compiler.
     *
     * @param params build parameters for the build target
     * @param sources source files to compile
     * @param compilerFlags flags to pass to the compiler
     * @param buildRuleResolver resolver for build rules
     * @param cxxPlatform the C++ platform to compile for
     * @param dBuckConfig the Buck configuration for D
     * @return the new build rule
     */
    public static CxxLink createNativeLinkable(BuildRuleParams params, BuildRuleResolver buildRuleResolver,
            CxxPlatform cxxPlatform, DBuckConfig dBuckConfig, CxxBuckConfig cxxBuckConfig,
            ImmutableList<String> compilerFlags, SourceList sources, ImmutableList<String> linkerFlags,
            DIncludes includes) throws NoSuchBuildTargetException {

        BuildTarget buildTarget = params.getBuildTarget();
        SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
        SourcePathResolver sourcePathResolver = new SourcePathResolver(ruleFinder);

        ImmutableList<SourcePath> sourcePaths = sourcePathsForCompiledSources(params, buildRuleResolver,
                sourcePathResolver, ruleFinder, cxxPlatform, dBuckConfig, compilerFlags, sources, includes);

        // Return a rule to link the .o for the binary together with its
        // dependencies.
        return CxxLinkableEnhancer.createCxxLinkableBuildRule(cxxBuckConfig, cxxPlatform, params, buildRuleResolver,
                sourcePathResolver, ruleFinder, buildTarget, Linker.LinkType.EXECUTABLE, Optional.empty(),
                BuildTargets.getGenPath(params.getProjectFilesystem(), buildTarget,
                        "%s/" + buildTarget.getShortName()),
                Linker.LinkableDepType.STATIC, FluentIterable.from(params.getDeps()).filter(NativeLinkable.class),
                /* cxxRuntimeType */ Optional.empty(), /* bundleLoader */ Optional.empty(), ImmutableSet.of(),
                NativeLinkableInput.builder().addAllArgs(StringArg.from(dBuckConfig.getLinkerFlags()))
                        .addAllArgs(StringArg.from(linkerFlags))
                        .addAllArgs(SourcePathArg.from(sourcePathResolver, sourcePaths)).build());
    }

    public static BuildTarget getSymlinkTreeTarget(BuildTarget baseTarget) {
        return BuildTarget.builder(baseTarget).addFlavors(SOURCE_LINK_TREE).build();
    }

    public static SymlinkTree createSourceSymlinkTree(BuildTarget target, BuildRuleParams baseParams,
            SourcePathResolver pathResolver, SourceList sources) {
        Preconditions.checkState(target.getFlavors().contains(SOURCE_LINK_TREE));
        return new SymlinkTree(
                baseParams.copyWithChanges(target, Suppliers.ofInstance(ImmutableSortedSet.of()),
                        Suppliers.ofInstance(ImmutableSortedSet.of())),
                pathResolver,
                BuildTargets.getGenPath(baseParams.getProjectFilesystem(), baseParams.getBuildTarget(), "%s"),
                MoreMaps.transformKeys(sources.toNameMap(baseParams.getBuildTarget(), pathResolver, "srcs"),
                        MorePaths.toPathFn(baseParams.getProjectFilesystem().getRootPath().getFileSystem())));
    }

    private static ImmutableMap<BuildTarget, DLibrary> getTransitiveDLibraryRules(
            Iterable<? extends BuildRule> inputs) {
        final ImmutableMap.Builder<BuildTarget, DLibrary> libraries = ImmutableMap.builder();
        new AbstractBreadthFirstTraversal<BuildRule>(inputs) {
            @Override
            public ImmutableSet<BuildRule> visit(BuildRule rule) {
                if (rule instanceof DLibrary) {
                    libraries.put(rule.getBuildTarget(), (DLibrary) rule);
                    return rule.getDeps();
                }
                return ImmutableSet.of();
            }
        }.start();
        return libraries.build();
    }

    /**
     * Ensures that a DCompileBuildRule exists for the given target, creating a DCompileBuildRule
     * if neccesary.
     * @param baseParams build parameters for the rule
     * @param buildRuleResolver BuildRuleResolver the rule should be in
     * @param sourcePathResolver used to resolve source paths
     * @param src the source file to be compiled
     * @param compilerFlags flags to pass to the compiler
     * @param compileTarget the target the rule should be for
     * @param dBuckConfig the Buck configuration for D
     * @return the build rule
     */
    public static DCompileBuildRule requireBuildRule(BuildTarget compileTarget, BuildRuleParams baseParams,
            BuildRuleResolver buildRuleResolver, SourcePathResolver sourcePathResolver,
            SourcePathRuleFinder ruleFinder, DBuckConfig dBuckConfig, ImmutableList<String> compilerFlags,
            String name, SourcePath src, DIncludes includes) throws NoSuchBuildTargetException {
        Optional<BuildRule> existingRule = buildRuleResolver.getRuleOptional(compileTarget);
        if (existingRule.isPresent()) {
            return (DCompileBuildRule) existingRule.get();
        } else {
            Tool compiler = dBuckConfig.getDCompiler();

            Map<BuildTarget, DIncludes> transitiveIncludes = new TreeMap<>();
            transitiveIncludes.put(baseParams.getBuildTarget(), includes);
            for (Map.Entry<BuildTarget, DLibrary> library : getTransitiveDLibraryRules(baseParams.getDeps())
                    .entrySet()) {
                transitiveIncludes.put(library.getKey(), library.getValue().getIncludes());
            }

            ImmutableSortedSet.Builder<BuildRule> depsBuilder = ImmutableSortedSet.naturalOrder();
            depsBuilder.addAll(compiler.getDeps(ruleFinder));
            depsBuilder.addAll(ruleFinder.filterBuildRuleInputs(src));
            for (DIncludes dIncludes : transitiveIncludes.values()) {
                depsBuilder.addAll(dIncludes.getDeps(ruleFinder));
            }
            ImmutableSortedSet<BuildRule> deps = depsBuilder.build();

            return buildRuleResolver
                    .addToIndex(
                            new DCompileBuildRule(
                                    baseParams.copyWithChanges(compileTarget, Suppliers.ofInstance(deps),
                                            Suppliers.ofInstance(ImmutableSortedSet.of())),
                                    sourcePathResolver, compiler,
                                    ImmutableList.<String>builder().addAll(dBuckConfig.getBaseCompilerFlags())
                                            .addAll(compilerFlags).build(),
                                    name, ImmutableSortedSet.of(src),
                                    ImmutableList.copyOf(transitiveIncludes.values())));
        }
    }

    /**
     * Generates BuildTargets and BuildRules to compile D sources to object files, and
     * returns a list of SourcePaths referring to the generated object files.
     * @param sources source files to compile
     * @param compilerFlags flags to pass to the compiler
     * @param baseParams build parameters for the compilation
     * @param buildRuleResolver resolver for build rules
     * @param sourcePathResolver resolver for source paths
     * @param cxxPlatform the C++ platform to compile for
     * @param dBuckConfig the Buck configuration for D
     * @return SourcePaths of the generated object files
     */
    public static ImmutableList<SourcePath> sourcePathsForCompiledSources(BuildRuleParams baseParams,
            BuildRuleResolver buildRuleResolver, SourcePathResolver sourcePathResolver,
            SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, DBuckConfig dBuckConfig,
            ImmutableList<String> compilerFlags, SourceList sources, DIncludes includes)
            throws NoSuchBuildTargetException {
        ImmutableList.Builder<SourcePath> sourcePaths = ImmutableList.builder();
        for (Map.Entry<String, SourcePath> source : sources
                .toNameMap(baseParams.getBuildTarget(), sourcePathResolver, "srcs").entrySet()) {
            BuildTarget compileTarget = createDCompileBuildTarget(baseParams.getBuildTarget(), source.getKey(),
                    cxxPlatform);
            requireBuildRule(compileTarget, baseParams, buildRuleResolver, sourcePathResolver, ruleFinder,
                    dBuckConfig, compilerFlags, source.getKey(), source.getValue(), includes);
            sourcePaths.add(new BuildTargetSourcePath(compileTarget));
        }
        return sourcePaths.build();
    }

}