blob: 30da3e68660eaaf984dd2225ae15f640de7d0208 [file] [log] [blame]
/*
* Copyright 2012-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.android;
import static com.facebook.buck.rules.BuildableProperties.Kind.ANDROID;
import static com.facebook.buck.rules.BuildableProperties.Kind.LIBRARY;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetPattern;
import com.facebook.buck.rules.AbstractBuildRuleBuilderParams;
import com.facebook.buck.rules.AbstractBuildable;
import com.facebook.buck.rules.BuildContext;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.BuildRuleType;
import com.facebook.buck.rules.BuildableContext;
import com.facebook.buck.rules.BuildableProperties;
import com.facebook.buck.rules.RecordArtifactsInDirectoryStep;
import com.facebook.buck.rules.RuleKey;
import com.facebook.buck.rules.SrcsAttributeBuilder;
import com.facebook.buck.step.Step;
import com.facebook.buck.util.BuckConstant;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
/**
* An object that represents a collection of Android NDK source code.
* <p>
* Suppose this were a rule defined in <code>src/com/facebook/feed/jni/BUCK</code>:
* <pre>
* ndk_library(
* name = 'feed-jni',
* deps = [],
* flags = ["NDK_DEBUG=1", "V=1"],
* )
* </pre>
*/
public class NdkLibrary extends AbstractBuildable implements NativeLibraryBuildable {
private final static BuildableProperties PROPERTIES = new BuildableProperties(ANDROID, LIBRARY);
/** @see NativeLibraryBuildable#isAsset() */
private final boolean isAsset;
/** The directory containing the Android.mk file to use. This value includes a trailing slash. */
private final String makefileDirectory;
private final String lastPathComponent;
private final String buildArtifactsDirectory;
private final String genDirectory;
private final ImmutableSortedSet<String> sources;
private final ImmutableList<String> flags;
protected NdkLibrary(
BuildTarget buildTarget,
Set<String> sources,
List<String> flags,
boolean isAsset) {
this.isAsset = isAsset;
this.makefileDirectory = buildTarget.getBasePathWithSlash();
this.lastPathComponent = "__lib" + buildTarget.getShortName();
this.buildArtifactsDirectory = getBuildArtifactsDirectory(buildTarget, true /* isScratchDir */);
this.genDirectory = getBuildArtifactsDirectory(buildTarget, false /* isScratchDir */);
Preconditions.checkArgument(!sources.isEmpty(),
"Must include at least one file (Android.mk?) in ndk_library rule");
this.sources = ImmutableSortedSet.copyOf(sources);
this.flags = ImmutableList.copyOf(flags);
}
@Override
public boolean isAsset() {
return isAsset;
}
@Override
public String getLibraryPath() {
return genDirectory;
}
@Override
@Nullable
public String getPathToOutputFile() {
// An ndk_library() does not have a "primary output" at this time.
return null;
}
@Override
public List<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext)
throws IOException {
// .so files are written to the libs/ subdirectory of the output directory.
// All of them should be recorded via the BuildableContext.
Path binDirectory = Paths.get(buildArtifactsDirectory, "libs");
Step nkdBuildStep = new NdkBuildStep(makefileDirectory,
buildArtifactsDirectory + "/",
binDirectory,
flags);
Function<String, Path> artifactPathTransform = new Function<String, Path>() {
@Override
public Path apply(String pathRelativeTo) {
return Paths.get(lastPathComponent, pathRelativeTo);
}
};
Step recordStep = new RecordArtifactsInDirectoryStep(
buildableContext,
binDirectory,
genDirectory,
artifactPathTransform);
return ImmutableList.of(nkdBuildStep, recordStep);
}
/**
* @param isScratchDir true if this should be the "working directory" where a build rule may write
* intermediate files when computing its output. false if this should be the gen/ directory
* where the "official" outputs of the build rule should be written. Files of the latter type
* can be referenced via the genfile() function.
*/
private String getBuildArtifactsDirectory(BuildTarget target, boolean isScratchDir) {
return String.format("%s/%s%s",
isScratchDir ? BuckConstant.BIN_DIR : BuckConstant.GEN_DIR,
target.getBasePathWithSlash(),
lastPathComponent);
}
@Override
public BuildableProperties getProperties() {
return PROPERTIES;
}
@Override
public RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) throws IOException {
// TODO(#2493457): This rule uses the ndk-build script (part of the Android NDK), so the RuleKey
// should incorporate which version of the NDK is used.
return builder
.set("sources", sources)
.set("flags", flags)
.set("is_asset", isAsset());
}
@Override
public Iterable<String> getInputsToCompareToOutput() {
return this.sources;
}
public static Builder newNdkLibraryRuleBuilder(AbstractBuildRuleBuilderParams params) {
return new Builder(params);
}
public static class Builder extends AbstractBuildable.Builder implements SrcsAttributeBuilder {
private boolean isAsset = false;
private Set<String> sources = Sets.newHashSet();
private ImmutableList.Builder<String> flags = ImmutableList.builder();
private Builder(AbstractBuildRuleBuilderParams params) {
super(params);
}
@Override
public BuildRuleType getType() {
return BuildRuleType.NDK_LIBRARY;
}
@Override
protected NdkLibrary newBuildable(BuildRuleParams params, BuildRuleResolver resolver) {
return new NdkLibrary(params.getBuildTarget(), sources, flags.build(), isAsset);
}
public Builder setIsAsset(boolean isAsset) {
this.isAsset = isAsset;
return this;
}
@Override
public Builder setBuildTarget(BuildTarget buildTarget) {
super.setBuildTarget(buildTarget);
return this;
}
@Override
public Builder addVisibilityPattern(BuildTargetPattern visibilityPattern) {
super.addVisibilityPattern(visibilityPattern);
return this;
}
@Override
public Builder addSrc(String source) {
this.sources.add(source);
return this;
}
public Builder addFlag(String flag) {
this.flags.add(flag);
return this;
}
}
}