C++程序  |  166行  |  5.07 KB

//===- GroupCmd.cpp -------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Script/GroupCmd.h>
#include <mcld/Script/StringList.h>
#include <mcld/Script/InputToken.h>
#include <mcld/MC/InputBuilder.h>
#include <mcld/MC/Attribute.h>
#include <mcld/Support/Path.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/InputTree.h>
#include <mcld/LinkerScript.h>
#include <mcld/LD/GroupReader.h>
#include <llvm/Support/Casting.h>
#include <cassert>

using namespace mcld;

//===----------------------------------------------------------------------===//
// GroupCmd
//===----------------------------------------------------------------------===//
GroupCmd::GroupCmd(StringList& pStringList,
                   InputTree& pInputTree,
                   InputBuilder& pBuilder,
                   GroupReader& pGroupReader,
                   const LinkerConfig& pConfig)
  : ScriptCommand(ScriptCommand::GROUP),
    m_StringList(pStringList),
    m_InputTree(pInputTree),
    m_Builder(pBuilder),
    m_GroupReader(pGroupReader),
    m_Config(pConfig)
{
}

GroupCmd::~GroupCmd()
{
}

void GroupCmd::dump() const
{
  mcld::outs() << "GROUP ( ";
  bool prev = false, cur = false;
  for (StringList::const_iterator it = m_StringList.begin(),
    ie = m_StringList.end(); it != ie; ++it) {
    assert((*it)->kind() == StrToken::Input);
    InputToken* input = llvm::cast<InputToken>(*it);
    cur = input->asNeeded();
    if (!prev && cur)
      mcld::outs() << "AS_NEEDED ( ";
    else if (prev && !cur)
      mcld::outs() << " )";

    if (input->type() == InputToken::NameSpec)
      mcld::outs() << "-l";
    mcld::outs() << input->name() << " ";

    prev = cur;
  }

  if (!m_StringList.empty() && prev)
    mcld::outs() << " )";

  mcld::outs() << " )\n";
}

void GroupCmd::activate(Module& pModule)
{
  LinkerScript& script = pModule.getScript();
  // construct the Group tree
  m_Builder.setCurrentTree(m_InputTree);
  // --start-group
  m_Builder.enterGroup();
  InputTree::iterator group = m_Builder.getCurrentNode();

  for (StringList::const_iterator it = m_StringList.begin(),
    ie = m_StringList.end(); it != ie; ++it) {

    assert((*it)->kind() == StrToken::Input);
    InputToken* token = llvm::cast<InputToken>(*it);
    if (token->asNeeded())
      m_Builder.getAttributes().setAsNeeded();
    else
      m_Builder.getAttributes().unsetAsNeeded();

    switch (token->type()) {
    case InputToken::File: {
      sys::fs::Path path;

      // 1. Looking for file in the sysroot prefix, if a sysroot prefix is
      // configured and the filename starts with '/'
      if (script.hasSysroot() &&
          (token->name().size() > 0 && token->name()[0] == '/')) {
          path = script.sysroot();
          path.append(token->name());
      } else {
        // 2. Try to open the file in CWD
        path.assign(token->name());
        if (!sys::fs::exists(path)) {
          // 3. Search through the library search path
          sys::fs::Path* p =
            script.directories().find(token->name(), Input::Script);
          if (p != NULL)
            path = *p;
        }
      }

      if (!sys::fs::exists(path))
        fatal(diag::err_cannot_open_input) << path.filename() << path;

      m_Builder.createNode<InputTree::Positional>(
        path.filename().native(), path, Input::Unknown);
      break;
    }
    case InputToken::NameSpec: {
      const sys::fs::Path* path = NULL;
      // find out the real path of the namespec.
      if (m_Builder.getConstraint().isSharedSystem()) {
        // In the system with shared object support, we can find both archive
        // and shared object.
        if (m_Builder.getAttributes().isStatic()) {
          // with --static, we must search an archive.
          path = script.directories().find(token->name(), Input::Archive);
        } else {
          // otherwise, with --Bdynamic, we can find either an archive or a
          // shared object.
          path = script.directories().find(token->name(), Input::DynObj);
        }
      } else {
        // In the system without shared object support, only look for an archive
        path = script.directories().find(token->name(), Input::Archive);
      }

      if (NULL == path)
        fatal(diag::err_cannot_find_namespec) << token->name();

      m_Builder.createNode<InputTree::Positional>(
        token->name(), *path, Input::Unknown);
      break;
    }
    default:
      assert(0 && "Invalid script token in GROUP!");
      break;
    } // end of switch

    Input* input = *m_Builder.getCurrentNode();
    assert(input != NULL);
    if (!m_Builder.setMemory(*input, FileHandle::ReadOnly))
      error(diag::err_cannot_open_input) << input->name() << input->path();
    m_Builder.setContext(*input);
  }

  // --end-group
  m_Builder.exitGroup();

  // read the group
  m_GroupReader.readGroup(group, m_InputTree.end(), m_Builder, m_Config);
}