Index: lld/MachO/Driver.cpp =================================================================== --- lld/MachO/Driver.cpp +++ lld/MachO/Driver.cpp @@ -248,6 +248,7 @@ } static DenseMap loadedArchives; +static DenseSet commandLineInputs; static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive, bool isLazy = false, bool isExplicit = true, @@ -268,18 +269,39 @@ // loadArchiveMember() call below may recursively call addFile() and // invalidate this reference. auto entry = loadedArchives.find(path); - if (entry != loadedArchives.end()) + ArchiveFile::LoadScope currentScope; + if ((forceLoadArchive == ForceLoad::Default && config->allLoad) || + forceLoadArchive == ForceLoad::Yes) { + currentScope = ArchiveFile::LoadScope::AllLoad; + } else if (forceLoadArchive == ForceLoad::Default && + config->forceLoadObjC) { + currentScope = ArchiveFile::LoadScope::ObjCLoad; + } else { + currentScope = ArchiveFile::LoadScope::LazyLoad; + } + + ArchiveFile *file; + if (entry != loadedArchives.end() && + entry->second->loadScope >= currentScope) { + // Load scope is not enlarged, so we can use the cached archive return entry->second; + } - std::unique_ptr archive = CHECK( - object::Archive::create(mbref), path + ": failed to parse archive"); + if (entry == loadedArchives.end()) { + // No cached archive, we need to create a new one + std::unique_ptr archive = CHECK( + object::Archive::create(mbref), path + ": failed to parse archive"); - if (!archive->isEmpty() && !archive->hasSymbolTable()) - error(path + ": archive has no index; run ranlib to add one"); + if (!archive->isEmpty() && !archive->hasSymbolTable()) + error(path + ": archive has no index; run ranlib to add one"); + file = make(std::move(archive)); + } else { + // Load scope enlarged, we need to load more symbols by fetching members + file = entry->second; + } + file->loadScope = currentScope; - auto *file = make(std::move(archive)); - if ((forceLoadArchive == ForceLoad::Default && config->allLoad) || - forceLoadArchive == ForceLoad::Yes) { + if (currentScope == ArchiveFile::LoadScope::AllLoad) { if (Optional buffer = readFile(path)) { Error e = Error::success(); for (const object::Archive::Child &c : file->getArchive().children(e)) { @@ -293,8 +315,7 @@ error(toString(file) + ": Archive::children failed: " + toString(std::move(e))); } - } else if (forceLoadArchive == ForceLoad::Default && - config->forceLoadObjC) { + } else if (currentScope == ArchiveFile::LoadScope::ObjCLoad) { for (const object::Archive::Symbol &sym : file->getArchive().symbols()) if (sym.getName().startswith(objc::klass)) file->fetch(sym); @@ -976,6 +997,7 @@ switch (opt.getID()) { case OPT_INPUT: + commandLineInputs.insert(rerootPath(arg->getValue())); addFile(rerootPath(arg->getValue()), ForceLoad::Default, isLazy); break; case OPT_needed_library: @@ -999,7 +1021,9 @@ addFileList(arg->getValue(), isLazy); break; case OPT_force_load: - addFile(rerootPath(arg->getValue()), ForceLoad::Yes); + // Do not force-load archives that are already loaded from command line + if (!commandLineInputs.contains(rerootPath(arg->getValue()))) + addFile(rerootPath(arg->getValue()), ForceLoad::Yes); break; case OPT_l: case OPT_needed_l: Index: lld/MachO/InputFiles.h =================================================================== --- lld/MachO/InputFiles.h +++ lld/MachO/InputFiles.h @@ -266,6 +266,13 @@ const llvm::object::Archive &getArchive() const { return *file; }; static bool classof(const InputFile *f) { return f->kind() == ArchiveKind; } + enum class LoadScope { + LazyLoad = 0, + ObjCLoad = 1, + AllLoad = 2, + }; + LoadScope loadScope; + private: std::unique_ptr file; // Keep track of children fetched from the archive by tracking Index: lld/test/MachO/lc-linker-option.ll =================================================================== --- lld/test/MachO/lc-linker-option.ll +++ lld/test/MachO/lc-linker-option.ll @@ -77,6 +77,39 @@ ; SYMS-NEXT: g F __TEXT,__text __mh_execute_header ; SYMS-EMPTY: +;; Make sure -all_load has effect when libraries are loaded via LC_LINKER_OPTION flags and explicitly passed as well +; RUN: %lld -all_load %t/load-framework-foo.o %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -lfoo +; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS_ALL_LOAD + +;; Note that _OBJC_CLASS_$_TestClass is *included* here. +; SYMS_ALL_LOAD: SYMBOL TABLE: +; SYMS_ALL_LOAD-NEXT: g F __TEXT,__text _main +; SYMS_ALL_LOAD-NEXT: g O __DATA,__objc_data _OBJC_CLASS_$_TestClass +; SYMS_ALL_LOAD-NEXT: g F __TEXT,__text __mh_execute_header +; SYMS_ALL_LOAD-EMPTY: + +;; Make sure -force_load has effect when libraries are loaded via LC_LINKER_OPTION flags and explicitly passed as well +; RUN: %lld %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -force_load %t/libfoo.a +; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS_FORCE_LOAD + +;; Note that _OBJC_CLASS_$_TestClass is *included* here. +; SYMS_FORCE_LOAD: SYMBOL TABLE: +; SYMS_FORCE_LOAD-NEXT: g F __TEXT,__text _main +; SYMS_FORCE_LOAD-NEXT: g O __DATA,__objc_data _OBJC_CLASS_$_TestClass +; SYMS_FORCE_LOAD-NEXT: g F __TEXT,__text __mh_execute_header +; SYMS_FORCE_LOAD-EMPTY: + +;; Make sure -ObjC has effect when frameworks are loaded via LC_LINKER_OPTION flags and explicitly passed as well +; RUN: %lld -ObjC %t/load-framework-foo.o %t/load-library-foo.o %t/main.o -o %t/main -F%t -L%t -framework Foo +; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS_OBJC_LOAD + +;; Note that _OBJC_CLASS_$_TestClass is *included* here. +; SYMS_OBJC_LOAD: SYMBOL TABLE: +; SYMS_OBJC_LOAD-NEXT: g F __TEXT,__text _main +; SYMS_OBJC_LOAD-NEXT: g O __DATA,__objc_data _OBJC_CLASS_$_TestClass +; SYMS_OBJC_LOAD-NEXT: g F __TEXT,__text __mh_execute_header +; SYMS_OBJC_LOAD-EMPTY: + ;; Make sure that frameworks containing object files or bitcode instead of ;; dylibs or archives do not cause duplicate symbol errors ; RUN: mkdir -p %t/Foo.framework