[lld-macho][nfc] Parse more options using getLastArg{Value}

The option-iterating loop should be reserved for options whose command-line
order is important. I think LLD-ELF follows a similar design.

Reviewed By: #lld-macho, smeenai

Differential Revision: https://reviews.llvm.org/D97797
This commit is contained in:
Jez Ng 2021-03-03 15:52:06 -05:00
parent 58d531fd6f
commit 1168736c66
1 changed files with 22 additions and 18 deletions

View File

@ -560,13 +560,18 @@ static std::string lowerDash(StringRef s) {
map_iterator(s.end(), toLowerDash)); map_iterator(s.end(), toLowerDash));
} }
static void handlePlatformVersion(const opt::Arg *arg) { static PlatformInfo getPlatformVersion(const opt::ArgList &args) {
const opt::Arg *arg = args.getLastArg(OPT_platform_version);
PlatformInfo platform;
if (!arg)
return platform;
StringRef platformStr = arg->getValue(0); StringRef platformStr = arg->getValue(0);
StringRef minVersionStr = arg->getValue(1); StringRef minVersionStr = arg->getValue(1);
StringRef sdkVersionStr = arg->getValue(2); StringRef sdkVersionStr = arg->getValue(2);
// TODO(compnerd) see if we can generate this case list via XMACROS // TODO(compnerd) see if we can generate this case list via XMACROS
config->platform.kind = platform.kind =
StringSwitch<PlatformKind>(lowerDash(platformStr)) StringSwitch<PlatformKind>(lowerDash(platformStr))
.Cases("macos", "1", PlatformKind::macOS) .Cases("macos", "1", PlatformKind::macOS)
.Cases("ios", "2", PlatformKind::iOS) .Cases("ios", "2", PlatformKind::iOS)
@ -579,23 +584,25 @@ static void handlePlatformVersion(const opt::Arg *arg) {
.Cases("watchos-simulator", "9", PlatformKind::watchOSSimulator) .Cases("watchos-simulator", "9", PlatformKind::watchOSSimulator)
.Cases("driverkit", "10", PlatformKind::driverKit) .Cases("driverkit", "10", PlatformKind::driverKit)
.Default(PlatformKind::unknown); .Default(PlatformKind::unknown);
if (config->platform.kind == PlatformKind::unknown) if (platform.kind == PlatformKind::unknown)
error(Twine("malformed platform: ") + platformStr); error(Twine("malformed platform: ") + platformStr);
// TODO: check validity of version strings, which varies by platform // TODO: check validity of version strings, which varies by platform
// NOTE: ld64 accepts version strings with 5 components // NOTE: ld64 accepts version strings with 5 components
// llvm::VersionTuple accepts no more than 4 components // llvm::VersionTuple accepts no more than 4 components
// Has Apple ever published version strings with 5 components? // Has Apple ever published version strings with 5 components?
if (config->platform.minimum.tryParse(minVersionStr)) if (platform.minimum.tryParse(minVersionStr))
error(Twine("malformed minimum version: ") + minVersionStr); error(Twine("malformed minimum version: ") + minVersionStr);
if (config->platform.sdk.tryParse(sdkVersionStr)) if (platform.sdk.tryParse(sdkVersionStr))
error(Twine("malformed sdk version: ") + sdkVersionStr); error(Twine("malformed sdk version: ") + sdkVersionStr);
return platform;
} }
static void handleUndefined(const opt::Arg *arg) { static UndefinedSymbolTreatment
StringRef treatmentStr = arg->getValue(0); getUndefinedSymbolTreatment(const opt::ArgList &args) {
StringRef treatmentStr = args.getLastArgValue(OPT_undefined);
auto treatment = auto treatment =
StringSwitch<UndefinedSymbolTreatment>(treatmentStr) StringSwitch<UndefinedSymbolTreatment>(treatmentStr)
.Case("error", UndefinedSymbolTreatment::error) .Cases("error", "", UndefinedSymbolTreatment::error)
.Case("warning", UndefinedSymbolTreatment::warning) .Case("warning", UndefinedSymbolTreatment::warning)
.Case("suppress", UndefinedSymbolTreatment::suppress) .Case("suppress", UndefinedSymbolTreatment::suppress)
.Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup) .Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup)
@ -613,7 +620,7 @@ static void handleUndefined(const opt::Arg *arg) {
error("'-undefined suppress' only valid with '-flat_namespace'"); error("'-undefined suppress' only valid with '-flat_namespace'");
treatment = UndefinedSymbolTreatment::error; treatment = UndefinedSymbolTreatment::error;
} }
config->undefinedSymbolTreatment = treatment; return treatment;
} }
static void warnIfDeprecatedOption(const opt::Option &opt) { static void warnIfDeprecatedOption(const opt::Option &opt) {
@ -752,6 +759,7 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
config = make<Configuration>(); config = make<Configuration>();
symtab = make<SymbolTable>(); symtab = make<SymbolTable>();
target = createTargetInfo(args); target = createTargetInfo(args);
config->platform = getPlatformVersion(args);
config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"), config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"),
/*file=*/nullptr, /*file=*/nullptr,
@ -792,11 +800,12 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
config->staticLink = (arg->getOption().getID() == OPT_static); config->staticLink = (arg->getOption().getID() == OPT_static);
if (const opt::Arg *arg = if (const opt::Arg *arg =
args.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) { args.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace))
config->namespaceKind = arg->getOption().getID() == OPT_twolevel_namespace config->namespaceKind = arg->getOption().getID() == OPT_twolevel_namespace
? NamespaceKind::twolevel ? NamespaceKind::twolevel
: NamespaceKind::flat; : NamespaceKind::flat;
}
config->undefinedSymbolTreatment = getUndefinedSymbolTreatment(args);
config->systemLibraryRoots = getSystemLibraryRoots(args); config->systemLibraryRoots = getSystemLibraryRoots(args);
config->librarySearchPaths = config->librarySearchPaths =
@ -846,12 +855,13 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
initLLVM(); // must be run before any call to addFile() initLLVM(); // must be run before any call to addFile()
// This loop should be reserved for options whose exact ordering matters.
// Other options should be handled via filtered() and/or getLastArg().
for (const auto &arg : args) { for (const auto &arg : args) {
const auto &opt = arg->getOption(); const auto &opt = arg->getOption();
warnIfDeprecatedOption(opt); warnIfDeprecatedOption(opt);
warnIfUnimplementedOption(opt); warnIfUnimplementedOption(opt);
// TODO: are any of these better handled via filtered() or getLastArg()?
switch (opt.getID()) { switch (opt.getID()) {
case OPT_INPUT: case OPT_INPUT:
addFile(arg->getValue(), false); addFile(arg->getValue(), false);
@ -875,12 +885,6 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
case OPT_weak_framework: case OPT_weak_framework:
addFramework(arg->getValue(), opt.getID() == OPT_weak_framework); addFramework(arg->getValue(), opt.getID() == OPT_weak_framework);
break; break;
case OPT_platform_version:
handlePlatformVersion(arg);
break;
case OPT_undefined:
handleUndefined(arg);
break;
default: default:
break; break;
} }