// Copyright 2015 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.apple; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment; import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory; import com.google.devtools.build.lib.analysis.config.FragmentOptions; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.rules.apple.AppleCommandLineOptions.AppleBitcodeMode; import com.google.devtools.build.lib.rules.apple.ApplePlatform.PlatformType; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; import com.google.devtools.build.lib.util.Preconditions; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.annotation.Nullable; /** A configuration containing flags required for Apple platforms and tools. */ @SkylarkModule( name = "apple", doc = "A configuration fragment for Apple platforms.", category = SkylarkModuleCategory.CONFIGURATION_FRAGMENT ) @Immutable public class AppleConfiguration extends BuildConfiguration.Fragment { /** * Environment variable name for the xcode version. The value of this environment variable should * be set to the version (for example, "7.2") of xcode to use when invoking part of the apple * toolkit in action execution. **/ public static final String XCODE_VERSION_ENV_NAME = "XCODE_VERSION_OVERRIDE"; /** * Environment variable name for the apple SDK version. If unset, uses the system default of the * host for the platform in the value of {@link #APPLE_SDK_PLATFORM_ENV_NAME}. **/ public static final String APPLE_SDK_VERSION_ENV_NAME = "APPLE_SDK_VERSION_OVERRIDE"; /** * Environment variable name for the apple SDK platform. This should be set for all actions that * require an apple SDK. The valid values consist of {@link ApplePlatform} names. */ public static final String APPLE_SDK_PLATFORM_ENV_NAME = "APPLE_SDK_PLATFORM"; private static final DottedVersion MINIMUM_BITCODE_XCODE_VERSION = DottedVersion.fromString("7"); /** Prefix for iOS cpu values. */ public static final String IOS_CPU_PREFIX = "ios_"; /** Default cpu for iOS builds. */ @VisibleForTesting static final String DEFAULT_IOS_CPU = "x86_64"; @Nullable private final DottedVersion xcodeVersion; private final DottedVersion iosSdkVersion; private final DottedVersion iosMinimumOs; private final DottedVersion watchosSdkVersion; private final DottedVersion watchosMinimumOs; private final DottedVersion tvosSdkVersion; private final DottedVersion tvosMinimumOs; private final DottedVersion macosSdkVersion; private final DottedVersion macosMinimumOs; private final String iosCpu; private final String appleSplitCpu; private final PlatformType applePlatformType; private final ConfigurationDistinguisher configurationDistinguisher; private final ImmutableList iosMultiCpus; private final ImmutableList watchosCpus; private final ImmutableList tvosCpus; private final ImmutableList macosCpus; private final AppleBitcodeMode bitcodeMode; private final Label xcodeConfigLabel; private final DottedVersion xcodeVersionCommandLineFlag; private final boolean enableAppleCrosstool; private final AppleCommandLineOptions options; @Nullable private final String xcodeToolchain; @Nullable private final Label defaultProvisioningProfileLabel; private final boolean mandatoryMinimumVersion; AppleConfiguration( AppleCommandLineOptions options, String cpu, XcodeVersionProperties xcodeVersionProperties, DottedVersion iosSdkVersion, DottedVersion iosMinimumOs, DottedVersion watchosSdkVersion, DottedVersion watchosMinimumOs, DottedVersion tvosSdkVersion, DottedVersion tvosMinimumOs, DottedVersion macosSdkVersion, DottedVersion macosMinimumOs) { this.options = options; this.iosSdkVersion = Preconditions.checkNotNull(iosSdkVersion, "iosSdkVersion"); this.iosMinimumOs = Preconditions.checkNotNull(iosMinimumOs, "iosMinimumOs"); this.watchosSdkVersion = Preconditions.checkNotNull(watchosSdkVersion, "watchOsSdkVersion"); this.watchosMinimumOs = Preconditions.checkNotNull(watchosMinimumOs, "watchOsMinimumOs"); this.tvosSdkVersion = Preconditions.checkNotNull(tvosSdkVersion, "tvOsSdkVersion"); this.tvosMinimumOs = Preconditions.checkNotNull(tvosMinimumOs, "tvOsMinimumOs"); this.macosSdkVersion = Preconditions.checkNotNull(macosSdkVersion, "macOsSdkVersion"); this.macosMinimumOs = Preconditions.checkNotNull(macosMinimumOs, "macOsMinimumOs"); this.xcodeVersion = xcodeVersionProperties.getXcodeVersion().orNull(); this.iosCpu = iosCpuFromCpu(cpu); this.appleSplitCpu = Preconditions.checkNotNull(options.appleSplitCpu, "appleSplitCpu"); this.applePlatformType = Preconditions.checkNotNull(options.applePlatformType, "applePlatformType"); this.configurationDistinguisher = options.configurationDistinguisher; this.iosMultiCpus = ImmutableList.copyOf( Preconditions.checkNotNull(options.iosMultiCpus, "iosMultiCpus")); this.watchosCpus = (options.watchosCpus == null || options.watchosCpus.isEmpty()) ? ImmutableList.of(AppleCommandLineOptions.DEFAULT_WATCHOS_CPU) : ImmutableList.copyOf(options.watchosCpus); this.tvosCpus = (options.tvosCpus == null || options.tvosCpus.isEmpty()) ? ImmutableList.of(AppleCommandLineOptions.DEFAULT_TVOS_CPU) : ImmutableList.copyOf(options.tvosCpus); this.macosCpus = (options.macosCpus == null || options.macosCpus.isEmpty()) ? ImmutableList.of(AppleCommandLineOptions.DEFAULT_MACOS_CPU) : ImmutableList.copyOf(options.macosCpus); this.bitcodeMode = options.appleBitcodeMode; this.xcodeConfigLabel = Preconditions.checkNotNull(options.xcodeVersionConfig, "xcodeConfigLabel"); this.xcodeVersionCommandLineFlag = options.xcodeVersion; this.enableAppleCrosstool = options.enableAppleCrosstoolTransition; this.defaultProvisioningProfileLabel = options.defaultProvisioningProfile; this.xcodeToolchain = options.xcodeToolchain; this.mandatoryMinimumVersion = options.mandatoryMinimumVersion; } /** Determines cpu value from apple-specific toolchain identifier. */ public static String iosCpuFromCpu(String cpu) { if (cpu.startsWith(IOS_CPU_PREFIX)) { return cpu.substring(IOS_CPU_PREFIX.length()); } else { return DEFAULT_IOS_CPU; } } public AppleCommandLineOptions getOptions() { return options; } /** * Returns the minimum iOS version supported by binaries and libraries. Any dependencies on newer * iOS version features or libraries will become weak dependencies which are only loaded if the * runtime OS supports them. * * @deprecated use {@link XcodeConfig#getMinimumOsForPlatformType(RuleContext, PlatformType)}. */ @SkylarkCallable(name = "ios_minimum_os", structField = true, doc = "Deprecated. Use " + "minimum_os_for_platform_type(apple_common.platform_type.ios) instead. " + "The minimum compatible iOS version for target simulators and devices.") @Deprecated // Bug tracking the removal of this method: https://github.com/bazelbuild/bazel/issues/3424 public DottedVersion getMinimumOs() { // TODO(bazel-team): Deprecate in favor of getMinimumOsForPlatformType(IOS). return iosMinimumOs; } /*** * @deprecated use {@link XcodeConfig#getMinimumOsForPlatformType(RuleContext, PlatformType)}. */ @SkylarkCallable( name = "minimum_os_for_platform_type", doc = "The minimum compatible OS version for target simulator and devices for a particular " + "platform type.") @Deprecated // Bug tracking the removal of this method: https://github.com/bazelbuild/bazel/issues/3424 public DottedVersion getMinimumOsForPlatformType(PlatformType platformType) { // TODO(b/37240784): Look into using only a single minimum OS flag tied to the current // apple_platform_type. switch (platformType) { case IOS: return iosMinimumOs; case TVOS: return tvosMinimumOs; case WATCHOS: return watchosMinimumOs; case MACOS: return macosMinimumOs; default: throw new IllegalArgumentException("Unhandled platform: " + platformType); } } /** * Returns the SDK version for ios SDKs (whether they be for simulator or device). This is * directly derived from --ios_sdk_version. * * @deprecated use {@link XcodeConfig#getSdkVersionForPlatform(RuleContext, ApplePlatform)} */ // Bug tracking the removal of this method: https://github.com/bazelbuild/bazel/issues/3424 @Deprecated public DottedVersion getIosSdkVersion() { return getSdkVersionForPlatform(ApplePlatform.IOS_DEVICE); } /** * Returns the SDK version for a platform (whether they be for simulator or device). This is * directly derived from command line args. * * @deprecated use {@link XcodeConfig#getSdkVersionForPlatform(RuleContext, ApplePlatform)} */ @SkylarkCallable( name = "sdk_version_for_platform", doc = "The version of the platform SDK that will be used to build targets for the given " + "platform.") @Deprecated // Bug tracking the removal of this method: https://github.com/bazelbuild/bazel/issues/3424 public DottedVersion getSdkVersionForPlatform(ApplePlatform platform) { switch (platform) { case IOS_DEVICE: case IOS_SIMULATOR: return iosSdkVersion; case TVOS_DEVICE: case TVOS_SIMULATOR: return tvosSdkVersion; case WATCHOS_DEVICE: case WATCHOS_SIMULATOR: return watchosSdkVersion; case MACOS: return macosSdkVersion; } throw new AssertionError(); } /** * Returns the value of the xcode version, if available. This is determined based on a combination * of the {@code --xcode_version} build flag and the {@code xcode_config} target defined in the * {@code --xcode_version_config} flag. Returns null if no xcode is available. * * @deprecated use {@link XcodeConfig#getXcodeVersion(RuleContext)}. */ @SkylarkCallable( name = "xcode_version", doc = "Returns the Xcode version that is being used to build.

