/*
* 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.android;
import static com.facebook.buck.android.AndroidBinaryResourcesGraphEnhancer.PACKAGE_STRING_ASSETS_FLAVOR;
import com.facebook.buck.android.AndroidBinary.ExopackageMode;
import com.facebook.buck.android.AndroidBinary.PackageType;
import com.facebook.buck.android.AndroidBinary.RelinkerMode;
import com.facebook.buck.android.FilterResourcesStep.ResourceFilter;
import com.facebook.buck.android.NdkCxxPlatforms.TargetCpuType;
import com.facebook.buck.android.ResourcesFilter.ResourceCompressionMode;
import com.facebook.buck.android.aapt.RDotTxtEntry.RType;
import com.facebook.buck.android.redex.RedexOptions;
import com.facebook.buck.cli.BuckConfig;
import com.facebook.buck.cxx.CxxBuckConfig;
import com.facebook.buck.dalvik.ZipSplitter.DexSplitStrategy;
import com.facebook.buck.event.PerfEventId;
import com.facebook.buck.event.SimplePerfEvent;
import com.facebook.buck.jvm.java.JavaBuckConfig;
import com.facebook.buck.jvm.java.JavaLibrary;
import com.facebook.buck.jvm.java.JavaOptions;
import com.facebook.buck.jvm.java.JavacFactory;
import com.facebook.buck.jvm.java.JavacOptions;
import com.facebook.buck.jvm.java.Keystore;
import com.facebook.buck.log.Logger;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.Flavored;
import com.facebook.buck.model.MacroException;
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.CellPathResolver;
import com.facebook.buck.rules.CommonDescriptionArg;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.HasDeclaredDeps;
import com.facebook.buck.rules.HasTests;
import com.facebook.buck.rules.Hint;
import com.facebook.buck.rules.ImplicitDepsInferringDescription;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.rules.args.MacroArg;
import com.facebook.buck.rules.coercer.BuildConfigFields;
import com.facebook.buck.rules.coercer.ManifestEntries;
import com.facebook.buck.rules.macros.ExecutableMacroExpander;
import com.facebook.buck.rules.macros.LocationMacroExpander;
import com.facebook.buck.rules.macros.MacroHandler;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.MoreCollectors;
import com.facebook.buck.util.RichStream;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.google.common.base.Preconditions;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableCollection;
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 com.google.common.collect.Ordering;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.immutables.value.Value;
public class AndroidBinaryDescription
implements Description<AndroidBinaryDescriptionArg>,
Flavored,
ImplicitDepsInferringDescription<
AndroidBinaryDescription.AbstractAndroidBinaryDescriptionArg> {
private static final Logger LOG = Logger.get(AndroidBinaryDescription.class);
private static final String SECTION = "android";
private static final String CONFIG_PARAM_REDEX = "redex";
/**
* By default, assume we have 5MB of linear alloc, 1MB of which is taken up by the framework, so
* that leaves 4MB.
*/
private static final long DEFAULT_LINEAR_ALLOC_HARD_LIMIT = 4 * 1024 * 1024;
private static final MacroHandler MACRO_HANDLER =
new MacroHandler(
ImmutableMap.of(
"exe", new ExecutableMacroExpander(),
"location", new LocationMacroExpander()));
private static final Pattern COUNTRY_LOCALE_PATTERN = Pattern.compile("([a-z]{2})-[A-Z]{2}");
private static final ImmutableSet<Flavor> FLAVORS =
ImmutableSet.of(
PACKAGE_STRING_ASSETS_FLAVOR, AndroidBinaryResourcesGraphEnhancer.AAPT2_LINK_FLAVOR);
private final JavaBuckConfig javaBuckConfig;
private final JavaOptions javaOptions;
private final JavacOptions javacOptions;
private final ProGuardConfig proGuardConfig;
private final BuckConfig buckConfig;
private final CxxBuckConfig cxxBuckConfig;
private final DxConfig dxConfig;
private final ImmutableMap<TargetCpuType, NdkCxxPlatform> nativePlatforms;
private final ListeningExecutorService dxExecutorService;
public AndroidBinaryDescription(
JavaBuckConfig javaBuckConfig,
JavaOptions javaOptions,
JavacOptions javacOptions,
ProGuardConfig proGuardConfig,
ImmutableMap<TargetCpuType, NdkCxxPlatform> nativePlatforms,
ListeningExecutorService dxExecutorService,
BuckConfig buckConfig,
CxxBuckConfig cxxBuckConfig,
DxConfig dxConfig) {
this.javaBuckConfig = javaBuckConfig;
this.javaOptions = javaOptions;
this.javacOptions = javacOptions;
this.proGuardConfig = proGuardConfig;
this.buckConfig = buckConfig;
this.cxxBuckConfig = cxxBuckConfig;
this.nativePlatforms = nativePlatforms;
this.dxExecutorService = dxExecutorService;
this.dxConfig = dxConfig;
}
@Override
public Class<AndroidBinaryDescriptionArg> getConstructorArgType() {
return AndroidBinaryDescriptionArg.class;
}
@Override
public BuildRule createBuildRule(
TargetGraph targetGraph,
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots,
AndroidBinaryDescriptionArg args)
throws NoSuchBuildTargetException {
try (SimplePerfEvent.Scope ignored =
SimplePerfEvent.scope(
Optional.ofNullable(resolver.getEventBus()),
PerfEventId.of("AndroidBinaryDescription"),
"target",
params.getBuildTarget().toString())) {
ResourceCompressionMode compressionMode = getCompressionMode(args);
BuildTarget target = params.getBuildTarget();
boolean isFlavored = target.isFlavored();
if (isFlavored) {
if (target.getFlavors().contains(PACKAGE_STRING_ASSETS_FLAVOR)
&& !compressionMode.isStoreStringsAsAssets()) {
throw new HumanReadableException(
"'package_string_assets' flavor does not exist for %s.",
target.getUnflavoredBuildTarget());
}
params = params.withBuildTarget(BuildTarget.of(target.getUnflavoredBuildTarget()));
}
BuildRule keystore = resolver.getRule(args.getKeystore());
if (!(keystore instanceof Keystore)) {
throw new HumanReadableException(
"In %s, keystore='%s' must be a keystore() but was %s().",
params.getBuildTarget(), keystore.getFullyQualifiedName(), keystore.getType());
}
APKModuleGraph apkModuleGraph = null;
if (!args.getApplicationModuleConfigs().isEmpty()) {
apkModuleGraph =
new APKModuleGraph(
Optional.of(args.getApplicationModuleConfigs()), targetGraph, target);
} else {
apkModuleGraph =
new APKModuleGraph(
targetGraph, target, Optional.of(args.getApplicationModuleTargets()));
}
ProGuardObfuscateStep.SdkProguardType androidSdkProguardConfig =
args.getAndroidSdkProguardConfig().orElse(ProGuardObfuscateStep.SdkProguardType.DEFAULT);
// If the old boolean version of this argument was specified, make sure the new form
// was not specified, and allow the old form to override the default.
if (args.getUseAndroidProguardConfigWithOptimizations().isPresent()) {
Preconditions.checkArgument(
!args.getAndroidSdkProguardConfig().isPresent(),
"The deprecated use_android_proguard_config_with_optimizations parameter"
+ " cannot be used with android_sdk_proguard_config.");
LOG.error(
"Target %s specified use_android_proguard_config_with_optimizations, "
+ "which is deprecated. Use android_sdk_proguard_config.",
params.getBuildTarget());
androidSdkProguardConfig =
args.getUseAndroidProguardConfigWithOptimizations().orElse(false)
? ProGuardObfuscateStep.SdkProguardType.OPTIMIZED
: ProGuardObfuscateStep.SdkProguardType.DEFAULT;
}
EnumSet<ExopackageMode> exopackageModes = EnumSet.noneOf(ExopackageMode.class);
if (!args.getExopackageModes().isEmpty()) {
exopackageModes = EnumSet.copyOf(args.getExopackageModes());
} else if (args.isExopackage().orElse(false)) {
LOG.error(
"Target %s specified exopackage=True, which is deprecated. Use exopackage_modes.",
params.getBuildTarget());
exopackageModes = EnumSet.of(ExopackageMode.SECONDARY_DEX);
}
DexSplitMode dexSplitMode = createDexSplitMode(args, exopackageModes);
PackageType packageType = getPackageType(args);
boolean shouldPreDex =
!args.getDisablePreDex()
&& PackageType.DEBUG.equals(packageType)
&& !args.getPreprocessJavaClassesBash().isPresent();
ResourceFilter resourceFilter = new ResourceFilter(args.getResourceFilter());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
AndroidBinaryGraphEnhancer graphEnhancer =
new AndroidBinaryGraphEnhancer(
params,
resolver,
args.getAaptMode(),
compressionMode,
resourceFilter,
args.getEffectiveBannedDuplicateResourceTypes(),
args.getResourceUnionPackage(),
addFallbackLocales(args.getLocales()),
args.getManifest(),
packageType,
ImmutableSet.copyOf(args.getCpuFilters()),
args.isBuildStringSourceMap(),
shouldPreDex,
AndroidBinary.getPrimaryDexPath(
params.getBuildTarget(), params.getProjectFilesystem()),
dexSplitMode,
args.getNoDx(),
/* resourcesToExclude */ ImmutableSet.of(),
args.isSkipCrunchPngs(),
args.isIncludesVectorDrawables(),
javaBuckConfig,
JavacFactory.create(ruleFinder, javaBuckConfig, null),
javacOptions,
exopackageModes,
args.getBuildConfigValues(),
args.getBuildConfigValuesFile(),
Optional.empty(),
args.isTrimResourceIds(),
args.getKeepResourcePattern(),
nativePlatforms,
Optional.of(args.getNativeLibraryMergeMap()),
args.getNativeLibraryMergeGlue(),
args.getNativeLibraryMergeCodeGenerator(),
args.getNativeLibraryMergeLocalizedSymbols(),
args.getNativeLibraryProguardConfigGenerator(),
args.isEnableRelinker() ? RelinkerMode.ENABLED : RelinkerMode.DISABLED,
dxExecutorService,
args.getManifestEntries(),
cxxBuckConfig,
apkModuleGraph,
dxConfig,
getPostFilterResourcesArgs(args, params, resolver, cellRoots));
AndroidGraphEnhancementResult result = graphEnhancer.createAdditionalBuildables();
if (target.getFlavors().contains(PACKAGE_STRING_ASSETS_FLAVOR)) {
Optional<PackageStringAssets> packageStringAssets = result.getPackageStringAssets();
Preconditions.checkState(packageStringAssets.isPresent());
return packageStringAssets.get();
}
if (target.getFlavors().contains(AndroidBinaryResourcesGraphEnhancer.AAPT2_LINK_FLAVOR)) {
// Rule already added to index during graph enhancement.
return resolver.getRule(target);
}
// Build rules added to "no_dx" are only hints, not hard dependencies. Therefore, although a
// target may be mentioned in that parameter, it may not be present as a build rule.
ImmutableSortedSet.Builder<BuildRule> builder = ImmutableSortedSet.naturalOrder();
for (BuildTarget noDxTarget : args.getNoDx()) {
Optional<BuildRule> ruleOptional = resolver.getRuleOptional(noDxTarget);
if (ruleOptional.isPresent()) {
builder.add(ruleOptional.get());
} else {
LOG.info("%s: no_dx target not a dependency: %s", target, noDxTarget);
}
}
ImmutableSortedSet<BuildRule> buildRulesToExcludeFromDex = builder.build();
ImmutableSortedSet<JavaLibrary> rulesToExcludeFromDex =
RichStream.from(buildRulesToExcludeFromDex)
.filter(JavaLibrary.class)
.collect(MoreCollectors.toImmutableSortedSet(Ordering.natural()));
Optional<RedexOptions> redexOptions = getRedexOptions(params, resolver, cellRoots, args);
ImmutableSortedSet<BuildRule> redexExtraDeps =
redexOptions
.map(
a ->
a.getRedexExtraArgs()
.stream()
.flatMap(arg -> arg.getDeps(ruleFinder).stream())
.collect(MoreCollectors.toImmutableSortedSet(Ordering.natural())))
.orElse(ImmutableSortedSet.of());
return new AndroidBinary(
params
.copyReplacingExtraDeps(Suppliers.ofInstance(result.getFinalDeps()))
.copyAppendingExtraDeps(
ruleFinder.filterBuildRuleInputs(
result.getPackageableCollection().getProguardConfigs()))
.copyAppendingExtraDeps(rulesToExcludeFromDex)
.copyAppendingExtraDeps(redexExtraDeps),
ruleFinder,
proGuardConfig.getProguardJarOverride(),
proGuardConfig.getProguardMaxHeapSize(),
Optional.of(args.getProguardJvmArgs()),
proGuardConfig.getProguardAgentPath(),
(Keystore) keystore,
packageType,
dexSplitMode,
args.getNoDx(),
androidSdkProguardConfig,
args.getOptimizationPasses(),
args.getProguardConfig(),
args.isSkipProguard(),
redexOptions,
compressionMode,
args.getCpuFilters(),
resourceFilter,
exopackageModes,
MACRO_HANDLER.getExpander(params.getBuildTarget(), cellRoots, resolver),
args.getPreprocessJavaClassesBash(),
rulesToExcludeFromDex,
result,
args.isReorderClassesIntraDex(),
args.getDexReorderToolFile(),
args.getDexReorderDataDumpFile(),
args.getXzCompressionLevel(),
dxExecutorService,
args.isPackageAssetLibraries(),
args.isCompressAssetLibraries(),
args.getManifestEntries(),
javaOptions.getJavaRuntimeLauncher(),
dxConfig.getDxMaxHeapSize());
}
}
private DexSplitMode createDexSplitMode(
AndroidBinaryDescriptionArg args, EnumSet<ExopackageMode> exopackageModes) {
// Exopackage builds default to JAR, otherwise, default to RAW.
DexStore defaultDexStore =
ExopackageMode.enabledForSecondaryDexes(exopackageModes) ? DexStore.JAR : DexStore.RAW;
DexSplitStrategy dexSplitStrategy =
args.getMinimizePrimaryDexSize()
? DexSplitStrategy.MINIMIZE_PRIMARY_DEX_SIZE
: DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE;
return new DexSplitMode(
args.getUseSplitDex(),
dexSplitStrategy,
args.getDexCompression().orElse(defaultDexStore),
args.getLinearAllocHardLimit(),
args.getPrimaryDexPatterns(),
args.getPrimaryDexClassesFile(),
args.getPrimaryDexScenarioFile(),
args.isPrimaryDexScenarioOverflowAllowed(),
args.getSecondaryDexHeadClassesFile(),
args.getSecondaryDexTailClassesFile());
}
private PackageType getPackageType(AndroidBinaryDescriptionArg args) {
if (!args.getPackageType().isPresent()) {
return PackageType.DEBUG;
}
return PackageType.valueOf(args.getPackageType().get().toUpperCase(Locale.US));
}
private ResourceCompressionMode getCompressionMode(AndroidBinaryDescriptionArg args) {
if (!args.getResourceCompression().isPresent()) {
return ResourceCompressionMode.DISABLED;
}
return ResourceCompressionMode.valueOf(
args.getResourceCompression().get().toUpperCase(Locale.US));
}
private ImmutableSet<String> addFallbackLocales(ImmutableSet<String> locales) {
ImmutableSet.Builder<String> allLocales = ImmutableSet.builder();
for (String locale : locales) {
allLocales.add(locale);
Matcher matcher = COUNTRY_LOCALE_PATTERN.matcher(locale);
if (matcher.matches()) {
allLocales.add(matcher.group(1));
}
}
return allLocales.build();
}
@Override
public boolean hasFlavors(ImmutableSet<Flavor> flavors) {
for (Flavor flavor : flavors) {
if (!FLAVORS.contains(flavor)) {
return false;
}
}
return true;
}
@Override
public void findDepsForTargetFromConstructorArgs(
BuildTarget buildTarget,
CellPathResolver cellRoots,
AbstractAndroidBinaryDescriptionArg constructorArg,
ImmutableCollection.Builder<BuildTarget> extraDepsBuilder,
ImmutableCollection.Builder<BuildTarget> targetGraphOnlyDepsBuilder) {
if (constructorArg.getRedex()) {
// If specified, this option may point to either a BuildTarget or a file.
Optional<BuildTarget> redexTarget =
buckConfig.getMaybeBuildTarget(SECTION, CONFIG_PARAM_REDEX);
if (redexTarget.isPresent()) {
extraDepsBuilder.add(redexTarget.get());
}
constructorArg
.getRedexExtraArgs()
.forEach(
a ->
addDepsFromParam(
buildTarget, cellRoots, a, extraDepsBuilder, targetGraphOnlyDepsBuilder));
}
}
private void addDepsFromParam(
BuildTarget target,
CellPathResolver cellNames,
String paramValue,
ImmutableCollection.Builder<BuildTarget> buildDefsBuilder,
ImmutableCollection.Builder<BuildTarget> nonBuildDefsBuilder) {
try {
MACRO_HANDLER.extractParseTimeDeps(
target, cellNames, paramValue, buildDefsBuilder, nonBuildDefsBuilder);
} catch (MacroException e) {
throw new HumanReadableException(e, "%s: %s", target, e.getMessage());
}
}
private Optional<com.facebook.buck.rules.args.Arg> getPostFilterResourcesArgs(
AndroidBinaryDescriptionArg arg,
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots) {
return arg.getPostFilterResourcesCmd()
.map(
MacroArg.toMacroArgFunction(MACRO_HANDLER, params.getBuildTarget(), cellRoots, resolver)
::apply);
}
private Optional<RedexOptions> getRedexOptions(
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots,
AndroidBinaryDescriptionArg arg) {
boolean redexRequested = arg.getRedex();
if (!redexRequested) {
return Optional.empty();
}
Optional<Tool> redexBinary = buckConfig.getTool(SECTION, CONFIG_PARAM_REDEX, resolver);
if (!redexBinary.isPresent()) {
throw new HumanReadableException(
"Requested running ReDex for %s but the path to the tool"
+ "has not been specified in the %s.%s .buckconfig section.",
params.getBuildTarget(), SECTION, CONFIG_PARAM_REDEX);
}
java.util.function.Function<String, com.facebook.buck.rules.args.Arg> macroArgFunction =
MacroArg.toMacroArgFunction(MACRO_HANDLER, params.getBuildTarget(), cellRoots, resolver)
::apply;
List<com.facebook.buck.rules.args.Arg> redexExtraArgs =
arg.getRedexExtraArgs().stream().map(macroArgFunction).collect(Collectors.toList());
return Optional.of(
RedexOptions.builder()
.setRedex(redexBinary.get())
.setRedexConfig(arg.getRedexConfig())
.setRedexExtraArgs(redexExtraArgs)
.build());
}
@BuckStyleImmutable
@Value.Immutable
interface AbstractAndroidBinaryDescriptionArg
extends CommonDescriptionArg, HasDeclaredDeps, HasTests {
SourcePath getManifest();
BuildTarget getKeystore();
Optional<String> getPackageType();
@Hint(isDep = false)
ImmutableSet<BuildTarget> getNoDx();
@Value.Default
default boolean getUseSplitDex() {
return false;
}
@Value.Default
default boolean getMinimizePrimaryDexSize() {
return false;
}
@Value.Default
default boolean getDisablePreDex() {
return false;
}
// TODO(natthu): mark this as deprecated.
Optional<Boolean> isExopackage();
Set<ExopackageMode> getExopackageModes();
Optional<DexStore> getDexCompression();
Optional<ProGuardObfuscateStep.SdkProguardType> getAndroidSdkProguardConfig();
Optional<Boolean> getUseAndroidProguardConfigWithOptimizations();
Optional<Integer> getOptimizationPasses();
List<String> getProguardJvmArgs();
Optional<SourcePath> getProguardConfig();
Optional<String> getResourceCompression();
@Value.Default
default boolean isSkipCrunchPngs() {
return false;
}
@Value.Default
default boolean isIncludesVectorDrawables() {
return false;
}
List<String> getPrimaryDexPatterns();
Optional<SourcePath> getPrimaryDexClassesFile();
Optional<SourcePath> getPrimaryDexScenarioFile();
@Value.Default
default boolean isPrimaryDexScenarioOverflowAllowed() {
return false;
}
Optional<SourcePath> getSecondaryDexHeadClassesFile();
Optional<SourcePath> getSecondaryDexTailClassesFile();
Set<BuildTarget> getApplicationModuleTargets();
Map<String, List<BuildTarget>> getApplicationModuleConfigs();
@Value.Default
default long getLinearAllocHardLimit() {
return DEFAULT_LINEAR_ALLOC_HARD_LIMIT;
}
List<String> getResourceFilter();
// Do not inspect this, getAllowedDuplicateResourcesTypes, or getBannedDuplicateResourceTypes directly, use
// getEffectiveBannedDuplicateResourceTypes.
// Ideally these should be private, but Arg-population doesn't allow that.
//
// If set to ALLOW_BY_DEFAULT, bannedDuplicateResourceTypes is used and setting
// allowedDuplicateResourceTypes is an error.
//
// If set to BAN_BY_DEFAULT, allowedDuplicateResourceTypes is used and setting
// bannedDuplicateResourceTypes is an error.
// This only exists to enable migration from allowing by default to banning by default.
@Value.Default
default DuplicateResourceBehaviour getDuplicateResourceBehavior() {
return DuplicateResourceBehaviour.ALLOW_BY_DEFAULT;
}
Set<RType> getAllowedDuplicateResourceTypes();
Set<RType> getBannedDuplicateResourceTypes();
@Value.Default
default AndroidBinary.AaptMode getAaptMode() {
return AndroidBinary.AaptMode.AAPT1;
}
@Value.Default
default boolean isTrimResourceIds() {
return false;
}
Optional<String> getKeepResourcePattern();
Optional<String> getResourceUnionPackage();
ImmutableSet<String> getLocales();
@Value.Default
default boolean isBuildStringSourceMap() {
return false;
}
Set<TargetCpuType> getCpuFilters();
@Value.NaturalOrder
ImmutableSortedSet<BuildTarget> getPreprocessJavaClassesDeps();
Optional<String> getPreprocessJavaClassesBash();
@Value.Default
default boolean isReorderClassesIntraDex() {
return false;
}
Optional<SourcePath> getDexReorderToolFile();
Optional<SourcePath> getDexReorderDataDumpFile();
Optional<Integer> getXzCompressionLevel();
@Value.Default
default boolean isPackageAssetLibraries() {
return false;
}
@Value.Default
default boolean isCompressAssetLibraries() {
return false;
}
Map<String, List<Pattern>> getNativeLibraryMergeMap();
Optional<BuildTarget> getNativeLibraryMergeGlue();
Optional<BuildTarget> getNativeLibraryMergeCodeGenerator();
Optional<ImmutableSortedSet<String>> getNativeLibraryMergeLocalizedSymbols();
Optional<BuildTarget> getNativeLibraryProguardConfigGenerator();
@Value.Default
default boolean isEnableRelinker() {
return false;
}
@Value.Default
default ManifestEntries getManifestEntries() {
return ManifestEntries.empty();
}
@Value.Default
default BuildConfigFields getBuildConfigValues() {
return BuildConfigFields.empty();
}
@Value.Default
default boolean getRedex() {
return false;
}
Optional<SourcePath> getRedexConfig();
ImmutableList<String> getRedexExtraArgs();
Optional<String> getPostFilterResourcesCmd();
Optional<SourcePath> getBuildConfigValuesFile();
@Value.Default
default boolean isSkipProguard() {
return false;
}
@Value.Derived
default EnumSet<RType> getEffectiveBannedDuplicateResourceTypes() {
if (getDuplicateResourceBehavior() == DuplicateResourceBehaviour.ALLOW_BY_DEFAULT) {
if (!getAllowedDuplicateResourceTypes().isEmpty()) {
throw new IllegalArgumentException(
"Cannot set allowed_duplicate_resource_types if "
+ "duplicate_resource_behaviour is allow_by_default");
}
if (!getBannedDuplicateResourceTypes().isEmpty()) {
return EnumSet.copyOf(getBannedDuplicateResourceTypes());
} else {
return EnumSet.noneOf(RType.class);
}
} else if (getDuplicateResourceBehavior() == DuplicateResourceBehaviour.BAN_BY_DEFAULT) {
if (!getBannedDuplicateResourceTypes().isEmpty()) {
throw new IllegalArgumentException(
"Cannot set banned_duplicate_resource_types if "
+ "duplicate_resource_behaviour is ban_by_default");
}
if (!getAllowedDuplicateResourceTypes().isEmpty()) {
return EnumSet.complementOf(EnumSet.copyOf(getAllowedDuplicateResourceTypes()));
} else {
return EnumSet.allOf(RType.class);
}
} else {
throw new IllegalArgumentException(
"Unrecognized duplicate_resource_behavior: " + getDuplicateResourceBehavior());
}
}
enum DuplicateResourceBehaviour {
ALLOW_BY_DEFAULT,
BAN_BY_DEFAULT
}
}
}