| // Copyright 2016 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.objc; |
| |
| import com.google.common.base.Strings; |
| import com.google.common.collect.ImmutableList; |
| 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.CoreOptions; |
| import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions; |
| import com.google.devtools.build.lib.rules.apple.AppleConfiguration; |
| import com.google.devtools.build.lib.rules.apple.AppleConfiguration.ConfigurationDistinguisher; |
| import com.google.devtools.build.lib.rules.apple.ApplePlatform; |
| import com.google.devtools.build.lib.rules.cpp.CppOptions; |
| import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; |
| |
| /** |
| * Transition that produces a configuration that causes c++ toolchain selection to use the |
| * CROSSTOOL given in apple_crosstool_top. |
| */ |
| public class AppleCrosstoolTransition implements PatchTransition { |
| |
| /** A singleton instance of AppleCrosstoolTransition. */ |
| @AutoCodec |
| public static final PatchTransition APPLE_CROSSTOOL_TRANSITION = new AppleCrosstoolTransition(); |
| |
| @Override |
| public BuildOptions patch(BuildOptions buildOptions) { |
| BuildOptions result = buildOptions.clone(); |
| |
| AppleCommandLineOptions appleOptions = buildOptions.get(AppleCommandLineOptions.class); |
| CoreOptions configOptions = buildOptions.get(CoreOptions.class); |
| |
| if (appleOptions.configurationDistinguisher != ConfigurationDistinguisher.UNKNOWN) { |
| // The configuration distinguisher is only set by AppleCrosstoolTransition and |
| // AppleBinaryTransition, both of which also set the Crosstool and the CPU to Apple ones. |
| // So we are fine not doing anything. |
| return buildOptions; |
| } |
| |
| String cpu = |
| ApplePlatform.cpuStringForTarget( |
| appleOptions.applePlatformType, |
| determineSingleArchitecture(appleOptions, configOptions)); |
| setAppleCrosstoolTransitionConfiguration(buildOptions, result, cpu); |
| return result; |
| } |
| |
| /** |
| * Sets configuration fields required for a transition that uses apple_crosstool_top in place of |
| * the default CROSSTOOL. |
| * |
| * @param from options from the originating configuration |
| * @param to options for the destination configuration. This instance will be modified |
| * to so the destination configuration uses the apple crosstool |
| * @param cpu {@code --cpu} value for toolchain selection in the destination configuration |
| */ |
| public static void setAppleCrosstoolTransitionConfiguration(BuildOptions from, |
| BuildOptions to, String cpu) { |
| Label crosstoolTop = from.get(AppleCommandLineOptions.class).appleCrosstoolTop; |
| Label libcTop = from.get(AppleCommandLineOptions.class).appleLibcTop; |
| String cppCompiler = from.get(AppleCommandLineOptions.class).cppCompiler; |
| |
| CoreOptions toOptions = to.get(CoreOptions.class); |
| CppOptions toCppOptions = to.get(CppOptions.class); |
| |
| if (toOptions.cpu.equals(cpu) && toCppOptions.crosstoolTop.equals(crosstoolTop)) { |
| // If neither the CPU nor the Crosstool changes, do nothing. This is so that C++ to |
| // Objective-C dependencies work if the top-level configuration is already an Apple one. |
| // Removing the configuration distinguisher (which can't be set from the command line) and |
| // putting the platform type in the output directory name, which would obviate the need for |
| // this hack. |
| // TODO(b/112834725): Remove this branch by unifying the distinguisher and the platform type. |
| return; |
| } |
| |
| toOptions.cpu = cpu; |
| toCppOptions.crosstoolTop = crosstoolTop; |
| to.get(AppleCommandLineOptions.class).configurationDistinguisher = |
| ConfigurationDistinguisher.APPLE_CROSSTOOL; |
| to.get(CppOptions.class).cppCompiler = cppCompiler; |
| to.get(CppOptions.class).libcTopLabel = libcTop; |
| |
| // OSX toolchains do not support fission. |
| to.get(CppOptions.class).fissionModes = ImmutableList.of(); |
| |
| // Ensure platforms aren't set so that platform mapping can take place. |
| to.get(PlatformOptions.class).platforms = ImmutableList.of(); |
| } |
| |
| /** Returns the Apple architecture implied by AppleCommandLineOptions and CoreOptions */ |
| private String determineSingleArchitecture( |
| AppleCommandLineOptions appleOptions, CoreOptions configOptions) { |
| if (!Strings.isNullOrEmpty(appleOptions.appleSplitCpu)) { |
| return appleOptions.appleSplitCpu; |
| } |
| switch (appleOptions.applePlatformType) { |
| case IOS: |
| if (!appleOptions.iosMultiCpus.isEmpty()) { |
| return appleOptions.iosMultiCpus.get(0); |
| } else { |
| return AppleConfiguration.iosCpuFromCpu(configOptions.cpu); |
| } |
| case WATCHOS: |
| if (appleOptions.watchosCpus.isEmpty()) { |
| return AppleCommandLineOptions.DEFAULT_WATCHOS_CPU; |
| } |
| return appleOptions.watchosCpus.get(0); |
| case TVOS: |
| if (appleOptions.tvosCpus.isEmpty()) { |
| return AppleCommandLineOptions.DEFAULT_TVOS_CPU; |
| } |
| return appleOptions.tvosCpus.get(0); |
| case MACOS: |
| if (appleOptions.macosCpus.isEmpty()) { |
| return AppleCommandLineOptions.DEFAULT_MACOS_CPU; |
| } |
| return appleOptions.macosCpus.get(0); |
| default: |
| throw new IllegalArgumentException( |
| "Unhandled platform type " + appleOptions.applePlatformType); |
| } |
| } |
| } |