diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -30,7 +30,6 @@ llvm::MachO::Architecture arch; llvm::MachO::HeaderFileType outputType; std::vector librarySearchPaths; - // TODO: use the framework search paths std::vector frameworkSearchPaths; llvm::DenseMap priorities; }; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -30,6 +30,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -98,6 +99,32 @@ return {}; } +static Optional findFramework(StringRef name) { + // TODO: support .tbd files + llvm::SmallString<260> symlink; + llvm::SmallString<260> location; + StringRef suffix; + std::tie(name, suffix) = name.split(","); + for (StringRef dir : config->frameworkSearchPaths) { + symlink = dir; + path::append(symlink, name + ".framework", name); + // If the symlink fails to resolve, skip to the next search path. + // NOTE: we must resolve the symlink before trying the suffixes, because + // there are no symlinks for the suffixed paths. + if (fs::real_path(symlink, location)) + continue; + if (!suffix.empty()) { + llvm::Twine suffixed = location + suffix; + if (fs::exists(suffixed)) + return suffixed.str(); + // Suffix lookup failed, fall through to the no-suffix case. + } + if (fs::exists(location)) + return location.str().str(); + } + return {}; +} + static TargetInfo *createTargetInfo(opt::InputArgList &args) { StringRef arch = args.getLastArgValue(OPT_arch, "x86_64"); config->arch = llvm::MachO::getArchitectureFromName( @@ -393,13 +420,24 @@ error("library not found for -l" + name); break; } + case OPT_framework: { + StringRef name = arg->getValue(); + if (Optional path = findFramework(name)) { + addFile(*path); + break; + } + error("framework not found for -framework " + name); + break; + } case OPT_platform_version: handlePlatformVersion(arg); break; case OPT_o: case OPT_dylib: case OPT_e: + case OPT_F: case OPT_L: + case OPT_install_name: case OPT_Z: case OPT_arch: // handled elsewhere diff --git a/lld/test/MachO/framework.s b/lld/test/MachO/framework.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/framework.s @@ -0,0 +1,29 @@ +# REQUIRES: x86, shell +# RUN: mkdir -p %t +# RUN: echo ".globl _foo; _foo: ret" | llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/foo.o +# RUN: mkdir -p %t/Foo.framework/Versions/A +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -dylib -install_name %t/Foo.framework/Versions/A/Foo %t/foo.o -o %t/Foo.framework/Versions/A/Foo +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -dylib -install_name %t/Foo.framework/Versions/A/Foobar %t/foo.o -o %t/Foo.framework/Versions/A/Foobar +# RUN: ln -sf %t/Foo.framework/Versions/A %t/Foo.framework/Versions/Current +# RUN: ln -sf %t/Foo.framework/Versions/Current/Foo %t/Foo.framework/Foo + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin -o %t/test.o %s +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -F%t -framework Foo %t/test.o -o %t/test +# RUN: llvm-objdump --macho --lazy-bind %t/test | FileCheck %s --check-prefix=NOSUFFIX +# NOSUFFIX: __DATA __la_symbol_ptr 0x{{[0-9a-f]*}} {{.*}}Foo _foo + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -F%t -framework Foo,baz %t/test.o -o %t/test-wrong-suffix +# RUN: llvm-objdump --macho --lazy-bind %t/test-wrong-suffix | FileCheck %s --check-prefix=NOSUFFIX + +# RUN: lld -flavor darwinnew -L%S/Inputs/MacOSX.sdk/usr/lib -lSystem -F%t -framework Foo,bar %t/test.o -o %t/test-suffix +# RUN: llvm-objdump --macho --lazy-bind %t/test-suffix | FileCheck %s --check-prefix=SUFFIX +# SUFFIX: __DATA __la_symbol_ptr 0x{{[0-9a-f]*}} {{.*}}Foobar _foo + +.globl _main +.text +_main: + sub $8, %rsp # 16-byte-align the stack; dylld -flavor darwinnew checks for this + callq _foo + mov $0, %rax + add $8, %rsp + ret