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