com.facebook.buck.cxx.CxxPythonExtensionDescription.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.cxx.CxxPythonExtensionDescription.java

Source

/*
 * Copyright 2014-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.cxx;

import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.FlavorDomain;
import com.facebook.buck.model.FlavorDomainException;
import com.facebook.buck.python.PythonUtil;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildRuleType;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.ImplicitDepsInferringDescription;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import java.nio.file.Path;
import java.util.Map;

public class CxxPythonExtensionDescription implements Description<CxxPythonExtensionDescription.Arg>,
        ImplicitDepsInferringDescription<CxxPythonExtensionDescription.Arg> {

    private enum Type {
        EXTENSION,
    }

    private static final FlavorDomain<Type> LIBRARY_TYPE = new FlavorDomain<>("C/C++ Library Type",
            ImmutableMap.of(CxxDescriptionEnhancer.SHARED_FLAVOR, Type.EXTENSION));

    public static final BuildRuleType TYPE = BuildRuleType.of("cxx_python_extension");

    private final CxxBuckConfig cxxBuckConfig;
    private final FlavorDomain<CxxPlatform> cxxPlatforms;

    public CxxPythonExtensionDescription(CxxBuckConfig cxxBuckConfig, FlavorDomain<CxxPlatform> cxxPlatforms) {
        this.cxxBuckConfig = cxxBuckConfig;
        this.cxxPlatforms = cxxPlatforms;
    }

    @Override
    public Arg createUnpopulatedConstructorArg() {
        return new Arg();
    }

    @VisibleForTesting
    protected BuildTarget getExtensionTarget(BuildTarget target, Flavor platform) {
        return CxxDescriptionEnhancer.createSharedLibraryBuildTarget(target, platform);
    }

    @VisibleForTesting
    protected String getExtensionName(BuildTarget target) {
        // .so is used on OS X too (as opposed to dylib).
        return String.format("%s.so", target.getShortName());
    }

    @VisibleForTesting
    protected Path getExtensionPath(BuildTarget target, Flavor platform) {
        return BuildTargets.getGenPath(getExtensionTarget(target, platform), "%s")
                .resolve(getExtensionName(target));
    }

    private <A extends Arg> BuildRule createExtensionBuildRule(TargetGraph targetGraph, BuildRuleParams params,
            BuildRuleResolver ruleResolver, CxxPlatform cxxPlatform, A args) {
        SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

        // Extract all C/C++ sources from the constructor arg.
        ImmutableMap<String, CxxSource> srcs = CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver,
                cxxPlatform, args);
        ImmutableMap<Path, SourcePath> headers = CxxDescriptionEnhancer.parseHeaders(params, ruleResolver,
                cxxPlatform, args);
        ImmutableMap<String, SourcePath> lexSrcs = CxxDescriptionEnhancer.parseLexSources(params, ruleResolver,
                args);
        ImmutableMap<String, SourcePath> yaccSrcs = CxxDescriptionEnhancer.parseYaccSources(params, ruleResolver,
                args);

        CxxHeaderSourceSpec lexYaccSources = CxxDescriptionEnhancer.createLexYaccBuildRules(params, ruleResolver,
                cxxPlatform, ImmutableList.<String>of(), lexSrcs, ImmutableList.<String>of(), yaccSrcs);

        // Setup the header symlink tree and combine all the preprocessor input from this rule
        // and all dependencies.
        HeaderSymlinkTree headerSymlinkTree = CxxDescriptionEnhancer.requireHeaderSymlinkTree(params, ruleResolver,
                new SourcePathResolver(ruleResolver), cxxPlatform, /* includeLexYaccHeaders */ true, lexSrcs,
                yaccSrcs, headers, HeaderVisibility.PRIVATE);
        ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput = CxxDescriptionEnhancer
                .collectCxxPreprocessorInput(targetGraph, params, cxxPlatform,
                        CxxFlags.getLanguageFlags(args.preprocessorFlags, args.platformPreprocessorFlags,
                                args.langPreprocessorFlags, cxxPlatform),
                        ImmutableList.of(headerSymlinkTree), ImmutableSet.<Path>of(), CxxPreprocessables
                                .getTransitiveCxxPreprocessorInput(targetGraph, cxxPlatform, params.getDeps()));

        ImmutableMap<String, CxxSource> allSources = ImmutableMap.<String, CxxSource>builder().putAll(srcs)
                .putAll(lexYaccSources.getCxxSources()).build();

        // Generate rule to build the object files.
        ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects = CxxSourceRuleFactory
                .requirePreprocessAndCompileRules(params, ruleResolver, pathResolver, cxxPlatform,
                        cxxPreprocessorInput,
                        CxxFlags.getFlags(args.compilerFlags, args.platformCompilerFlags, cxxPlatform),
                        args.prefixHeader, cxxBuckConfig.getPreprocessMode(), allSources,
                        CxxSourceRuleFactory.PicType.PIC);

        // Setup the rules to link the shared library.
        String extensionName = getExtensionName(params.getBuildTarget());
        Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor());
        return CxxLinkableEnhancer.createCxxLinkableBuildRule(targetGraph, cxxPlatform, params, pathResolver,
                /* extraLdFlags */ CxxFlags.getFlags(args.linkerFlags, args.platformLinkerFlags, cxxPlatform),
                getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()), Linker.LinkType.SHARED,
                Optional.of(extensionName), extensionPath, picObjects.values(),
                /* extraInputs */ ImmutableList.<SourcePath>of(), Linker.LinkableDepType.SHARED, params.getDeps(),
                args.cxxRuntimeType, Optional.<SourcePath>absent(), ImmutableSet.<BuildRule>of());
    }

    @Override
    public <A extends Arg> BuildRule createBuildRule(TargetGraph targetGraph, BuildRuleParams params,
            BuildRuleResolver ruleResolver, A args) {

        // See if we're building a particular "type" of this library, and if so, extract
        // it as an enum.
        Optional<Map.Entry<Flavor, Type>> type;
        Optional<Map.Entry<Flavor, CxxPlatform>> platform;
        try {
            type = LIBRARY_TYPE.getFlavorAndValue(ImmutableSet.copyOf(params.getBuildTarget().getFlavors()));
            platform = cxxPlatforms.getFlavorAndValue(ImmutableSet.copyOf(params.getBuildTarget().getFlavors()));
        } catch (FlavorDomainException e) {
            throw new HumanReadableException("%s: %s", params.getBuildTarget(), e.getMessage());
        }

        // If we *are* building a specific type of this lib, call into the type specific
        // rule builder methods.  Currently, we only support building a shared lib from the
        // pre-existing static lib, which we do here.
        if (type.isPresent()) {
            Preconditions.checkState(type.get().getValue() == Type.EXTENSION);
            Preconditions.checkState(platform.isPresent());
            return createExtensionBuildRule(targetGraph, params, ruleResolver, 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.
        SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);
        Path baseModule = PythonUtil.getBasePath(params.getBuildTarget(), args.baseModule);
        return new CxxPythonExtension(params, ruleResolver, pathResolver,
                baseModule.resolve(getExtensionName(params.getBuildTarget())));
    }

    @Override
    public BuildRuleType getBuildRuleType() {
        return TYPE;
    }

    @Override
    public Iterable<BuildTarget> findDepsForTargetFromConstructorArgs(BuildTarget buildTarget, Arg constructorArg) {
        ImmutableSet.Builder<BuildTarget> deps = ImmutableSet.builder();

        deps.add(cxxBuckConfig.getPythonDep());

        if (constructorArg.lexSrcs.isPresent() && !constructorArg.lexSrcs.get().isEmpty()) {
            deps.add(cxxBuckConfig.getLexDep());
        }

        return deps.build();
    }

    @SuppressFieldNotInitialized
    public static class Arg extends CxxConstructorArg {
        public Optional<String> baseModule;
    }

}