diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -170,7 +170,8 @@ bool errorForArchMismatch = false; bool ignoreAutoLink = false; // ld64 allows invalid auto link options as long as the link succeeds. LLD - // does not, but there are cases in the wild where the invalid linker options + // does not. Instead, it emits warnings on missing frameworks/libraries. + // But there are cases in the wild where the invalid linker options // exist. This allows users to ignore the specific invalid options in the case // they can't easily fix them. llvm::StringSet<> ignoreAutoLinkOptions; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -408,7 +408,7 @@ static void addLibrary(StringRef name, bool isNeeded, bool isWeak, bool isReexport, bool isHidden, bool isExplicit, - LoadType loadType) { + LoadType loadType, InputFile *refLoc = nullptr) { if (std::optional path = findLibrary(name)) { if (auto *dylibFile = dyn_cast_or_null( addFile(*path, loadType, /*isLazy=*/false, isExplicit, @@ -424,12 +424,23 @@ } return; } - error("library not found for -l" + name); + + // We only emit a warning rather than an errors to make it easier + // for new users with existing bad LC_LINKER_OPTIONs to migrate to LLD. + // This is deliberately different from LD64's approach, which is that it'd + // swallow the errors if the link succeeds, because we'd like to be able + // to identify these bad LC_LINKER_OPTIONs and fix them. + if (loadType == LoadType::LCLinkerOption) + warn((refLoc == nullptr ? "" : toString(refLoc) + ": ") + + "library not found for -l" + name + ", from LC_LINKER_OPTION"); + else + error("library not found for -l" + name); } static DenseSet loadedObjectFrameworks; static void addFramework(StringRef name, bool isNeeded, bool isWeak, - bool isReexport, bool isExplicit, LoadType loadType) { + bool isReexport, bool isExplicit, LoadType loadType, + InputFile *refLoc = nullptr) { if (std::optional path = findFramework(name)) { if (loadedObjectFrameworks.contains(*path)) return; @@ -456,7 +467,12 @@ } return; } - error("framework not found for -framework " + name); + if (loadType == LoadType::LCLinkerOption) + warn((refLoc == nullptr ? "" : toString(refLoc) + ": ") + + "framework not found for -framework " + name + + ", from LC_LINKER_OPTION "); + else + error("framework not found for -framework " + name); } // Parses LC_LINKER_OPTION contents, which can add additional command line @@ -482,14 +498,14 @@ return; addLibrary(arg, /*isNeeded=*/false, /*isWeak=*/false, /*isReexport=*/false, /*isHidden=*/false, /*isExplicit=*/false, - LoadType::LCLinkerOption); + LoadType::LCLinkerOption, f); } else if (arg == "-framework") { StringRef name = argv[++i]; if (config->ignoreAutoLinkOptions.contains(name)) return; addFramework(name, /*isNeeded=*/false, /*isWeak=*/false, /*isReexport=*/false, /*isExplicit=*/false, - LoadType::LCLinkerOption); + LoadType::LCLinkerOption, f); } else { error(arg + " is not allowed in LC_LINKER_OPTION"); } 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 @@ -134,6 +134,21 @@ ; 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 +;; Checks that "framework/library not found" from LC_LINKER_OPTIONS are reported +;; as warnings and not errors. +; RUN: %no-fatal-warnings-lld -ObjC %t/load-framework-foo.o %t/main.o -o %t/main-no-foo.out 2>&1 | FileCheck %s --check-prefix=WARN-FW +; RUN: %no-fatal-warnings-lld -dylib -ObjC %t/load-library-foo.o -o %t/no-lib-foo.out 2>&1 | FileCheck %s --check-prefix=WARN-LIB + +; RUN: llvm-objdump --macho --syms %t/main-no-foo.out | FileCheck %s --check-prefix=SYMS_NO_FOO + +; WARN-FW: warning: {{.+}}load-framework-foo.o: framework not found for -framework Foo, from LC_LINKER_OPTION +; WARN-LIB:warning: {{.+}}load-library-foo.o: library not found for -lfoo, from LC_LINKER_OPTION + +;; Verify that nothing from the framework is included. +; SYMS_NO_FOO: SYMBOL TABLE: +; SYMS_NO_FOO-NEXT: g F __TEXT,__text _main +; SYMS_NO_FOO-NOT: g O __DATA,__objc_data _OBJC_CLASS_$_TestClass + ;--- 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"