【问题标题】:batch created C interface in nimlang with template/macro?使用模板/宏在 nimlang 中批量创建 C 接口?
【发布时间】:2019-01-26 08:32:24
【问题描述】:

背景

事实上,我正在将FLTK C 1.3.3 for FreeBASIC 移植到nimlang。请注意FLTK C 1.3.3 for FreeBASICFLTK in CPP 上的C 接口。

DLL 中的许多函数都满足相同的类似名称格式,例如

#inclib "fltk-c-1.3.3-64" ' Windows 64-bit

function Fl_ButtonExNew (byval x as long, byval y as long, byval w as long, byval h as long, byval title as const zstring ptr=0) as Fl_ButtonEx Ptr
sub Fl_ButtonExDelete(byval x as Fl_ButtonEx ptr)

function Fl_BoxExNew (byval x as long, byval y as long, byval w as long, byval h as long, byval title as const zstring ptr=0) as Fl_BoxEx Ptr
sub Fl_BoxExDelete(byval x as Fl_BoxEx ptr)

and so on

似乎被删除的函数/子会自动加载 fltk-c-1.3.3-64.dll 中的同名函数(如果错了,请纠正我)

FreeBASIC 中的解决方案

所以在 FreeBASIC 标头 fltk-main.bi 中,有一个辅助宏

#macro DeclareEx(_name_)
declare function _name_##ExNew(byval x as long, byval y as long, byval w as long, byval h as long, byval title as const zstring ptr=0) as _name_##Ex ptr
declare sub      _name_##ExDelete         (byref ex as _name_##Ex ptr)
#endmacro

借助它,上述代码(和许多其他代码)可以通过简单的一行代码生成:

DeclareEx(Fl_Button)
DeclareEx(Fl_Box)

我在 nimlang 中的问题

在nimlang中(请暂时忽略数字类型转换),上面的代码可以手动翻译为

const fltk = "fltk-c-1.3.3-64.dll"
type long = int64
proc Fl_ButtonExNew (x: long, y: long, w: long, h: long, title: cstring=nil): Ptr Fl_ButtonEx {.cdecl, importc: "Fl_ButtonExNew", dynlib: fltk, discardable.}
proc Fl_ButtonExDelete(x: ptr Fl_ButtonEx) {.cdecl, importc: "Fl_ButtonExDelete", dynlib: fltk, discardable.}

proc Fl_BoxExNew (x: long, y: long, w: long, h: long, title: cstring=nil): Ptr Fl_BoxEx {.cdecl, importc: "Fl_BoxExNew", dynlib: fltk, discardable.}
proc Fl_BoxExDelete(x: ptr Fl_BoxEx) {.cdecl, importc: "Fl_BoxExDelete", dynlib: fltk, discardable.}

所以我尝试模仿 FreeBASIC 宏的作用

const fltk = "fltk-c-1.3.3-64.dll"
type long = int64

template DeclareEx*(name: untyped) {.dirty.}=
    type `name Ex` = object
    type `name ExNew`* = proc(x: long, y: long, w: long, h: long, title: cstring=nil): ptr `name Ex` {.cdecl, importc: "name New", dynlib: fltk, discardable.}
    type `name ExDelete`*  = proc(ex: ptr `name Ex`) {.cdecl, importc: "name ExDelete", dynlib: fltk, discardable.}

DeclareEx(Fl_Button)

但是当我编译它时,我得到了

d.nim(9, 10) 模板/通用实例化 DeclareEx 从这里

d.nim(6, 118) 错误:无效的编译指示:importc: "name New"

那么,有什么解决办法吗?谢谢

【问题讨论】:

    标签: templates dll macros nim-lang


    【解决方案1】:

    模板中提供的反引号插值只能用于需要标识符的位置。 importc pragma 需要一个常量字符串表达式。您可以使用 astToStr 魔法将任何 AST 输入转换为其相应的字符串表示形式,这是解决此问题的关键:

    const fltk = "fltk-c-1.3.3-64.dll"
    type long = int64
    
    template DeclareEx*(name: untyped) =
      const
        newProc = astToStr(name) & "New"
        deleteProc = astToStr(name) & "ExDelete"
    
      type `name Ex`* {.inject.} = object
      proc `name ExNew`*(x: long, y: long, w: long, h: long, title: cstring=nil): ptr `name Ex` {.cdecl, inject, importc: newProc, dynlib: fltk, discardable.}
      proc `name ExDelete`* (ex: ptr `name Ex`) {.cdecl, inject, importc: deleteProc, dynlib: fltk, discardable.}
    
    DeclareEx(Fl_Button)
    DeclareEx(Fl_Window)
    
    var btn: ptr Fl_ButtonEx
    Fl_ButtonExDelete(btn)
    

    【讨论】:

    • 谢谢,但我无法理解 importc: "x" 的部分。如何翻译成,例如importc: "Fl_BoxExNew"
    • 啊,我错过了对代码进行最后的修改。这个想法是我将新常量传递给importc。该示例现已修复。
    • 当我多次使用这个模板时,例如DeclareEx(Fl_Button)DeclareEx(Fl_Table),我得到Error: redefinition of 'newProc'; previous declaration here: a.nim(6, 5)。所以未导出的newProc 的行为不像模板中的本地变体。
    • 这可以通过编写 "proc name ExNew*(x: long, y: long, w: long, h: long, title: cstring=nil): ptr name Ex {. cdecl, importc: astToStr(name) & "ExNew", dynlib: fltk, discardable.}";但我更喜欢你帖子中的方式(即在使用它之前先定义字符串,这使得代码清晰/易于阅读),但是我们如何使newProc 成为本地变体?谢谢
    • 这是因为模板被标记为dirty(有关说明,请参见hygiene in templates)。该问题通过使用gensym pragma 标记常量来解决。
    【解决方案2】:

    importc pragma 用于从 C 中导入过程或变量。但是,您正在编写 importc: "name New",而 name New 在 C 中不是有效的标识符,因为它有一个空格。您需要尝试将传递给模板的变量的符号名称与该附加字符串后缀连接起来。

    不过,我不知道如何在模板中做到这一点。也许您可以传递一个字符串作为参数,然后使用& 运算符将其与importc 的后缀连接起来。

    【讨论】:

      猜你喜欢
      • 2016-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 1970-01-01
      • 2018-03-27
      相关资源
      最近更新 更多