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