diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -30,6 +30,14 @@ llvm::VersionTuple sdk; }; +enum class UndefinedSymbolTreatment : unsigned { + unknown = 0, + error = 1, + warning = 2, + suppress = 3, + dynamic_lookup = 4, +}; + struct Configuration { Symbol *entry; bool hasReexports = false; @@ -52,6 +60,8 @@ bool demangle = false; llvm::MachO::Architecture arch; PlatformInfo platform; + UndefinedSymbolTreatment undefinedSymbolTreatment = + UndefinedSymbolTreatment::error; llvm::MachO::HeaderFileType outputType; std::vector systemLibraryRoots; std::vector librarySearchPaths; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -597,6 +597,19 @@ error(Twine("malformed sdk version: ") + sdkVersionStr); } +static void handleUndefined(const opt::Arg *arg) { + StringRef treatmentStr = arg->getValue(0); + config->undefinedSymbolTreatment = + llvm::StringSwitch(treatmentStr) + .Case("error", UndefinedSymbolTreatment::error) + .Case("warning", UndefinedSymbolTreatment::warning) + .Case("suppress", UndefinedSymbolTreatment::suppress) + .Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup) + .Default(UndefinedSymbolTreatment::unknown); + if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::unknown) + error(Twine("malformed undefined-symbol treatment: ") + treatmentStr); +} + static void warnIfDeprecatedOption(const opt::Option &opt) { if (!opt.getGroup().isValid()) return; @@ -827,6 +840,9 @@ case OPT_platform_version: handlePlatformVersion(arg); break; + case OPT_undefined: + handleUndefined(arg); + break; default: break; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -435,7 +435,6 @@ def undefined : Separate<["-"], "undefined">, MetaVarName<"">, HelpText<"Handle undefined symbols according to : error, warning, suppress, or dynamic_lookup (default is error)">, - Flags<[HelpHidden]>, Group; def rpath : Separate<["-"], "rpath">, MetaVarName<"">, diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -55,6 +55,9 @@ std::vector symVector; }; +extern bool undefinedSymbol(const std::string symbolName, + const std::string referenceName); + extern SymbolTable *symtab; } // namespace macho diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SymbolTable.h" +#include "Config.h" #include "InputFiles.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" @@ -141,4 +142,27 @@ return s; } +bool lld::macho::undefinedSymbol(const std::string symbolName, + const std::string referenceName) { + std::string message = "undefined symbol " + symbolName; + if (referenceName != "") + message += ", referenced from " + referenceName; + switch (config->undefinedSymbolTreatment) { + case UndefinedSymbolTreatment::suppress: + return true; + case UndefinedSymbolTreatment::error: + error(message); + return false; + case UndefinedSymbolTreatment::warning: + warn(message); + return true; + case UndefinedSymbolTreatment::dynamic_lookup: + error("dynamic_lookup unimplemented for " + message); + return false; + default: + fatal("malformed -undefined treatment"); + return false; + } +} + SymbolTable *macho::symtab; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -411,8 +411,7 @@ for (Reloc &r : isec->relocs) { if (auto *s = r.referent.dyn_cast()) { if (isa(s)) - error("undefined symbol " + toString(*s) + ", referenced from " + - toString(isec->file)); + undefinedSymbol(toString(*s), toString(isec->file)); else target->prepareSymbolRelocation(s, isec, r); } else {