//===- 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/LD/GroupReader.h"
#include "mcld/MC/InputBuilder.h"
#include "mcld/MC/Attribute.h"
#include "mcld/Script/InputToken.h"
#include "mcld/Script/StringList.h"
#include "mcld/Support/MsgHandling.h"
#include "mcld/Support/Path.h"
#include "mcld/Support/raw_ostream.h"
#include "mcld/InputTree.h"
#include "mcld/LinkerScript.h"
#include <llvm/Support/Casting.h>
#include <cassert>
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 (path == NULL)
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::OpenMode(FileHandle::ReadOnly),
FileHandle::Permission(FileHandle::System))) {
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);
}
} // namespace mcld