d导入c的示例
原文
在语言中拥有ImportC有个非常酷的好处.使我们能够动态绑定到C库,而无需手动编写任何绑定代码!
窍门:
第1步:预处理C库头文件,以便可在D中导入它.
第2步:使用D的编译时内省来生成函数指针和相关的加载程序例程.
第3步:后续动作
第4步:利润!
static import portaudio;
import std.meta;
import std.stdio;
import std.traits;
import core.sys.windows.windows;
struct Tuple(_FuncType, string _Name) {
alias FuncType = _FuncType;
enum Name = _Name;
}
//取实际函数的函数指针类型
template FuncType(alias symbol) {
ReturnType!symbol function(Parameters!symbol) func;
alias FuncType = SetFunctionAttributes!(typeof(func), functionLinkage!symbol,
functionAttributes!(typeof(func)));
}
//取模块序列(函数类型,名)
template GetFunctionList(alias Module) {
alias GetFunctionList = AliasSeq!();
static foreach (idx, member; __traits(allMembers, Module)) {
static if (isFunction!(__traits(getMember, Module, member))) {
GetFunctionList = AliasSeq!(GetFunctionList,
Tuple!(FuncType!(__traits(getMember, Module, member)), member));
}
}
}
//生成模块和加载库的动态绑定
class Dynamic(alias Module, string SharedLib)
{
//加载动态库
static HANDLE dll;
static this() {
dll = LoadLibraryA(SharedLib);
!dll && assert(0);
}
//声明函数指针
static foreach (Tup; GetFunctionList!Module) {
mixin("Tup.FuncType " ~ Tup.Name ~ ";");
}
//加载函数指针
this()
{
static foreach (Tup; GetFunctionList!Module) {
*(cast(void**)&__traits(getMember, this, Tup.Name))
= cast(void*)GetProcAddress(dll, Tup.Name);
}
}
}
void main() {
// 简单!
auto dynamic = new Dynamic!(portaudio, "portaudio_x64.dll");
printf("版本信息%s\n", dynamic.Pa_GetVersionText());
}
好的!我想知道它是否也可以用来生成静态绑定?就像,只是用它来输出有正确函数/结构定义的D模块?
#defines仍然没有帮助
可用
typeof(&__traits(getMember, Module, member))
替换
FuncType!(__traits(getMember, Module, member))
来完全消除FuncType模板.
std.meta/std.traits臃肿而缓慢,我建议坚持使用简单的__traits并复制/粘贴需要的少数(2-3)个函数.
简单的结构就可以了.
static import不好,它会泄漏所有函数到全局范围,一个小技巧:
import pa = portaudio;
(..)
auto dynamic = Dynamic!(pa, "portaudio_x64.dll")();
因此,生成静态绑定可避免大量样板工作,还可得到importC无法完成的完整绑定.
dstep需要libclang,而importC不需要
可用常数组生成枚来替代#defines.
__traits(comment)取注释.
浙公网安备 33010602011771号