blob: 8eaa07760fea399ad3af8aad31b6cea49d03c40e [file] [log] [blame]
// Copyright 2021 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.rules.android;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.analysis.PlatformOptions;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
import com.google.devtools.build.lib.analysis.config.CoreOptions;
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.analysis.config.transitions.StarlarkExposedRuleTransitionFactory;
import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
import com.google.devtools.build.lib.analysis.starlark.FunctionTransitionUtil;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.RuleTransitionData;
import com.google.devtools.build.lib.rules.cpp.CppOptions;
/**
* Ensures that Android binaries have a valid target platform by resetting the "--platforms" flag to
* match the first value from "--android_platforms". This will enable the application to select a
* valid Android SDK via toolchain resolution. android_binary itself should only need the SDK, not
* an NDK, so in theory every platform passed to "--android_platforms" should be equivalent.
*/
public final class AndroidPlatformsTransition implements PatchTransition {
private static final AndroidPlatformsTransition INSTANCE = new AndroidPlatformsTransition();
/** Machinery to expose the transition to Starlark. */
public static final class AndroidPlatformsTransitionFactory
implements StarlarkExposedRuleTransitionFactory {
@Override
public PatchTransition create(RuleTransitionData unused) {
return INSTANCE;
}
}
public static TransitionFactory<RuleTransitionData> create() {
return new AndroidPlatformsTransitionFactory();
}
@Override
public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
return ImmutableSet.of(
AndroidConfiguration.Options.class,
PlatformOptions.class,
CoreOptions.class,
CppOptions.class);
}
@Override
public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
AndroidConfiguration.Options androidOptions = options.get(AndroidConfiguration.Options.class);
if (!androidOptions.incompatibleUseToolchainResolution) {
// No change.
return options.underlying();
}
BuildOptionsView newOptions = options.clone();
PlatformOptions newPlatformOptions = newOptions.get(PlatformOptions.class);
// Set the value of --platforms for this target and its dependencies.
// 1. If --android_platforms is set, use a value from that.
// 2. Otherwise, leave --platforms alone (this will probably lead to build errors).
if (!androidOptions.androidPlatforms.isEmpty()) {
// If the current value of --platforms is not one of the values of --android_platforms, change
// it to be the first one. If the curent --platforms is part of --android_platforms, leave it
// as-is.
// NOTE: This does not handle aliases at all, so if someone is using aliases with platform
// definitions this check will break.
if (!androidOptions.androidPlatforms.containsAll(newPlatformOptions.platforms)) {
newPlatformOptions.platforms = ImmutableList.of(androidOptions.androidPlatforms.get(0));
}
}
// If we are using toolchain resolution for Android, also use it for CPP.
// This needs to be before the AndroidBinary is analyzed so that all native dependencies
// use the same configuration.
if (androidOptions.incompatibleUseToolchainResolution) {
newOptions.get(CppOptions.class).enableCcToolchainResolution = true;
}
if (androidOptions.androidPlatformsTransitionsUpdateAffected) {
ImmutableSet.Builder<String> affected = ImmutableSet.builder();
if (!options
.get(PlatformOptions.class)
.platforms
.equals(newOptions.get(PlatformOptions.class).platforms)) {
affected.add("//command_line_option:platforms");
}
if (options.get(CppOptions.class).enableCcToolchainResolution
!= newOptions.get(CppOptions.class).enableCcToolchainResolution) {
affected.add("//command_line_option:incompatible_enable_cc_toolchain_resolution");
}
FunctionTransitionUtil.updateAffectedByStarlarkTransition(
newOptions.get(CoreOptions.class), affected.build());
}
return newOptions.underlying();
}
@Override
public String reasonForOverride() {
return "properly set the target platform for Android binaries";
}
}