blob: f54b9a6a08c4ad8e727a4a6c3255fa0518052f94 [file] [log] [blame]
/*
* 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.ImmutableBuildRuleType;
import com.facebook.buck.rules.ImplicitDepsInferringDescription;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SymlinkTree;
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 static 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 = ImmutableBuildRuleType.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) {
return String.format("%s.so", target.getShortName());
}
@VisibleForTesting
protected Path getExtensionPath(BuildTarget target, Flavor platform) {
return BuildTargets.getBinPath(getExtensionTarget(target, platform), "%s")
.resolve(getExtensionName(target));
}
private <A extends Arg> BuildRule createExtensionBuildRule(
BuildRuleParams params,
BuildRuleResolver ruleResolver,
CxxPlatform cxxPlatform,
A args) {
// Extract all C/C++ sources from the constructor arg.
ImmutableMap<String, CxxSource> srcs =
CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver, args);
ImmutableMap<Path, SourcePath> headers =
CxxDescriptionEnhancer.parseHeaders(
params,
ruleResolver,
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.
SymlinkTree headerSymlinkTree = CxxDescriptionEnhancer.createHeaderSymlinkTreeBuildRule(
params,
ruleResolver,
cxxPlatform.getFlavor(),
ImmutableMap.<Path, SourcePath>builder()
.putAll(headers)
.putAll(lexYaccSources.getCxxHeaders())
.build(),
CxxDescriptionEnhancer.HeaderVisibility.PRIVATE);
CxxPreprocessorInput cxxPreprocessorInput = CxxDescriptionEnhancer.combineCxxPreprocessorInput(
params,
cxxPlatform,
CxxPreprocessorFlags.fromArgs(
args.preprocessorFlags,
args.langPreprocessorFlags),
args.prefixHeaders.get(),
ImmutableList.of(headerSymlinkTree),
ImmutableList.<Path>of());
ImmutableMap<String, CxxSource> allSources =
ImmutableMap.<String, CxxSource>builder()
.putAll(srcs)
.putAll(lexYaccSources.getCxxSources())
.build();
ImmutableMap<String, CxxSource> preprocessed =
CxxPreprocessables.createPreprocessBuildRules(
params,
ruleResolver,
cxxPlatform,
cxxPreprocessorInput,
/* pic */ true,
allSources);
ImmutableList<SourcePath> picObjects =
CxxDescriptionEnhancer.createCompileBuildRules(
params,
ruleResolver,
cxxPlatform,
args.compilerFlags.or(ImmutableList.<String>of()),
/* pic */ true,
preprocessed);
// Setup the rules to link the shared library.
String extensionName = getExtensionName(params.getBuildTarget());
Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor());
return CxxLinkableEnhancer.createCxxLinkableBuildRule(
cxxPlatform,
params,
new SourcePathResolver(ruleResolver),
/* extraCxxLdFlags */ ImmutableList.<String>of(),
/* extraLdFlags */ ImmutableList.<String>builder()
.addAll(args.linkerFlags.or(ImmutableList.<String>of()))
.addAll(
CxxDescriptionEnhancer.getPlatformFlags(
args.platformLinkerFlags.get(),
cxxPlatform.getFlavor().toString()))
.build(),
getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()),
Linker.LinkType.SHARED,
Optional.of(extensionName),
extensionPath,
picObjects,
Linker.LinkableDepType.SHARED,
params.getDeps());
}
@Override
public <A extends Arg> BuildRule createBuildRule(
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(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;
}
}