diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -43,8 +43,8 @@ // Check for both libfoo.dylib and libfoo.tbd (in that order). llvm::Optional resolveDylibPath(llvm::StringRef path); -llvm::Optional makeDylibFromTAPI(llvm::MemoryBufferRef mbref, - DylibFile *umbrella = nullptr); +llvm::Optional loadDylib(llvm::MemoryBufferRef mbref, + DylibFile *umbrella = nullptr); uint32_t getModTime(llvm::StringRef path); diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -309,10 +309,8 @@ break; case file_magic::macho_dynamically_linked_shared_lib: case file_magic::macho_dynamically_linked_shared_lib_stub: - newFile = make(mbref); - break; case file_magic::tapi_file: { - if (Optional dylibFile = makeDylibFromTAPI(mbref)) + if (Optional dylibFile = loadDylib(mbref)) newFile = *dylibFile; break; } diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -14,6 +14,7 @@ #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Reproduce.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" @@ -166,7 +167,7 @@ return {}; } -Optional macho::makeDylibFromTAPI(MemoryBufferRef mbref, +static Optional makeDylibFromTapi(MemoryBufferRef mbref, DylibFile *umbrella) { Expected> result = TextAPIReader::get(mbref); if (!result) { @@ -177,6 +178,24 @@ return make(**result, umbrella); } +static StringSet<> loadedDylibs; + +Optional macho::loadDylib(MemoryBufferRef mbref, + DylibFile *umbrella) { + StringRef path = mbref.getBufferIdentifier(); + if (loadedDylibs.contains(path)) + return {}; + loadedDylibs.insert(path); + + file_magic magic = identify_magic(mbref.getBuffer()); + if (magic == file_magic::tapi_file) + return makeDylibFromTapi(mbref, umbrella); + + assert(magic == file_magic::macho_dynamically_linked_shared_lib || + magic == file_magic::macho_dynamically_linked_shared_lib_stub); + return make(mbref, umbrella); +} + uint32_t macho::getModTime(StringRef path) { fs::file_status stat; if (!fs::status(path, stat)) diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -457,12 +457,7 @@ error("could not read dylib file at " + path); return {}; } - - file_magic magic = identify_magic(mbref->getBuffer()); - if (magic == file_magic::tapi_file) - return makeDylibFromTAPI(*mbref, umbrella); - assert(magic == file_magic::macho_dynamically_linked_shared_lib); - return make(*mbref, umbrella); + return loadDylib(*mbref, umbrella); } // TBD files are parsed into a series of TAPI documents (InterfaceFiles), with diff --git a/lld/test/MachO/implicit-dylibs.s b/lld/test/MachO/implicit-dylibs.s --- a/lld/test/MachO/implicit-dylibs.s +++ b/lld/test/MachO/implicit-dylibs.s @@ -50,6 +50,11 @@ # LOAD-NEXT: cmdsize # LOAD-NEXT: name [[DIR]]/libreexporter.dylib +## Check that we don't create duplicate LC_LOAD_DYLIBs. +# RUN: %lld -syslibroot %t -o %t/test -lSystem -L%t -lreexporter -ltoplevel %t/test.o +# RUN: llvm-objdump --macho --all-headers %t/test | FileCheck %s \ +# RUN: --check-prefix=LOAD -DDIR=%t --implicit-check-not LC_LOAD_DYLIB + # RUN: %lld -no_implicit_dylibs -syslibroot %t -o %t/no-implicit -lSystem -L%t -lreexporter %t/test.o # RUN: llvm-objdump --bind --no-show-raw-insn -d %t/no-implicit | FileCheck %s --check-prefix=NO-IMPLICIT # NO-IMPLICIT: Bind table: