[lld-macho] improve handling of -platform_version
authorGreg McGary <gkm@fb.com>
Tue, 11 Aug 2020 01:47:16 +0000 (18:47 -0700)
committerJez Ng <jezng@fb.com>
Tue, 11 Aug 2020 01:47:16 +0000 (18:47 -0700)
This improves the handling of `-platform_version` by addressing the FIXME in the code to process the arguments.

Reviewed By: int3, #lld-macho

Differential Revision: https://reviews.llvm.org/D81413

lld/MachO/Config.h
lld/MachO/Driver.cpp
lld/test/MachO/platform-version.s [new file with mode: 0644]
lld/test/MachO/platform-version.test [deleted file]

index f65ff7c..da217cf 100644 (file)
@@ -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 <vector>
 
@@ -22,6 +24,12 @@ namespace macho {
 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 @@ struct Configuration {
   llvm::StringRef installName;
   llvm::StringRef outputFile;
   llvm::MachO::Architecture arch;
+  PlatformInfo platform;
   llvm::MachO::HeaderFileType outputType;
   std::vector<llvm::StringRef> librarySearchPaths;
   std::vector<llvm::StringRef> frameworkSearchPaths;
index 93b61fc..ccbd77d 100644 (file)
@@ -36,6 +36,8 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 
+#include <algorithm>
+
 using namespace llvm;
 using namespace llvm::MachO;
 using namespace llvm::sys;
@@ -358,8 +360,49 @@ static bool markSubLibrary(StringRef searchName) {
   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<llvm::MachO::PlatformKind>(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 (file)
index 0000000..5feb2b2
--- /dev/null
@@ -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 (file)
index baa4ced..0000000
+++ /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