blob: 04217fbc0aa96f0e1a5a16670132e7c62071c531 [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.java;
import com.facebook.buck.cxx.CxxPlatform;
import com.facebook.buck.graph.AbstractBreadthFirstTraversal;
import com.facebook.buck.io.DefaultDirectoryTraverser;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.ImmutableFlavor;
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.BuildTargetSourcePath;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.ImmutableBuildRuleType;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
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.nio.file.Path;
public class JavaBinaryDescription implements Description<JavaBinaryDescription.Args> {
public static final BuildRuleType TYPE = ImmutableBuildRuleType.of("java_binary");
private static final Flavor FAT_JAR_INNER_JAR_FLAVOR = ImmutableFlavor.of("inner-jar");
private final JavacOptions javacOptions;
private final CxxPlatform cxxPlatform;
public JavaBinaryDescription(
JavacOptions javacOptions,
CxxPlatform cxxPlatform) {
this.javacOptions = Preconditions.checkNotNull(javacOptions);
this.cxxPlatform = Preconditions.checkNotNull(cxxPlatform);
}
@Override
public BuildRuleType getBuildRuleType() {
return TYPE;
}
@Override
public Args createUnpopulatedConstructorArg() {
return new Args();
}
/**
* @return all the transitive native libraries we depend on, represented as a map from their
* system-specific library names to their {@link SourcePath} objects.
*/
private ImmutableMap<String, SourcePath> getNativeLibraries(Iterable<BuildRule> deps) {
final ImmutableMap.Builder<String, SourcePath> libraries = ImmutableMap.builder();
new AbstractBreadthFirstTraversal<BuildRule>(deps) {
@Override
public ImmutableSet<BuildRule> visit(BuildRule rule) {
if (rule instanceof JavaNativeLinkable) {
JavaNativeLinkable linkable = (JavaNativeLinkable) rule;
libraries.putAll(linkable.getSharedLibraries(cxxPlatform));
}
if (rule instanceof JavaNativeLinkable ||
rule instanceof JavaLibrary) {
return rule.getDeps();
} else {
return ImmutableSet.of();
}
}
}.start();
return libraries.build();
}
@Override
public <A extends Args> BuildRule createBuildRule(
BuildRuleParams params,
BuildRuleResolver resolver,
A args) {
SourcePathResolver pathResolver = new SourcePathResolver(resolver);
ImmutableMap<String, SourcePath> nativeLibraries = getNativeLibraries(params.getDeps());
BuildRuleParams binaryParams = params;
// If we're packaging native libraries, we'll build the binary JAR in a separate rule and
// package it into the final fat JAR, so adjust it's params to use a flavored target.
if (!nativeLibraries.isEmpty()) {
binaryParams = params.copyWithChanges(
params.getBuildRuleType(),
BuildTarget.builder(params.getBuildTarget()).addFlavors(FAT_JAR_INNER_JAR_FLAVOR).build(),
Suppliers.ofInstance(params.getDeclaredDeps()),
Suppliers.ofInstance(params.getExtraDeps()));
}
// Construct the build rule to build the binary JAR.
BuildRule rule = new JavaBinary(
binaryParams,
pathResolver,
args.mainClass.orNull(),
args.manifestFile.orNull(),
args.mergeManifests.or(true),
args.metaInfDirectory.orNull(),
args.blacklist.or(ImmutableSortedSet.<String>of()),
new DefaultDirectoryTraverser());
// If we're packaging native libraries, construct the rule to build the fat JAR, which packages
// up the original binary JAR and any required native libraries.
if (!nativeLibraries.isEmpty()) {
BuildRule innerJarRule = rule;
resolver.addToIndex(innerJarRule);
SourcePath innerJar = new BuildTargetSourcePath(
innerJarRule.getProjectFilesystem(),
innerJarRule.getBuildTarget());
rule = new JarFattener(
params.appendExtraDeps(
Suppliers.<Iterable<BuildRule>>ofInstance(
pathResolver.filterBuildRuleInputs(
ImmutableList.<SourcePath>builder()
.add(innerJar)
.addAll(nativeLibraries.values())
.build()))),
pathResolver,
javacOptions,
innerJar,
nativeLibraries);
}
return rule;
}
@SuppressFieldNotInitialized
public static class Args {
public Optional<ImmutableSortedSet<BuildTarget>> deps;
public Optional<String> mainClass;
public Optional<SourcePath> manifestFile;
public Optional<Boolean> mergeManifests;
@Beta
public Optional<Path> metaInfDirectory;
@Beta
public Optional<ImmutableSortedSet<String>> blacklist;
}
}