尝试使用 libclang 提取 C Union 的信息

最终目标:仅依赖 libclang 定义 @cunion 宏,在 julia 中模拟 C 语言 Union 的行为。

ref: integrate CUnion.jl · Issue #1 · Gnimuc/CSyntax.jl


看上去有用的函数

进度

  • 20191218:能拿到 union 的大小

getUnionSize.jl

using Clang
const cl = Clang

trans_unit = parse_header("./utest.h")
root_cursor = getcursor(trans_unit)
childrens = children(root_cursor)
for ch in childrens
    type_ch = cl.clang_getCursorType(ch)
    union_size = cl.clang_Type_getSizeOf(type_ch)
    print(ch.cursor)
    println(" [$union_size]")
end
C union 测试样例
  • 20191218

utest.h

// simple test
union int_char {    // 4
    int  a;
    char b;
};
union char_char {   // 1
    char a;
    char b;
};


/* 
    padding test
*/
union char10 {
    char arr[10];
};
union char13 {
    char arr[13];
};

union int_char13 {
    char name[13];
    int age;
};

// [Union declaration - cppreference.com](https://en.cppreference.com/w/c/language/union)
union char5_float { // 8
   char  c[5];   // occupies 5 bytes
   float f;      // occupies 4 bytes, imposes alignment 4
};

// [c - Padding in union is present or not - Stack Overflow](https://stackoverflow.com/questions/16749343/padding-in-union-is-present-or-not)
union char9_double {
    char arr[sizeof (double) + 1];
    double d;
};

// [c - sizeof union larger than expected. how does type alignment take place here? - Stack Overflow](https://stackoverflow.com/questions/8453881/sizeof-union-larger-than-expected-how-does-type-alignment-take-place-here?rq=1)
struct p_int {
    int *i;
};
struct int_int {
    int i, j;
};
union u1 { // 8
    struct {
        int *i;
    } s1;
    struct {
        int i, j;
    } s2;
};

struct p_int_int {
    int *i, j;
};
union u2 { // 16
    struct {
        int *i, j;
    } s1;
    struct {
        int i, j;
    } s2;
};

输出

CXCursor_UnionDecl: int_char [4]
CXCursor_UnionDecl: char_char [1]
CXCursor_UnionDecl: char10 [10]
CXCursor_UnionDecl: char13 [13]
CXCursor_UnionDecl: int_char13 [16]
CXCursor_UnionDecl: char5_float [8]
CXCursor_UnionDecl: char9_double [16]
CXCursor_StructDecl: p_int [8]
CXCursor_StructDecl: int_int [8]
CXCursor_UnionDecl: u1 [8]
CXCursor_StructDecl: p_int_int [16]
CXCursor_UnionDecl: u2 [16]
1 个赞

看起来 按照这个思路可以自动生成C库的wrapper

对啊,JuliaInterop/Clang.jl 目前能做大部分的 wrapper 工作,试了下头文件内还不能识别&替换宏定义,不能自动转化 union,不能抽取 docstring。

解决完这三个问题,用 Clang.jl 为导出了 C 接口的库自动生成 wrapper 就很好用了。生成完基本不用大改。

更多问题见: Improvement Meta-list v2 · Issue #228 · JuliaInterop/Clang.jl

既然是代码生成,那么不用追求宏语法(不需要用户手写的),直接生成 getproperty 定义就可以了,你现在的用户是使用 Clang.jl 的 wrapper 作者

至于 CUnion 主要还是提供一个纯 Julia 的手写舒服的形式,MacroTools 之类的依赖理论上可以干掉,但手写宏实在太累了…(本来就是写着玩的项目

@Gnimuc
Union 目前没什么好的想法,我看坑有点深,先放一下。


docstring 试了一下,能凑合着用了,算是从无到有。

然后就想把它变得美观,并且支持对其他结构(enum、union)的注释。
这样就需要一个自定义的转换函数,把 cpp 的注释解析也好,替换也好,变成 julia 格式的 docstring。
类似于 deformat_clang_docstring 干的事情。

它放在 warp_c 里当然不好,毕竟不是完全通用的。(开阶段发临时放一下,最后要放进 generator.jl
我就想把这个函数交给用户,然他们去定义 String -> String 的函数,传进来,我们调用就行.
直接的方法就是 WrapContext & ctx 加个字段,默认值是个啥也不干的函数 id,用户需要就传自定义的函数进来。

目前是这样想的。函数定义,也就是 libclang_api.jl 里的目前看效果可以,等我再把其他情形 enum、struct (libclang_common.jl)的试一试。然后加字段,就可以提 pr 了。