diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -12,7 +12,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/Platform.h" #include @@ -22,6 +24,12 @@ class Symbol; struct SymbolPriorityEntry; +struct PlatformInfo { + llvm::MachO::PlatformKind kind; + llvm::VersionTuple minimum; + llvm::VersionTuple sdk; +}; + struct Configuration { Symbol *entry; bool hasReexports = false; @@ -29,6 +37,7 @@ llvm::StringRef installName; llvm::StringRef outputFile; llvm::MachO::Architecture arch; + PlatformInfo platform; llvm::MachO::HeaderFileType outputType; std::vector librarySearchPaths; std::vector frameworkSearchPaths; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -36,6 +36,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include + using namespace llvm; using namespace llvm::MachO; using namespace llvm::sys; @@ -358,8 +360,49 @@ return false; } +static inline char toLowerDash(char x) { + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + else if (x == ' ') + return '-'; + return x; +} + +static std::string lowerDash(StringRef s) { + return std::string(map_iterator(s.begin(), toLowerDash), + map_iterator(s.end(), toLowerDash)); +} + static void handlePlatformVersion(const opt::Arg *arg) { - // TODO: implementation coming very soon ... + StringRef platformStr = arg->getValue(0); + StringRef minVersionStr = arg->getValue(1); + StringRef sdkVersionStr = arg->getValue(2); + + // TODO(compnerd) see if we can generate this case list via XMACROS + config->platform.kind = + llvm::StringSwitch(lowerDash(platformStr)) + .Cases("macos", "1", llvm::MachO::PlatformKind::macOS) + .Cases("ios", "2", llvm::MachO::PlatformKind::iOS) + .Cases("tvos", "3", llvm::MachO::PlatformKind::tvOS) + .Cases("watchos", "4", llvm::MachO::PlatformKind::watchOS) + .Cases("bridgeos", "5", llvm::MachO::PlatformKind::bridgeOS) + .Cases("mac-catalyst", "6", llvm::MachO::PlatformKind::macCatalyst) + .Cases("ios-simulator", "7", llvm::MachO::PlatformKind::iOSSimulator) + .Cases("tvos-simulator", "8", + llvm::MachO::PlatformKind::tvOSSimulator) + .Cases("watchos-simulator", "9", + llvm::MachO::PlatformKind::watchOSSimulator) + .Default(llvm::MachO::PlatformKind::unknown); + if (config->platform.kind == llvm::MachO::PlatformKind::unknown) + error(Twine("malformed platform: ") + platformStr); + // TODO: check validity of version strings, which varies by platform + // NOTE: ld64 accepts version strings with 5 components + // llvm::VersionTuple accepts no more than 4 components + // Has Apple ever published version strings with 5 components? + if (config->platform.minimum.tryParse(minVersionStr)) + error(Twine("malformed minimum version: ") + minVersionStr); + if (config->platform.sdk.tryParse(sdkVersionStr)) + error(Twine("malformed sdk version: ") + sdkVersionStr); } static void warnIfDeprecatedOption(const opt::Option &opt) { diff --git a/lld/test/MachO/platform-version.s b/lld/test/MachO/platform-version.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/platform-version.s @@ -0,0 +1,67 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o + +### We test every platform keyword. Sometimes good keywords are coupled +### with bad version strings, so we use *-NOT patterns to ensure that +### no "malformed platform" diagnostic appears in those cases. + +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version \ +# RUN: | FileCheck --check-prefix=FAIL-MISSING %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version wtf \ +# RUN: | FileCheck --check-prefix=FAIL-MISSING %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version lolz 1.2.3.4.5 \ +# RUN: | FileCheck --check-prefix=FAIL-MISSING %s +# FAIL-MISSING: -platform_version: missing argument +# FAIL-MISSING-NOT: malformed platform: {{.*}} +# FAIL-MISSING-NOT: malformed {{minimum|sdk}} version: {{.*}} + +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version macOS -lfoo 2 \ +# RUN: | FileCheck --check-prefix=FAIL-MALFORM %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version iOS 1 2.a \ +# RUN: | FileCheck --check-prefix=FAIL-MALFORM %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version tvOS 1.2.3.4.5 10 \ +# RUN: | FileCheck --check-prefix=FAIL-MALFORM %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version watchOS 10 1.2.3.4.5 \ +# RUN: | FileCheck --check-prefix=FAIL-MALFORM %s +# FAIL-MALFORM-NOT: malformed platform: {{.*}} +# FAIL-MALFORM: malformed {{minimum|sdk}} version: {{.*}} + +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version bridgeOS 1 5 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version "Mac Catalyst" 1.2 5.6 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version "iOS Simulator" 1.2.3 5.6.7 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version "tvOS Simulator" 1.2.3.4 5.6.7.8 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version "watchOS Simulator" 1 5 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version 1 1 5 +# RUN: lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version 9 1 5 + +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version wtf 1 5 \ +# RUN: | FileCheck --check-prefix=FAIL-PLATFORM %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version 0 1 5 \ +# RUN: | FileCheck --check-prefix=FAIL-PLATFORM %s +# RUN: not lld -flavor darwinnew -Z -o %t %t.o 2>&1 \ +# RUN: -platform_version 10 1 5 \ +# RUN: | FileCheck --check-prefix=FAIL-PLATFORM %s +# FAIL-PLATFORM: malformed platform: {{.*}} +# FAIL-PLATFORM-NOT: malformed {{minimum|sdk}} version: {{.*}} + +.text +.global _main +_main: + mov $0, %eax + ret diff --git a/lld/test/MachO/platform-version.test b/lld/test/MachO/platform-version.test deleted file mode 100644 --- a/lld/test/MachO/platform-version.test +++ /dev/null @@ -1,17 +0,0 @@ -# RUN: not lld -flavor darwinnew -platform_version 2>&1 \ -# RUN: | FileCheck --check-prefix=MISSING %s -# RUN: not lld -flavor darwinnew -platform_version macos 2>&1 \ -# RUN: | FileCheck --check-prefix=MISSING %s -# RUN: not lld -flavor darwinnew -platform_version macos 10.15 2>&1 \ -# RUN: | FileCheck --check-prefix=MISSING %s -# RUN: not lld -flavor darwinnew -platform_version macos -lfoo 10.15 2>&1 \ -# RUN: | FileCheck --check-prefix=GOOD %s -# RUN: not lld -flavor darwinnew -platform_version macos 10.15 10.15.4 2>&1 \ -# RUN: | FileCheck --check-prefix=GOOD %s -# RUN: not lld -flavor darwinnew -platform_version macos 10.15 10.15.4 foobar 2>&1 \ -# RUN: | FileCheck --check-prefix=FAIL_FILE %s - -MISSING: -platform_version: missing argument -FAIL: usage: -platform_version platform min_version sdk_version -GOOD: undefined symbol: _main -FAIL_FILE: cannot open foobar