ExternLayer.cpp
No OneTemporary

File Metadata

Created
Wed, Jul 8, 2:05 AM

ExternLayer.cpp

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ExternLayer.cpp
*
* Created on: 4/21/15
* Author: pgess <v.melnychenko@xreate.org>
*/
#include "ExternLayer.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/CodeGenABITypes.h"
#include <llvm/Support/DynamicLibrary.h>
#include <boost/format.hpp>
#include <boost/algorithm/string/join.hpp>
#include <cstdio>
#include <iostream>
#include <clang/Frontend/CompilerInstance.h>
using namespace std;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace clang::ast_matchers;
using namespace llvm;
namespace xreate{
class FinderCallbackTypeDecl : public MatchFinder::MatchCallback{
public:
QualType typeResult;
virtual void
run(const MatchFinder::MatchResult &Result) {
if (const TypedefDecl * decl = Result.Nodes.getNodeAs<clang::TypedefDecl>("typename")) {
typeResult = decl->getUnderlyingType();
}
}
} ;
class FinderCallbackFunction : public MatchFinder::MatchCallback{
public:
QualType typeResult;
virtual void
run(const MatchFinder::MatchResult &Result) {
if (const FunctionDecl * decl = Result.Nodes.getNodeAs<clang::FunctionDecl>("function")) {
typeResult = decl->getType();
}
}
} ;
void
ExternData::addLibAlias(Atom<Identifier_t>&& alias, std::string&& package) {
__aliases.emplace(alias.get(), package.get());
}
void
ExternData::requireHeaders(const std::list<std::string>& headers){
__requiredHeaders.insert(
std::inserter(__requiredHeaders, __requiredHeaders.end()),
headers.begin(), headers.end());
}
void
ExternData::requireLibPackage(Atom<String_t>&& package){
__requiredPackages.push_back(package.get());
}
void
ExternData::requireLibAlias(Atom<Identifier_t>&& alias){
assert(__aliases.count(alias.get());
__requiredPackages.push_back(__aliases.at(alias.get()));
}
void
ExternLayer::addExternalData(const std::vector<ExternEntry>& data) {
entries.insert(entries.end(), data.begin(), data.end());
}
ExternLayer::ExternLayer(LLVMLayer *llvm)
: __llvm(llvm) { }
std::vector<string>
ExternLayer::fetchPackageFlags(const std::string& package) {
std::vector<string> args;
FILE* flags = popen((string("pkg-config --cflags ") + package).c_str(), "r");
size_t linesize = 0;
char* linebuf = 0;
ssize_t linelen = 0;
while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) {
if (linebuf[0] == '\n') continue;
if (linelen == 1 && linebuf[0] == ' ') continue;
//cut unwanted symbols at the end
char symbLast = linebuf[linelen - 1 ];
if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0;
//print header for debug purposes
llvm::outs() << '<' << linebuf << "> ";
args.push_back(linebuf);
free(linebuf);
linebuf = 0;
}
pclose(flags);
return (args);
}
std::vector<string>
ExternLayer::fetchPackageLibs(const std::string& package) {
std::vector<string> libs;
FILE* flags = popen((string("pkg-config --libs ") + package).c_str(), "r");
size_t linesize = 0;
char* linebuf = 0;
ssize_t linelen = 0;
while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) {
if (linebuf[0] == '\n') continue;
if (linelen == 1 && linebuf[0] == ' ') continue;
//cut unwanted symbols at the end
char symbLast = linebuf[linelen - 1 ];
if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0;
//cut unwanted symbols at the beginning
if (linelen > 1 && linebuf[0] == '-' && linebuf[1] == 'l') {
libs.push_back(linebuf + 2);
} else {
libs.push_back(linebuf);
}
//print lib name for debug purposes
llvm::outs() << '<' << linebuf << "> ";
free(linebuf);
linebuf = 0;
}
pclose(flags);
return (libs);
}
void
ExternLayer::loadLibraries(vector<string>&& libs) {
string msgErr;
for (const string& lib : libs) {
const string& libName = string("lib") + lib + ".so";
if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)) {
llvm::errs() << "\n" << "Loading library " << lib << ". " << msgErr << "\n";
}
}
}
void
ExternLayer::init(const AST* ast) {
std::vector<string> args{
"-isystem"
};
list<string> code;
std::vector<string> libs;
boost::format formatInclude("#include \"%1%\"");
for(const ExternData& entry : ast->__externdata) {
llvm::outs() << "[ExternC] Processing package: " << entry.package << "\n";
llvm::outs() << "[ExternC] args: ";
vector<string>&& args2 = fetchPackageFlags(entry);
args.insert(args.end(), args2.begin(), args2.end());
for(const string arg : args2) {
llvm::outs() << "<" << arg << "> ";
}
llvm::outs() << "\n[ExternC] libs: ";
args2 = fetchPackageLibs(entry);
for(const string arg : args2) {
llvm::outs() << "<" << arg << "> ";
}
libs.insert(libs.end(), args2.begin(), args2.end());
llvm::outs() << "\n[ExternC] headers: ";
std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()),
[&formatInclude](const string header ) {
string line = boost::str(formatInclude % header);
llvm::outs() << "<" << line << "> ";
return line;
});
llvm::outs() << '\n';
}
loadLibraries(move(libs));
ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args);
__llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayout());
__clang.reset(new CompilerInstance());
__clang->createDiagnostics();
__codegen.reset(CreateLLVMCodeGen(
__clang->getDiagnostics(),
__llvm->module->getName(),
__clang->getHeaderSearchOpts(),
__clang->getPreprocessorOpts(),
clang::CodeGenOptions(),
__llvm->llvmContext
));
__codegen->Initialize(ast->getASTContext());
};
bool
ExternLayer::isPointer(const clang::QualType &t) {
const clang::Type * tInfo = t.getTypePtr();
assert(tInfo);
return tInfo->isAnyPointerType();
}
llvm::Type*
ExternLayer::toLLVMType(const clang::QualType& t) {
return CodeGen::convertTypeForMemory( __codegen->CGM(), t);
}
std::vector<std::string>
ExternLayer::getStructFields(const clang::QualType& ty) {
clang::QualType t = ty;
if (isPointer(ty)) {
const clang::PointerType* tPtr = ty->getAs<clang::PointerType>();
t = tPtr->getPointeeType();
}
assert(t.getTypePtr()->isRecordType());
const RecordType *record = t->getAsStructureType();
assert(record);
std::vector<std::string> result;
//FieldDecl* field: record->getDecl()->fields()
for (auto i = record->getDecl()->field_begin(); i != record->getDecl()->field_end(); ++i) {
result.push_back(i->getName());
}
return result;
}
bool
ExternLayer::isArrayType(const std::string& type){
clang::QualType typeRaw = lookupType(type);
if (isPointer(typeRaw)) {
const clang::PointerType* typePtr = typeRaw->getAs<clang::PointerType>();
typeRaw = typePtr->getPointeeType();
}
return typeRaw->isArrayType();
}
bool
ExternLayer::isRecordType(const std::string& type){
clang::QualType typeRaw = lookupType(type);
if (isPointer(typeRaw)) {
const clang::PointerType* typePtr = typeRaw->getAs<clang::PointerType>();
typeRaw = typePtr->getPointeeType();
}
return typeRaw->isRecordType();
}
clang::QualType
ExternLayer::lookupType(const std::string& id) {
MatchFinder finder;
FinderCallbackTypeDecl callbackTypeDecl;
auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename");
finder.addMatcher(matcherTypeDecl, &callbackTypeDecl);
finder.matchAST(ast->getASTContext());
assert(! callbackTypeDecl.typeResult.isNull());
return callbackTypeDecl.typeResult;
}
llvm::Function*
ExternLayer::lookupFunction(const std::string& name) {
if (__functions.count(name)) {
return __functions.at(name);
}
MatchFinder finder;
FinderCallbackFunction callback;
auto matcher = functionDecl(hasName(name)).bind("function");
finder.addMatcher(matcher, &callback);
finder.matchAST(ast->getASTContext());
if (callback.typeResult.isNull()) {
cout << "[External Layer] " << "Unknown function: " << name << endl;
assert(false && "Unknown external function");
}
const QualType& tyFuncQual = callback.typeResult;
llvm::Type *tyRaw = CodeGen::convertTypeForMemory(__codegen->CGM(), tyFuncQual);
llvm::FunctionType* tyRawFunc = llvm::dyn_cast<llvm::FunctionType>(tyRaw);
llvm::Function* function = llvm::Function::Create(
tyRawFunc,
llvm::GlobalValue::ExternalLinkage,
name,
__llvm->module.get());
__functions.emplace(name, function);
return function;
}
}//end of xreate namespace

Event Timeline