| // 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"; |
| } |
| } |