diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -597,32 +597,44 @@ return !errorCount(); } + DenseSet weakImportPaths; + for (const auto &arg : args) { const auto &opt = arg->getOption(); warnIfDeprecatedOption(opt); - switch (arg->getOption().getID()) { + switch (opt.getID()) { case OPT_INPUT: addFile(arg->getValue()); break; + case OPT_weak_library: + addFile(arg->getValue()); + weakImportPaths.insert(arg->getValue()); + break; case OPT_filelist: addFileList(arg->getValue()); break; case OPT_force_load: forceLoadArchive(arg->getValue()); break; - case OPT_l: { + case OPT_l: + case OPT_weak_l: { StringRef name = arg->getValue(); if (Optional path = findLibrary(name)) { addFile(*path); + if (opt.getID() == OPT_weak_l) + weakImportPaths.insert(saver.save(*path)); break; } error("library not found for -l" + name); break; } - case OPT_framework: { + case OPT_framework: + case OPT_weak_framework: { StringRef name = arg->getValue(); if (Optional path = findFramework(name)) { addFile(*path); + if (opt.getID() == OPT_weak_framework) + weakImportPaths.insert(saver.save(*path)); break; } error("framework not found for -framework " + name); @@ -661,6 +673,11 @@ config->outputType == MH_BUNDLE || (config->outputType == MH_EXECUTE && args.hasArg(OPT_pie)); + for (InputFile *file : inputFiles) + if (auto *dylibFile = dyn_cast(file)) + if (weakImportPaths.contains(file->getName())) + dylibFile->forceWeakImport = true; + // Now that all dylibs have been loaded, search for those that should be // re-exported. for (opt::Arg *arg : args.filtered(OPT_sub_library)) { diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -109,6 +109,7 @@ StringRef dylibName; uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel bool reexport = false; + bool forceWeakImport = false; std::vector reexported; }; diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -65,12 +65,10 @@ def weak_l : Joined<["-"], "weak-l">, MetaVarName<"">, HelpText<"Like -l, but mark library and its references as weak imports">, - Flags<[HelpHidden]>, Group; def weak_library : Separate<["-"], "weak_library">, MetaVarName<"">, HelpText<"Like bare , but mark library and its references as weak imports">, - Flags<[HelpHidden]>, Group; def reexport_l : Joined<["-"], "reexport-l">, MetaVarName<"">, @@ -120,7 +118,6 @@ def weak_framework : Separate<["-"], "weak_framework">, MetaVarName<"">, HelpText<"Like -framework , but mark framework and its references as weak imports">, - Flags<[HelpHidden]>, Group; def reexport_framework : Separate<["-"], "reexport_framework">, MetaVarName<"">, diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -385,8 +385,11 @@ uint64_t dylibOrdinal = 1; for (InputFile *file : inputFiles) { if (auto *dylibFile = dyn_cast(file)) { - in.header->addLoadCommand( - make(LC_LOAD_DYLIB, dylibFile->dylibName)); + // TODO: dylibs that are only referenced by weak refs should also be + // loaded via LC_LOAD_WEAK_DYLIB. + LoadCommandType lcType = + dylibFile->forceWeakImport ? LC_LOAD_WEAK_DYLIB : LC_LOAD_DYLIB; + in.header->addLoadCommand(make(lcType, dylibFile->dylibName)); dylibFile->ordinal = dylibOrdinal++; if (dylibFile->reexport) diff --git a/lld/test/MachO/weak-import.s b/lld/test/MachO/weak-import.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/weak-import.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o +# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib %t/foo.o -o %t/libfoo.dylib + +# RUN: lld -flavor darwinnew -syslibroot %S/Inputs/MacOSX.sdk -weak-lSystem %t/test.o -weak_framework CoreFoundation -weak_library %t/libfoo.dylib -o %t/test +# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s -DDIR=%t + +# CHECK: cmd LC_LOAD_WEAK_DYLIB +# CHECK-NEXT: cmdsize +# CHECK-NEXT: name /usr/lib/libSystem.B.dylib + +# CHECK: cmd LC_LOAD_WEAK_DYLIB +# CHECK-NEXT: cmdsize +# CHECK-NEXT: name /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation + +# CHECK: cmd LC_LOAD_WEAK_DYLIB +# CHECK-NEXT: cmdsize +# CHECK-NEXT: name [[DIR]]/libfoo.dylib + +#--- foo.s +.globl _foo +_foo: + ret + +#--- test.s +.globl _main +.text +_main: + ret