" + "This will return None if no Xcode versions are available.", allowReturnNones = true) @Nullable @Deprecated // Bug tracking the removal of this method: https://github.com/bazelbuild/bazel/issues/3424 public DottedVersion getXcodeVersion() { return xcodeVersion; } /** * Returns a map of environment variables (derived from configuration) that should be propagated * for actions pertaining to the given apple platform. Keys are variable names and values are * their corresponding values. */ @SkylarkCallable( name = "target_apple_env", doc = "Returns a dict of environment variables that should be set for actions " + "that build targets of the given Apple platform type. For example, this dictionary " + "contains variables that denote the platform name and SDK version with which to " + "build. The keys are variable names and the values are their corresponding values.") public ImmutableMap getTargetAppleEnvironment(ApplePlatform platform) { ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); mapBuilder.putAll(appleTargetPlatformEnv(platform)); return mapBuilder.build(); } /** * Returns a map of environment variables that should be propagated for actions that build on an * apple host system. These environment variables are needed by the apple toolchain. Keys are * variable names and values are their corresponding values. */ @SkylarkCallable( name = "apple_host_system_env", doc = "Returns a dict of environment variables that should be set " + "for actions that need to run build tools on an Apple host system, such as the version " + "of Xcode that should be used. The keys are variable names and the values are their " + "corresponding values.") public ImmutableMap getAppleHostSystemEnv() { DottedVersion xcodeVersion = getXcodeVersion(); if (xcodeVersion != null) { return getXcodeVersionEnv(xcodeVersion); } else { return ImmutableMap.of(); } } /** * Returns a map of environment variables that should be propagated for actions that require * a version of xcode to be explicitly declared. Keys are variable names and values are their * corresponding values. */ public ImmutableMap getXcodeVersionEnv(DottedVersion xcodeVersion) { return ImmutableMap.of(AppleConfiguration.XCODE_VERSION_ENV_NAME, xcodeVersion.toString()); } /** * Returns a map of environment variables (derived from configuration) that should be propagated * for actions pertaining to building applications for apple platforms. These environment * variables are needed to use apple toolkits. Keys are variable names and values are their * corresponding values. */ public Map appleTargetPlatformEnv(ApplePlatform platform) { ImmutableMap.Builder builder = ImmutableMap.builder(); String sdkVersion = getSdkVersionForPlatform(platform).toStringWithMinimumComponents(2); builder .put(AppleConfiguration.APPLE_SDK_VERSION_ENV_NAME, sdkVersion) .put(AppleConfiguration.APPLE_SDK_PLATFORM_ENV_NAME, platform.getNameInPlist()); return builder.build(); } /** * Returns the value of {@code ios_cpu} for this configuration. This is not necessarily the * platform or cpu for all actions spawned in this configuration; it is appropriate for * identifying the target cpu of iOS compile and link actions within this configuration. */ @SkylarkCallable( name = "ios_cpu", doc = "Deprecated. Use single_arch_cpu instead. " + "The value of ios_cpu for this configuration.") public String getIosCpu() { return iosCpu; } /** * Gets the single "effective" architecture for this configuration's {@link PlatformType} (for * example, "i386" or "arm64"). Prefer this over {@link #getMultiArchitectures(PlatformType)} only * if in the context of rule logic which is only concerned with a single architecture (such as in * {@code objc_library}, which registers single-architecture compile actions). * *

