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