在一些LLVM教程中,我看到将C函数绑定到基于LLVM的自定义语言相当容易。 LLVM向程序员提供指向该函数的指针,然后该函数可以与LLVM生成的代码混合在一起。
使用C ++库执行此操作的最佳方法是什么。假设我有一个相当复杂的库,比如Qt或Boost,我想绑定到我的自定义语言。我是否需要创建存根库(如Python或Lua需要),或者LLVM是否提供某种外部函数接口(FFI)?
答案 0 :(得分:13)
在我的LLVM代码中,我为此创建了extern "C"
包装器函数,并将LLVM函数声明插入到模块中以便调用它们。然后,让LLVM了解函数的一个好方法是不要让它使用dlopen
并在执行二进制文件中搜索函数名称(这是一个痛苦的屁股,因为函数名称需要在.dynsym
部分,也很慢),但要使用ExecutionEngine::addGlobalMapping手动执行映射。
只需获取该声明的llvm::Function*
和C ++中给出的&functionname
转换为void*
的函数的地址,并将这两项内容传递给LLVM。执行您的东西的JIT将知道在哪里找到该功能。
例如,如果你想包装QString
,你可以创建几个创建,销毁和调用这种对象函数的函数
extern "C" void createQString(void *p, char const*v) {
new (p) QString(v); // placement-new
}
extern "C" int32_t countQString(void *p) {
QString *q = static_cast<QString*>(p);
return q->count();
}
extern "C" void destroyQString(void *p) {
QString *q = static_cast<QString*>(p);
q->~QString();
}
并创建适当的声明和映射。然后你可以call
这些函数,传递一个适当的对齐和大小适合QString
(可能是alloca
'ed)的内存区域和一个指向C字符串数据的i8*
初始化。
答案 1 :(得分:3)
如果你用C ++编译一些代码,用另一种语言编译一些代码到LLVM bitcode,那么完全可以将这些代码链接在一起,让一个人调用另一个...理论上。
实际上,您需要使用胶水代码在不同语言的类型之间进行转换(例如,除非您使用CPython,否则在C ++中没有等效的Python字符串,因此void reverse(std::string s)
可以使用{{1}进行调用你需要一个转换 - 更糟糕的是,整个对象模型是非常不同的)。而Qt特别具有很多魔力,可能需要更多努力才能在编译后暴露出来。此外,还有一些我不知道的潜在问题。
即使这样有效,使用它也可能非常难看。尽管Python是非常方便的描述符,但PyQt上仍然有str
和get*
个函数 - 并且PyQt付出了很多努力,它们不只是创建了一些存根。