编写要从 gcc 应用程序调用的 Delphi/FreePascal DLL
我需要将我的 Win32 Delphi 应用程序的一部分可供另一家公司的 Linux gcc 程序使用。
吞吐量和部署要求使得任何类型的远程服务都不适合,因此我正在考虑使用 FreePascal 构建 gcc 应用程序可以调用的 .SO(相当于 DLL 的 Linux)。
我已经很长时间没有使用 C/C++ 了,而且从未在 Linux 上使用过,所以我有点不确定如何最好地构造 DLL/SO 接口以与 gcc 调用者兼容。
这是我的数据结构的表示
TFoo = record
x, y : double;
a : smallint;
b : string;
end;
TBar = record
a : double;
b : longint;
c : string;
end;
TFooBar = record
foo : array of TFoo;
bar : array of TBar;
end;
procedure Process(const inFooBar : TFooBar);
要通过 FreePascal 使此 Process 方法在外部可用。那么我需要如何修改这些声明?我正在思考类似
TFoo = record
x, y : double;
a : smallint;
b : PChar;
end;
TBar = record
a : double;
b : longint;
c : PChar;
end;
TFooBar = record
foo : ^TFoo;
foo_count : longint;
bar : ^TBar;
bar_count : longint;
end;
procedure Process(const inFooBar : TFooBar);
我走在正确的轨道上吗?我不必完全正确,其他公司的程序员很可能会修复我的错误。我只是不想让他们看到我发给他们的内容时笑得太厉害。
I need to make parts of my Win32 Delphi app available to another company's Linux gcc program.
Throughput and deployment requirements make any sort of remote service unsuitable so I'm looking at using FreePascal to build a .SO (Linux equivalent of a DLL) that the gcc app can call.
It's a long time since I used C/C++ and never on Linux so I'm a little unsure as to how best to structure the DLL/SO interface for compatibility with a gcc caller.
Here's a representation of my data structures
TFoo = record
x, y : double;
a : smallint;
b : string;
end;
TBar = record
a : double;
b : longint;
c : string;
end;
TFooBar = record
foo : array of TFoo;
bar : array of TBar;
end;
procedure Process(const inFooBar : TFooBar);
To make this Process method externally available via a FreePascal .SO how do I need to modify these declarations? I'm thinking something along the lines of
TFoo = record
x, y : double;
a : smallint;
b : PChar;
end;
TBar = record
a : double;
b : longint;
c : PChar;
end;
TFooBar = record
foo : ^TFoo;
foo_count : longint;
bar : ^TBar;
bar_count : longint;
end;
procedure Process(const inFooBar : TFooBar);
Am I on the right track? I don't have to get this exactly right, the other company's programmers will very likely fix up my mistakes. I just don't want them to laugh too hard when they see what I've sent them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用
PAnsiChar
代替PChar
,使用integer
代替longint/smallint
(因为您使用对齐记录,所以有使用smallint 字段没有任何好处)。定义一些指针类型,如
PFoo
和PBar
,这会比^TFoo
写得更好,例如如果你需要访问一些数组,你可以定义
TFooArray
和TBarArray
,如下面的代码所示。不要忘记任何函数/过程的
cdecl
或stdcall
调用约定。您的进程将是只读的吗?
如果C部分需要添加一些项目,则必须向外部库提供一些内存重新分配方法,至少映射
reallocmem()
。请注意,Delphi 动态数组可以轻松映射到 C 兼容结构,如下所示:
这可以使您的 Delphi 代码更具可读性。看看我们的
TDynArray
包装器 如果您希望使用类似TList
的方法对此类动态记录数组进行高级访问。由于
AnsiString
类型映射PAnsiChar
,从二进制的角度来看,您甚至可以这样定义记录:当映射到 gcc 应用程序时,它将被读取为常规的
*char
。在这里使用
AnsiString
,您将不需要处理 Delphi 代码中的内存分配。通过关联的动态数组,它可以使您的 Delphi 代码更易于维护。请注意,我们的TDynArray
包装器将按预期处理记录中的嵌套AnsiString
,即使对于最高级别的方法(例如二进制序列化或哈希)也是如此。Use
PAnsiChar
instead ofPChar
, andinteger
instead oflongint/smallint
(since you use aligned records, there is no benefit of using a smallint field).Define some pointer types like
PFoo
andPBar
, which will be better written than^TFoo
e.g.If you need to access some arrays, you could define
TFooArray
andTBarArray
, as in the code below.Don't forget the
cdecl
orstdcall
calling convention for any function/procedure.Will be your process read-only?
If the C part need to add some items, you'll have to provide some memory reallocation methods to the external library, mapping at least
reallocmem()
.Note that Delphi dynamic arrays can be mapped easily into C compatible structure, as such:
This could make your Delphi code much more readable. Take a look at our
TDynArray
wrapper if you want high-level access to such a dynamic array of records, withTList
-like methods.Since the
AnsiString
type maps aPAnsiChar
, from the binary point of view, you can even define your records as such:When mapped to the gcc application, it will be read as a regular
*char
.Using
AnsiString
here you won't need to handle memory allocation from your Delphi code. With an associated dynamic array, it could make your Delphi code much easier to maintain. Note that ourTDynArray
wrapper will handle nestedAnsiString
in records as expected, even for the highest level methods (e.g. binary serialization or hashing).为了确保记录打包/对齐/填充符合 GCC 的预期,请将 {$packrecords c} 添加到您的 Pascal 源中。请注意,该指令特定于 Free Pascal 编译器,Delphi 不支持它。
To ensure that the record packing/alignment/padding is as GCC expects, add {$packrecords c} to your Pascal source. Note that this directive is specific to the Free Pascal Compiler, Delphi does not support it.
看起来不错。想法:
您的数组(声明为指针和计数)将完全手动管理 - 这对您来说没问题吗?
你应该改变:
包含 C 兼容的调用约定。我不确定 FreePascal 和 GCC 都支持什么,但是像
cdecl
这样的东西应该可以正常工作。您还应该(为了安全)指定结构对齐/打包。
PChar
应该明确地窄或宽(现在宽是正常的。)Looks pretty good. Thoughts:
Your arrays (declared as a pointer and count) are going to be fully manually managed - that's fine for you?
You should change:
to include a C-compatible calling convention. I'm not sure what FreePascal and GCC both support, but something like
cdecl
should work fine.You should also (for safety) specify the structure alignment / packing.
PChar
should be explicitly narrow or wide (wide is normal these days.)