| //===- lib/Driver/GnuLdInputGraph.cpp -------------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "lld/Driver/GnuLdInputGraph.h" |
| #include "lld/ReaderWriter/LinkerScript.h" |
| |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/Path.h" |
| |
| using namespace lld; |
| |
| /// \brief Parse the input file to lld::File. |
| std::error_code ELFFileNode::parse(const LinkingContext &ctx, |
| raw_ostream &diagnostics) { |
| ErrorOr<StringRef> filePath = getPath(ctx); |
| if (std::error_code ec = filePath.getError()) |
| return ec; |
| if (std::error_code ec = getBuffer(*filePath)) |
| return ec; |
| if (ctx.logInputFiles()) |
| diagnostics << *filePath << "\n"; |
| |
| if (_attributes._isWholeArchive) { |
| std::vector<std::unique_ptr<File>> parsedFiles; |
| if (std::error_code ec = ctx.registry().parseFile(_buffer, parsedFiles)) |
| return ec; |
| assert(parsedFiles.size() == 1); |
| std::unique_ptr<File> f(parsedFiles[0].release()); |
| if (const auto *archive = dyn_cast<ArchiveLibraryFile>(f.get())) { |
| // Have this node own the FileArchive object. |
| _archiveFile.reset(archive); |
| f.release(); |
| // Add all members to _files vector |
| return archive->parseAllMembers(_files); |
| } |
| // if --whole-archive is around non-archive, just use it as normal. |
| _files.push_back(std::move(f)); |
| return std::error_code(); |
| } |
| return ctx.registry().parseFile(_buffer, _files); |
| } |
| |
| /// \brief Parse the GnuLD Script |
| std::error_code GNULdScript::parse(const LinkingContext &ctx, |
| raw_ostream &diagnostics) { |
| ErrorOr<StringRef> filePath = getPath(ctx); |
| if (std::error_code ec = filePath.getError()) |
| return ec; |
| if (std::error_code ec = getBuffer(*filePath)) |
| return ec; |
| |
| if (ctx.logInputFiles()) |
| diagnostics << *filePath << "\n"; |
| |
| _lexer.reset(new script::Lexer(std::move(_buffer))); |
| _parser.reset(new script::Parser(*_lexer.get())); |
| |
| _linkerScript = _parser->parse(); |
| |
| if (!_linkerScript) |
| return LinkerScriptReaderError::parse_error; |
| |
| return std::error_code(); |
| } |
| |
| static bool isPathUnderSysroot(StringRef sysroot, StringRef path) { |
| if (sysroot.empty()) |
| return false; |
| |
| while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path)) |
| path = llvm::sys::path::parent_path(path); |
| |
| return !path.empty(); |
| } |
| |
| /// \brief Handle GnuLD script for ELF. |
| std::error_code ELFGNULdScript::parse(const LinkingContext &ctx, |
| raw_ostream &diagnostics) { |
| ELFFileNode::Attributes attributes; |
| if (std::error_code ec = GNULdScript::parse(ctx, diagnostics)) |
| return ec; |
| StringRef sysRoot = _elfLinkingContext.getSysroot(); |
| if (!sysRoot.empty() && isPathUnderSysroot(sysRoot, *getPath(ctx))) |
| attributes.setSysRooted(true); |
| for (const script::Command *c : _linkerScript->_commands) { |
| auto *group = dyn_cast<script::Group>(c); |
| if (!group) |
| continue; |
| std::unique_ptr<Group> groupStart(new Group()); |
| for (const script::Path &path : group->getPaths()) { |
| // TODO : Propagate Set WholeArchive/dashlPrefix |
| attributes.setAsNeeded(path._asNeeded); |
| attributes.setDashlPrefix(path._isDashlPrefix); |
| auto inputNode = new ELFFileNode( |
| _elfLinkingContext, _elfLinkingContext.allocateString(path._path), |
| attributes); |
| std::unique_ptr<InputElement> inputFile(inputNode); |
| groupStart.get()->addFile(std::move(inputFile)); |
| } |
| _expandElements.push_back(std::move(groupStart)); |
| } |
| return std::error_code(); |
| } |