diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -121,9 +121,17 @@ uint32_t dylibCurrentVersion = 0; uint32_t timeTraceGranularity = 500; std::string progName; + + // For `clang -arch arm64 -arch x86_64`, clang will: + // 1. invoke the linker twice, to write one temporary output per arch + // 2. invoke `lipo` to merge the two outputs into a single file + // `outputFile` is the name of the temporary file the linker writes to. + // `finalOutput `is the name of the file lipo writes to after the link. + llvm::StringRef outputFile; + llvm::StringRef finalOutput; + llvm::StringRef installName; llvm::StringRef mapFile; - llvm::StringRef outputFile; llvm::StringRef ltoObjPath; llvm::StringRef thinLTOJobs; llvm::StringRef umbrella; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1106,6 +1106,10 @@ config->mapFile = args.getLastArgValue(OPT_map); config->outputFile = args.getLastArgValue(OPT_o, "a.out"); + if (const Arg *arg = args.getLastArg(OPT_final_output)) + config->finalOutput = arg->getValue(); + else + config->finalOutput = config->outputFile; config->astPaths = args.getAllArgValues(OPT_add_ast_path); config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32); config->headerPadMaxInstallNames = @@ -1169,7 +1173,7 @@ else config->installName = arg->getValue(); } else if (config->outputType == MH_DYLIB) { - config->installName = config->outputFile; + config->installName = config->finalOutput; } if (args.hasArg(OPT_mark_dead_strippable_dylib)) { diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp --- a/lld/MachO/InputFiles.cpp +++ b/lld/MachO/InputFiles.cpp @@ -867,6 +867,7 @@ path.consume_front("@executable_path/")) { // ld64 allows overriding this with the undocumented flag -executable_path. // lld doesn't currently implement that flag. + // FIXME: Consider using finalOutput instead of outputFile. path::append(newPath, path::parent_path(config->outputFile), path); path = newPath; } else if (path.consume_front("@loader_path/")) { diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -873,8 +873,7 @@ Group; def final_output : Separate<["-"], "final_output">, MetaVarName<"">, - HelpText<"Specify the dylib install name if -install_name is not used--used by compiler driver for multiple -arch arguments">, - Flags<[HelpHidden]>, + HelpText<"Specify dylib install name if -install_name is not used; used by compiler driver for multiple -arch arguments">, Group; def arch_multiple : Flag<["-"], "arch_multiple">, HelpText<"Augment error and warning messages with the architecture name">, diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1044,6 +1044,7 @@ CodeSignatureSection::CodeSignatureSection() : LinkEditSection(segment_names::linkEdit, section_names::codeSignature) { align = 16; // required by libstuff + // FIXME: Consider using finalOutput instead of outputFile. fileName = config->outputFile; size_t slashIndex = fileName.rfind("/"); if (slashIndex != std::string::npos) diff --git a/lld/test/MachO/final-output.s b/lld/test/MachO/final-output.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/final-output.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t.o %s + +## -final_output sets the default for -install_name, but an explicit +## -install_name wins +# RUN: %lld -dylib -o %t.dylib -final_output /lib/foo.dylib %t.o +# RUN: llvm-otool -D %t.dylib | FileCheck -DID=/lib/foo.dylib %s + +# RUN: %lld -dylib -o %t.dylib -install_name /foo/bar.dylib \ +# RUN: -final_output /lib/foo.dylib %t.o +# RUN: llvm-otool -D %t.dylib | FileCheck -DID=/foo/bar.dylib %s + +# CHECK: [[ID]] + +.globl __Z3foo +__Z3foo: + ret