diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -19,6 +19,7 @@ public: MachOOptTable(); llvm::opt::InputArgList parse(ArrayRef argv); + void printHelp(const char *argv0); }; // Create enum with OPT_xxx values for each option in Options.td diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -33,6 +33,8 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include + using namespace llvm; using namespace llvm::MachO; using namespace llvm::sys; @@ -73,6 +75,12 @@ return args; } +void MachOOptTable::printHelp(const char *argv0) { + PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(), + "LLVM Linker", false); + lld::outs() << "\n"; +} + // This is for -lfoo. We'll look for libfoo.dylib from search paths. static Optional findDylib(StringRef name) { for (StringRef dir : config->searchPaths) { @@ -146,7 +154,7 @@ // entry (the one nearest to the front of the list.) // // The file can also have line comments that start with '#'. -void parseOrderFile(StringRef path) { +static void parseOrderFile(StringRef path) { Optional buffer = readFile(path); if (!buffer) { error("Could not read order file at " + path); @@ -236,15 +244,114 @@ return false; } -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"); +template +static bool parsePackedVersion(StringRef str, UI &result) { + if (str.empty()) + return true; + + result = 0; + SmallVector parts; + llvm::SplitString(str, parts, "."); + auto count = parts.size(); + + // The first version-number component uses all of the highest-order + // bits remaining after bits have been allocated for the lower-order + // version components. + unsigned long long maxNum = + (1 << (std::numeric_limits::digits - ((count - 1) * width))); + for (StringRef str : parts) { + unsigned long long num; + if (llvm::getAsUnsignedInteger(str, 10, num)) + return true; + if (num >= maxNum) + return true; + maxNum = (1 << width); // max for the lower-order components + result |= num; + result <<= width; + } + result <<= (width * (capacity - count)); + + return false; +} + +static bool parsePackedVersion32(StringRef str, uint32_t &result) { + return parsePackedVersion(str, result); +} + +static bool parsePackedVersion64(StringRef str, uint64_t &result) { + return parsePackedVersion(str, result); +} + +static void usageError(const opt::Arg *arg) { + const auto &opt = arg->getOption(); + error("usage: " + opt.getPrefixedName() + " " + opt.getMetaVar()); +} + +static void parseCurrentVersion(const opt::Arg *arg) { + const char *sourceVersionStr = arg->getValue(0); + uint64_t sourceVersion; + if (parsePackedVersion64(sourceVersionStr, sourceVersion)) + usageError(arg); + // FIXME: add semantics +} + +static void parsePlatformVersion(const opt::Arg *arg) { + static const std::unordered_map platforms = { + {"macos", 1}, {"ios", 2}, {"tvos", 3}, {"watchos", 4}, + {"bridgeos", 5}, {"mac-catalyst", 6}, {"ios-sim", 7}, {"tvos-sim", 8}, + {"watchos-sim", 9}, {"driverkit", 10}, + }; + + const char *platformStr = arg->getValue(0); + const char *minVersionStr = arg->getValue(1); + const char *sdkVersionStr = arg->getValue(2); + unsigned long long platform; + uint32_t minVersion; + uint32_t sdkVersion; + + if (!llvm::getAsUnsignedInteger(platformStr, 10, platform)) { + const auto &p = platforms.find(platformStr); + platform = (p == platforms.end() ? 0 : p->second); + } + if (parsePackedVersion32(minVersionStr, minVersion) || + parsePackedVersion32(sdkVersionStr, sdkVersion) || platform < 1 || + platform > 10) { + usageError(arg); + } + // FIXME: add semantics +} + +static void warnIfDeprecatedOption(const opt::Option &opt) { + if (!opt.getGroup().isValid()) + return; + if (opt.getGroup().getID() == OPT_grp_deprecated) { + warn("Option `" + opt.getPrefixedName() + "' is deprecated in ld64:"); + warn(opt.getHelpText()); + } +} + +static void warnIfUnimplementedOption(const opt::Option &opt) { + if (!opt.getGroup().isValid()) + return; + switch (opt.getGroup().getID()) { + case OPT_grp_deprecated: + // warn about deprecated options elsewhere + break; + case OPT_grp_undocumented: + warn("Option `" + opt.getPrefixedName() + + "' is undocumented for ld64. Should ldd implement it?"); + break; + case OPT_grp_obsolete: + warn("Option `" + opt.getPrefixedName() + + "' is obsolete in ld64. Please modernize your usage"); + break; + case OPT_grp_ignored: + warn("Option `" + opt.getPrefixedName() + "' is ignored in ld64"); + break; + default: + warn("Option `" + opt.getPrefixedName() + + "' is not yet implemented. Stay tuned..."); + break; } } @@ -259,6 +366,11 @@ MachOOptTable parser; opt::InputArgList args = parser.parse(argsArr.slice(1)); + if (args.hasArg(OPT_help)) { + parser.printHelp(argsArr[0]); + return 0; + } + config = make(); symtab = make(); target = createTargetInfo(args); @@ -279,10 +391,17 @@ return !errorCount(); } - for (opt::ArgList::iterator it = args.begin(), end = args.end(); it != end; - ++it) { - const opt::Arg *arg = *it; - switch (arg->getOption().getID()) { + for (auto &arg : args) { + const auto &opt = arg->getOption(); + warnIfDeprecatedOption(opt); + switch (opt.getID()) { + case OPT_o: + case OPT_dylib: + // handled elsewhere ... + break; + default: + warnIfUnimplementedOption(opt); + break; case OPT_INPUT: addFile(arg->getValue()); break; @@ -290,10 +409,12 @@ if (Optional path = findDylib(arg->getValue())) addFile(*path); break; - case OPT_platform_version: { - handlePlatformVersion(it, end); // Can advance "it". + case OPT_current_version: + parseCurrentVersion(arg); + break; + case OPT_platform_version: + parsePlatformVersion(arg); break; - } } } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -1,42 +1,1001 @@ include "llvm/Option/OptParser.td" -def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, - HelpText<"Add directory to library search path">; +def help : Flag<["-", "--"], "help">; -def Z: Flag<["-"], "Z">, - HelpText<"Do not add standard directories to library search path">; +def grp_kind : OptionGroup<"kind">, HelpText<"OUTPUT KIND">; -def arch: Separate<["-"], "arch">, MetaVarName<"">, - HelpText<"Architecture to link">; +def execute : Flag<["-"], "execute">, + HelpText<"Produce a main executable (default)">, + Group; +def dylib : Flag<["-"], "dylib">, + HelpText<"Produce a shared library">, + Group; +def bundle : Flag<["-"], "bundle">, + HelpText<"Produce a bundle">, + Group; +def r : Flag<["-"], "r">, + HelpText<"Merge multiple object files into one, retaining relocations">, + Group; +def dylinker : Flag<["-"], "dylinker">, + HelpText<"Produce a dylinker only used when building dyld">, + Group; +def dynamic : Flag<["-"], "dynamic">, + HelpText<"Link dynamically (default)">, + Group; +def static : Flag<["-"], "static">, + HelpText<"Link statically">, + Group; +def preload : Flag<["-"], "preload">, + HelpText<"Produce an unsegmented binary for embedded systems">, + Group; +def arch : Separate<["-"], "arch">, + MetaVarName<"">, + HelpText<"The architecture (e.g. ppc, ppc64, i386, x86_64)">, + Group; +def o : Separate<["-"], "o">, + MetaVarName<"">, + HelpText<"The name of the output file (default: `a.out')">, + Group; -def dylib: Flag<["-"], "dylib">, HelpText<"Emit a shared library">; +def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARIES">; -def e: Separate<["-"], "e">, HelpText<"Name of entry point symbol">; +def l : Joined<["-"], "l">, + MetaVarName<"">, + HelpText<"Search for lib.dylib or lib.a on the library search path">, + Group; +def weak_l : Joined<["-"], "weak-l">, + MetaVarName<"">, + HelpText<"Like -l, but mark library and its references as weak imports">, + Group; +def weak_library : Separate<["-"], "weak_library">, + MetaVarName<"">, + HelpText<"Like bare , but mark library and its references as weak imports">, + Group; +def reexport_l : Joined<["-"], "reexport-l">, + MetaVarName<"">, + HelpText<"Like -l, but export all symbols of from newly created library">, + Group; +def reexport_library : Separate<["-"], "reexport_library">, + MetaVarName<"">, + HelpText<"Like bare , but export all symbols of from newly created library">, + Group; +def upward_l : Joined<["-"], "upward-l">, + MetaVarName<"">, + HelpText<"Like -l, but specify dylib as an upward dependency">, + Group; +def upward_library : Separate<["-"], "upward_library">, + MetaVarName<"">, + HelpText<"Like bare , but specify dylib as an upward dependency">, + Group; +def L : JoinedOrSeparate<["-"], "L">, + MetaVarName<"">, + HelpText<"Add dir to the library search path">, + Group; +def Z : Flag<["-"], "Z">, + HelpText<"Remove standard directories from the library and framework search paths">, + Group; +def syslibroot : Separate<["-"], "syslibroot">, + MetaVarName<"">, + HelpText<"Prepend to all library and framework search paths">, + Group; +def search_paths_first : Flag<["-"], "search_paths_first">, + HelpText<"Search for lib.dylib and lib.a at each step in traversing search path (default for Xcode 4 and later)">, + Group; +def search_dylibs_first : Flag<["-"], "search_dylibs_first">, + HelpText<"Search for lib.dylib on first pass, then for lib.a on second pass through search path (default for Xcode 3 and earlier)">, + Group; +def framework : Separate<["-"], "framework">, + MetaVarName<"">, + HelpText<"Search for .framework/ on the framework search path">, + Group; +def weak_framework : Separate<["-"], "weak_framework">, + MetaVarName<"">, + HelpText<"Like -framework , but mark framework and its references as weak imports">, + Group; +def reexport_framework : Separate<["-"], "reexport_framework">, + MetaVarName<"">, + HelpText<"Like -framework , but export all symbols of from the newly created library">, + Group; +def upward_framework : Separate<["-"], "upward_framework">, + MetaVarName<"">, + HelpText<"Like -framework , but specify the framework as an upward dependency">, + Group; +def F : JoinedOrSeparate<["-"], "F">, + MetaVarName<"">, + HelpText<"Add dir to the framework search path">, + Group; +def all_load : Flag<["-"], "all_load">, + HelpText<"Load all members of all static archive libraries">, + Group; +def ObjC : Flag<["-"], "ObjC">, + HelpText<"Load all members of static archives that are an Objective-C class or category.">, + Group; +def force_load : Separate<["-"], "force_load">, + MetaVarName<"">, + HelpText<"Load all members static archive library at ">, + Group; -def install_name: Separate<["-"], "install_name">, - MetaVarName<"">, - HelpText<"Set the install path of the dynamic library.">; +def grp_content : OptionGroup<"content">, HelpText<"ADDITIONAL CONTENT">; -def l: Joined<["-"], "l">, MetaVarName<"">, - HelpText<"Base name of library searched for in -L directories">; +def sectcreate : MultiArg<["-"], "sectcreate", 3>, + MetaVarName<"
">, + HelpText<"Create
in from the contents of ">, + Group; +def segcreate : MultiArg<["-"], "segcreate", 3>, + MetaVarName<"
">, + Alias, + HelpText<"Alias for -sectcreate">; +def filelist : Separate<["-"], "filelist">, + MetaVarName<"">, + HelpText<"Read names of files to link from ">, + Group; +def dtrace : Separate<["-"], "dtrace">, + MetaVarName<"