首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C++Builder项目的Delphi单元中使用Crtl?(或链接到C++Builder C运行时库)

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

Stack Overflow用户
提问于 2011-03-14 19:41:57
回答 3查看 2K关注 0票数 3

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

代码语言:javascript
复制
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)中编译该单元,它将失败,并出现错误:

代码语言:javascript
复制
[ILINK32 Error] Fatal: Unable to open file 'CRTL.OBJ'

实际上,RAD安装文件夹中没有crtl.obj文件。有一个.dcu,但没有.pas。试图将crtdbg添加到uses子句(定义_assert的C头)会产生一个错误,无法找到crtdbg.dcu

如果删除使用子句,它反而会失败,而错误则找不到__assert_memmove

因此,在C++Builder项目中的Delphi中,如何从C运行时库导出函数,使它们可用于链接?

我已经知道鲁迪·维尔萨斯的文章了。如果可能的话,我想避免手动编写Delphi,因为我在Delphi中不需要它们,而且C++Builder必须已经包含了必要的功能。

编辑

对于任何想在家里玩的人来说,代码可以在Abbrevia在https://tpabbrevia.svn.sourceforge.net/svnroot/tpabbrevia/trunk的Subversion存储库中获得。我采纳了David的建议,增加了一个"AbCrtl.pas“单元,在C++Builder中编译时模仿crtl.dcu。这使PPMd支持正常工作,但是Lzma和WavPack库都失败了,链接错误如下:

代码语言:javascript
复制
[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 1实际上是在AbLzma.pas中声明的,所以它也被纯Delphi编译所使用。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-14 19:50:55

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

在C++构建器版本中,您只需编译并链接foolib.c,就好像它是一个C文件(它是!)在Delphi版本的程序中,您使用bcc32创建bcc32,使用ctrl等,如所述。

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

编辑1

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

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

如果您只缺少几个函数,这可能是一个很有吸引力的选择。通常,获取它们的最简洁的方法是从msvcrt.dll链接它们,这是当今的一个标准系统组件。当然,在msvcrt.dll中链接似乎有点重量级,只是为了获得memset()memcpy()等。

在编译没有crtl的Delphi单元时,有多少缺少函数?

编辑2

我将这个添加到答案中,以显示一些代码。根据我自己的代码库,我提供以下内容:

代码语言:javascript
复制
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编译器中的一个库文件中提取的。

我认为strncmp应该是在朴素Pascal中实现的相当例行的程序。

sprintf在全局性上更加困难,但是您可能会发现它只用于一些琐碎的事情,比如整数到字符串。在这种情况下,您可以伪造C代码来调用一个专用于此的例程,并尽可能地实现它。

老实说,我觉得“msvcrt.dll”看起来很有吸引力!

编辑3

我很快就跟你说话了吗?您可以从user32.dll中提取一个完全可用的sprintf,无论如何,几乎所有的进程都已经加载了它。如果wsprintfA是您需要的ANSI版本,一定要选择它。

编辑4

我注意到_beginthreadex。您说这是在不同的Delphi单元中定义的。为了让编译器看到它,您需要在AbCtrl.pas中重新声明它,然后在AbLzma.pas中调用真正的版本。

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

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

票数 4
EN

Stack Overflow用户

发布于 2011-03-14 21:38:15

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

票数 0
EN

Stack Overflow用户

发布于 2012-01-08 12:50:48

虽然很晚,但更完整:从crtl.dcu到XE2,从D2005到XE2都没有问题。

对于D6和D7,存在对midaslib.dcu的依赖关系。嗯,不完全是,dcu是通过一个脏用子句分发的。

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

代码语言:javascript
复制
unit midaslib;
interface
implementation
end.

现在您可以使用crtl.dcu而没有内部错误!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5303568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档