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,11 @@ llvm::VersionTuple sdk; }; +enum class NamespaceKind { + twolevel, + flat, +}; + enum class UndefinedSymbolTreatment { unknown, error, @@ -61,6 +66,7 @@ bool demangle = false; llvm::MachO::Architecture arch; PlatformInfo platform; + NamespaceKind namespaceKind = NamespaceKind::twolevel; UndefinedSymbolTreatment undefinedSymbolTreatment = UndefinedSymbolTreatment::error; llvm::MachO::HeaderFileType outputType; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -582,18 +582,27 @@ static void handleUndefined(const opt::Arg *arg) { StringRef treatmentStr = arg->getValue(0); - config->undefinedSymbolTreatment = + auto treatment = 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) { + if (treatment == UndefinedSymbolTreatment::unknown) { warn(Twine("unknown -undefined TREATMENT '") + treatmentStr + "', defaulting to 'error'"); - config->undefinedSymbolTreatment = UndefinedSymbolTreatment::error; + treatment = UndefinedSymbolTreatment::error; + } else if (config->namespaceKind == NamespaceKind::twolevel && + (treatment == UndefinedSymbolTreatment::warning || + treatment == UndefinedSymbolTreatment::suppress)) { + if (treatment == UndefinedSymbolTreatment::warning) + error("'-undefined warning' only valid with '-flat_namespace'"); + else + error("'-undefined suppress' only valid with '-flat_namespace'"); + treatment = UndefinedSymbolTreatment::error; } + config->undefinedSymbolTreatment = treatment; } static void warnIfDeprecatedOption(const opt::Option &opt) { @@ -760,6 +769,18 @@ if (const opt::Arg *arg = args.getLastArg(OPT_static, OPT_dynamic)) config->staticLink = (arg->getOption().getID() == OPT_static); + if (const opt::Arg *arg = + args.getLastArg(OPT_flat_namespace, OPT_twolevel_namespace)) { + config->namespaceKind = arg->getOption().getID() == OPT_twolevel_namespace + ? NamespaceKind::twolevel + : NamespaceKind::flat; + if (config->namespaceKind == NamespaceKind::flat) { + warn("Option '" + arg->getOption().getPrefixedName() + + "' is not yet implemented. Stay tuned..."); + config->namespaceKind = NamespaceKind::twolevel; + } + } + config->systemLibraryRoots = getSystemLibraryRoots(args); config->librarySearchPaths = getLibrarySearchPaths(args, config->systemLibraryRoots); diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -448,9 +448,12 @@ Flags<[HelpHidden]>, Group; def flat_namespace : Flag<["-"], "flat_namespace">, - HelpText<"Resolve symbols from all dylibs, both direct & transitive. Do not record source libraries: dyld must re-search at runtime and use the first definition found">, + HelpText<"Resolve symbols from all dylibs, both direct and transitive. Do not record source libraries: dyld must re-search at runtime and use the first definition found">, Flags<[HelpHidden]>, Group; +def twolevel_namespace : Flag<["-"], "twolevel_namespace">, + HelpText<"Make dyld look up symbols by (dylib,name) pairs (default)">, + Group; def u : Separate<["-"], "u">, MetaVarName<"">, HelpText<"Require that be defined for the link to succeed">, @@ -1302,10 +1305,6 @@ HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, Group; -def twolevel_namespace : Flag<["-"], "twolevel_namespace">, - HelpText<"This option is undocumented in ld64">, - Flags<[HelpHidden]>, - Group; def verbose_optimization_hints : Flag<["-"], "verbose_optimization_hints">, HelpText<"This option is undocumented in ld64">, Flags<[HelpHidden]>, diff --git a/lld/test/MachO/treat-undef-sym.s b/lld/test/MachO/treat-undef-sym.s --- a/lld/test/MachO/treat-undef-sym.s +++ b/lld/test/MachO/treat-undef-sym.s @@ -5,14 +5,29 @@ # RUN: FileCheck %s -check-prefix=UNKNOWN # RUN: not %lld -undefined error -o /dev/null %t.o 2>&1 | \ # RUN: FileCheck %s -check-prefix=ERROR -# RUN: %no_fatal_warnings_lld -undefined warning -o /dev/null %t.o 2>&1 | \ -# RUN: FileCheck %s -check-prefix=WARNING -# RUN: %lld -undefined suppress -o /dev/null %t.o 2>&1 | \ -# RUN: FileCheck %s -check-prefix=SUPPRESS --allow-empty + +# RUN: not %lld -undefined warning -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=INVAL-WARNING +# RUN: not %lld -undefined suppress -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=INVAL-SUPPRESS + +# FIXME: Enable these -undefined checks once -flat_namespace is implemented. +# RN: %no_fatal_warnings_lld -flat_namespace -undefined warning \ +# RN: -o /dev/null %t.o 2>&1 | \ +# RN: FileCheck %s -check-prefix=WARNING +# RN: %lld -flat_namespace -undefined suppress -o /dev/null %t.o 2>&1 | \ +# RN: FileCheck %s -check-prefix=SUPPRESS --allow-empty # ERROR: error: undefined symbol: _bar # ERROR-NEXT: >>> referenced by +# INVAL-WARNING: error: '-undefined warning' only valid with '-flat_namespace' +# INVAL-WARNING-NEXT: error: undefined symbol: _bar + +# INVAL-SUPPRESS: error: '-undefined suppress' only valid with '-flat_namespace' +# INVAL-SUPPRESS-NEXT: error: undefined symbol: _bar + + # WARNING: warning: undefined symbol: _bar # WARNING-NEXT: >>> referenced by