如何在Squeak FFI中支持32位和64位目标

时间:2018-04-11 21:10:35

标签: smalltalk ffi squeak

我必须处理具有此类定义struct foo {float *data; size_t len;};

的外部库

首先,我在Squeak

中定义相应的结构
ExternalStructure subclass: #Foo 
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'FFI-Tests'.

然后Squeak FFI可以处理不同的指针大小 我知道我必须通过Foo defineFields重新生成字段访问权限。 但是,我可以在包装加载postscript中处理这个问题。

不幸的是,Squeak FFI没有size_t支持。在我想支持的平台上,我知道它将是uint32_t和uint64_t,它们分别在Squeak FFI中转换为unsigned longunsigned long long(这些类型是从Squeak图像大小查看的固定大小)。

那我该怎么办?有两个不同的Foo定义(但是我必须使用foo复制所有类型,并使用foo复制原型的接口)

Foo32 class>fields
    ^#(
        (data 'float*')
        (len 'ulong')
      )


Foo64 class>fields
    ^#(
        (data 'float*')
        (len 'ulonglong')
      )

还是有其他解决方案(例如手动定义字段/偏移/ byteSize和Smalltalk wordSize=4 ifTrue: [] ifFalse: [])?

3 个答案:

答案 0 :(得分:1)

我不能告诉你如何在Squeak中做到这一点,但我可以与你分享我们使用的Smalltalk方言所采用的方法。

  1. 为每个将字段名称与结构中的偏移量相关联的字段共享变量
  2. 默认情况下,所有此类偏移都适用于32位目标平台
  3. 使用这些共享变量(而不是文字数字)编写访问者方法
  4. 有一个#offsets64类侧方法,可以使用64位
  5. 的偏移字典进行回答
  6. 启动时,如果系统正在运行64位,请使用#offsets64字典将共享关联的值替换为64位偏移量。这不需要访问器上的条件逻辑,也不需要重新编译方法。如果字段的相对位置随平台变化,它也可以很好地工作。
  7. 请注意,仅当结构布局取决于位长度时才需要执行步骤4和5(情况并非总是如此)。

    如果您的系统支持“本地池字典”,这是一个具有类变量范围的池字典,则所有这些都可以简化。

答案 1 :(得分:1)

自mt.101起,您还可以为原子类型使用轻量级别名,这些原子类型通常以“类型常量”协议的形式在ExternalType class上作为消息实现。参见source.squeak.org/FFI/FFI-Kernel-mt.101.diff

<stddef.h><stdint.h>已知的typedef已有通用别名,例如size_t(或uintptr_t),您可以在字段定义中使用它们的外部结构和FFI调用的参数定义。

您现在可以跨平台编写您的示例:

Foo class>>fields
    ^ #(
        (data 'float*')
        (len 'size_t')
      )

答案 2 :(得分:0)

现在我发现How one deals with typedefs in Squeak FFI报告的别名(typedef)我看到了一个解决方案:
定义Size_t别名

ExternalStructure subclass: #'Size_t'
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'FFI-Tests'

然后定义平台相关字段:

Size_t class>>fields
   ^(Smalltalk wordSize = 4)
       ifTrue: [#( nil 'ulong' )]
       ifFalse: [#( nil 'ulonglong' )]

然后执行Size_t defineFields,现在我有一个Size_t类型,可以在函数原型中使用,也可以用于组合其他结构。 32位和64位图像的布局会有所不同,但我不必更改客户端代码。

对于特定于平台的&#uns; long&#39;而言,这有点问题。因为Windows 64位上的LLP64是受支持的平台之一:

ExternalStructure subclass: #'Unsigned_long'
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'FFI-Tests'

Unsigned_long class>>fields
   ^(Smalltalk wordSize = 4 or: [Smalltalk platformName = 'Win64'])
       ifTrue: [#( nil 'ulong' )]
       ifFalse: [#( nil 'ulonglong' )]

然后我必须在启动映像时检查平台的更改并重新编译所有ExternalType。
这个重新编译必须以正确的顺序执行,再一次,我在Squeak FFI中看不到任何支持,这将需要更多的工作......

编辑我修改了Squeak FFI,以便在另一个平台上恢复图像时引入自动重新编译支持,以及嵌套结构的正确初始化顺序。
http://source.squeak.org/FFI/FFI-Kernel-nice.49.diff