-
Notifications
You must be signed in to change notification settings - Fork 139
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use the target triple from the C++ toolchain instead of deriving it f…
…rom values in the Apple configuration fragment. When using `--host_cpu=darwin_x86_64` on an ARM (Apple Silicon) host, the value returned by the Apple configuration fragment is wrong, and we end up compiling Swift for `arm64`. Since the C++ toolchain already has the correct triple verbatim as we want it in the `target_gnu_system_name` field, just use that, and add some generally useful utilities for manipulating the triples and their components. Note to open-source rules maintainers: This change requires/assumes that your C++ toolchain configuration returns a complete target triple that includes minimum OS version and target environment; for example, `x86_64-apple-ios13.0-simulator`. PiperOrigin-RevId: 429897884 (cherry picked from commit 62b33ed)
- Loading branch information
Showing
2 changed files
with
281 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
# Copyright 2022 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. | ||
|
||
"""Utility functions to inspect and manipulate target triples.""" | ||
|
||
def _make(*, cpu, vendor, os, environment = None): | ||
"""Creates a target triple struct from the given values. | ||
Args: | ||
cpu: The CPU of the triple (e.g., `x86_64` or `arm`). | ||
vendor: The vendor component of the triple (e.g., `apple` or | ||
`unknown`). | ||
os: The operating system or platform name of the triple (e.g., `macos` | ||
or `linux`). | ||
environment: The environment or ABI component of the triple, if it was | ||
present. If this argument is omitted, it defaults to `None`. | ||
Returns: | ||
A `struct` containing the fields `cpu`, `vendor`, `os`, and | ||
`environment` which correspond to the arguments passed to this function. | ||
""" | ||
if not cpu or not vendor or not os: | ||
fail("A triple must have a non-empty CPU, vendor, and OS.") | ||
|
||
return struct( | ||
cpu = cpu, | ||
vendor = vendor, | ||
os = os, | ||
environment = environment, | ||
) | ||
|
||
def _normalize_apple_cpu(cpu): | ||
"""Normalizes the CPU component of an Apple target triple. | ||
This function is equivalent to `getArchForAppleTargetSpecificModuleTrple` in | ||
https://github.com/apple/swift/blob/main/lib/Basic/Platform.cpp. | ||
""" | ||
if cpu in ("arm64", "aarch64"): | ||
return "arm64" | ||
if cpu in ("arm64_32", "aarch64_32"): | ||
return "arm64_32" | ||
if cpu in ("x86_64", "amd64"): | ||
return "x86_64" | ||
if cpu in ("i386", "i486", "i586", "i686", "i786", "i886", "i986"): | ||
return "i386" | ||
if not cpu: | ||
return "unknown" | ||
return cpu | ||
|
||
def _normalize_apple_environment(environment): | ||
"""Normalizes the environment component of an Apple target triple. | ||
This function is equivalent to | ||
`getEnvironmentForAppleTargetSpecificModuleTriple` in | ||
https://github.com/apple/swift/blob/main/lib/Basic/Platform.cpp. | ||
""" | ||
if environment == "unknown" or not environment: | ||
return None | ||
return environment | ||
|
||
def _normalize_apple_os(os, *, unversioned = False): | ||
"""Normalizes the OS component of an Apple target triple. | ||
This function is equivalent to `getOSForAppleTargetSpecificModuleTriple` in | ||
https://github.com/apple/swift/blob/main/lib/Basic/Platform.cpp. | ||
""" | ||
os_name, version = _split_os_version(os) | ||
if os_name in ("macos", "macosx", "darwin"): | ||
os_name = "macos" | ||
elif not os_name: | ||
os_name = "unknown" | ||
return os_name if unversioned else (os_name + version) | ||
|
||
def _normalize_for_swift(triple, *, unversioned = False): | ||
"""Normalizes a target triple for use with the Swift compiler. | ||
This function performs that normalization, as well as other normalization | ||
implemented in | ||
https://github.com/apple/swift/blob/main/lib/Basic/Platform.cpp. It is named | ||
_specifically_ `normalize_for_swift` to differentiate it from the behavior | ||
defined in the `llvm::Triple::normalize` method, which has slightly | ||
different semantics. | ||
Args: | ||
triple: A target triple struct, as returned by `target_triples.make` or | ||
`target_triples.parse`. | ||
unversioned: A Boolean value indicating whether any OS version number | ||
component should be removed from the triple, if present. | ||
Returns: | ||
A target triple struct containing the normalized triple. | ||
""" | ||
os = _normalize_apple_os(triple.os, unversioned = unversioned) | ||
if os.startswith(("ios", "macos", "tvos", "watchos")): | ||
return _make( | ||
cpu = _normalize_apple_cpu(triple.cpu), | ||
vendor = "apple", | ||
os = os, | ||
environment = _normalize_apple_environment(triple.environment), | ||
) | ||
|
||
return triple | ||
|
||
def _parse(triple_string): | ||
"""Parses a target triple string and returns its fields as a struct. | ||
Args: | ||
triple_string: A string representing a target triple. | ||
Returns: | ||
A `struct` containing the following fields: | ||
* `cpu`: The CPU of the triple (e.g., `x86_64` or `arm`). | ||
* `vendor`: The vendor component of the triple (e.g., `apple` or | ||
`unknown`). | ||
* `os`: The operating system or platform name of the triple (e.g., | ||
`darwin` or `linux`). | ||
* `environment`: The environment or ABI component of the triple, if | ||
it was present. This component may be `None`. | ||
""" | ||
components = triple_string.split("-") | ||
return _make( | ||
cpu = components[0], | ||
vendor = components[1], | ||
os = components[2], | ||
environment = components[3] if len(components) > 3 else None, | ||
) | ||
|
||
def _platform_name_for_swift(triple): | ||
"""Returns the platform name used by Swift to refer to the triple. | ||
The platform name is used as the name of the subdirectory under the Swift | ||
resource directory where libraries and modules are stored. On some | ||
platforms, such as Apple operating systems, this name encodes both OS and | ||
environment information from the triple: for example, | ||
`x86_64-apple-ios-simulator` has a platform name of `iphonesimulator` | ||
(matching the platform name from Xcode). | ||
Args: | ||
triple: A target triple struct, as returned by `target_triples.make` or | ||
`target_triples.parse`. | ||
Returns: | ||
A string representing the platform name. | ||
""" | ||
os = _normalize_apple_os(_unversioned_os(triple), unversioned = True) | ||
if os == "macos": | ||
return "macosx" | ||
|
||
is_simulator = (triple.environment == "simulator") | ||
if os == "ios": | ||
return "iphonesimulator" if is_simulator else "iphoneos" | ||
if os == "tvos": | ||
return "appletvsimulator" if is_simulator else "appletvos" | ||
if os == "watchos": | ||
return "watchsimulator" if is_simulator else "watchos" | ||
|
||
# Fall back to the operating system name if we aren't one of the cases | ||
# covered above. If more platforms need to be supported in the future, add | ||
# them here. | ||
return os | ||
|
||
def _str(triple): | ||
"""Returns the string representation of the target triple. | ||
Args: | ||
triple: A target triple struct, as returned by `target_triples.make` or | ||
`target_triples.parse`. | ||
Returns: | ||
The string representation of the target triple. | ||
""" | ||
result = "{}-{}-{}".format(triple.cpu, triple.vendor, triple.os) | ||
if triple.environment: | ||
result += "-{}".format(triple.environment) | ||
return result | ||
|
||
def _split_os_version(os): | ||
"""Splits the OS version number from the end of the given component. | ||
Args: | ||
os: The OS component of a target triple. | ||
Returns: | ||
A tuple containing two elements: the operating system name and the | ||
version number. If there was no version number, then the second element | ||
will be the empty string. | ||
""" | ||
for index in range(len(os)): | ||
if os[index].isdigit(): | ||
return (os[:index], os[index:]) | ||
return (os, "") | ||
|
||
def _unversioned_os(triple): | ||
"""Returns the operating system of the triple without the version number.""" | ||
return _split_os_version(triple.os)[0] | ||
|
||
target_triples = struct( | ||
make = _make, | ||
normalize_for_swift = _normalize_for_swift, | ||
parse = _parse, | ||
platform_name_for_swift = _platform_name_for_swift, | ||
str = _str, | ||
unversioned_os = _unversioned_os, | ||
) |
Oops, something went wrong.