diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -126,6 +126,7 @@ llvm::StringRef outputFile; llvm::StringRef ltoObjPath; llvm::StringRef thinLTOJobs; + llvm::StringRef umbrella; uint32_t ltoo = 2; bool deadStripDylibs = false; bool demangle = false; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1121,6 +1121,11 @@ addFile(arg->getValue(), /*forceLoadArchive=*/false, /*isExplicit=*/false, /*isBundleLoader=*/true); } + if (const Arg *arg = args.getLastArg(OPT_umbrella)) { + if (config->outputType != MH_DYLIB) + warn("-umbrella used, but not creating dylib"); + config->umbrella = arg->getValue(); + } config->ltoObjPath = args.getLastArgValue(OPT_object_path_lto); config->ltoNewPassManager = args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager, diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -780,9 +780,8 @@ Flags<[HelpHidden]>, Group; def umbrella : Separate<["-"], "umbrella">, - MetaVarName<"<>">, - HelpText<"Re-export this dylib through the umbrella framework a">, - Flags<[HelpHidden]>, + MetaVarName<"">, + HelpText<"Re-export this dylib through the umbrella framework ">, Group; def headerpad : Separate<["-"], "headerpad">, MetaVarName<"">, diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -128,6 +128,31 @@ ExportSection *exportSection; }; +class LCSubFramework final : public LoadCommand { +public: + LCSubFramework(StringRef umbrella) : umbrella(umbrella) {} + + uint32_t getSize() const override { + return alignTo(sizeof(sub_framework_command) + umbrella.size() + 1, + target->wordSize); + } + + void writeTo(uint8_t *buf) const override { + auto *c = reinterpret_cast(buf); + buf += sizeof(sub_framework_command); + + c->cmd = LC_SUB_FRAMEWORK; + c->cmdsize = getSize(); + c->umbrella = sizeof(sub_framework_command); + + memcpy(buf, umbrella.data(), umbrella.size()); + buf[umbrella.size()] = '\0'; + } + +private: + const StringRef umbrella; +}; + class LCFunctionStarts final : public LoadCommand { public: explicit LCFunctionStarts(FunctionStartsSection *functionStartsSection) @@ -665,6 +690,8 @@ in.header->addLoadCommand(make(symtabSection, stringTableSection)); in.header->addLoadCommand( make(symtabSection, indirectSymtabSection)); + if (!config->umbrella.empty()) + in.header->addLoadCommand(make(config->umbrella)); if (functionStartsSection) in.header->addLoadCommand(make(functionStartsSection)); if (dataInCodeSection) diff --git a/lld/test/MachO/umbrella.s b/lld/test/MachO/umbrella.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/umbrella.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t.o %s +# RUN: %lld -dylib -o %t.dylib -umbrella umbrella.dylib %t.o +# RUN: llvm-otool -lv %t.dylib | FileCheck %s + +# RUN: %no_fatal_warnings_lld -bundle -o %t.so -umbrella umbrella.dylib %t.o \ +# RUN: 2>&1 | FileCheck --check-prefix=WARN %s +# WARN: warning: -umbrella used, but not creating dylib +# RUN: llvm-otool -lv %t.so | FileCheck %s + +# CHECK: cmd LC_SUB_FRAMEWORK +# CHECK-NEXT: cmdsize 32 +# CHECK-NEXT: umbrella umbrella.dylib (offset 12) + +.globl __Z3foo +__Z3foo: + ret