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