1//===- InputCmd.cpp -------------------------------------------------------===// 2// 3// The MCLinker Project 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9#include "mcld/Script/InputCmd.h" 10 11#include "mcld/LD/Archive.h" 12#include "mcld/LD/ArchiveReader.h" 13#include "mcld/LD/DynObjReader.h" 14#include "mcld/LD/ObjectReader.h" 15#include "mcld/MC/Attribute.h" 16#include "mcld/MC/InputBuilder.h" 17#include "mcld/Script/InputToken.h" 18#include "mcld/Script/StringList.h" 19#include "mcld/Support/MsgHandling.h" 20#include "mcld/Support/Path.h" 21#include "mcld/Support/raw_ostream.h" 22#include "mcld/InputTree.h" 23#include "mcld/LinkerScript.h" 24#include "mcld/LinkerConfig.h" 25#include "mcld/Module.h" 26 27#include <llvm/Support/Casting.h> 28 29#include <cassert> 30#include <iostream> 31 32namespace mcld { 33 34//===----------------------------------------------------------------------===// 35// InputCmd 36//===----------------------------------------------------------------------===// 37InputCmd::InputCmd(StringList& pStringList, 38 InputTree& pInputTree, 39 InputBuilder& pBuilder, 40 ObjectReader& pObjectReader, 41 ArchiveReader& pArchiveReader, 42 DynObjReader& pDynObjReader, 43 const LinkerConfig& pConfig) 44 : ScriptCommand(ScriptCommand::INPUT), 45 m_StringList(pStringList), 46 m_InputTree(pInputTree), 47 m_Builder(pBuilder), 48 m_ObjectReader(pObjectReader), 49 m_ArchiveReader(pArchiveReader), 50 m_DynObjReader(pDynObjReader), 51 m_Config(pConfig) { 52} 53 54InputCmd::~InputCmd() { 55} 56 57void InputCmd::dump() const { 58 mcld::outs() << "INPUT ( "; 59 bool prev = false, cur = false; 60 for (StringList::const_iterator it = m_StringList.begin(), 61 ie = m_StringList.end(); 62 it != ie; 63 ++it) { 64 assert((*it)->kind() == StrToken::Input); 65 InputToken* input = llvm::cast<InputToken>(*it); 66 cur = input->asNeeded(); 67 if (!prev && cur) 68 mcld::outs() << "AS_NEEDED ( "; 69 else if (prev && !cur) 70 mcld::outs() << " )"; 71 72 if (input->type() == InputToken::NameSpec) 73 mcld::outs() << "-l"; 74 mcld::outs() << input->name() << " "; 75 76 prev = cur; 77 } 78 79 if (!m_StringList.empty() && prev) 80 mcld::outs() << " )"; 81 82 mcld::outs() << " )\n"; 83} 84 85void InputCmd::activate(Module& pModule) { 86 LinkerScript& script = pModule.getScript(); 87 // construct the INPUT tree 88 m_Builder.setCurrentTree(m_InputTree); 89 90 bool is_begin_marked = false; 91 InputTree::iterator input_begin; 92 93 for (StringList::const_iterator it = m_StringList.begin(), 94 ie = m_StringList.end(); 95 it != ie; 96 ++it) { 97 assert((*it)->kind() == StrToken::Input); 98 InputToken* token = llvm::cast<InputToken>(*it); 99 if (token->asNeeded()) 100 m_Builder.getAttributes().setAsNeeded(); 101 else 102 m_Builder.getAttributes().unsetAsNeeded(); 103 104 switch (token->type()) { 105 case InputToken::File: { 106 sys::fs::Path path; 107 108 // 1. Looking for file in the sysroot prefix, if a sysroot prefix is 109 // configured and the filename starts with '/' 110 if (script.hasSysroot() && 111 (token->name().size() > 0 && token->name()[0] == '/')) { 112 path = script.sysroot(); 113 path.append(token->name()); 114 } else { 115 // 2. Try to open the file in CWD 116 path.assign(token->name()); 117 if (!sys::fs::exists(path)) { 118 // 3. Search through the library search path 119 sys::fs::Path* p = 120 script.directories().find(token->name(), Input::Script); 121 if (p != NULL) 122 path = *p; 123 } 124 } 125 126 if (!sys::fs::exists(path)) 127 fatal(diag::err_cannot_open_input) << path.filename() << path; 128 129 m_Builder.createNode<InputTree::Positional>( 130 path.filename().native(), path, Input::Unknown); 131 break; 132 } 133 case InputToken::NameSpec: { 134 const sys::fs::Path* path = NULL; 135 // find out the real path of the namespec. 136 if (m_Builder.getConstraint().isSharedSystem()) { 137 // In the system with shared object support, we can find both archive 138 // and shared object. 139 if (m_Builder.getAttributes().isStatic()) { 140 // with --static, we must search an archive. 141 path = script.directories().find(token->name(), Input::Archive); 142 } else { 143 // otherwise, with --Bdynamic, we can find either an archive or a 144 // shared object. 145 path = script.directories().find(token->name(), Input::DynObj); 146 } 147 } else { 148 // In the system without shared object support, only look for an 149 // archive 150 path = script.directories().find(token->name(), Input::Archive); 151 } 152 153 if (path == NULL) 154 fatal(diag::err_cannot_find_namespec) << token->name(); 155 156 m_Builder.createNode<InputTree::Positional>( 157 token->name(), *path, Input::Unknown); 158 break; 159 } 160 default: 161 assert(0 && "Invalid script token in INPUT!"); 162 break; 163 } // end of switch 164 165 InputTree::iterator input = m_Builder.getCurrentNode(); 166 if (!is_begin_marked) { 167 input_begin = input; 168 is_begin_marked = true; 169 } 170 assert(*input != NULL); 171 if (!m_Builder.setMemory(**input, 172 FileHandle::OpenMode(FileHandle::ReadOnly), 173 FileHandle::Permission(FileHandle::System))) { 174 error(diag::err_cannot_open_input) << (*input)->name() 175 << (*input)->path(); 176 } 177 m_Builder.setContext(**input); 178 } 179 180 for (InputTree::iterator input = input_begin, ie = m_InputTree.end(); 181 input != ie; 182 ++input) { 183 bool doContinue = false; 184 if (m_ObjectReader.isMyFormat(**input, doContinue)) { 185 (*input)->setType(Input::Object); 186 m_ObjectReader.readHeader(**input); 187 m_ObjectReader.readSections(**input); 188 m_ObjectReader.readSymbols(**input); 189 pModule.getObjectList().push_back(*input); 190 } else if (doContinue && m_DynObjReader.isMyFormat(**input, doContinue)) { 191 (*input)->setType(Input::DynObj); 192 m_DynObjReader.readHeader(**input); 193 m_DynObjReader.readSymbols(**input); 194 pModule.getLibraryList().push_back(*input); 195 } else if (doContinue && m_ArchiveReader.isMyFormat(**input, doContinue)) { 196 (*input)->setType(Input::Archive); 197 if (m_Config.options().isInExcludeLIBS(**input)) { 198 (*input)->setNoExport(); 199 } 200 Archive archive(**input, m_Builder); 201 m_ArchiveReader.readArchive(m_Config, archive); 202 if (archive.numOfObjectMember() > 0) { 203 m_InputTree.merge<InputTree::Inclusive>(input, archive.inputs()); 204 } 205 } else { 206 if (m_Config.options().warnMismatch()) 207 warning(diag::warn_unrecognized_input_file) 208 << (*input)->path() << m_Config.targets().triple().str(); 209 } 210 } 211} 212 213} // namespace mcld 214