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 
     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 //===----------------------------------------------------------------------===//
     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 
     43 GroupCmd::~GroupCmd() {
     44 }
     45 
     46 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 
     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