Home | History | Annotate | Download | only in Script
      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 //===----------------------------------------------------------------------===//
     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 
     42 GroupCmd::~GroupCmd()
     43 {
     44 }
     45 
     46 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 
     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