Single effective architecture is determined using the following rules: * *

    *
  1. If {@code --apple_split_cpu} is set (done via prior configuration transition), then that is * the effective architecture. *
  2. If the multi cpus flag (e.g. {@code --ios_multi_cpus}) is set and non-empty, then the first * such architecture is returned. *
  3. In the case of iOS, use {@code --ios_cpu} for backwards compatibility. *
  4. Use the default. *
*/ @SkylarkCallable( name = "single_arch_cpu", structField = true, doc = "The single \"effective\" architecture for this configuration (e.g., i386 or " + "arm64) in the context of rule logic that is only concerned with a " + "single architecture (such as objc_library, which registers " + "single-architecture compile actions)." ) public String getSingleArchitecture() { if (!Strings.isNullOrEmpty(appleSplitCpu)) { return appleSplitCpu; } switch (applePlatformType) { case IOS: if (!getIosMultiCpus().isEmpty()) { return getIosMultiCpus().get(0); } else { return getIosCpu(); } case WATCHOS: return watchosCpus.get(0); case TVOS: return tvosCpus.get(0); case MACOS: return macosCpus.get(0); default: throw new IllegalArgumentException("Unhandled platform type " + applePlatformType); } } /** * Gets the "effective" architecture(s) for the given {@link PlatformType}. For example, * "i386" or "arm64". At least one architecture is always returned. Prefer this over * {@link #getSingleArchitecture} in rule logic which may support multiple architectures, such * as bundling rules. * *

Effective architecture(s) is determined using the following rules: *

    *
  1. If {@code --apple_split_cpu} is set (done via prior configuration transition), then * that is the effective architecture.
  2. *
  3. If the multi-cpu flag (for example, {@code --ios_multi_cpus}) is non-empty, then, return * all architectures from that flag.
  4. *
  5. In the case of iOS, use {@code --ios_cpu} for backwards compatibility.
  6. *
  7. Use the default.
* * @throws IllegalArgumentException if {@code --apple_platform_type} is set (via prior * configuration transition) yet does not match {@code platformType} */ public List getMultiArchitectures(PlatformType platformType) { if (!Strings.isNullOrEmpty(appleSplitCpu)) { if (applePlatformType != platformType) { throw new IllegalArgumentException( String.format("Expected post-split-transition platform type %s to match input %s ", applePlatformType, platformType)); } return ImmutableList.of(appleSplitCpu); } switch (platformType) { case IOS: if (getIosMultiCpus().isEmpty()) { return ImmutableList.of(getIosCpu()); } else { return getIosMultiCpus(); } case WATCHOS: return watchosCpus; case TVOS: return tvosCpus; case MACOS: return macosCpus; default: throw new IllegalArgumentException("Unhandled platform type " + platformType); } } /** * Gets the single "effective" platform for this configuration's {@link PlatformType} and * architecture. Prefer this over {@link #getMultiArchPlatform(PlatformType)} only in cases if in * the context of rule logic which is only concerned with a single architecture (such as in {@code * objc_library}, which registers single-architecture compile actions). */ @SkylarkCallable( name = "single_arch_platform", doc = "The platform of the current configuration. This should only be invoked in a context " + "where only a single architecture may be supported; consider " + "mutli_arch_platform for other cases.", structField = true ) public ApplePlatform getSingleArchPlatform() { return ApplePlatform.forTarget(applePlatformType, getSingleArchitecture()); } /** * Gets the current configuration {@link ApplePlatform} for the given {@link PlatformType}. * ApplePlatform is determined via a combination between the given platform type and the * "effective" architectures of this configuration, as returned by {@link #getMultiArchitectures}; * if any of the supported architectures are of device type, this will return a device platform. * Otherwise, this will return a simulator platform. */ // TODO(bazel-team): This should support returning multiple platforms. @SkylarkCallable( name = "multi_arch_platform", doc = "The platform of the current configuration for the given platform type. This should only " + "be invoked in a context where multiple architectures may be supported; consider " + "single_arch_platform for other cases." ) public ApplePlatform getMultiArchPlatform(PlatformType platformType) { List architectures = getMultiArchitectures(platformType); switch (platformType) { case IOS: for (String arch : architectures) { if (ApplePlatform.forTarget(PlatformType.IOS, arch) == ApplePlatform.IOS_DEVICE) { return ApplePlatform.IOS_DEVICE; } } return ApplePlatform.IOS_SIMULATOR; case WATCHOS: for (String arch : architectures) { if (ApplePlatform.forTarget(PlatformType.WATCHOS, arch) == ApplePlatform.WATCHOS_DEVICE) { return ApplePlatform.WATCHOS_DEVICE; } } return ApplePlatform.WATCHOS_SIMULATOR; case TVOS: for (String arch : architectures) { if (ApplePlatform.forTarget(PlatformType.TVOS, arch) == ApplePlatform.TVOS_DEVICE) { return ApplePlatform.TVOS_DEVICE; } } return ApplePlatform.TVOS_SIMULATOR; case MACOS: return ApplePlatform.MACOS; default: throw new IllegalArgumentException("Unsupported platform type " + platformType); } } /** * Returns the {@link ApplePlatform} represented by {@code ios_cpu} (see {@link #getIosCpu}. (For * example, {@code i386} maps to {@link ApplePlatform#IOS_SIMULATOR}.) Note that this is not * necessarily the effective platform for all ios actions in the current context: This is * typically the correct platform for implicityly-ios compile and link actions in the current * context. For effective platform for bundling actions, see {@link * #getMultiArchPlatform(PlatformType)}. */ // TODO(b/28754442): Deprecate for more general skylark-exposed platform retrieval. @SkylarkCallable( name = "ios_cpu_platform", doc = "Deprecated. Use single_arch_platform or " + "multi_arch_platform instead. " + "The platform given by the ios_cpu flag.") public ApplePlatform getIosCpuPlatform() { return ApplePlatform.forTarget(PlatformType.IOS, iosCpu); } /** * Returns the architecture for which we keep dependencies that should be present only once (in a * single architecture). * *

