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
32 namespace mcld {
33
34 //===----------------------------------------------------------------------===//
35 // InputCmd
36 //===----------------------------------------------------------------------===//
InputCmd(StringList & pStringList,InputTree & pInputTree,InputBuilder & pBuilder,ObjectReader & pObjectReader,ArchiveReader & pArchiveReader,DynObjReader & pDynObjReader,const LinkerConfig & pConfig)37 InputCmd::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
~InputCmd()54 InputCmd::~InputCmd() {
55 }
56
dump() const57 void 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
activate(Module & pModule)85 void 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