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