When building with multiple architectures there are some dependencies we want to avoid * duplicating: they would show up more than once in the same location in the final application * bundle which is illegal. Instead we pick one architecture for which to keep all dependencies * and discard any others. */ public String getDependencySingleArchitecture() { if (!getIosMultiCpus().isEmpty()) { return getIosMultiCpus().get(0); } return getIosCpu(); } /** * List of all CPUs that this invocation is being built for. Different from {@link #getIosCpu()} * which is the specific CPU this target is being built for. */ public ImmutableList getIosMultiCpus() { return iosMultiCpus; } /** * Returns the label of the default provisioning profile to use when bundling/signing an ios * application. Returns null if the target platform is not an iOS device (for example, if * iOS simulator is being targeted). */ @Nullable public Label getDefaultProvisioningProfileLabel() { return defaultProvisioningProfileLabel; } /** * Returns the bitcode mode to use for compilation steps. This should only be invoked in * single-architecture contexts. * *

Users can control bitcode mode using the {@code apple_bitcode} build flag, but bitcode * will be disabled for all simulator architectures regardless of this flag. * * @see AppleBitcodeMode */ @SkylarkCallable( name = "bitcode_mode", doc = "Returns the Bitcode mode to use for compilation steps.

" + "This field is only valid for device builds; for simulator builds, it always returns " + "'none'.", structField = true ) public AppleBitcodeMode getBitcodeMode() { if (getSingleArchPlatform().isDevice()) { return bitcodeMode; } else { return AppleBitcodeMode.NONE; } } /** * Returns the label of the xcode_config rule to use for resolving the host system xcode version. */ public Label getXcodeConfigLabel() { return xcodeConfigLabel; } /** * Returns the explicit Xcode version specified on the command line. */ public DottedVersion getXcodeVersionCommandLineFlag() { return xcodeVersionCommandLineFlag; } /** * Returns the unique identifier distinguishing configurations that are otherwise the same. * *

Use this value for situations in which two configurations create two outputs that are the * same but are not collapsed due to their different configuration owners. */ public ConfigurationDistinguisher getConfigurationDistinguisher() { return configurationDistinguisher; } private boolean shouldDistinguishOutputDirectory() { if (configurationDistinguisher == ConfigurationDistinguisher.UNKNOWN) { return false; } else if (configurationDistinguisher == ConfigurationDistinguisher.APPLE_CROSSTOOL && isAppleCrosstoolEnabled()) { return false; } else { return true; } } @Nullable @Override public String getOutputDirectoryName() { List components = new ArrayList<>(); if (!appleSplitCpu.isEmpty()) { components.add(applePlatformType.toString().toLowerCase()); components.add(appleSplitCpu); components.add("min" + getMinimumOsForPlatformType(applePlatformType)); } if (shouldDistinguishOutputDirectory()) { components.add(configurationDistinguisher.getFileSystemName()); } if (components.isEmpty()) { return null; } return Joiner.on('-').join(components); } /** Returns the identifier for an Xcode toolchain to use with tools. */ @SkylarkCallable( name = "xcode_toolchain", doc = "Identifier for the custom Xcode toolchain to use in build, or None if it " + "is not specified.", allowReturnNones = true, structField = true ) public String getXcodeToolchain() { return xcodeToolchain; } /** Returns true if the minimum_os_version attribute should be mandatory on rules with linking. */ public boolean isMandatoryMinimumVersion() { return mandatoryMinimumVersion; } /** Returns true if {@link AppleCrosstoolTransition} should be applied to every apple rule. */ public boolean isAppleCrosstoolEnabled() { return enableAppleCrosstool; } @Override public Map lateBoundOptionDefaults() { // xcode_version and *_sdk_version defaults come from processing the // target with label given in --xcode_version_override. ImmutableMap.Builder mapBuilder = ImmutableMap.builder(); if (xcodeVersion != null) { mapBuilder.put("xcode_version", xcodeVersion); } return mapBuilder .put("ios_sdk_version", iosSdkVersion) .put("tvos_sdk_version", tvosSdkVersion) .put("watchos_sdk_version", watchosSdkVersion) .put("macos_sdk_version", macosSdkVersion) .build(); } /** * Loads {@link AppleConfiguration} from build options. */ public static class Loader implements ConfigurationFragmentFactory { @Override public AppleConfiguration create(ConfigurationEnvironment env, BuildOptions buildOptions) throws InvalidConfigurationException, InterruptedException { AppleCommandLineOptions appleOptions = buildOptions.get(AppleCommandLineOptions.class); String cpu = buildOptions.get(BuildConfiguration.Options.class).cpu; XcodeVersionProperties xcodeVersionProperties = XcodeConfig. getXcodeVersionProperties(env, appleOptions); DottedVersion iosSdkVersion = (appleOptions.iosSdkVersion != null) ? appleOptions.iosSdkVersion : xcodeVersionProperties.getDefaultIosSdkVersion(); DottedVersion iosMinimumOsVersion = (appleOptions.iosMinimumOs != null) ? appleOptions.iosMinimumOs : iosSdkVersion; DottedVersion watchosSdkVersion = (appleOptions.watchOsSdkVersion != null) ? appleOptions.watchOsSdkVersion : xcodeVersionProperties.getDefaultWatchosSdkVersion(); DottedVersion watchosMinimumOsVersion = (appleOptions.watchosMinimumOs != null) ? appleOptions.watchosMinimumOs : watchosSdkVersion; DottedVersion tvosSdkVersion = (appleOptions.tvOsSdkVersion != null) ? appleOptions.tvOsSdkVersion : xcodeVersionProperties.getDefaultTvosSdkVersion(); DottedVersion tvosMinimumOsVersion = (appleOptions.tvosMinimumOs != null) ? appleOptions.tvosMinimumOs : tvosSdkVersion; DottedVersion macosSdkVersion = (appleOptions.macOsSdkVersion != null) ? appleOptions.macOsSdkVersion : xcodeVersionProperties.getDefaultMacosSdkVersion(); DottedVersion macosMinimumOsVersion = (appleOptions.macosMinimumOs != null) ? appleOptions.macosMinimumOs : macosSdkVersion; AppleConfiguration configuration = new AppleConfiguration( appleOptions, cpu, xcodeVersionProperties, iosSdkVersion, iosMinimumOsVersion, watchosSdkVersion, watchosMinimumOsVersion, tvosSdkVersion, tvosMinimumOsVersion, macosSdkVersion, macosMinimumOsVersion); validate(configuration); return configuration; } private void validate(AppleConfiguration config) throws InvalidConfigurationException { DottedVersion xcodeVersion = config.getXcodeVersion(); if (config.getBitcodeMode() != AppleBitcodeMode.NONE && xcodeVersion != null && xcodeVersion.compareTo(MINIMUM_BITCODE_XCODE_VERSION) < 0) { throw new InvalidConfigurationException( String.format("apple_bitcode mode '%s' is unsupported for xcode version '%s'", config.getBitcodeMode(), xcodeVersion)); } } @Override public Class creates() { return AppleConfiguration.class; } @Override public ImmutableSet> requiredOptions() { return ImmutableSet.>of(AppleCommandLineOptions.class); } } /** * Value used to avoid multiple configurations from conflicting. No two instances of this * transition may exist with the same value in a single Bazel invocation. */ public enum ConfigurationDistinguisher { UNKNOWN("unknown"), /** Split transition distinguisher for {@code ios_extension} rule. */ IOS_EXTENSION("ios_extension"), /** Split transition distinguisher for {@code ios_application} rule. */ IOS_APPLICATION("ios_application"), /** Split transition distinguisher for {@code ios_framework} rule. */ FRAMEWORK("framework"), /** Distinguisher for {@code apple_binary} rule with "ios" platform_type. */ APPLEBIN_IOS("applebin_ios"), /** Distinguisher for {@code apple_binary} rule with "watchos" platform_type. */ APPLEBIN_WATCHOS("applebin_watchos"), /** Distinguisher for {@code apple_binary} rule with "tvos" platform_type. */ APPLEBIN_TVOS("applebin_tvos"), /** Distinguisher for {@code apple_binary} rule with "macos" platform_type. */ APPLEBIN_MACOS("applebin_macos"), /** * Distinguisher for the apple crosstool configuration. We use "apl" for output directory * names instead of "apple_crosstool" to avoid oversized path names, which can be problematic * on OSX. */ APPLE_CROSSTOOL("apl"); private final String fileSystemName; private ConfigurationDistinguisher(String fileSystemName) { this.fileSystemName = fileSystemName; } /** * Returns the distinct string that should be used in creating output directories for a * configuration with this distinguisher. */ public String getFileSystemName() { return fileSystemName; } } }