|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | #include "swift/Basic/Platform.h"
|
| 14 | +#include "llvm/ADT/StringExtras.h" |
| 15 | +#include "llvm/ADT/StringSwitch.h" |
14 | 16 | #include "llvm/ADT/Triple.h"
|
15 | 17 |
|
16 | 18 | using namespace swift;
|
@@ -189,3 +191,126 @@ StringRef swift::getMajorArchitectureName(const llvm::Triple &Triple) {
|
189 | 191 | return Triple.getArchName();
|
190 | 192 | }
|
191 | 193 | }
|
| 194 | + |
| 195 | +// The code below is responsible for normalizing target triples into the form |
| 196 | +// used to name target-specific swiftmodule, swiftinterface, and swiftdoc files. |
| 197 | +// If two triples have incompatible ABIs or can be distinguished by Swift #if |
| 198 | +// declarations, they should normalize to different values. |
| 199 | +// |
| 200 | +// This code is only really used on platforms with toolchains supporting fat |
| 201 | +// binaries (a single binary containing multiple architectures). On these |
| 202 | +// platforms, this code should strip unnecessary details from target triple |
| 203 | +// components and map synonyms to canonical values. Even values which don't need |
| 204 | +// any special canonicalization should be documented here as comments. |
| 205 | +// |
| 206 | +// (Fallback behavior does not belong here; it should be implemented in code |
| 207 | +// that calls this function, most importantly in SerializedModuleLoaderBase.) |
| 208 | +// |
| 209 | +// If you're trying to refer to this code to understand how Swift behaves and |
| 210 | +// you're unfamiliar with LLVM internals, here's a cheat sheet for reading it: |
| 211 | +// |
| 212 | +// * llvm::Triple is the type for a target name. It's a bit of a misnomer, |
| 213 | +// because it can contain three or four values: arch-vendor-os[-environment]. |
| 214 | +// |
| 215 | +// * In .Cases and .Case, the last argument is the value the arguments before it |
| 216 | +// map to. That is, `.Cases("bar", "baz", "foo")` will return "foo" if it sees |
| 217 | +// "bar" or "baz". |
| 218 | +// |
| 219 | +// * llvm::Optional is similar to a Swift Optional: it either contains a value |
| 220 | +// or represents the absence of one. `None` is equivalent to `nil`; leading |
| 221 | +// `*` is equivalent to trailing `!`; conversion to `bool` is a not-`None` |
| 222 | +// check. |
| 223 | + |
| 224 | +static StringRef |
| 225 | +getArchForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { |
| 226 | + auto tripleArchName = triple.getArchName(); |
| 227 | + |
| 228 | + return llvm::StringSwitch<StringRef>(tripleArchName) |
| 229 | + .Cases("arm64", "aarch64", "arm64") |
| 230 | + .Cases("x86_64", "amd64", "x86_64") |
| 231 | + .Cases("i386", "i486", "i586", "i686", "i786", "i886", "i986", |
| 232 | + "i386") |
| 233 | + .Cases("unknown", "", "unknown") |
| 234 | + // These values are also supported, but are handled by the default case below: |
| 235 | + // .Case ("armv7s", "armv7s") |
| 236 | + // .Case ("armv7k", "armv7k") |
| 237 | + // .Case ("armv7", "armv7") |
| 238 | + .Default(tripleArchName); |
| 239 | +} |
| 240 | + |
| 241 | +static StringRef |
| 242 | +getVendorForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { |
| 243 | + // We unconditionally normalize to "apple" because it's relatively common for |
| 244 | + // build systems to omit the vendor name or use an incorrect one like |
| 245 | + // "unknown". Most parts of the compiler ignore the vendor, so you might not |
| 246 | + // notice such a mistake. |
| 247 | + // |
| 248 | + // Please don't depend on this behavior--specify 'apple' if you're building |
| 249 | + // for an Apple platform. |
| 250 | + |
| 251 | + assert(triple.isOSDarwin() && |
| 252 | + "shouldn't normalize non-Darwin triple to 'apple'"); |
| 253 | + |
| 254 | + return "apple"; |
| 255 | +} |
| 256 | + |
| 257 | +static StringRef |
| 258 | +getOSForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { |
| 259 | + auto tripleOSName = triple.getOSName(); |
| 260 | + |
| 261 | + // Truncate the OS name before the first digit. "Digit" here is ASCII '0'-'9'. |
| 262 | + auto tripleOSNameNoVersion = tripleOSName.take_until(llvm::isDigit); |
| 263 | + |
| 264 | + return llvm::StringSwitch<StringRef>(tripleOSNameNoVersion) |
| 265 | + .Cases("macos", "macosx", "darwin", "macos") |
| 266 | + .Cases("unknown", "", "unknown") |
| 267 | + // These values are also supported, but are handled by the default case below: |
| 268 | + // .Case ("ios", "ios") |
| 269 | + // .Case ("tvos", "tvos") |
| 270 | + // .Case ("watchos", "watchos") |
| 271 | + .Default(tripleOSNameNoVersion); |
| 272 | +} |
| 273 | + |
| 274 | +static Optional<StringRef> |
| 275 | +getEnvironmentForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { |
| 276 | + auto tripleEnvironment = triple.getEnvironmentName(); |
| 277 | + |
| 278 | + // If the environment is empty, infer a "simulator" environment based on the |
| 279 | + // OS and architecture combination. This feature is deprecated and exists for |
| 280 | + // backwards compatibility only; build systems should pass the "simulator" |
| 281 | + // environment explicitly if they know they're building for a simulator. |
| 282 | + if (tripleEnvironment == "" && swift::tripleIsAnySimulator(triple)) |
| 283 | + return StringRef("simulator"); |
| 284 | + |
| 285 | + return llvm::StringSwitch<Optional<StringRef>>(tripleEnvironment) |
| 286 | + .Cases("unknown", "", None) |
| 287 | + // These values are also supported, but are handled by the default case below: |
| 288 | + // .Case ("simulator", StringRef("simulator")) |
| 289 | + .Default(tripleEnvironment); |
| 290 | +} |
| 291 | + |
| 292 | +llvm::Triple swift::getTargetSpecificModuleTriple(const llvm::Triple &triple) { |
| 293 | + // isOSDarwin() returns true for all Darwin-style OSes, including macOS, iOS, |
| 294 | + // etc. |
| 295 | + if (triple.isOSDarwin()) { |
| 296 | + StringRef newArch = getArchForAppleTargetSpecificModuleTriple(triple); |
| 297 | + |
| 298 | + StringRef newVendor = getVendorForAppleTargetSpecificModuleTriple(triple); |
| 299 | + |
| 300 | + StringRef newOS = getOSForAppleTargetSpecificModuleTriple(triple); |
| 301 | + |
| 302 | + Optional<StringRef> newEnvironment = |
| 303 | + getEnvironmentForAppleTargetSpecificModuleTriple(triple); |
| 304 | + |
| 305 | + if (!newEnvironment) |
| 306 | + // Generate an arch-vendor-os triple. |
| 307 | + return llvm::Triple(newArch, newVendor, newOS); |
| 308 | + |
| 309 | + // Generate an arch-vendor-os-environment triple. |
| 310 | + return llvm::Triple(newArch, newVendor, newOS, *newEnvironment); |
| 311 | + } |
| 312 | + |
| 313 | + // Other platforms get no normalization. |
| 314 | + return triple; |
| 315 | +} |
| 316 | + |
0 commit comments