diff options
Diffstat (limited to 'lld/lib/Driver')
-rw-r--r-- | lld/lib/Driver/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/Driver/CoreDriver.cpp | 145 | ||||
-rw-r--r-- | lld/lib/Driver/DarwinLdDriver.cpp | 108 | ||||
-rw-r--r-- | lld/lib/Driver/Driver.cpp | 22 | ||||
-rw-r--r-- | lld/lib/Driver/GnuLdDriver.cpp | 279 | ||||
-rw-r--r-- | lld/lib/Driver/InputGraph.cpp | 56 | ||||
-rw-r--r-- | lld/lib/Driver/LDOptions.td | 14 | ||||
-rw-r--r-- | lld/lib/Driver/WinLinkDriver.cpp | 463 |
8 files changed, 581 insertions, 507 deletions
diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt index 11d288809a1..bea845bf764 100644 --- a/lld/lib/Driver/CMakeLists.txt +++ b/lld/lib/Driver/CMakeLists.txt @@ -9,6 +9,7 @@ tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(DriverOptionsTableGen) add_lld_library(lldDriver + InputGraph.cpp CoreDriver.cpp DarwinLdDriver.cpp Driver.cpp diff --git a/lld/lib/Driver/CoreDriver.cpp b/lld/lib/Driver/CoreDriver.cpp index c0869b790f6..9e4ca1228e0 100644 --- a/lld/lib/Driver/CoreDriver.cpp +++ b/lld/lib/Driver/CoreDriver.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" +#include "lld/Driver/CoreInputGraph.h" #include "lld/ReaderWriter/CoreLinkingContext.h" #include "lld/ReaderWriter/Reader.h" @@ -61,103 +62,105 @@ public: CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; - - } // namespace anonymous namespace lld { +std::unique_ptr<lld::LinkerInput> +COREFileNode::createLinkerInput(const LinkingContext &info) { + return std::unique_ptr<LinkerInput>(new LinkerInput(path(info))); +} + bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) { CoreLinkingContext info; if (parse(argc, argv, info)) return true; - + return Driver::link(info); } -bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &info, +bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx, raw_ostream &diagnostics) { // Parse command line options using CoreOptions.td std::unique_ptr<llvm::opt::InputArgList> parsedArgs; CoreOptTable table; unsigned missingIndex; unsigned missingCount; - parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], - missingIndex, missingCount)); + parsedArgs.reset( + table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs->getArgString(missingIndex) - << "' expected " << missingCount << " argument(s).\n"; + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; return true; } - for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), - ie = parsedArgs->filtered_end(); it != ie; ++it) { - diagnostics << "warning: ignoring unknown argument: " - << (*it)->getAsString(*parsedArgs) << "\n"; - } - - // Copy mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - info.appendLLVMOption((*it)->getValue()); - } - - // Handle -e xxx - if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) - info.setEntrySymbolName(entry->getValue()); - - // Handle -o xxx - if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) - info.setOutputPath(outpath->getValue()); - else - info.setOutputPath("-"); - - // Handle --dead_strip - if (parsedArgs->getLastArg(OPT_dead_strip)) - info.setDeadStripping(true); - else - info.setDeadStripping(false); - - // Handle --keep-globals - if (parsedArgs->getLastArg(OPT_keep_globals)) - info.setGlobalsAreDeadStripRoots(true); - else - info.setGlobalsAreDeadStripRoots(false); - - // Handle --undefines-are-errors - if (parsedArgs->getLastArg(OPT_undefines_are_errors)) { - info.setPrintRemainingUndefines(true); - info.setAllowRemainingUndefines(false); - } - else { - info.setPrintRemainingUndefines(false); - info.setAllowRemainingUndefines(true); + std::unique_ptr<InputGraph> inputGraph(new InputGraph()); + + // Set default options + ctx.setOutputPath("-"); + ctx.setDeadStripping(false); + ctx.setGlobalsAreDeadStripRoots(false); + ctx.setPrintRemainingUndefines(false); + ctx.setAllowRemainingUndefines(true); + ctx.setSearchArchivesToOverrideTentativeDefinitions(false); + + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx.appendLLVMOption(inputArg->getValue()); + break; + + case OPT_entry: + ctx.setEntrySymbolName(inputArg->getValue()); + break; + + case OPT_output: + ctx.setOutputPath(inputArg->getValue()); + break; + + case OPT_dead_strip: + ctx.setDeadStripping(true); + break; + + case OPT_keep_globals: + ctx.setGlobalsAreDeadStripRoots(true); + break; + + case OPT_undefines_are_errors: + ctx.setPrintRemainingUndefines(true); + ctx.setAllowRemainingUndefines(false); + break; + + case OPT_commons_search_archives: + ctx.setSearchArchivesToOverrideTentativeDefinitions(true); + break; + + case OPT_add_pass: + ctx.addPassNamed(inputArg->getValue()); + break; + + case OPT_INPUT: { + inputGraph->addInputElement(std::unique_ptr<InputElement>( + new COREFileNode(ctx, inputArg->getValue()))); + } break; + + default: + break; + } } - // Handle --commons-search-archives - if (parsedArgs->getLastArg(OPT_commons_search_archives)) - info.setSearchArchivesToOverrideTentativeDefinitions(true); - else - info.setSearchArchivesToOverrideTentativeDefinitions(false); - - // Handle --add-pass xxx option - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_add_pass), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - info.addPassNamed((*it)->getValue()); + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; } - // Handle input files - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - info.appendInputFile((*it)->getValue()); - } - - return false; + ctx.setInputGraph(std::move(inputGraph)); + + // Validate the combination of options used. + return ctx.validate(diagnostics); } } // namespace lld diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp index 2e3d695d12f..90469d89731 100644 --- a/lld/lib/Driver/DarwinLdDriver.cpp +++ b/lld/lib/Driver/DarwinLdDriver.cpp @@ -14,9 +14,9 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" +#include "lld/Driver/DarwinInputGraph.h" #include "lld/ReaderWriter/MachOLinkingContext.h" -#include "../ReaderWriter/MachO/MachOFormat.hpp" - +#include "lld/ReaderWriter/MachOFormat.hpp" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" @@ -71,31 +71,35 @@ public: namespace lld { -bool DarwinLdDriver::linkMachO(int argc, const char *argv[], - raw_ostream &diagnostics) { - MachOLinkingContext info; - if (parse(argc, argv, info, diagnostics)) +std::unique_ptr<lld::LinkerInput> +MachOFileNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx))); +} + +bool DarwinLdDriver::linkMachO(int argc, const char *argv[], + raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (parse(argc, argv, ctx, diagnostics)) return true; - if ( info.doNothing() ) + if (ctx.doNothing()) return false; - - return link(info, diagnostics); + + return link(ctx, diagnostics); } bool DarwinLdDriver::parse(int argc, const char *argv[], - MachOLinkingContext &info, - raw_ostream &diagnostics) { + MachOLinkingContext &ctx, raw_ostream &diagnostics) { // Parse command line options using DarwinOptions.td std::unique_ptr<llvm::opt::InputArgList> parsedArgs; DarwinLdOptTable table; unsigned missingIndex; unsigned missingCount; - parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc], - missingIndex, missingCount)); + parsedArgs.reset( + table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs->getArgString(missingIndex) - << "' expected " << missingCount << " argument(s).\n"; + diagnostics << "error: missing arg value for '" + << parsedArgs->getArgString(missingIndex) << "' expected " + << missingCount << " argument(s).\n"; return true; } @@ -104,52 +108,52 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], diagnostics << "warning: ignoring unknown argument: " << (*it)->getAsString(*parsedArgs) << "\n"; } - + // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable, OPT_bundle, OPT_static, OPT_preload)) { switch (kind->getOption().getID()) { case OPT_dylib: - info.setOutputFileType(mach_o::MH_DYLIB); - info.setGlobalsAreDeadStripRoots(true); + ctx.setOutputFileType(mach_o::MH_DYLIB); + ctx.setGlobalsAreDeadStripRoots(true); break; case OPT_relocatable: - info.setPrintRemainingUndefines(false); - info.setAllowRemainingUndefines(true); - info.setOutputFileType(mach_o::MH_OBJECT); + ctx.setPrintRemainingUndefines(false); + ctx.setAllowRemainingUndefines(true); + ctx.setOutputFileType(mach_o::MH_OBJECT); break; case OPT_bundle: - info.setOutputFileType(mach_o::MH_BUNDLE); + ctx.setOutputFileType(mach_o::MH_BUNDLE); break; case OPT_static: - info.setOutputFileType(mach_o::MH_EXECUTE); + ctx.setOutputFileType(mach_o::MH_EXECUTE); break; case OPT_preload: - info.setOutputFileType(mach_o::MH_PRELOAD); + ctx.setOutputFileType(mach_o::MH_PRELOAD); break; } } - + // Handle -e xxx if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) - info.setEntrySymbolName(entry->getValue()); + ctx.setEntrySymbolName(entry->getValue()); // Handle -o xxx if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output)) - info.setOutputPath(outpath->getValue()); - + ctx.setOutputPath(outpath->getValue()); + // Handle -dead_strip if (parsedArgs->getLastArg(OPT_dead_strip)) - info.setDeadStripping(true); - + ctx.setDeadStripping(true); + // Handle -all_load if (parsedArgs->getLastArg(OPT_all_load)) - info.setForceLoadAllArchives(true); - + ctx.setForceLoadAllArchives(true); + // Handle -arch xxx if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) { - info.setArch(MachOLinkingContext::archFromName(archStr->getValue())); - if (info.arch() == MachOLinkingContext::arch_unknown) { + ctx.setArch(MachOLinkingContext::archFromName(archStr->getValue())); + if (ctx.arch() == MachOLinkingContext::arch_unknown) { diagnostics << "error: unknown arch named '" << archStr->getValue() << "'\n"; return true; @@ -163,20 +167,20 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], OPT_ios_simulator_version_min)) { switch (minOS->getOption().getID()) { case OPT_macosx_version_min: - if (info.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) { diagnostics << "error: malformed macosx_version_min value\n"; return true; } break; case OPT_ios_version_min: - if (info.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) { diagnostics << "error: malformed ios_version_min value\n"; return true; } break; case OPT_ios_simulator_version_min: - if (info.setOS(MachOLinkingContext::OS::iOS_simulator, - minOS->getValue())) { + if (ctx.setOS(MachOLinkingContext::OS::iOS_simulator, + minOS->getValue())) { diagnostics << "error: malformed ios_simulator_version_min value\n"; return true; } @@ -185,34 +189,32 @@ bool DarwinLdDriver::parse(int argc, const char *argv[], } else { // No min-os version on command line, check environment variables - } - + + std::unique_ptr<InputGraph> inputGraph(new InputGraph()); + // Handle input files for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), ie = parsedArgs->filtered_end(); it != ie; ++it) { - info.appendInputFile((*it)->getValue()); + inputGraph->addInputElement(std::unique_ptr<InputElement>( + new MachOFileNode(ctx, (*it)->getValue()))); } - - // Handle -help - if (parsedArgs->getLastArg(OPT_help)) { - table.PrintHelp(llvm::outs(), argv[0], "LLVM Darwin Linker", false); - // If only -help on command line, don't try to do any linking - if ( argc == 2 ) { - info.setDoNothing(true); - return false; - } + + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; } + ctx.setInputGraph(std::move(inputGraph)); + // Validate the combination of options used. - if (info.validate(diagnostics)) + if (ctx.validate(diagnostics)) return true; return false; } - } // namespace lld diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp index d76bbdd31d4..ae20f84c973 100644 --- a/lld/lib/Driver/Driver.cpp +++ b/lld/lib/Driver/Driver.cpp @@ -40,21 +40,31 @@ bool Driver::link(const LinkingContext &context, raw_ostream &diagnostics) { args[numArgs + 1] = 0; llvm::cl::ParseCommandLineOptions(numArgs + 1, args); } + InputGraph &inputGraph = context.inputGraph(); + if (!inputGraph.numFiles()) + return true; // Read inputs ScopedTask readTask(getDefaultDomain(), "Read Args"); - std::vector<std::vector<std::unique_ptr<File>> > files( - context.inputFiles().size()); + std::vector<std::vector<std::unique_ptr<File> > > files( + inputGraph.numFiles()); size_t index = 0; std::atomic<bool> fail(false); TaskGroup tg; - for (const auto &input : context.inputFiles()) { + std::vector<std::unique_ptr<LinkerInput> > linkerInputs; + for (auto &ie : inputGraph) { + if (ie->kind() == InputElement::Kind::File) { + FileNode *fileNode = (llvm::dyn_cast<FileNode>)(ie.get()); + linkerInputs.push_back(std::move(fileNode->createLinkerInput(context))); + } + } + for (const auto &input : linkerInputs) { if (context.logInputFiles()) - llvm::outs() << input.getPath() << "\n"; + llvm::outs() << input->getPath() << "\n"; tg.spawn([ &, index]{ - if (error_code ec = context.readFile(input.getPath(), files[index])) { - diagnostics << "Failed to read file: " << input.getPath() << ": " + if (error_code ec = context.readFile(input->getPath(), files[index])) { + diagnostics << "Failed to read file: " << input->getPath() << ": " << ec.message() << "\n"; fail = true; return; diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index 01c7c489b1a..96fa31905fc 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" +#include "lld/Driver/GnuLDInputGraph.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -71,10 +71,20 @@ public: } // namespace +std::unique_ptr<lld::LinkerInput> +ELFFileNode::createLinkerInput(const LinkingContext &ctx) { + std::unique_ptr<LinkerInput> inputFile(new LinkerInput(path(ctx))); + inputFile->setAsNeeded(_asNeeded); + inputFile->setForceLoad(_isWholeArchive); + return std::move(inputFile); +} +StringRef ELFFileNode::path(const LinkingContext &) const { + return _elfLinkingContext.searchLibrary(_path, _libraryPaths); +} bool GnuLdDriver::linkELF(int argc, const char *argv[], - raw_ostream &diagnostics) { + raw_ostream &diagnostics) { std::unique_ptr<ELFLinkingContext> options; bool error = parse(argc, argv, options, diagnostics); if (error) @@ -93,6 +103,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[], GnuLdOptTable table; unsigned missingIndex; unsigned missingCount; + parsedArgs.reset( table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount)); if (missingCount) { @@ -102,13 +113,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[], return true; } - for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN), - ie = parsedArgs->filtered_end(); it != ie; ++it) { - diagnostics << "warning: ignoring unknown argument: " << (*it)->getAsString( - *parsedArgs) - << "\n"; - } - // Handle --help if (parsedArgs->getLastArg(OPT_help)) { table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); @@ -121,154 +125,181 @@ bool GnuLdDriver::parse(int argc, const char *argv[], triple = llvm::Triple(trip->getValue()); else triple = getDefaultTarget(argv[0]); - std::unique_ptr<ELFLinkingContext> options(ELFLinkingContext::create(triple)); + std::unique_ptr<ELFLinkingContext> ctx(ELFLinkingContext::create(triple)); - if (!options) { + if (!ctx) { diagnostics << "unknown target triple\n"; return true; } - // Handle -e xxx - if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry)) - options->setEntrySymbolName(entry->getValue()); - - // Handle -emit-yaml - if (parsedArgs->getLastArg(OPT_emit_yaml)) - options->setOutputYAML(true); - - // Handle -o xxx - if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output)) - options->setOutputPath(output->getValue()); - else if (options->outputYAML()) - options->setOutputPath("-"); // yaml writes to stdout by default - else - options->setOutputPath("a.out"); - - // Handle -r, -shared, or -static - if (llvm::opt::Arg *kind = - parsedArgs->getLastArg(OPT_relocatable, OPT_shared, OPT_static)) { - switch (kind->getOption().getID()) { + std::unique_ptr<InputGraph> inputGraph(new InputGraph()); + std::stack<InputElement *> controlNodeStack; + + // Positional options for an Input File + std::vector<StringRef> searchPath; + bool isWholeArchive = false; + bool asNeeded = false; + bool _outputOptionSet = false; + + // Create a dynamic executable by default + ctx->setOutputFileType(llvm::ELF::ET_EXEC); + ctx->setIsStaticExecutable(false); + ctx->setAllowShlibUndefines(false); + ctx->setUseShlibUndefines(true); + + // Set the output file to be a.out + ctx->setOutputPath("a.out"); + + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx->appendLLVMOption(inputArg->getValue()); + break; case OPT_relocatable: - options->setOutputFileType(llvm::ELF::ET_REL); - options->setPrintRemainingUndefines(false); - options->setAllowRemainingUndefines(true); + ctx->setOutputFileType(llvm::ELF::ET_REL); + ctx->setPrintRemainingUndefines(false); + ctx->setAllowRemainingUndefines(true); + break; + case OPT_static: + ctx->setOutputFileType(llvm::ELF::ET_EXEC); + ctx->setIsStaticExecutable(true); break; case OPT_shared: - options->setOutputFileType(llvm::ELF::ET_DYN); - options->setAllowShlibUndefines(true); - options->setUseShlibUndefines(false); + ctx->setOutputFileType(llvm::ELF::ET_DYN); + ctx->setAllowShlibUndefines(true); + ctx->setUseShlibUndefines(false); break; - case OPT_static: - options->setOutputFileType(llvm::ELF::ET_EXEC); - options->setIsStaticExecutable(true); + case OPT_entry: + ctx->setEntrySymbolName(inputArg->getValue()); break; - } - } else { - options->setOutputFileType(llvm::ELF::ET_EXEC); - options->setIsStaticExecutable(false); - options->setAllowShlibUndefines(false); - options->setUseShlibUndefines(true); - } - - // Handle --noinhibit-exec - if (parsedArgs->getLastArg(OPT_noinhibit_exec)) - options->setAllowRemainingUndefines(true); - // Handle --force-load - if (parsedArgs->getLastArg(OPT_force_load)) - options->setForceLoadAllArchives(true); + case OPT_output: + _outputOptionSet = true; + ctx->setOutputPath(inputArg->getValue()); + break; - // Handle --merge-strings - if (parsedArgs->getLastArg(OPT_merge_strings)) - options->setMergeCommonStrings(true); + case OPT_noinhibit_exec: + ctx->setAllowRemainingUndefines(true); + break; - // Handle -t - if (parsedArgs->getLastArg(OPT_t)) - options->setLogInputFiles(true); + case OPT_merge_strings: + ctx->setMergeCommonStrings(true); + break; - // Handle --no-allow-shlib-undefined - if (parsedArgs->getLastArg(OPT_no_allow_shlib_undefs)) - options->setAllowShlibUndefines(false); + case OPT_all_load: + ctx->setForceLoadAllArchives(true); + break; - // Handle --allow-shlib-undefined - if (parsedArgs->getLastArg(OPT_allow_shlib_undefs)) - options->setAllowShlibUndefines(true); + case OPT_t: + ctx->setLogInputFiles(true); + break; - // Handle --use-shlib-undefs - if (parsedArgs->getLastArg(OPT_use_shlib_undefs)) - options->setUseShlibUndefines(true); + case OPT_no_allow_shlib_undefs: + ctx->setAllowShlibUndefines(false); + break; - // Handle --dynamic-linker - if (llvm::opt::Arg *dynamicLinker = - parsedArgs->getLastArg(OPT_dynamic_linker)) - options->setInterpreter(dynamicLinker->getValue()); + case OPT_allow_shlib_undefs: + ctx->setAllowShlibUndefines(true); + break; - // Handle NMAGIC - if (parsedArgs->getLastArg(OPT_nmagic)) - options->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); + case OPT_use_shlib_undefs: + ctx->setUseShlibUndefines(true); + break; - // Handle OMAGIC - if (parsedArgs->getLastArg(OPT_omagic)) - options->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); + case OPT_dynamic_linker: + ctx->setInterpreter(inputArg->getValue()); + break; - // Handle --no-omagic - if (parsedArgs->getLastArg(OPT_no_omagic)) { - options->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); - options->setNoAllowDynamicLibraries(); - } + case OPT_nmagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC); + ctx->setIsStaticExecutable(true); + break; - // If either of the options NMAGIC/OMAGIC have been set, make the executable - // static - if (!options->allowLinkWithDynamicLibraries()) - options->setIsStaticExecutable(true); + case OPT_omagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC); + ctx->setIsStaticExecutable(true); + break; - // Handle -u, --undefined option - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_u), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->addInitialUndefinedSymbol((*it)->getValue()); - } + case OPT_no_omagic: + ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT); + ctx->setNoAllowDynamicLibraries(); + break; - // Handle -Lxxx - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->appendSearchPath((*it)->getValue()); - } + case OPT_u: + ctx->addInitialUndefinedSymbol(inputArg->getValue()); + break; - // Copy mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - options->appendLLVMOption((*it)->getValue()); - } + case OPT_emit_yaml: + if (!_outputOptionSet) + ctx->setOutputPath("-"); + ctx->setOutputYAML(true); + break; - // Handle input files (full paths and -lxxx) - for (llvm::opt::arg_iterator - it = parsedArgs->filtered_begin(OPT_INPUT, OPT_l), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - switch ((*it)->getOption().getID()) { - case OPT_INPUT: - options->appendInputFile((*it)->getValue()); + case OPT_no_whole_archive: + isWholeArchive = false; + break; + case OPT_whole_archive: + isWholeArchive = true; + break; + case OPT_as_needed: + asNeeded = true; break; - case OPT_l: - if (options->appendLibrary((*it)->getValue())) { - diagnostics << "Failed to find library for " << (*it)->getValue() - << "\n"; - return true; - } + case OPT_no_as_needed: + asNeeded = false; break; + case OPT_L: + searchPath.push_back(inputArg->getValue()); + break; + + case OPT_start_group: { + std::unique_ptr<InputElement> controlStart(new ELFGroup(*ctx)); + controlNodeStack.push(controlStart.get()); + (llvm::dyn_cast<ControlNode>)(controlNodeStack.top()) + ->processControlEnter(); + inputGraph->addInputElement(std::move(controlStart)); + } break; + + case OPT_end_group: + (llvm::dyn_cast<ControlNode>)(controlNodeStack.top()) + ->processControlExit(); + controlNodeStack.pop(); + return false; + + case OPT_INPUT: + case OPT_l: { + std::unique_ptr<InputElement> inputFile = + std::move(std::unique_ptr<InputElement>( + new ELFFileNode(*ctx, inputArg->getValue(), isWholeArchive, + asNeeded, searchPath))); + if (controlNodeStack.empty()) + inputGraph->addInputElement(std::move(inputFile)); + else + (llvm::dyn_cast<ControlNode>)(controlNodeStack.top()) + ->processInputElement(std::move(inputFile)); + } break; + default: - llvm_unreachable("input option type not handled"); - } + break; + } // end switch on option ID + } // end for + + if (!inputGraph->numFiles()) { + diagnostics << "No input files\n"; + return true; } + if (ctx->outputYAML()) + inputGraph->dump(diagnostics); + // Validate the combination of options used. - if (options->validate(diagnostics)) + if (ctx->validate(diagnostics)) return true; - context.swap(options); + ctx->setInputGraph(std::move(inputGraph)); + + context.swap(ctx); + return false; } diff --git a/lld/lib/Driver/InputGraph.cpp b/lld/lib/Driver/InputGraph.cpp new file mode 100644 index 00000000000..001cfed4e27 --- /dev/null +++ b/lld/lib/Driver/InputGraph.cpp @@ -0,0 +1,56 @@ +//===- lib/Driver/InputGraph.cpp ------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "lld/Driver/InputGraph.h" + +using namespace lld; + +namespace { +bool sortInputElements(const std::unique_ptr<InputElement> &a, + const std::unique_ptr<InputElement> &b) { + return a->getOrdinal() < b->getOrdinal(); +} +} + +bool InputGraph::addInputElement(std::unique_ptr<InputElement> ie) { + switch (ie->kind()) { + case InputElement::Kind::Control: + ++_numElements; + break; + case InputElement::Kind::File: + ++_numElements; + ++_numFiles; + break; + } + _inputArgs.push_back(std::move(ie)); + return true; +} + +bool InputGraph::assignOrdinals() { + for (auto &ie : _inputArgs) + ie->setOrdinal(++_ordinal); + return true; +} + +void InputGraph::doPostProcess() { + std::stable_sort(_inputArgs.begin(), _inputArgs.end(), sortInputElements); +} + +bool InputGraph::validate() { + for (auto &ie : _inputArgs) + if (!ie->validate()) + return false; + return true; +} + +bool InputGraph::dump(raw_ostream &diagnostics) { + for (auto &ie : _inputArgs) + if (!ie->dump(diagnostics)) + return false; + return true; +} diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td index e941d547c9b..8f5a87996df 100644 --- a/lld/lib/Driver/LDOptions.td +++ b/lld/lib/Driver/LDOptions.td @@ -80,8 +80,18 @@ def undefined : Separate<["--"], "undefined">, Alias<u>; def u_equal : Joined<["-"], "u=">, Alias<u>; def undefined_equal : Joined<["--"], "undefined=">, Alias<u>; +def as_needed : Flag<["--"], "as-needed">, + HelpText<"This option affects ELF DT_NEEDED tags for dynamic libraries mentioned on the command line">; +def no_as_needed : Flag<["--"], "no-as-needed">, + HelpText<"This option restores the default behavior of adding DT_NEEDED entries">; + // extensions def emit_yaml : Flag<["-"], "emit-yaml">, HelpText<"Write YAML instead of ELF">; -def force_load : Flag<["--"], "force-load">, - HelpText<"Force load of all members in all static libraries">; +def whole_archive: Flag<["--"], "whole-archive">, + HelpText<"Force load of all members in a static library">; +def no_whole_archive: Flag<["--"], "no-whole-archive">, + HelpText<"Restores the default behavior of loading archive members">; + +def all_load : Flag<["-"], "all_load">, + HelpText<"Forces all members of all static libraries to be loaded">; diff --git a/lld/lib/Driver/WinLinkDriver.cpp b/lld/lib/Driver/WinLinkDriver.cpp index 54dbe843292..d863aa73362 100644 --- a/lld/lib/Driver/WinLinkDriver.cpp +++ b/lld/lib/Driver/WinLinkDriver.cpp @@ -17,15 +17,16 @@ #include <sstream> #include <map> +#include "lld/Driver/Driver.h" +#include "lld/Driver/WinLinkInputGraph.h" +#include "lld/ReaderWriter/PECOFFLinkingContext.h" + #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/Arg.h" #include "llvm/Option/Option.h" #include "llvm/Support/Path.h" -#include "lld/Driver/Driver.h" -#include "lld/ReaderWriter/PECOFFLinkingContext.h" - namespace lld { namespace { @@ -62,135 +63,6 @@ public: WinLinkOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} }; -// Displays error message if the given version does not match with -// /^\d+$/. -bool checkNumber(StringRef version, const char *errorMessage, - raw_ostream &diagnostics) { - if (version.str().find_first_not_of("0123456789") != std::string::npos - || version.empty()) { - diagnostics << "error: " << errorMessage << version << "\n"; - return false; - } - return true; -} - -// Parse an argument for /base, /stack or /heap. The expected string -// is "<integer>[,<integer>]". -bool parseMemoryOption(const StringRef &arg, raw_ostream &diagnostics, - uint64_t &reserve, uint64_t &commit) { - StringRef reserveStr, commitStr; - llvm::tie(reserveStr, commitStr) = arg.split(','); - if (!checkNumber(reserveStr, "invalid size: ", diagnostics)) - return false; - reserve = atoi(reserveStr.str().c_str()); - if (!commitStr.empty()) { - if (!checkNumber(commitStr, "invalid size: ", diagnostics)) - return false; - commit = atoi(commitStr.str().c_str()); - } - return true; -} - -// Parse /base command line option. The argument for the parameter is in the -// form of "<address>[:<size>]". -bool parseBaseOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - // Size should be set to SizeOfImage field in the COFF header, and if it's - // smaller than the actual size, the linker should warn about that. Currently - // we just ignore the value of size parameter. - uint64_t addr, size; - if (!parseMemoryOption(arg, diagnostics, addr, size)) - return false; - // It's an error if the base address is not multiple of 64K. - if (addr & 0xffff) { - diagnostics << "Base address have to be multiple of 64K, but got " - << addr << "\n"; - return false; - } - context.setBaseAddress(addr); - return true; -} - -// Parse /stack command line option -bool parseStackOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - uint64_t reserve; - uint64_t commit = context.getStackCommit(); - if (!parseMemoryOption(arg, diagnostics, reserve, commit)) - return false; - context.setStackReserve(reserve); - context.setStackCommit(commit); - return true; -} - -// Parse /heap command line option. -bool parseHeapOption(PECOFFLinkingContext &context, const StringRef &arg, - raw_ostream &diagnostics) { - uint64_t reserve; - uint64_t commit = context.getHeapCommit(); - if (!parseMemoryOption(arg, diagnostics, reserve, commit)) - return false; - context.setHeapReserve(reserve); - context.setHeapCommit(commit); - return true; -} - -// Returns subsystem type for the given string. -llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) { - std::string arg(str.lower()); - return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(arg) - .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) - .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) - .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN); -} - -bool parseMinOSVersion(PECOFFLinkingContext &context, - const StringRef &osVersion, raw_ostream &diagnostics) { - StringRef majorVersion, minorVersion; - llvm::tie(majorVersion, minorVersion) = osVersion.split('.'); - if (minorVersion.empty()) - minorVersion = "0"; - if (!checkNumber(majorVersion, "invalid OS major version: ", diagnostics)) - return false; - if (!checkNumber(minorVersion, "invalid OS minor version: ", diagnostics)) - return false; - PECOFFLinkingContext::OSVersion minOSVersion( - atoi(majorVersion.str().c_str()), atoi(minorVersion.str().c_str())); - context.setMinOSVersion(minOSVersion); - return true; -} - -// Parse /subsystem command line option. The form of /subsystem is -// "subsystem_name[,majorOSVersion[.minorOSVersion]]". -bool parseSubsystemOption(PECOFFLinkingContext &context, std::string arg, - raw_ostream &diagnostics) { - StringRef subsystemStr, osVersionStr; - llvm::tie(subsystemStr, osVersionStr) = StringRef(arg).split(','); - - // Parse optional OS version if exists. - if (!osVersionStr.empty()) - if (!parseMinOSVersion(context, osVersionStr, diagnostics)) - return false; - - // Parse subsystem name. - llvm::COFF::WindowsSubsystem subsystem = stringToWinSubsystem(subsystemStr); - if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) { - diagnostics << "error: unknown subsystem name: " << subsystemStr << "\n"; - return false; - } - context.setSubsystem(subsystem); - return true; -} - -// Replace a file extension with ".exe". If the given file has no -// extension, just add ".exe". -StringRef getDefaultOutputFileName(PECOFFLinkingContext &context, - StringRef path) { - SmallString<128> smallStr = path; - llvm::sys::path::replace_extension(smallStr, ".exe"); - return context.allocateString(smallStr.str()); -} - // Split the given string with spaces. std::vector<std::string> splitArgList(std::string str) { std::stringstream stream(str); @@ -210,6 +82,26 @@ std::vector<StringRef> splitPathList(StringRef str) { return std::move(ret); } +// Parse an argument for /base, /stack or /heap. The expected string +// is "<integer>[,<integer>]". +bool parseMemoryOption(StringRef arg, uint64_t &reserve, uint64_t &commit) { + StringRef reserveStr, commitStr; + llvm::tie(reserveStr, commitStr) = arg.split(','); + if (reserveStr.getAsInteger(0, reserve)) + return true; + if (!commitStr.empty() && (commitStr.getAsInteger(0, commit))) + return true; + return false; +} + +// Returns subsystem type for the given string. +llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) { + return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower()) + .Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI) + .Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI) + .Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN); +} + // Handle /failifmatch option. bool handleFailIfMismatchOption(StringRef option, std::map<StringRef, StringRef> &mustMatch, @@ -218,26 +110,16 @@ bool handleFailIfMismatchOption(StringRef option, llvm::tie(key, value) = option.split('='); if (key.empty() || value.empty()) { diagnostics << "error: malformed /failifmatch option: " << option << "\n"; - return false; + return true; } auto it = mustMatch.find(key); if (it != mustMatch.end() && it->second != value) { diagnostics << "error: mismatch detected: '" << it->second << "' and '" << value << "' for key '" << key << "'\n"; - return false; + return true; } mustMatch[key] = value; - return true; -} - -// Add ".lib" extension if the path does not already have the extension to mimic -// link.exe behavior. -StringRef canonicalizeImportLibraryPath(PECOFFLinkingContext &context, - StringRef path) { - std::string s(path.lower()); - if (StringRef(s).endswith(".lib")) - return path; - return context.allocateString(std::string(path).append(".lib")); + return false; } // Process "LINK" environment variable. If defined, the value of the variable @@ -299,6 +181,29 @@ std::unique_ptr<llvm::opt::InputArgList> parseArgs(int argc, const char *argv[], } // namespace +std::unique_ptr<lld::LinkerInput> +PECOFFFileNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx))); +} + +std::unique_ptr<lld::LinkerInput> +PECOFFLibraryNode::createLinkerInput(const LinkingContext &ctx) { + return std::unique_ptr<LinkerInput>(new LinkerInput(path(ctx))); +} + +StringRef PECOFFFileNode::path(const LinkingContext &) const { + if (_path.endswith(".lib")) + return _ctx.searchLibraryFile(_path); + if (llvm::sys::path::extension(_path).empty()) + return (_path.str() + ".obj"); + return _path; +} + +StringRef PECOFFLibraryNode::path(const LinkingContext &) const { + if (!_path.endswith(".lib")) + return _ctx.searchLibraryFile(_path.str() + ".lib"); + return _ctx.searchLibraryFile(_path); +} bool WinLinkDriver::linkPECOFF(int argc, const char *argv[], raw_ostream &diagnostics) { @@ -311,14 +216,19 @@ bool WinLinkDriver::linkPECOFF(int argc, const char *argv[], } bool WinLinkDriver::parse(int argc, const char *argv[], - PECOFFLinkingContext &context, - raw_ostream &diagnostics) { + PECOFFLinkingContext &ctx, raw_ostream &diagnostics) { + std::map<StringRef, StringRef> failIfMismatchMap; // Parse the options. std::unique_ptr<llvm::opt::InputArgList> parsedArgs = parseArgs( argc, argv, diagnostics); if (!parsedArgs) return true; + if (!ctx.hasInputGraph()) + ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph())); + + InputGraph &inputGraph = ctx.inputGraph(); + // handle /help if (parsedArgs->getLastArg(OPT_help)) { WinLinkOptTable table; @@ -326,75 +236,6 @@ bool WinLinkDriver::parse(int argc, const char *argv[], return true; } - // Copy -mllvm - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.appendLLVMOption((*it)->getValue()); - } - - // handle /base - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_base)) - if (!parseBaseOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /stack - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_stack)) - if (!parseStackOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /heap - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_heap)) - if (!parseHeapOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /subsystem - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_subsystem)) - if (!parseSubsystemOption(context, arg->getValue(), diagnostics)) - return true; - - // handle /entry - if (llvm::opt::Arg *arg = parsedArgs->getLastArg(OPT_entry)) - context.setEntrySymbolName(arg->getValue()); - - // handle /libpath - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_libpath), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.appendInputSearchPath((*it)->getValue()); - } - - // handle /force - if (parsedArgs->getLastArg(OPT_force)) - context.setAllowRemainingUndefines(true); - - // handle /nxcompat:no - if (parsedArgs->getLastArg(OPT_no_nxcompat)) - context.setNxCompat(false); - - // handle /largeaddressaware - if (parsedArgs->getLastArg(OPT_largeaddressaware)) - context.setLargeAddressAware(true); - - // handle /fixed - if (parsedArgs->getLastArg(OPT_fixed)) - context.setBaseRelocationEnabled(false); - - // handle /tsaware:no - if (parsedArgs->getLastArg(OPT_no_tsaware)) - context.setTerminalServerAware(false); - - // handle /include - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_incl), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - context.addInitialUndefinedSymbol((*it)->getValue()); - } - - // handle /out - if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_out)) - context.setOutputPath(outpath->getValue()); - // handle /defaultlib std::vector<StringRef> defaultLibs; for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_defaultlib), @@ -403,29 +244,143 @@ bool WinLinkDriver::parse(int argc, const char *argv[], defaultLibs.push_back((*it)->getValue()); } - // Handle /failifmismatch. /failifmismatch is the hidden linker option behind - // the scenes of "detect_mismatch" pragma. If the compiler finds "#pragma - // detect_mismatch(name, value)", it outputs "/failifmismatch:name=value" to - // the .drectve section of the resultant object file. The linker raises an - // error if conflicting /failmismatch options are given. Conflicting options - // are the options with the same key but with different values. - // - // This feature is used to prevent inconsistent object files from linking. - std::map<StringRef, StringRef> mustMatch; - for (llvm::opt::arg_iterator - it = parsedArgs->filtered_begin(OPT_failifmismatch), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - if (!handleFailIfMismatchOption((*it)->getValue(), mustMatch, diagnostics)) - return true; - } - - // Add input files - std::vector<StringRef> inputPaths; - for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT), - ie = parsedArgs->filtered_end(); - it != ie; ++it) { - inputPaths.push_back((*it)->getValue()); + // Process all the arguments and create Input Elements + for (auto inputArg : *parsedArgs) { + switch (inputArg->getOption().getID()) { + case OPT_mllvm: + ctx.appendLLVMOption(inputArg->getValue()); + break; + + case OPT_base: + // Parse /base command line option. The argument for the parameter is in + // the + // form of "<address>[:<size>]". + uint64_t addr, size; + // Size should be set to SizeOfImage field in the COFF header, and if + // it's smaller than the actual size, the linker should warn about that. + // Currently we just ignore the value of size parameter. + if (parseMemoryOption(inputArg->getValue(), addr, size)) + return true; + // It's an error if the base address is not multiple of 64K. + // TODO: move this to validation of LinkingContext + if (addr & 0xffff) { + diagnostics << "Base address have to be multiple of 64K, but got " + << addr << "\n"; + return true; + } + ctx.setBaseAddress(addr); + break; + case OPT_stack: { + // Parse /stack command line option + uint64_t reserve; + uint64_t commit = ctx.getStackCommit(); + if (parseMemoryOption(inputArg->getValue(), reserve, commit)) + return true; + ctx.setStackReserve(reserve); + ctx.setStackCommit(commit); + } break; + case OPT_heap: { + // Parse /heap command line option + uint64_t reserve; + uint64_t commit = ctx.getHeapCommit(); + if (parseMemoryOption(inputArg->getValue(), reserve, commit)) + return true; + ctx.setHeapReserve(reserve); + ctx.setHeapCommit(commit); + } break; + case OPT_subsystem: { + // Parse /subsystem command line option. The form of /subsystem is + // "subsystem_name[,majorOSVersion[.minorOSVersion]]". + StringRef subsystemStr, osVersion; + llvm::tie(subsystemStr, osVersion) = + StringRef(inputArg->getValue()).split(','); + if (!osVersion.empty()) { + StringRef majorVersion, minorVersion; + llvm::tie(majorVersion, minorVersion) = osVersion.split('.'); + if (minorVersion.empty()) + minorVersion = "0"; + int32_t major, minor; + if (majorVersion.getAsInteger(0, major)) + return true; + if (minorVersion.getAsInteger(0, minor)) + return true; + ctx.setMinOSVersion(PECOFFLinkingContext::OSVersion(major, minor)); + } + // Parse subsystem name. + llvm::COFF::WindowsSubsystem subsystem = + stringToWinSubsystem(subsystemStr); + if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) { + diagnostics << "error: unknown subsystem name: " << subsystemStr + << "\n"; + return true; + } + ctx.setSubsystem(subsystem); + } break; + + case OPT_failifmismatch: + if (handleFailIfMismatchOption(inputArg->getValue(), failIfMismatchMap, + diagnostics)) + return true; + break; + + case OPT_entry: + // handle /entry + ctx.setEntrySymbolName(inputArg->getValue()); + break; + + case OPT_libpath: + // handle /libpath + ctx.appendInputSearchPath(inputArg->getValue()); + break; + + case OPT_force: + // handle /force + ctx.setAllowRemainingUndefines(true); + break; + + case OPT_no_nxcompat: + // handle /nxcompat:no + ctx.setNxCompat(false); + break; + + case OPT_largeaddressaware: + // handle /largeaddressaware + ctx.setLargeAddressAware(true); + break; + + case OPT_fixed: + // handle /fixed + ctx.setBaseRelocationEnabled(false); + break; + + case OPT_tsaware: + // handle /tsaware + ctx.setTerminalServerAware(true); + break; + + case OPT_no_tsaware: + // handle /tsaware:no + ctx.setTerminalServerAware(false); + break; + + case OPT_incl: + // handle /incl + ctx.addInitialUndefinedSymbol(inputArg->getValue()); + break; + + case OPT_out: + // handle /out + ctx.setOutputPath(inputArg->getValue()); + break; + + case OPT_INPUT: { + inputGraph.addInputElement(std::unique_ptr<InputElement>( + new PECOFFFileNode(ctx, inputArg->getValue()))); + } break; + + default: + break; + } } // Arguments after "--" are interpreted as filenames even if they @@ -433,27 +388,33 @@ bool WinLinkDriver::parse(int argc, const char *argv[], // but useful for us to test lld on Unix. if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH)) { for (const StringRef value : dashdash->getValues()) - inputPaths.push_back(value); + inputGraph.addInputElement( + std::unique_ptr<InputElement>(new PECOFFFileNode(ctx, value))); } - // Add input files specified via the command line. - for (const StringRef path : inputPaths) - context.appendInputFileOrLibrary(path); + // Add ".lib" extension if the path does not already have the extension to + // mimic link.exe behavior. + for (auto defaultLibPath : defaultLibs) + inputGraph.addInputElement(std::unique_ptr<InputElement>( + new PECOFFLibraryNode(ctx, defaultLibPath))); - // Add the library files specified by /defaultlib option. The files - // specified by the option should have lower precedence than the other files - // added above, which is important for link.exe compatibility. - for (const StringRef path : defaultLibs) - context.appendLibraryFile(canonicalizeImportLibraryPath(context, path)); + if (!inputGraph.numFiles()) { + diagnostics << "No input files\n"; + return true; + } // If /out option was not specified, the default output file name is // constructed by replacing an extension of the first input file // with ".exe". - if (context.outputPath().empty() && !inputPaths.empty()) - context.setOutputPath(getDefaultOutputFileName(context, inputPaths[0])); + if (ctx.outputPath().empty()) { + SmallString<128> firstInputFilePath = + (llvm::dyn_cast<FileNode>(&((inputGraph)[0])))->path(ctx); + (llvm::sys::path::replace_extension(firstInputFilePath, ".exe")); + ctx.setOutputPath(firstInputFilePath.str()); + } // Validate the combination of options used. - return context.validate(diagnostics); + return ctx.validate(diagnostics); } } // namespace lld |