繁体   English   中英

如何在C ++ Builder项目的Delphi单元中使用Crtl? (或链接到C ++ Builder C运行时库)

[英]How to use Crtl in a Delphi unit in a C++Builder project? (or link to C++Builder C runtime library)

我有一个使用{$L xxx}指令静态链接C .obj文件的Delphi单元。 C文件使用C ++ Builder的命令行编译器进行编译。 为了满足C文件的运行时库依赖性(_assert,memmove等),我包括了此处提到的crtl单元Allen Bauer。

unit FooWrapper;

interface

implementation

uses
 Crtl; // Part of the Delphi RTL

{$L FooLib.obj}  // Compiled with "bcc32 -q -c foolib.c"

procedure Foo; cdecl; external;

end.

如果我在Delphi项目(.dproj)中编译该单元,则一切正常。

如果我在C ++ Builder项目(.cbproj)中编译该单元,它将失败并显示以下错误:

[ILINK32 Error] Fatal: Unable to open file 'CRTL.OBJ'

确实,RAD Studio安装文件夹中没有crtl.obj文件。 有一个.dcu,但没有.pas。 尝试将crtdbg添加到uses子句(定义_assert的C头),会导致错误,导致找不到crtdbg.dcu

如果删除了uses子句,它会因找不到__assert_memmove错误而失败。

因此,在C ++ Builder项目的Delphi单元中,如何从C运行时库中导出函数以便可以将其链接?

我已经知道Rudy Velthuis的文章 我想避免在可能的情况下手动编写Delphi包装器,因为在Delphi中不需要它们,并且C ++ Builder必须已经包含必需的函数。

编辑

对于想在家玩的人,可以在Abbrevia的Subversion存储库中找到该代码, 网址https://tpabbrevia.svn.sourceforge.net/svnroot/tpabbrevia/trunk 我接受了David Heffernan的建议,并添加了一个“ AbCrtl.pas”单元,该单元在C ++ Builder中进行编译时模仿crtl.dcu。 PPMd支持工作了,但是Lzma和WavPack库都因链接错误而失败:

[ILINK32 Error] Error: Unresolved external '_beginthreadex' referenced from ABLZMA.OBJ
[ILINK32 Error] Error: Unresolved external 'sprintf' referenced from ABWAVPACK.OBJ
[ILINK32 Error] Error: Unresolved external 'strncmp' referenced from ABWAVPACK.OBJ
[ILINK32 Error] Error: Unresolved external '_ftol' referenced from ABWAVPACK.OBJ

AFAICT都正确地声明了它们,并且_beginthreadex实际上是在AbLzma.pas中声明的,因此纯Delphi编译器也使用它。

要自己查看,只需下载主干(或仅下载“ source”和“ packages”目录),禁用AbDefine.inc底部的{$ IFDEF BCB}块,然后尝试编译C ++ Builder“ Abbrevia .cbproj”项目。

我对此的看法是,在项目的Delphi版本中只需要Delphi单元。

在C ++构建器版本中,您只需编译并链接foolib.c就好像它是一个C文件一样(它是!)。在该程序的Delphi版本中,您可以使用bcc32创建.obj,并按照说明使用ctrl等。

为什么要在Delphi包装器中将其包装成C库以便在C ++中使用?

编辑1

您已在评论中添加了说明。

要考虑的另一种选择是避免crtl并实现FooWrapper中缺少的功能。 我这样做不是使用crtl,因为这样做可以给我更多的控制权,并且我理解被调用的内容。 例如,我不希望任何对printf()调用泄漏到我的GUI应用程序或DLL中。

如果您只缺少一些功能,那么这可能是一个有吸引力的选择。 通常,获取它们的最捷径是从当今作为标准系统组件的msvcrt.dll进行链接。 当然,链接msvcrt.dll只是为了获得memset()memcpy()等似乎有点重量级。

在不使用crtl的情况下编译Delphi单元时,有多少个缺少的函数?

编辑2

我将其添加到答案中以显示一些代码。 从我自己的代码库中,我提供了这一点:

const
  __turboFloat: Longint=0;
  (* We don't actually know the type but it is 4 bytes long and initialised to zero.  This can be determined
     using tdump initcvt.obj.  It doesn't actually matter how we define this since it is ultimately not
     referred to and is stripped from the executable by the linker. *)

对于ftol我链接到ftol.obj中,我认为它是从我使用的BCC55编译器中的一个lib文件中提取的。

我认为strncmp应该是在纯Pascal中实现的常规程序。

sprintf很难完全概括,但是您可能会发现它仅用于一些琐碎的事情,例如整数到字符串。 在这种情况下,您可以伪造C代码以调用专用于该例程的例程并轻松实现该例程。

老实说,我认为“ msvcrt.dll”看起来很吸引人!

编辑3

我有话要说吗? 您可以从几乎所有进程都已加载的user32.dll中拉出一个完全可维护的sprintf 如果您需要的是ANSI版本,请确保选择wsprintfA

编辑4

我注意到_beginthreadex 您说这是在另一个Delphi单元中定义的。 为了使编译器能够看到它,您需要在AbCtrl.pas中重新声明它,然后从那里在AbLzma.pas中调用真实版本。

在Delphi .pas文件中包含.obj时,编译器必须能够从链接到.obj的Delphi单元中解析.obj文件中的所有引用。 整个游戏是由编译器而不是链接器处理的。

有时您会纠结于包含.obj文件的顺序,解决方案是使用前向声明,但这是另一回事了。

在这种情况下,假定您感兴趣的功能可直接从C RTL获得,因此用伪(空)obj文件伪造链接器应该可以工作,因为它将满足寻找Delphi告诉它的obj文件的链接器的要求。您需要,但仍然可以在RTL中找到功能。

较晚,但更完整:从D2005到XE2,crtl.dcu都可以正常工作。

对于D6和D7,依赖于midaslib.dcu。 好吧,不是真的,dcu分配了一个肮脏的use子句。

对于D6和D7,您应该创建一个EMPTY midaslib.pas代理,例如:

unit midaslib;
interface
implementation
end.

现在,您可以使用crtl.dcu而不会出现内部错误!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM