diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -174,6 +174,10 @@ // exist. This allows users to ignore the specific invalid options in the case // they can't easily fix them. llvm::StringSet<> ignoreAutoLinkOptions; + // This is the more relaxed option to ignore all framework not found errors. + // In some cases, it's not practical to find and list all the framework names + // with --ignore-auto-link-options. + bool ignoreAutoLinkErrors = false; PlatformInfo platformInfo; std::optional secondaryPlatformInfo; NamespaceKind namespaceKind = NamespaceKind::twolevel; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -428,6 +428,7 @@ } static DenseSet loadedObjectFrameworks; +static DenseSet missingAutolinkFrameworks; static void addFramework(StringRef name, bool isNeeded, bool isWeak, bool isReexport, bool isExplicit, LoadType loadType) { if (std::optional path = findFramework(name)) { @@ -456,6 +457,10 @@ } return; } + if (loadType == LoadType::LCLinkerOption && config->ignoreAutoLinkErrors) { + missingAutolinkFrameworks.insert(name); + return; + } error("framework not found for -framework " + name); } @@ -1348,6 +1353,7 @@ inputSections.clear(); loadedArchives.clear(); loadedObjectFrameworks.clear(); + missingAutolinkFrameworks.clear(); syntheticSections.clear(); thunkMap.clear(); @@ -1569,6 +1575,8 @@ for (const Arg *arg : args.filtered(OPT_ignore_auto_link_option)) config->ignoreAutoLinkOptions.insert(arg->getValue()); + config->ignoreAutoLinkErrors = args.hasArg(OPT_ignore_auto_link_errors); + for (const Arg *arg : args.filtered(OPT_alias)) { config->aliasedSymbols.push_back( std::make_pair(arg->getValue(0), arg->getValue(1))); @@ -1882,5 +1890,11 @@ timeTraceProfilerCleanup(); } - return errorCount() == 0; + + bool hasErrors = errorCount() != 0; + if (hasErrors) + for (const auto &framework : missingAutolinkFrameworks) + warn("framework not found for -framework " + framework); + + return !hasErrors; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -101,6 +101,9 @@ Alias(ignore_auto_link_option)>, HelpText<"Ignore a single auto-linked library or framework. Useful to ignore invalid options that ld64 ignores">, Group; +def ignore_auto_link_errors : Flag<["--"], "ignore-auto-link-errors">, + HelpText<"Ignore framework or library not found errors if they are loaded via LC_LINKER_OPTIONS">, + Group; // This is a complete Options.td compiled from Apple's ld(1) manpage // dated 2018-03-07 and cross checked with ld64 source code in repo 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 @@ -64,6 +64,7 @@ ;; that this test can run on Windows. ; RUN: llvm-ar rcs %t/Foo.framework/Foo %t/foo.o ; RUN: llc %t/load-framework-foo.ll -o %t/load-framework-foo.o -filetype=obj +; RUN: llc %t/load-framework-undefined-symbol.ll -o %t/load-framework-undefined-symbol.o -filetype=obj ; RUN: llc %t/main.ll -o %t/main.o -filetype=obj ; RUN: %lld %t/load-framework-foo.o %t/main.o -o %t/main -F%t ; RUN: llvm-objdump --macho --syms %t/main | FileCheck %s --check-prefix=SYMS @@ -134,6 +135,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 not found" errors from LC_LINKER_OPTIONS are not emitted when +;; -ignore-auto-link-errors is set. +; RUN: %lld --ignore-auto-link-errors -ObjC %t/load-framework-foo.o %t/main.o -o %t/main-no-foo.out +; RUN: llvm-objdump --macho --syms %t/main-no-foo.out | FileCheck %s --check-prefix=SYMS_NO_FOO +; RUN: not %lld --ignore-auto-link-errors -ObjC %t/load-framework-undefined-symbol.o %t/main.o -o %t/main-no-foo.out 2>&1 \ +; RUN: | FileCheck %s --check-prefix=MISSING_FRAMEWORK + +;; 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 + +; MISSING_FRAMEWORK: undefined symbol: __SomeUndefinedSymbol +; MISSING_FRAMEWORK: framework not found for -framework Foo + ;--- 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" @@ -184,6 +200,19 @@ !0 = !{!"-framework", !"Foo"} !llvm.linker.options = !{!0} +;--- load-framework-undefined-symbol.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" + +declare void @_SomeUndefinedSymbol(...) +define void @foo() { + call void @_SomeUndefinedSymbol() + ret void +} + +!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"