blob: 36b4a853e4112897f1ddb9fe16acfa52e53c9a63 [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.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
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.SplitTransition;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.ConfigurationDistinguisher;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.Options;
import com.google.devtools.build.lib.rules.cpp.CppOptions;
import com.google.devtools.build.lib.starlarkbuildapi.android.AndroidSplitTransititionApi;
import net.starlark.java.eval.Printer;
/** Android Split configuration transition for properly handling native dependencies */
final class AndroidSplitTransition implements SplitTransition, AndroidSplitTransititionApi {
@Override
public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
return ImmutableSet.of(
AndroidConfiguration.Options.class,
CoreOptions.class,
CppOptions.class,
PlatformOptions.class);
}
@Override
public ImmutableMap<String, BuildOptions> split(
BuildOptionsView buildOptions, EventHandler eventHandler) {
AndroidConfiguration.Options androidOptions =
buildOptions.get(AndroidConfiguration.Options.class);
CppOptions cppOptions = buildOptions.get(CppOptions.class);
if (!androidOptions.fatApkCpus.isEmpty()) {
return handleFatApkCpus(buildOptions, androidOptions);
} else if (!androidOptions.cpu.isEmpty()
&& androidOptions.androidCrosstoolTop != null
&& !androidOptions.androidCrosstoolTop.equals(cppOptions.crosstoolTop)) {
return handleAndroidCpu(buildOptions, androidOptions);
} else {
return handleDefaultSplit(buildOptions, buildOptions.get(CoreOptions.class).cpu);
}
}
/** Returns a single-split transition that uses the "--cpu" and does not change any flags. */
private ImmutableMap<String, BuildOptions> handleDefaultSplit(
BuildOptionsView buildOptions, String cpu) {
return ImmutableMap.of(cpu, buildOptions.underlying());
}
/**
* Returns a single-split transition that sets "--cpu" to the value of "--android_cpu" and sets
* other C++ flags based on the corresponding Android flags.
*/
private ImmutableMap<String, BuildOptions> handleAndroidCpu(
BuildOptionsView buildOptions, Options androidOptions) {
BuildOptionsView splitOptions = buildOptions.clone();
splitOptions.get(CoreOptions.class).cpu = androidOptions.cpu;
setCcFlagsFromAndroid(androidOptions, splitOptions);
return handleDefaultSplit(splitOptions, androidOptions.cpu);
}
/**
* Returns a multi-split transition that sets "--cpu" with the values of "--fat_apk_cpu" and sets
* other C++ flags based on the corresponding Android flags.
*/
private ImmutableMap<String, BuildOptions> handleFatApkCpus(
BuildOptionsView buildOptions, Options androidOptions) {
ImmutableMap.Builder<String, BuildOptions> result = ImmutableMap.builder();
for (String cpu : ImmutableSortedSet.copyOf(androidOptions.fatApkCpus)) {
BuildOptionsView splitOptions = buildOptions.clone();
// Disable fat APKs for the child configurations.
splitOptions.get(Options.class).fatApkCpus = ImmutableList.of();
// Set the cpu & android_cpu.
// TODO(bazel-team): --android_cpu doesn't follow --cpu right now; it should.
splitOptions.get(Options.class).cpu = cpu;
splitOptions.get(CoreOptions.class).cpu = cpu;
setCcFlagsFromAndroid(androidOptions, splitOptions);
result.put(cpu, splitOptions.underlying());
if (cpu.equals("arm64-v8a") && androidOptions.fatApkHwasan) {
BuildOptionsView hwasanSplitOptions = splitOptions.clone();
// A HWASAN build is different from a regular one in these ways:
// - The native library install directory gets a "-hwasan" suffix
// - Some compiler/linker command line options are different (defined in the Android C++
// toolchain)
// - The name of the output directory is changed so that HWASAN and non-HWASAN artifacts
// do not conflict
hwasanSplitOptions.get(CppOptions.class).outputDirectoryTag = "hwasan";
hwasanSplitOptions.get(AndroidConfiguration.Options.class).hwasan = true;
result.put(cpu + "-hwasan", hwasanSplitOptions.underlying());
}
}
return result.build();
}
private void setCcFlagsFromAndroid(
AndroidConfiguration.Options androidOptions, BuildOptionsView newOptions) {
// Set the CC options needed to build native code.
CppOptions newCppOptions = newOptions.get(CppOptions.class);
newCppOptions.cppCompiler = androidOptions.cppCompiler;
newCppOptions.libcTopLabel = androidOptions.androidLibcTopLabel;
newCppOptions.dynamicMode = androidOptions.dynamicMode;
if (androidOptions.androidCrosstoolTop != null) {
newCppOptions.crosstoolTop = androidOptions.androidCrosstoolTop;
}
newOptions.get(AndroidConfiguration.Options.class).configurationDistinguisher =
ConfigurationDistinguisher.ANDROID;
// Ensure platforms aren't set so that platform mapping can take place.
newOptions.get(PlatformOptions.class).platforms = ImmutableList.of();
}
@Override
public boolean isImmutable() {
return true;
}
@Override
public void repr(Printer printer) {
printer.append("android_common.multi_cpu_configuration");
}
}