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,12 +24,19 @@ class Symbol; struct SymbolPriorityEntry; +struct PlatformInfo { + llvm::MachO::PlatformKind kind; + llvm::VersionTuple minimum; + llvm::VersionTuple sdk; +}; + struct Configuration { Symbol *entry; bool hasReexports = false; llvm::StringRef installName; llvm::StringRef outputFile; llvm::MachO::Architecture arch; + PlatformInfo platform; llvm::MachO::HeaderFileType outputType; std::vector searchPaths; llvm::DenseMap priorities; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -34,6 +34,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include + using namespace llvm; using namespace llvm::MachO; using namespace llvm::sys; @@ -259,16 +261,45 @@ return false; } +// -platform_version takes 3 args, which LLVM's option library doesn't support +// directly. So this explicitly handles that. static void handlePlatformVersion(opt::ArgList::iterator &it, const opt::ArgList::iterator &end) { - // -platform_version takes 3 args, which LLVM's option library doesn't - // support directly. So this explicitly handles that. - // FIXME: stash skipped args for later use. - for (int i = 0; i < 3; ++i) { - ++it; - if (it == end || (*it)->getOption().getID() != OPT_INPUT) - fatal("usage: -platform_version platform min_version sdk_version"); - } + // increment over OPT_platform_version + opt::ArgList::iterator argument = ++it; + // ensure that we have 3 input arguments + if (std::distance(argument, end) < 3 || + std::any_of(argument, std::next(argument, 3), [](const opt::Arg *arg) { + return arg->getOption().getID() != OPT_INPUT; + })) + fatal("usage: -platform_version platform min_version sdk_version"); + + // TODO(compnerd) see if we can generate this case list via XMACROS + config->platform.kind = + llvm::StringSwitch((*it++)->getValue()) + .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-sim", "7", llvm::MachO::PlatformKind::iOSSimulator) + .Cases("tvos-sim", "8", llvm::MachO::PlatformKind::tvOSSimulator) + .Cases("watchos-sim", "9", llvm::MachO::PlatformKind::watchOSSimulator) + // FIXME: add DriverKit to the enumeration (might require switching to + // `llvm::MachO::PlatformType` instead of + // `llvm::MachO::PlatformKind` + // .Cases("driverkit", "10", llvm::MachO::PlatformKind::DriverKit) + .Default(llvm::MachO::PlatformKind::unknown); + if (auto version = (*it++)->getValue()) + if (config->platform.minimum.tryParse(version)) + fatal(Twine("malformed minimum version: ") + version); + // NOTE: do *NOT* increment here, because the outer loop will increment the + // iterator here. Doing so will yield `end`, and incrementing past `end` is + // undefined behaviour! + if (auto version = (*it)->getValue()) + if (config->platform.sdk.tryParse(version)) + fatal(Twine("malformed sdk version: ") + version); } bool macho::link(llvm::ArrayRef argsArr, bool canExitEarly,