1 //===- GroupCmd.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/GroupCmd.h" 10 11 #include "mcld/LD/GroupReader.h" 12 #include "mcld/MC/InputBuilder.h" 13 #include "mcld/MC/Attribute.h" 14 #include "mcld/Script/InputToken.h" 15 #include "mcld/Script/StringList.h" 16 #include "mcld/Support/MsgHandling.h" 17 #include "mcld/Support/Path.h" 18 #include "mcld/Support/raw_ostream.h" 19 #include "mcld/InputTree.h" 20 #include "mcld/LinkerScript.h" 21 22 #include <llvm/Support/Casting.h> 23 #include <cassert> 24 25 namespace mcld { 26 27 //===----------------------------------------------------------------------===// 28 // GroupCmd 29 //===----------------------------------------------------------------------===// 30 GroupCmd::GroupCmd(StringList& pStringList, 31 InputTree& pInputTree, 32 InputBuilder& pBuilder, 33 GroupReader& pGroupReader, 34 const LinkerConfig& pConfig) 35 : ScriptCommand(ScriptCommand::GROUP), 36 m_StringList(pStringList), 37 m_InputTree(pInputTree), 38 m_Builder(pBuilder), 39 m_GroupReader(pGroupReader), 40 m_Config(pConfig) { 41 } 42 43 GroupCmd::~GroupCmd() { 44 } 45 46 void GroupCmd::dump() const { 47 mcld::outs() << "GROUP ( "; 48 bool prev = false, cur = false; 49 for (StringList::const_iterator it = m_StringList.begin(), 50 ie = m_StringList.end(); 51 it != ie; 52 ++it) { 53 assert((*it)->kind() == StrToken::Input); 54 InputToken* input = llvm::cast<InputToken>(*it); 55 cur = input->asNeeded(); 56 if (!prev && cur) 57 mcld::outs() << "AS_NEEDED ( "; 58 else if (prev && !cur) 59 mcld::outs() << " )"; 60 61 if (input->type() == InputToken::NameSpec) 62 mcld::outs() << "-l"; 63 mcld::outs() << input->name() << " "; 64 65 prev = cur; 66 } 67 68 if (!m_StringList.empty() && prev) 69 mcld::outs() << " )"; 70 71 mcld::outs() << " )\n"; 72 } 73 74 void GroupCmd::activate(Module& pModule) { 75 LinkerScript& script = pModule.getScript(); 76 // construct the Group tree 77 m_Builder.setCurrentTree(m_InputTree); 78 // --start-group 79 m_Builder.enterGroup(); 80 InputTree::iterator group = m_Builder.getCurrentNode(); 81 82 for (StringList::const_iterator it = m_StringList.begin(), 83 ie = m_StringList.end(); 84 it != ie; 85 ++it) { 86 assert((*it)->kind() == StrToken::Input); 87 InputToken* token = llvm::cast<InputToken>(*it); 88 if (token->asNeeded()) 89 m_Builder.getAttributes().setAsNeeded(); 90 else 91 m_Builder.getAttributes().unsetAsNeeded(); 92 93 switch (token->type()) { 94 case InputToken::File: { 95 sys::fs::Path path; 96 97 // 1. Looking for file in the sysroot prefix, if a sysroot prefix is 98 // configured and the filename starts with '/' 99 if (script.hasSysroot() && 100 (token->name().size() > 0 && token->name()[0] == '/')) { 101 path = script.sysroot(); 102 path.append(token->name()); 103 } else { 104 // 2. Try to open the file in CWD 105 path.assign(token->name()); 106 if (!sys::fs::exists(path)) { 107 // 3. Search through the library search path 108 sys::fs::Path* p = 109 script.directories().find(token->name(), Input::Script); 110 if (p != NULL) 111 path = *p; 112 } 113 } 114 115 if (!sys::fs::exists(path)) 116 fatal(diag::err_cannot_open_input) << path.filename() << path; 117 118 m_Builder.createNode<InputTree::Positional>( 119 path.filename().native(), path, Input::Unknown); 120 break; 121 } 122 case InputToken::NameSpec: { 123 const sys::fs::Path* path = NULL; 124 // find out the real path of the namespec. 125 if (m_Builder.getConstraint().isSharedSystem()) { 126 // In the system with shared object support, we can find both archive 127 // and shared object. 128 if (m_Builder.getAttributes().isStatic()) { 129 // with --static, we must search an archive. 130 path = script.directories().find(token->name(), Input::Archive); 131 } else { 132 // otherwise, with --Bdynamic, we can find either an archive or a 133 // shared object. 134 path = script.directories().find(token->name(), Input::DynObj); 135 } 136 } else { 137 // In the system without shared object support, only look for an 138 // archive 139 path = script.directories().find(token->name(), Input::Archive); 140 } 141 142 if (path == NULL) 143 fatal(diag::err_cannot_find_namespec) << token->name(); 144 145 m_Builder.createNode<InputTree::Positional>( 146 token->name(), *path, Input::Unknown); 147 break; 148 } 149 default: 150 assert(0 && "Invalid script token in GROUP!"); 151 break; 152 } // end of switch 153 154 Input* input = *m_Builder.getCurrentNode(); 155 assert(input != NULL); 156 if (!m_Builder.setMemory(*input, FileHandle::OpenMode(FileHandle::ReadOnly), 157 FileHandle::Permission(FileHandle::System))) { 158 error(diag::err_cannot_open_input) << input->name() << input->path(); 159 } 160 m_Builder.setContext(*input); 161 } 162 163 // --end-group 164 m_Builder.exitGroup(); 165 166 // read the group 167 m_GroupReader.readGroup(group, m_InputTree.end(), m_Builder, m_Config); 168 } 169 170 } // namespace mcld 171