| //===- InputCmd.cpp -------------------------------------------------------===// |
| // |
| // The MCLinker Project |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| #include "mcld/Script/InputCmd.h" |
| |
| #include "mcld/LD/Archive.h" |
| #include "mcld/LD/ArchiveReader.h" |
| #include "mcld/LD/DynObjReader.h" |
| #include "mcld/LD/ObjectReader.h" |
| #include "mcld/MC/Attribute.h" |
| #include "mcld/MC/InputBuilder.h" |
| #include "mcld/Script/InputToken.h" |
| #include "mcld/Script/StringList.h" |
| #include "mcld/Support/MsgHandling.h" |
| #include "mcld/Support/Path.h" |
| #include "mcld/Support/raw_ostream.h" |
| #include "mcld/InputTree.h" |
| #include "mcld/LinkerScript.h" |
| #include "mcld/LinkerConfig.h" |
| #include "mcld/Module.h" |
| |
| #include <llvm/Support/Casting.h> |
| |
| #include <cassert> |
| #include <iostream> |
| |
| namespace mcld { |
| |
| //===----------------------------------------------------------------------===// |
| // InputCmd |
| //===----------------------------------------------------------------------===// |
| InputCmd::InputCmd(StringList& pStringList, |
| InputTree& pInputTree, |
| InputBuilder& pBuilder, |
| ObjectReader& pObjectReader, |
| ArchiveReader& pArchiveReader, |
| DynObjReader& pDynObjReader, |
| const LinkerConfig& pConfig) |
| : ScriptCommand(ScriptCommand::INPUT), |
| m_StringList(pStringList), |
| m_InputTree(pInputTree), |
| m_Builder(pBuilder), |
| m_ObjectReader(pObjectReader), |
| m_ArchiveReader(pArchiveReader), |
| m_DynObjReader(pDynObjReader), |
| m_Config(pConfig) { |
| } |
| |
| InputCmd::~InputCmd() { |
| } |
| |
| void InputCmd::dump() const { |
| mcld::outs() << "INPUT ( "; |
| bool prev = false, cur = false; |
| for (StringList::const_iterator it = m_StringList.begin(), |
| ie = m_StringList.end(); |
| it != ie; |
| ++it) { |
| assert((*it)->kind() == StrToken::Input); |
| InputToken* input = llvm::cast<InputToken>(*it); |
| cur = input->asNeeded(); |
| if (!prev && cur) |
| mcld::outs() << "AS_NEEDED ( "; |
| else if (prev && !cur) |
| mcld::outs() << " )"; |
| |
| if (input->type() == InputToken::NameSpec) |
| mcld::outs() << "-l"; |
| mcld::outs() << input->name() << " "; |
| |
| prev = cur; |
| } |
| |
| if (!m_StringList.empty() && prev) |
| mcld::outs() << " )"; |
| |
| mcld::outs() << " )\n"; |
| } |
| |
| void InputCmd::activate(Module& pModule) { |
| LinkerScript& script = pModule.getScript(); |
| // construct the INPUT tree |
| m_Builder.setCurrentTree(m_InputTree); |
| |
| bool is_begin_marked = false; |
| InputTree::iterator input_begin; |
| |
| for (StringList::const_iterator it = m_StringList.begin(), |
| ie = m_StringList.end(); |
| it != ie; |
| ++it) { |
| assert((*it)->kind() == StrToken::Input); |
| InputToken* token = llvm::cast<InputToken>(*it); |
| if (token->asNeeded()) |
| m_Builder.getAttributes().setAsNeeded(); |
| else |
| m_Builder.getAttributes().unsetAsNeeded(); |
| |
| switch (token->type()) { |
| case InputToken::File: { |
| sys::fs::Path path; |
| |
| // 1. Looking for file in the sysroot prefix, if a sysroot prefix is |
| // configured and the filename starts with '/' |
| if (script.hasSysroot() && |
| (token->name().size() > 0 && token->name()[0] == '/')) { |
| path = script.sysroot(); |
| path.append(token->name()); |
| } else { |
| // 2. Try to open the file in CWD |
| path.assign(token->name()); |
| if (!sys::fs::exists(path)) { |
| // 3. Search through the library search path |
| sys::fs::Path* p = |
| script.directories().find(token->name(), Input::Script); |
| if (p != NULL) |
| path = *p; |
| } |
| } |
| |
| if (!sys::fs::exists(path)) |
| fatal(diag::err_cannot_open_input) << path.filename() << path; |
| |
| m_Builder.createNode<InputTree::Positional>( |
| path.filename().native(), path, Input::Unknown); |
| break; |
| } |
| case InputToken::NameSpec: { |
| const sys::fs::Path* path = NULL; |
| // find out the real path of the namespec. |
| if (m_Builder.getConstraint().isSharedSystem()) { |
| // In the system with shared object support, we can find both archive |
| // and shared object. |
| if (m_Builder.getAttributes().isStatic()) { |
| // with --static, we must search an archive. |
| path = script.directories().find(token->name(), Input::Archive); |
| } else { |
| // otherwise, with --Bdynamic, we can find either an archive or a |
| // shared object. |
| path = script.directories().find(token->name(), Input::DynObj); |
| } |
| } else { |
| // In the system without shared object support, only look for an |
| // archive |
| path = script.directories().find(token->name(), Input::Archive); |
| } |
| |
| if (path == NULL) |
| fatal(diag::err_cannot_find_namespec) << token->name(); |
| |
| m_Builder.createNode<InputTree::Positional>( |
| token->name(), *path, Input::Unknown); |
| break; |
| } |
| default: |
| assert(0 && "Invalid script token in INPUT!"); |
| break; |
| } // end of switch |
| |
| InputTree::iterator input = m_Builder.getCurrentNode(); |
| if (!is_begin_marked) { |
| input_begin = input; |
| is_begin_marked = true; |
| } |
| assert(*input != NULL); |
| if (!m_Builder.setMemory(**input, |
| FileHandle::OpenMode(FileHandle::ReadOnly), |
| FileHandle::Permission(FileHandle::System))) { |
| error(diag::err_cannot_open_input) << (*input)->name() |
| << (*input)->path(); |
| } |
| m_Builder.setContext(**input); |
| } |
| |
| for (InputTree::iterator input = input_begin, ie = m_InputTree.end(); |
| input != ie; |
| ++input) { |
| bool doContinue = false; |
| if (m_ObjectReader.isMyFormat(**input, doContinue)) { |
| (*input)->setType(Input::Object); |
| m_ObjectReader.readHeader(**input); |
| m_ObjectReader.readSections(**input); |
| m_ObjectReader.readSymbols(**input); |
| pModule.getObjectList().push_back(*input); |
| } else if (doContinue && m_DynObjReader.isMyFormat(**input, doContinue)) { |
| (*input)->setType(Input::DynObj); |
| m_DynObjReader.readHeader(**input); |
| m_DynObjReader.readSymbols(**input); |
| pModule.getLibraryList().push_back(*input); |
| } else if (doContinue && m_ArchiveReader.isMyFormat(**input, doContinue)) { |
| (*input)->setType(Input::Archive); |
| if (m_Config.options().isInExcludeLIBS(**input)) { |
| (*input)->setNoExport(); |
| } |
| Archive archive(**input, m_Builder); |
| m_ArchiveReader.readArchive(m_Config, archive); |
| if (archive.numOfObjectMember() > 0) { |
| m_InputTree.merge<InputTree::Inclusive>(input, archive.inputs()); |
| } |
| } else { |
| if (m_Config.options().warnMismatch()) |
| warning(diag::warn_unrecognized_input_file) |
| << (*input)->path() << m_Config.targets().triple().str(); |
| } |
| } |
| } |
| |
| } // namespace mcld |