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 //===----------------------------------------------------------------------===//
GroupCmd(StringList & pStringList,InputTree & pInputTree,InputBuilder & pBuilder,GroupReader & pGroupReader,const LinkerConfig & pConfig)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
~GroupCmd()42 GroupCmd::~GroupCmd()
43 {
44 }
45
dump() const46 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
activate(Module & pModule)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