You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
7.0 KiB
214 lines
7.0 KiB
//===- InputCmd.cpp -------------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/Script/InputCmd.h"
|
|
|
|
#include "mcld/LD/Archive.h"
|
|
#include "mcld/LD/ArchiveReader.h"
|
|
#include "mcld/LD/DynObjReader.h"
|
|
#include "mcld/LD/ObjectReader.h"
|
|
#include "mcld/MC/Attribute.h"
|
|
#include "mcld/MC/InputBuilder.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 "mcld/LinkerConfig.h"
|
|
#include "mcld/Module.h"
|
|
|
|
#include <llvm/Support/Casting.h>
|
|
|
|
#include <cassert>
|
|
#include <iostream>
|
|
|
|
namespace mcld {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// InputCmd
|
|
//===----------------------------------------------------------------------===//
|
|
InputCmd::InputCmd(StringList& pStringList,
|
|
InputTree& pInputTree,
|
|
InputBuilder& pBuilder,
|
|
ObjectReader& pObjectReader,
|
|
ArchiveReader& pArchiveReader,
|
|
DynObjReader& pDynObjReader,
|
|
const LinkerConfig& pConfig)
|
|
: ScriptCommand(ScriptCommand::INPUT),
|
|
m_StringList(pStringList),
|
|
m_InputTree(pInputTree),
|
|
m_Builder(pBuilder),
|
|
m_ObjectReader(pObjectReader),
|
|
m_ArchiveReader(pArchiveReader),
|
|
m_DynObjReader(pDynObjReader),
|
|
m_Config(pConfig) {
|
|
}
|
|
|
|
InputCmd::~InputCmd() {
|
|
}
|
|
|
|
void InputCmd::dump() const {
|
|
mcld::outs() << "INPUT ( ";
|
|
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 InputCmd::activate(Module& pModule) {
|
|
LinkerScript& script = pModule.getScript();
|
|
// construct the INPUT tree
|
|
m_Builder.setCurrentTree(m_InputTree);
|
|
|
|
bool is_begin_marked = false;
|
|
InputTree::iterator input_begin;
|
|
|
|
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 INPUT!");
|
|
break;
|
|
} // end of switch
|
|
|
|
InputTree::iterator input = m_Builder.getCurrentNode();
|
|
if (!is_begin_marked) {
|
|
input_begin = input;
|
|
is_begin_marked = true;
|
|
}
|
|
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);
|
|
}
|
|
|
|
for (InputTree::iterator input = input_begin, ie = m_InputTree.end();
|
|
input != ie;
|
|
++input) {
|
|
bool doContinue = false;
|
|
if (m_ObjectReader.isMyFormat(**input, doContinue)) {
|
|
(*input)->setType(Input::Object);
|
|
m_ObjectReader.readHeader(**input);
|
|
m_ObjectReader.readSections(**input);
|
|
m_ObjectReader.readSymbols(**input);
|
|
pModule.getObjectList().push_back(*input);
|
|
} else if (doContinue && m_DynObjReader.isMyFormat(**input, doContinue)) {
|
|
(*input)->setType(Input::DynObj);
|
|
m_DynObjReader.readHeader(**input);
|
|
m_DynObjReader.readSymbols(**input);
|
|
pModule.getLibraryList().push_back(*input);
|
|
} else if (doContinue && m_ArchiveReader.isMyFormat(**input, doContinue)) {
|
|
(*input)->setType(Input::Archive);
|
|
if (m_Config.options().isInExcludeLIBS(**input)) {
|
|
(*input)->setNoExport();
|
|
}
|
|
Archive archive(**input, m_Builder);
|
|
m_ArchiveReader.readArchive(m_Config, archive);
|
|
if (archive.numOfObjectMember() > 0) {
|
|
m_InputTree.merge<InputTree::Inclusive>(input, archive.inputs());
|
|
}
|
|
} else {
|
|
if (m_Config.options().warnMismatch())
|
|
warning(diag::warn_unrecognized_input_file)
|
|
<< (*input)->path() << m_Config.targets().triple().str();
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace mcld
|