2017-11-02 05:16:06 +08:00
|
|
|
//===- dsymutil.cpp - Debug info dumping utility for llvm -----------------===//
|
2014-12-13 01:31:24 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This program is a utility that aims to be a dropin replacement for
|
|
|
|
// Darwin's dsymutil.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-10-31 21:54:15 +08:00
|
|
|
#include "dsymutil.h"
|
2014-12-13 01:31:24 +08:00
|
|
|
#include "DebugMap.h"
|
2015-08-06 02:27:44 +08:00
|
|
|
#include "MachOUtils.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
2015-08-06 06:33:28 +08:00
|
|
|
#include "llvm/Object/MachO.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2015-08-07 05:05:06 +08:00
|
|
|
#include "llvm/Support/FileSystem.h"
|
2014-12-13 01:31:24 +08:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2015-01-14 19:23:27 +08:00
|
|
|
#include "llvm/Support/PrettyStackTrace.h"
|
2014-12-13 01:31:24 +08:00
|
|
|
#include "llvm/Support/Signals.h"
|
2015-02-28 08:29:11 +08:00
|
|
|
#include "llvm/Support/TargetSelect.h"
|
2017-10-31 21:54:15 +08:00
|
|
|
#include "llvm/Support/ThreadPool.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-11-02 05:16:06 +08:00
|
|
|
#include "llvm/Support/thread.h"
|
|
|
|
#include <algorithm>
|
2015-10-09 23:04:05 +08:00
|
|
|
#include <cstdint>
|
2017-11-02 05:16:06 +08:00
|
|
|
#include <cstdlib>
|
2014-12-13 01:31:24 +08:00
|
|
|
#include <string>
|
2017-11-02 05:16:06 +08:00
|
|
|
#include <system_error>
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2017-11-16 04:55:53 +08:00
|
|
|
using namespace llvm;
|
2014-12-13 01:31:24 +08:00
|
|
|
using namespace llvm::cl;
|
2017-11-02 05:16:06 +08:00
|
|
|
using namespace llvm::dsymutil;
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2017-11-02 05:16:06 +08:00
|
|
|
static OptionCategory DsymCategory("Specific Options");
|
2015-07-30 06:29:46 +08:00
|
|
|
static opt<bool> Help("h", desc("Alias for -help"), Hidden);
|
2015-07-30 06:29:50 +08:00
|
|
|
static opt<bool> Version("v", desc("Alias for -version"), Hidden);
|
2015-07-30 06:29:46 +08:00
|
|
|
|
2015-08-01 04:22:20 +08:00
|
|
|
static list<std::string> InputFiles(Positional, OneOrMore,
|
|
|
|
desc("<input files>"), cat(DsymCategory));
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2015-06-04 00:57:07 +08:00
|
|
|
static opt<std::string>
|
|
|
|
OutputFileOpt("o",
|
|
|
|
desc("Specify the output file. default: <input file>.dwarf"),
|
2015-07-30 06:29:46 +08:00
|
|
|
value_desc("filename"), cat(DsymCategory));
|
2015-02-28 08:29:03 +08:00
|
|
|
|
2015-06-04 00:57:07 +08:00
|
|
|
static opt<std::string> OsoPrependPath(
|
|
|
|
"oso-prepend-path",
|
|
|
|
desc("Specify a directory to prepend to the paths of object files."),
|
2015-07-30 06:29:46 +08:00
|
|
|
value_desc("path"), cat(DsymCategory));
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2015-08-31 08:29:09 +08:00
|
|
|
static opt<bool> DumpStab(
|
|
|
|
"symtab",
|
|
|
|
desc("Dumps the symbol table found in executable or object file(s) and\n"
|
|
|
|
"exits."),
|
|
|
|
init(false), cat(DsymCategory));
|
|
|
|
static alias DumpStabA("s", desc("Alias for --symtab"), aliasopt(DumpStab));
|
|
|
|
|
2015-08-07 05:05:01 +08:00
|
|
|
static opt<bool> FlatOut("flat",
|
|
|
|
desc("Produce a flat dSYM file (not a bundle)."),
|
|
|
|
init(false), cat(DsymCategory));
|
|
|
|
static alias FlatOutA("f", desc("Alias for --flat"), aliasopt(FlatOut));
|
|
|
|
|
2017-11-02 01:15:29 +08:00
|
|
|
static opt<unsigned> NumThreads(
|
|
|
|
"num-threads",
|
2017-10-31 21:54:15 +08:00
|
|
|
desc("Specifies the maximum number (n) of simultaneous threads to use\n"
|
|
|
|
"when linking multiple architectures."),
|
|
|
|
value_desc("n"), init(0), cat(DsymCategory));
|
2017-11-02 01:15:29 +08:00
|
|
|
static alias NumThreadsA("j", desc("Alias for --num-threads"),
|
|
|
|
aliasopt(NumThreads));
|
2017-10-31 21:54:15 +08:00
|
|
|
|
2015-07-30 06:29:46 +08:00
|
|
|
static opt<bool> Verbose("verbose", desc("Verbosity level"), init(false),
|
|
|
|
cat(DsymCategory));
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2015-06-04 00:57:07 +08:00
|
|
|
static opt<bool>
|
|
|
|
NoOutput("no-output",
|
|
|
|
desc("Do the link in memory, but do not emit the result file."),
|
2015-07-30 06:29:46 +08:00
|
|
|
init(false), cat(DsymCategory));
|
2017-11-02 05:16:06 +08:00
|
|
|
|
2017-10-13 22:41:23 +08:00
|
|
|
static opt<bool>
|
|
|
|
NoTimestamp("no-swiftmodule-timestamp",
|
|
|
|
desc("Don't check timestamp for swiftmodule files."),
|
|
|
|
init(false), cat(DsymCategory));
|
2017-11-02 05:16:06 +08:00
|
|
|
|
2015-08-06 06:33:28 +08:00
|
|
|
static list<std::string> ArchFlags(
|
|
|
|
"arch",
|
|
|
|
desc("Link DWARF debug information only for specified CPU architecture\n"
|
|
|
|
"types. This option can be specified multiple times, once for each\n"
|
2017-11-03 02:44:54 +08:00
|
|
|
"desired architecture. All CPU architectures will be linked by\n"
|
|
|
|
"default."), value_desc("arch"),
|
2015-08-06 06:33:28 +08:00
|
|
|
ZeroOrMore, cat(DsymCategory));
|
|
|
|
|
2015-07-22 06:41:43 +08:00
|
|
|
static opt<bool>
|
|
|
|
NoODR("no-odr",
|
|
|
|
desc("Do not use ODR (One Definition Rule) for type uniquing."),
|
2015-07-30 06:29:46 +08:00
|
|
|
init(false), cat(DsymCategory));
|
2015-07-22 06:41:43 +08:00
|
|
|
|
2015-06-04 00:57:12 +08:00
|
|
|
static opt<bool> DumpDebugMap(
|
|
|
|
"dump-debug-map",
|
|
|
|
desc("Parse and dump the debug map to standard output. Not DWARF link "
|
|
|
|
"will take place."),
|
2015-07-30 06:29:46 +08:00
|
|
|
init(false), cat(DsymCategory));
|
2015-06-04 04:29:24 +08:00
|
|
|
|
|
|
|
static opt<bool> InputIsYAMLDebugMap(
|
|
|
|
"y", desc("Treat the input file is a YAML debug map rather than a binary."),
|
2015-07-30 06:29:46 +08:00
|
|
|
init(false), cat(DsymCategory));
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2015-08-07 05:05:06 +08:00
|
|
|
static bool createPlistFile(llvm::StringRef BundleRoot) {
|
|
|
|
if (NoOutput)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Create plist file to write to.
|
|
|
|
llvm::SmallString<128> InfoPlist(BundleRoot);
|
|
|
|
llvm::sys::path::append(InfoPlist, "Contents/Info.plist");
|
|
|
|
std::error_code EC;
|
|
|
|
llvm::raw_fd_ostream PL(InfoPlist, EC, llvm::sys::fs::F_Text);
|
|
|
|
if (EC) {
|
|
|
|
llvm::errs() << "error: cannot create plist file " << InfoPlist << ": "
|
|
|
|
<< EC.message() << '\n';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Use CoreFoundation to get executable bundle info. Use
|
|
|
|
// dummy values for now.
|
|
|
|
std::string bundleVersionStr = "1", bundleShortVersionStr = "1.0",
|
|
|
|
bundleIDStr;
|
|
|
|
|
|
|
|
llvm::StringRef BundleID = *llvm::sys::path::rbegin(BundleRoot);
|
|
|
|
if (llvm::sys::path::extension(BundleRoot) == ".dSYM")
|
|
|
|
bundleIDStr = llvm::sys::path::stem(BundleID);
|
|
|
|
else
|
|
|
|
bundleIDStr = BundleID;
|
|
|
|
|
|
|
|
// Print out information to the plist file.
|
|
|
|
PL << "<?xml version=\"1.0\" encoding=\"UTF-8\"\?>\n"
|
|
|
|
<< "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
|
|
|
|
<< "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
|
|
|
<< "<plist version=\"1.0\">\n"
|
|
|
|
<< "\t<dict>\n"
|
|
|
|
<< "\t\t<key>CFBundleDevelopmentRegion</key>\n"
|
|
|
|
<< "\t\t<string>English</string>\n"
|
|
|
|
<< "\t\t<key>CFBundleIdentifier</key>\n"
|
|
|
|
<< "\t\t<string>com.apple.xcode.dsym." << bundleIDStr << "</string>\n"
|
|
|
|
<< "\t\t<key>CFBundleInfoDictionaryVersion</key>\n"
|
|
|
|
<< "\t\t<string>6.0</string>\n"
|
|
|
|
<< "\t\t<key>CFBundlePackageType</key>\n"
|
|
|
|
<< "\t\t<string>dSYM</string>\n"
|
|
|
|
<< "\t\t<key>CFBundleSignature</key>\n"
|
|
|
|
<< "\t\t<string>\?\?\?\?</string>\n"
|
|
|
|
<< "\t\t<key>CFBundleShortVersionString</key>\n"
|
|
|
|
<< "\t\t<string>" << bundleShortVersionStr << "</string>\n"
|
|
|
|
<< "\t\t<key>CFBundleVersion</key>\n"
|
|
|
|
<< "\t\t<string>" << bundleVersionStr << "</string>\n"
|
|
|
|
<< "\t</dict>\n"
|
|
|
|
<< "</plist>\n";
|
|
|
|
|
|
|
|
PL.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool createBundleDir(llvm::StringRef BundleBase) {
|
|
|
|
if (NoOutput)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
llvm::SmallString<128> Bundle(BundleBase);
|
|
|
|
llvm::sys::path::append(Bundle, "Contents", "Resources", "DWARF");
|
|
|
|
if (std::error_code EC = create_directories(Bundle.str(), true,
|
|
|
|
llvm::sys::fs::perms::all_all)) {
|
|
|
|
llvm::errs() << "error: cannot create directory " << Bundle << ": "
|
|
|
|
<< EC.message() << "\n";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-11-18 01:33:09 +08:00
|
|
|
static std::string getOutputFileName(llvm::StringRef InputFile) {
|
2015-08-07 05:05:06 +08:00
|
|
|
if (FlatOut) {
|
|
|
|
// If a flat dSYM has been requested, things are pretty simple.
|
|
|
|
if (OutputFileOpt.empty()) {
|
|
|
|
if (InputFile == "-")
|
|
|
|
return "a.out.dwarf";
|
|
|
|
return (InputFile + ".dwarf").str();
|
|
|
|
}
|
|
|
|
|
|
|
|
return OutputFileOpt;
|
2015-08-06 02:27:34 +08:00
|
|
|
}
|
2015-08-07 05:05:06 +08:00
|
|
|
|
|
|
|
// We need to create/update a dSYM bundle.
|
|
|
|
// A bundle hierarchy looks like this:
|
|
|
|
// <bundle name>.dSYM/
|
|
|
|
// Contents/
|
|
|
|
// Info.plist
|
|
|
|
// Resources/
|
|
|
|
// DWARF/
|
|
|
|
// <DWARF file(s)>
|
|
|
|
std::string DwarfFile =
|
|
|
|
InputFile == "-" ? llvm::StringRef("a.out") : InputFile;
|
|
|
|
llvm::SmallString<128> BundleDir(OutputFileOpt);
|
|
|
|
if (BundleDir.empty())
|
|
|
|
BundleDir = DwarfFile + ".dSYM";
|
|
|
|
if (!createBundleDir(BundleDir) || !createPlistFile(BundleDir))
|
|
|
|
return "";
|
|
|
|
|
|
|
|
llvm::sys::path::append(BundleDir, "Contents", "Resources", "DWARF",
|
|
|
|
llvm::sys::path::filename(DwarfFile));
|
|
|
|
return BundleDir.str();
|
2015-08-06 02:27:34 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 01:33:09 +08:00
|
|
|
static Expected<sys::fs::TempFile> createTempFile() {
|
|
|
|
llvm::SmallString<128> TmpModel;
|
|
|
|
llvm::sys::path::system_temp_directory(true, TmpModel);
|
|
|
|
llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf");
|
|
|
|
return sys::fs::TempFile::create(TmpModel);
|
2015-08-06 02:27:38 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 01:33:09 +08:00
|
|
|
namespace {
|
|
|
|
struct TempFileVector {
|
|
|
|
std::vector<sys::fs::TempFile> Files;
|
|
|
|
~TempFileVector() {
|
|
|
|
for (sys::fs::TempFile &Tmp : Files) {
|
|
|
|
if (Error E = Tmp.discard())
|
|
|
|
errs() << toString(std::move(E));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
2014-12-13 01:31:24 +08:00
|
|
|
int main(int argc, char **argv) {
|
2016-06-09 08:53:21 +08:00
|
|
|
llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
|
2014-12-13 01:31:24 +08:00
|
|
|
llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
|
|
|
|
llvm::llvm_shutdown_obj Shutdown;
|
2015-02-28 08:29:07 +08:00
|
|
|
LinkOptions Options;
|
2017-11-18 01:33:09 +08:00
|
|
|
void *P = (void *)(intptr_t)getOutputFileName;
|
|
|
|
std::string SDKPath = llvm::sys::fs::getMainExecutable(argv[0], P);
|
2015-10-09 06:35:53 +08:00
|
|
|
SDKPath = llvm::sys::path::parent_path(SDKPath);
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2015-07-30 06:29:46 +08:00
|
|
|
HideUnrelatedOptions(DsymCategory);
|
|
|
|
llvm::cl::ParseCommandLineOptions(
|
|
|
|
argc, argv,
|
|
|
|
"manipulate archived DWARF debug symbol files.\n\n"
|
|
|
|
"dsymutil links the DWARF debug information found in the object files\n"
|
|
|
|
"for the executable <input file> by using debug symbols information\n"
|
|
|
|
"contained in its symbol table.\n");
|
|
|
|
|
2017-09-08 07:30:48 +08:00
|
|
|
if (Help) {
|
2015-07-30 06:29:46 +08:00
|
|
|
PrintHelpMessage();
|
2017-09-08 07:30:48 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-06-04 04:29:24 +08:00
|
|
|
|
2015-07-30 06:29:50 +08:00
|
|
|
if (Version) {
|
|
|
|
llvm::cl::PrintVersionMessage();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-02-28 08:29:07 +08:00
|
|
|
Options.Verbose = Verbose;
|
2015-02-28 08:29:11 +08:00
|
|
|
Options.NoOutput = NoOutput;
|
2015-07-22 06:41:43 +08:00
|
|
|
Options.NoODR = NoODR;
|
2017-10-13 22:41:23 +08:00
|
|
|
Options.NoTimestamp = NoTimestamp;
|
2015-09-23 02:51:01 +08:00
|
|
|
Options.PrependPath = OsoPrependPath;
|
2015-02-28 08:29:11 +08:00
|
|
|
|
|
|
|
llvm::InitializeAllTargetInfos();
|
|
|
|
llvm::InitializeAllTargetMCs();
|
|
|
|
llvm::InitializeAllTargets();
|
|
|
|
llvm::InitializeAllAsmPrinters();
|
2015-02-28 08:29:07 +08:00
|
|
|
|
2015-08-07 05:05:01 +08:00
|
|
|
if (!FlatOut && OutputFileOpt == "-") {
|
|
|
|
llvm::errs() << "error: cannot emit to standard output without --flat\n";
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) {
|
|
|
|
llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n";
|
2014-12-13 01:31:24 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-06 06:33:28 +08:00
|
|
|
for (const auto &Arch : ArchFlags)
|
|
|
|
if (Arch != "*" && Arch != "all" &&
|
|
|
|
!llvm::object::MachOObjectFile::isValidArch(Arch)) {
|
|
|
|
llvm::errs() << "error: Unsupported cpu architecture: '" << Arch << "'\n";
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2015-08-06 06:33:28 +08:00
|
|
|
}
|
|
|
|
|
2015-08-01 04:22:20 +08:00
|
|
|
for (auto &InputFile : InputFiles) {
|
2015-08-31 08:29:09 +08:00
|
|
|
// Dump the symbol table for each input file and requested arch
|
|
|
|
if (DumpStab) {
|
|
|
|
if (!dumpStab(InputFile, ArchFlags, OsoPrependPath))
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2015-08-31 08:29:09 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-08-06 06:33:28 +08:00
|
|
|
auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
|
|
|
|
Verbose, InputIsYAMLDebugMap);
|
2015-08-01 04:22:20 +08:00
|
|
|
|
2015-08-06 02:27:44 +08:00
|
|
|
if (auto EC = DebugMapPtrsOrErr.getError()) {
|
2015-08-01 04:22:20 +08:00
|
|
|
llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
|
|
|
|
<< "\": " << EC.message() << '\n';
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2015-08-01 04:22:20 +08:00
|
|
|
}
|
|
|
|
|
2015-08-06 06:33:28 +08:00
|
|
|
if (DebugMapPtrsOrErr->empty()) {
|
|
|
|
llvm::errs() << "error: no architecture to link\n";
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2015-08-06 06:33:28 +08:00
|
|
|
}
|
|
|
|
|
2017-11-02 01:15:29 +08:00
|
|
|
if (NumThreads == 0)
|
2017-10-31 21:54:15 +08:00
|
|
|
NumThreads = llvm::thread::hardware_concurrency();
|
|
|
|
if (DumpDebugMap || Verbose)
|
|
|
|
NumThreads = 1;
|
2017-11-02 01:15:29 +08:00
|
|
|
NumThreads = std::min<unsigned>(NumThreads, DebugMapPtrsOrErr->size());
|
2017-10-31 21:54:15 +08:00
|
|
|
|
|
|
|
|
2015-08-06 02:27:44 +08:00
|
|
|
// If there is more than one link to execute, we need to generate
|
|
|
|
// temporary files.
|
|
|
|
bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
|
|
|
|
llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
|
2017-11-18 01:33:09 +08:00
|
|
|
TempFileVector TempFileStore;
|
2015-08-06 02:27:44 +08:00
|
|
|
for (auto &Map : *DebugMapPtrsOrErr) {
|
|
|
|
if (Verbose || DumpDebugMap)
|
|
|
|
Map->print(llvm::outs());
|
|
|
|
|
|
|
|
if (DumpDebugMap)
|
|
|
|
continue;
|
2015-08-01 04:22:20 +08:00
|
|
|
|
2015-08-26 02:19:43 +08:00
|
|
|
if (Map->begin() == Map->end())
|
|
|
|
llvm::errs() << "warning: no debug symbols in executable (-arch "
|
2015-08-26 07:15:26 +08:00
|
|
|
<< MachOUtils::getArchName(Map->getTriple().getArchName())
|
|
|
|
<< ")\n";
|
2015-08-26 02:19:43 +08:00
|
|
|
|
2017-11-18 01:33:09 +08:00
|
|
|
std::string OutputFile = getOutputFileName(InputFile);
|
|
|
|
std::unique_ptr<raw_fd_ostream> OS;
|
|
|
|
if (NeedsTempFiles) {
|
|
|
|
Expected<sys::fs::TempFile> T = createTempFile();
|
|
|
|
if (!T) {
|
|
|
|
errs() << toString(T.takeError());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
OS = make_unique<raw_fd_ostream>(T->FD, /*shouldClose*/ false);
|
|
|
|
OutputFile = T->TmpName;
|
|
|
|
TempFileStore.Files.push_back(std::move(*T));
|
|
|
|
} else {
|
2017-11-16 04:55:53 +08:00
|
|
|
std::error_code EC;
|
2017-11-18 01:33:09 +08:00
|
|
|
OS = make_unique<raw_fd_ostream>(NoOutput ? "-" : OutputFile, EC,
|
|
|
|
sys::fs::F_None);
|
2017-11-16 04:55:53 +08:00
|
|
|
if (EC) {
|
|
|
|
errs() << OutputFile << ": " << EC.message();
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2017-11-16 04:55:53 +08:00
|
|
|
}
|
2017-11-18 01:33:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::atomic_char AllOK(1);
|
|
|
|
auto LinkLambda = [&]() {
|
|
|
|
AllOK.fetch_and(linkDwarf(*OS, *Map, Options));
|
2017-10-31 21:54:15 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME: The DwarfLinker can have some very deep recursion that can max
|
|
|
|
// out the (significantly smaller) stack when using threads. We don't
|
|
|
|
// want this limitation when we only have a single thread.
|
2017-11-03 04:22:03 +08:00
|
|
|
if (NumThreads == 1) {
|
2017-10-31 21:54:15 +08:00
|
|
|
LinkLambda();
|
2017-11-03 04:22:03 +08:00
|
|
|
} else {
|
|
|
|
llvm::ThreadPool Threads(NumThreads);
|
2017-10-31 21:54:15 +08:00
|
|
|
Threads.async(LinkLambda);
|
2017-11-03 04:22:03 +08:00
|
|
|
Threads.wait();
|
|
|
|
}
|
2017-11-18 01:33:09 +08:00
|
|
|
if (!AllOK)
|
|
|
|
return 1;
|
2015-08-01 04:22:20 +08:00
|
|
|
|
2015-08-06 02:27:44 +08:00
|
|
|
if (NeedsTempFiles)
|
|
|
|
TempFiles.emplace_back(Map->getTriple().getArchName().str(),
|
|
|
|
OutputFile);
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:54:15 +08:00
|
|
|
|
2015-08-06 02:27:44 +08:00
|
|
|
if (NeedsTempFiles &&
|
|
|
|
!MachOUtils::generateUniversalBinary(
|
2015-10-09 06:35:53 +08:00
|
|
|
TempFiles, getOutputFileName(InputFile), Options, SDKPath))
|
2017-11-18 01:33:09 +08:00
|
|
|
return 1;
|
2015-02-28 08:29:03 +08:00
|
|
|
}
|
2014-12-13 01:31:24 +08:00
|
|
|
|
2017-11-18 01:33:09 +08:00
|
|
|
return 0;
|
2014-12-13 01:31:24 +08:00
|
|
|
}
|