Home | History | Annotate | Download | only in Script
      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 //===----------------------------------------------------------------------===//
     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 
     54 InputCmd::~InputCmd() {
     55 }
     56 
     57 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 
     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