blob: ad6e13a566450a76ec2c04d8338681500852abca [file] [log] [blame]
//===- TestLinker.cpp -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "TestLinker.h"
#include <iostream>
#include <llvm/Support/TargetSelect.h>
#include <mcld/LD/TextDiagnosticPrinter.h>
#include <mcld/MC/InputTree.h>
#include <mcld/MC/MCLDDirectory.h>
#include <mcld/Target/TargetLDBackend.h>
#include <mcld/Support/RegionFactory.h>
#include <mcld/Support/TargetSelect.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/raw_ostream.h>
#include <mcld/Support/SystemUtils.h>
#include <mcld/Support/MemoryAreaFactory.h>
using namespace std;
using namespace mcld;
using namespace mcld::sys::fs;
using namespace mcld::test;
//===----------------------------------------------------------------------===//
// TestLinker
//===----------------------------------------------------------------------===//
TestLinker::TestLinker()
: m_pTarget(NULL), m_pDriver(NULL), m_pInfo(NULL), m_pDiagLineInfo(NULL),
m_pDiagPrinter(NULL), m_pBackend(NULL), m_pRegionFactory(NULL),
m_pMemAreaFactory(NULL) {
}
TestLinker::~TestLinker()
{
std::list<mcld::FileHandle*>::iterator file, fEnd = m_FileHandleList.end();
for (file = m_FileHandleList.begin(); file != fEnd; ++file)
delete (*file);
std::list<mcld::MemoryArea*>::iterator mem, mEnd = m_MemAreaList.end() ;
for (mem = m_MemAreaList.begin(); mem != mEnd; ++mem)
delete (*mem);
delete m_pDriver;
delete m_pInfo;
delete m_pDiagLineInfo;
delete m_pDiagPrinter;
delete m_pBackend;
delete m_pRegionFactory;
delete m_pMemAreaFactory;
}
bool TestLinker::initialize(const std::string &pTriple)
{
bool is_initialized = false;
if (is_initialized)
return false;
// initilaize all llvm::Target and mcld::Target
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllTargetMCs();
mcld::InitializeAllTargets();
mcld::InitializeAllDiagnostics();
// create mcld::MCLDInfo
m_pInfo = new MCLDInfo(pTriple, 1, 32);
m_Root = m_pInfo->inputs().root();
// create mcld::RegionFactory
m_pRegionFactory = new mcld::RegionFactory(32);
// specify mcld::Target
std::string error;
m_pTarget = mcld::TargetRegistry::lookupTarget(pTriple, error);
if (NULL == m_pTarget) {
fatal(diag::fatal_cannot_init_target) << pTriple << error;
return false;
}
// create mcld::DiagnosticEngine
m_pDiagLineInfo = m_pTarget->createDiagnosticLineInfo(*m_pTarget, pTriple);
if (NULL == m_pDiagLineInfo) {
fatal(diag::fatal_cannot_init_lineinfo) << pTriple;
return false;
}
m_pDiagPrinter = new mcld::TextDiagnosticPrinter(mcld::errs(), *m_pInfo);
mcld::InitializeDiagnosticEngine(*m_pInfo, m_pDiagLineInfo, m_pDiagPrinter);
// create mcld::TargetLDBackend
m_pBackend = m_pTarget->createLDBackend(pTriple);
if (NULL == m_pBackend) {
fatal(diag::fatal_cannot_init_backend) << pTriple;
return false;
}
m_pMemAreaFactory = new MemoryAreaFactory(32);
m_pDriver = new mcld::MCLDDriver(*m_pInfo, *m_pBackend, *m_pMemAreaFactory);
m_pDriver->initMCLinker();
is_initialized = true;
return true;
}
void TestLinker::addSearchDir(const std::string &pDirPath)
{
assert(NULL != m_pInfo && "initialize() must be called before addSearchDir");
assert(!m_pInfo->options().sysroot().empty() &&
"must setSysRoot before addSearchDir");
mcld::MCLDDirectory* sd = new mcld::MCLDDirectory(pDirPath);
if (sd->isInSysroot()) {
sd->setSysroot(m_pInfo->options().sysroot());
}
if (exists(sd->path()) && is_directory(sd->path())) {
m_pInfo->options().directories().add(*sd);
} else {
mcld::warning(mcld::diag::warn_cannot_open_search_dir) << sd->name();
}
}
void TestLinker::setSysRoot(const mcld::sys::fs::Path &pPath)
{
assert(NULL != m_pInfo && "initialize() must be called before setSysRoot");
m_pInfo->options().setSysroot(pPath);
}
void TestLinker::addObject(const std::string &pPath)
{
mcld::Input* input = m_pInfo->inputFactory().produce(pPath, pPath,
mcld::Input::Unknown);
m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
if (!handler->open(pPath, mcld::FileHandle::ReadOnly)) {
mcld::error(mcld::diag::err_cannot_open_file)
<< pPath
<< mcld::sys::strerror(handler->error());
}
mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce(pPath);
input->setContext(context);
}
void TestLinker::addObject(void* pMemBuffer, size_t pSize)
{
mcld::Input* input = m_pInfo->inputFactory().produce("memory object", "NAN",
mcld::Input::Unknown);
m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::Space* space = new mcld::Space(mcld::Space::EXTERNAL, pMemBuffer, pSize);
mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *space);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce();
input->setContext(context);
}
void TestLinker::addObject(int pFileHandler)
{
mcld::Input* input = m_pInfo->inputFactory().produce("handler object", "NAN",
mcld::Input::Unknown);
m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
handler->delegate(pFileHandler);
mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce();
input->setContext(context);
}
void TestLinker::addNameSpec(const std::string &pNameSpec)
{
mcld::sys::fs::Path* path = NULL;
// find out the real path of the namespec.
if (m_pInfo->attrFactory().constraint().isSharedSystem()) {
// In the system with shared object support, we can find both archive
// and shared object.
if (m_pInfo->attrFactory().last().isStatic()) {
// with --static, we must search an archive.
path = m_pInfo->options().directories().find(pNameSpec,
mcld::Input::Archive);
}
else {
// otherwise, with --Bdynamic, we can find either an archive or a
// shared object.
path = m_pInfo->options().directories().find(pNameSpec,
mcld::Input::DynObj);
}
}
else {
// In the system without shared object support, we only look for an
// archive.
path = m_pInfo->options().directories().find(pNameSpec,
mcld::Input::Archive);
}
if (NULL == path) {
mcld::fatal(diag::err_cannot_find_namespec) << pNameSpec;
return;
}
mcld::Input* input = m_pInfo->inputFactory().produce(pNameSpec, *path,
mcld::Input::Unknown);
m_pInfo->inputs().insert<mcld::InputTree::Positional>(m_Root, *input);
advanceRoot();
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
if (!handler->open(*path, mcld::FileHandle::ReadOnly)) {
mcld::error(mcld::diag::err_cannot_open_file)
<< *path
<< mcld::sys::strerror(handler->error());
}
mcld::MemoryArea* input_memory = new MemoryArea(*m_pRegionFactory, *handler);
input->setMemArea(input_memory);
m_MemAreaList.push_back(input_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce(*path);
input->setContext(context);
}
bool TestLinker::setOutput(const std::string &pPath)
{
if (m_pInfo->output().hasContext())
return false;
mcld::FileHandle* handler = new mcld::FileHandle();
m_FileHandleList.push_back(handler);
bool open_res = handler->open(pPath, mcld::FileHandle::ReadWrite |
mcld::FileHandle::Truncate |
mcld::FileHandle::Create,
mcld::FileHandle::Permission(0755));
if (!open_res) {
mcld::error(mcld::diag::err_cannot_open_file)
<< pPath
<< mcld::sys::strerror(handler->error());
}
mcld::MemoryArea* output_memory = new MemoryArea(*m_pRegionFactory, *handler);
m_pInfo->output().setMemArea(output_memory);
m_MemAreaList.push_back(output_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce(pPath);
m_pInfo->output().setContext(context);
// FIXME: remove the initStdSections().
m_pDriver->initStdSections();
return true;
}
bool TestLinker::setOutput(const sys::fs::Path &pPath)
{
return setOutput(pPath.native());
}
bool TestLinker::setOutput(int pFileHandler)
{
if (m_pInfo->output().hasContext())
return false;
mcld::FileHandle* handler = new mcld::FileHandle();
handler->delegate(pFileHandler);
m_FileHandleList.push_back(handler);
mcld::MemoryArea* output_memory = new MemoryArea(*m_pRegionFactory, *handler);
m_pInfo->output().setMemArea(output_memory);
m_MemAreaList.push_back(output_memory);
mcld::LDContext* context = m_pInfo->contextFactory().produce();
m_pInfo->output().setContext(context);
// FIXME: remove the initStdSections().
m_pDriver->initStdSections();
return true;
}
void TestLinker::advanceRoot()
{
if (m_Root.isRoot())
--m_Root;
else
++m_Root;
}