diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -388,12 +388,31 @@ error("library not found for -l" + name); } +static DenseSet loadedContainerFrameworks; static void addFramework(StringRef name, bool isNeeded, bool isWeak, bool isReexport, bool isExplicit, ForceLoad forceLoadArchive) { if (Optional path = findFramework(name)) { - if (auto *dylibFile = dyn_cast_or_null( - addFile(*path, forceLoadArchive, /*isLazy=*/false, isExplicit))) { + Optional buffer = readFile(*path); + if (!buffer) + return; + + bool cacheLoad = false; + file_magic magic = identify_magic((*buffer).getBuffer()); + switch (magic) { + case file_magic::macho_object: + case file_magic::bitcode: + if (loadedContainerFrameworks.contains(*path)) + return; + cacheLoad = true; + break; + default: + break; + } + + InputFile *file = + addFile(*path, forceLoadArchive, /*isLazy=*/false, isExplicit); + if (auto *dylibFile = dyn_cast_or_null(file)) { if (isNeeded) dylibFile->forceNeeded = true; if (isWeak) @@ -403,6 +422,9 @@ dylibFile->reexport = true; } } + if (cacheLoad && file) { + loadedContainerFrameworks.insert(*path); + } return; } error("framework not found for -framework " + name); @@ -1069,6 +1091,7 @@ inputFiles.clear(); inputSections.clear(); loadedArchives.clear(); + loadedContainerFrameworks.clear(); syntheticSections.clear(); thunkMap.clear(); diff --git a/lld/test/MachO/lc-linker-option.ll b/lld/test/MachO/lc-linker-option.ll --- a/lld/test/MachO/lc-linker-option.ll +++ b/lld/test/MachO/lc-linker-option.ll @@ -77,6 +77,21 @@ ; SYMS-NEXT: g F __TEXT,__text __mh_execute_header ; SYMS-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 +; RUN: llc --filetype=obj %t/foo.ll -o %t/Foo.framework/Foo +; RUN: llc --filetype=obj %t/load-framework-twice.ll -o %t/main +; Order of the object with the LC_LINKER_OPTION vs -framework arg is important. +; RUN: %lld %t/main -F %t -framework Foo -framework Foo -o /dev/null +; RUN: %lld -F %t -framework Foo -framework Foo %t/main -o /dev/null + +; RUN: llvm-as %t/foo.ll -o %t/Foo.framework/Foo +; RUN: llvm-as %t/load-framework-twice.ll -o %t/main +; Order of the object with the LC_LINKER_OPTION vs -framework arg is important. +; RUN: %lld %t/main -F %t -framework Foo -framework Foo -o /dev/null +; RUN: %lld -F %t -framework Foo -framework Foo %t/main -o /dev/null + ;--- framework.ll target triple = "x86_64-apple-macosx10.15.0" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" @@ -127,6 +142,17 @@ !0 = !{!"-framework", !"Foo"} !llvm.linker.options = !{!0} +;--- load-framework-twice.ll +target triple = "x86_64-apple-macosx10.15.0" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +!0 = !{!"-framework", !"Foo"} +!llvm.linker.options = !{!0, !0} + +define void @main() { + ret void +} + ;--- load-library-foo.ll target triple = "x86_64-apple-macosx10.15.0" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"