Index: lld/MachO/Driver.h =================================================================== --- lld/MachO/Driver.h +++ lld/MachO/Driver.h @@ -52,7 +52,7 @@ std::string createResponseFile(const llvm::opt::InputArgList &args); // Check for both libfoo.dylib and libfoo.tbd (in that order). -llvm::Optional resolveDylibPath(llvm::StringRef path); +llvm::Optional resolveDylibPath(llvm::StringRef path); DylibFile *loadDylib(llvm::MemoryBufferRef mbref, DylibFile *umbrella = nullptr, bool isBundleLoader = false); Index: lld/MachO/Driver.cpp =================================================================== --- lld/MachO/Driver.cpp +++ lld/MachO/Driver.cpp @@ -92,7 +92,7 @@ {".tbd", ".dylib", ".a"}); } -static Optional findFramework(StringRef name) { +static Optional findFramework(StringRef name) { SmallString<260> symlink; StringRef suffix; std::tie(name, suffix) = name.split(","); @@ -108,12 +108,12 @@ // only append suffix if realpath() succeeds Twine suffixed = location + suffix; if (fs::exists(suffixed)) - return suffixed.str(); + return saver.save(suffixed.str()); } // Suffix lookup failed, fall through to the no-suffix case. } - if (Optional path = resolveDylibPath(symlink)) + if (Optional path = resolveDylibPath(saver.save(symlink.str()))) return path; } return {}; @@ -351,7 +351,7 @@ static void addFramework(StringRef name, bool isNeeded, bool isWeak, bool isReexport, bool isExplicit) { - if (Optional path = findFramework(name)) { + if (Optional path = findFramework(name)) { if (auto *dylibFile = dyn_cast_or_null( addFile(*path, /*forceLoadArchive=*/false, isExplicit))) { if (isNeeded) Index: lld/MachO/DriverUtils.cpp =================================================================== --- lld/MachO/DriverUtils.cpp +++ lld/MachO/DriverUtils.cpp @@ -183,7 +183,7 @@ depTracker->logFileNotFound(path); } -Optional macho::resolveDylibPath(StringRef dylibPath) { +Optional macho::resolveDylibPath(StringRef dylibPath) { // TODO: if a tbd and dylib are both present, we should check to make sure // they are consistent. SmallString<261> tbdPath = dylibPath; @@ -191,12 +191,12 @@ bool tbdExists = fs::exists(tbdPath); searchedDylib(tbdPath, tbdExists); if (tbdExists) - return std::string(tbdPath); + return saver.save(tbdPath.str()); bool dylibExists = fs::exists(dylibPath); searchedDylib(dylibPath, dylibExists); if (dylibExists) - return std::string(dylibPath); + return dylibPath; return {}; } Index: lld/MachO/InputFiles.cpp =================================================================== --- lld/MachO/InputFiles.cpp +++ lld/MachO/InputFiles.cpp @@ -902,7 +902,8 @@ for (StringRef dir : config->frameworkSearchPaths) { SmallString<128> candidate = dir; path::append(candidate, frameworkName); - if (Optional dylibPath = resolveDylibPath(candidate)) + if (Optional dylibPath = + resolveDylibPath(saver.save(candidate.str()))) return loadDylib(*dylibPath, umbrella); } } else if (Optional dylibPath = findPathCombination( @@ -913,8 +914,8 @@ // 2. As absolute path. if (path::is_absolute(path, path::Style::posix)) for (StringRef root : config->systemLibraryRoots) - if (Optional dylibPath = - resolveDylibPath((root + path).str())) + if (Optional dylibPath = + resolveDylibPath(saver.save((root + path).str()))) return loadDylib(*dylibPath, umbrella); // 3. As relative path. @@ -943,7 +944,8 @@ path::remove_filename(newPath); } path::append(newPath, rpath, path.drop_front(strlen("@rpath/"))); - if (Optional dylibPath = resolveDylibPath(newPath)) + if (Optional dylibPath = + resolveDylibPath(saver.save(newPath.str()))) return loadDylib(*dylibPath, umbrella); } } @@ -961,7 +963,7 @@ } } - if (Optional dylibPath = resolveDylibPath(path)) + if (Optional dylibPath = resolveDylibPath(path)) return loadDylib(*dylibPath, umbrella); return nullptr; Index: lld/test/MachO/lc-linker-option.ll =================================================================== --- lld/test/MachO/lc-linker-option.ll +++ lld/test/MachO/lc-linker-option.ll @@ -48,6 +48,16 @@ ; RUN: not %lld %t/invalid.o -o /dev/null 2>&1 | FileCheck --check-prefix=INVALID %s ; INVALID: error: -why_load is not allowed in LC_LINKER_OPTION +; RUN: llc %t/foo.ll -o %t/foo.o -filetype=obj +; RUN: mkdir -p %t/foo.framework/Versions/A +; RUN: llvm-ar rcs %t/foo.framework/Versions/A/foo %t/foo.o +; RUN: ln -sf A %t/foo.framework/Versions/Current +; RUN: ln -sf Versions/Current/foo %t/foo.framework/foo +; RUN: llc %t/objfile1.ll -o %t/objfile1.o -filetype=obj +; RUN: llc %t/objfile2.ll -o %t/objfile2.o -filetype=obj +; RUN: llc %t/main.ll -o %t/main.o -filetype=obj +; RUN: %lld -demangle -ObjC %t/objfile1.o %t/objfile2.o %t/main.o -o %t/main.out -arch x86_64 -platform_version macos 11.0.0 0.0.0 -F%t + ;--- 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" @@ -90,3 +100,57 @@ define void @main() { ret void } + +;--- objfile1.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} + +;--- objfile2.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} + +;--- main.ll +; Function Attrs: noinline norecurse nounwind optnone ssp uwtable mustprogress +define dso_local i32 @main() #0 { + %1 = alloca i32, align 4 + store i32 0, i32* %1, align 4 + ret i32 0 +} + +;--- foo.ll +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +%0 = type opaque +%struct._class_t = type { %struct._class_t*, %struct._class_t*, i8* (i8*, i8*)**, %struct._class_ro_t* } +%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* } +%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] } +%struct._objc_method = type { i8*, i8*, i8* } +%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] } +%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8*, %struct._prop_list_t* } +%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] } +%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 } +%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] } +%struct._prop_t = type { i8*, i8* } + +@"OBJC_CLASS_$_TestClass" = global %struct._class_t { %struct._class_t* @"OBJC_METACLASS_$_TestClass", %struct._class_t* null, i8* (i8*, i8*)** null, %struct._class_ro_t* @"_OBJC_CLASS_RO_$_TestClass" }, section "__DATA, __objc_data", align 8 +@"OBJC_METACLASS_$_TestClass" = global %struct._class_t { %struct._class_t* @"OBJC_METACLASS_$_TestClass", %struct._class_t* @"OBJC_CLASS_$_TestClass", i8* (i8*, i8*)** null, %struct._class_ro_t* @"_OBJC_METACLASS_RO_$_TestClass" }, section "__DATA, __objc_data", align 8 +@OBJC_CLASS_NAME_ = private unnamed_addr constant [10 x i8] c"TestClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1 +@"_OBJC_METACLASS_RO_$_TestClass" = internal global %struct._class_ro_t { i32 131, i32 40, i32 40, i8* null, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), %struct.__method_list_t* null, %struct._objc_protocol_list* null, %struct._ivar_list_t* null, i8* null, %struct._prop_list_t* null }, section "__DATA, __objc_const", align 8 +@OBJC_METH_VAR_NAME_ = private unnamed_addr constant [14 x i8] c"ExampleMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +@OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1 +@"_OBJC_$_INSTANCE_METHODS_TestClass" = internal global { i32, i32, [1 x %struct._objc_method] } { i32 24, i32 1, [1 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast (void (%0*, i8*)* @"\01-[TestClass ExampleMethod]" to i8*) }] }, section "__DATA, __objc_const", align 8 +@"_OBJC_CLASS_RO_$_TestClass" = internal global %struct._class_ro_t { i32 130, i32 0, i32 0, i8* null, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), %struct.__method_list_t* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"_OBJC_$_INSTANCE_METHODS_TestClass" to %struct.__method_list_t*), %struct._objc_protocol_list* null, %struct._ivar_list_t* null, i8* null, %struct._prop_list_t* null }, section "__DATA, __objc_const", align 8 +@"OBJC_LABEL_CLASS_$" = private global [1 x i8*] [i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_TestClass" to i8*)], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8 +@llvm.compiler.used = appending global [5 x i8*] [i8* getelementptr inbounds ([10 x i8], [10 x i8]* @OBJC_CLASS_NAME_, i32 0, i32 0), i8* bitcast ([1 x i8*]* @"OBJC_LABEL_CLASS_$" to i8*), i8* getelementptr inbounds ([14 x i8], [14 x i8]* @OBJC_METH_VAR_NAME_, i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @OBJC_METH_VAR_TYPE_, i32 0, i32 0), i8* bitcast ({ i32, i32, [1 x %struct._objc_method] }* @"_OBJC_$_INSTANCE_METHODS_TestClass" to i8*)], section "llvm.metadata" + +; Function Attrs: norecurse nounwind optsize readnone ssp uwtable +define internal void @"\01-[TestClass ExampleMethod]"(%0* nocapture %0, i8* nocapture %1) #0 { + ret void +} \ No newline at end of file