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

我有一个Delphi单元,使用
{$L xxx}
指令静态链接C .obj文件。 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)中编译该单元,则everthing工作正常。 如果我在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的建议,并在C ++ Builder中编译时添加了一个模仿crtl.dcu的“AbCrtl.pas”单元。这使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编译使用。 要自己查看,只需下载trunk(或只是“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是目前的标准系统组件。当然,在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文件中提取的。 我认为在普通的Pascal中实现
strncmp
应该是非常常规的。
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是用脏使用条款分发的。 对于D6和D7,您应该创建一个EMPTY midaslib.pas代理,如:
unit midaslib;
interface
implementation
end.
现在你可以使用crtl.dcu而不会出现内部错误!     

要回复问题请先登录注册