diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -237,11 +237,12 @@ return v; } -static void addFile(StringRef path) { +static InputFile *addFile(StringRef path) { Optional buffer = readFile(path); if (!buffer) - return; + return nullptr; MemoryBufferRef mbref = *buffer; + InputFile *newFile = nullptr; switch (identify_magic(mbref.getBuffer())) { case file_magic::archive: { @@ -270,25 +271,27 @@ inputFiles.push_back(make(member)); } - inputFiles.push_back(make(std::move(file))); + newFile = make(std::move(file)); break; } case file_magic::macho_object: - inputFiles.push_back(make(mbref)); + newFile = make(mbref); break; case file_magic::macho_dynamically_linked_shared_lib: - inputFiles.push_back(make(mbref)); + newFile = make(mbref); break; case file_magic::tapi_file: { Optional dylibFile = makeDylibFromTAPI(mbref); if (!dylibFile) - return; - inputFiles.push_back(*dylibFile); + return nullptr; + newFile = *dylibFile; break; } default: error(path + ": unhandled file type"); } + inputFiles.push_back(newFile); + return newFile; } static void addFileList(StringRef path) { @@ -596,29 +599,41 @@ warnIfDeprecatedOption(opt); warnIfUnimplementedOption(opt); // TODO: are any of these better handled via filtered() or getLastArg()? - switch (arg->getOption().getID()) { + switch (opt.getID()) { case OPT_INPUT: addFile(arg->getValue()); break; + case OPT_weak_library: { + auto *dylibFile = dyn_cast_or_null(addFile(arg->getValue())); + if (dylibFile != nullptr) + dylibFile->forceWeakImport = true; + 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); + auto *dylibFile = dyn_cast_or_null(addFile(*path)); + if (opt.getID() == OPT_weak_l && dylibFile != nullptr) + dylibFile->forceWeakImport = true; 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); + auto *dylibFile = dyn_cast_or_null(addFile(*path)); + if (opt.getID() == OPT_weak_framework && dylibFile != nullptr) + dylibFile->forceWeakImport = true; break; } error("framework not found for -framework " + name); diff --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h --- a/lld/MachO/InputFiles.h +++ b/lld/MachO/InputFiles.h @@ -107,6 +107,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 @@ -64,12 +64,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<"">, @@ -115,7 +113,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 @@ -376,8 +376,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