|  | //===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===// | 
|  | // | 
|  | //                             The LLVM Linker | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "lld/Driver/Driver.h" | 
|  | #include "lld/Core/Instrumentation.h" | 
|  | #include "lld/Core/LLVM.h" | 
|  | #include "lld/Core/Parallel.h" | 
|  | #include "lld/Core/PassManager.h" | 
|  | #include "lld/Core/Resolver.h" | 
|  | #include "lld/Passes/RoundTripNativePass.h" | 
|  | #include "lld/Passes/RoundTripYAMLPass.h" | 
|  | #include "lld/ReaderWriter/Reader.h" | 
|  | #include "lld/ReaderWriter/Writer.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/Option/Arg.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/Path.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include <mutex> | 
|  |  | 
|  | namespace lld { | 
|  |  | 
|  | /// This is where the link is actually performed. | 
|  | bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) { | 
|  | // Honor -mllvm | 
|  | if (!context.llvmOptions().empty()) { | 
|  | unsigned numArgs = context.llvmOptions().size(); | 
|  | const char **args = new const char *[numArgs + 2]; | 
|  | args[0] = "lld (LLVM option parsing)"; | 
|  | for (unsigned i = 0; i != numArgs; ++i) | 
|  | args[i + 1] = context.llvmOptions()[i]; | 
|  | args[numArgs + 1] = 0; | 
|  | llvm::cl::ParseCommandLineOptions(numArgs + 1, args); | 
|  | } | 
|  | InputGraph &inputGraph = context.getInputGraph(); | 
|  | if (!inputGraph.size()) | 
|  | return false; | 
|  | inputGraph.normalize(); | 
|  |  | 
|  | bool fail = false; | 
|  |  | 
|  | // Read inputs | 
|  | ScopedTask readTask(getDefaultDomain(), "Read Args"); | 
|  | TaskGroup tg; | 
|  | std::mutex diagnosticsMutex; | 
|  | for (std::unique_ptr<InputElement> &ie : inputGraph.inputElements()) { | 
|  | tg.spawn([&] { | 
|  | // Writes to the same output stream is not guaranteed to be thread-safe. | 
|  | // We buffer the diagnostics output to a separate string-backed output | 
|  | // stream, acquire the lock, and then print it out. | 
|  | std::string buf; | 
|  | llvm::raw_string_ostream stream(buf); | 
|  |  | 
|  | if (std::error_code ec = ie->parse(context, stream)) { | 
|  | if (FileNode *fileNode = dyn_cast<FileNode>(ie.get())) | 
|  | stream << fileNode->errStr(ec) << "\n"; | 
|  | else if (dyn_cast<Group>(ie.get())) | 
|  | // FIXME: We need a better diagnostics here | 
|  | stream << "Cannot parse group input element\n"; | 
|  | else | 
|  | llvm_unreachable("Unknown type of input element"); | 
|  | fail = true; | 
|  | } | 
|  |  | 
|  | stream.flush(); | 
|  | if (!buf.empty()) { | 
|  | std::lock_guard<std::mutex> lock(diagnosticsMutex); | 
|  | diagnostics << buf; | 
|  | } | 
|  | }); | 
|  | } | 
|  | tg.sync(); | 
|  | readTask.end(); | 
|  |  | 
|  | if (fail) | 
|  | return false; | 
|  |  | 
|  | std::unique_ptr<SimpleFileNode> fileNode( | 
|  | new SimpleFileNode("Internal Files")); | 
|  |  | 
|  | InputGraph::FileVectorT internalFiles; | 
|  | context.createInternalFiles(internalFiles); | 
|  |  | 
|  | if (internalFiles.size()) | 
|  | fileNode->addFiles(std::move(internalFiles)); | 
|  |  | 
|  | // Give target a chance to add files. | 
|  | InputGraph::FileVectorT implicitFiles; | 
|  | context.createImplicitFiles(implicitFiles); | 
|  | if (implicitFiles.size()) | 
|  | fileNode->addFiles(std::move(implicitFiles)); | 
|  | context.getInputGraph().addInputElementFront(std::move(fileNode)); | 
|  |  | 
|  | // Do core linking. | 
|  | ScopedTask resolveTask(getDefaultDomain(), "Resolve"); | 
|  | Resolver resolver(context); | 
|  | if (!resolver.resolve()) | 
|  | return false; | 
|  | std::unique_ptr<MutableFile> merged = resolver.resultFile(); | 
|  | resolveTask.end(); | 
|  |  | 
|  | // Run passes on linked atoms. | 
|  | ScopedTask passTask(getDefaultDomain(), "Passes"); | 
|  | PassManager pm; | 
|  | context.addPasses(pm); | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | if (context.runRoundTripPass()) { | 
|  | pm.add(std::unique_ptr<Pass>(new RoundTripYAMLPass(context))); | 
|  | pm.add(std::unique_ptr<Pass>(new RoundTripNativePass(context))); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | pm.runOnFile(merged); | 
|  | passTask.end(); | 
|  |  | 
|  | // Give linked atoms to Writer to generate output file. | 
|  | ScopedTask writeTask(getDefaultDomain(), "Write"); | 
|  | if (std::error_code ec = context.writeFile(*merged)) { | 
|  | diagnostics << "Failed to write file '" << context.outputPath() | 
|  | << "': " << ec.message() << "\n"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | } // namespace |