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

StackOverflow https://stackoverflow.com/questions/5303568

  •  24-10-2019
  •  | 
  •  

我有一个Delphi单元,该单元在静态地链接C .OBJ文件 {$L xxx} 指示。 C文件与C ++构建器的命令行编译器一起编译。为了满足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 ++构建器项目(.cbproj)中编译该单元,则失败的错误:

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

确实,没有 crtl.obj 在Rad Studio安装文件夹中文件。有一个.dcu,但没有.pas。试图添加 crtdbg 对于使用条款(定义_assert的C标题)给出了一个错误,它找不到它 crtdbg.dcu.

如果我删除 用途 条款,它会因错误而失败 __assert_memmove 找不到。

因此,在C ++构建器项目中的Delphi单元中,如何从C运行时库中导出函数,以便它们可以链接?

我已经知道Rudy Velthuis的 文章. 。如果可能的话,我想避免手动编写Delphi包装器,因为我在Delphi中不需要它们,并且C ++构建器必须已经包含必要的功能。

编辑

对于任何想在家玩耍的人,该代码可在Abbrevia的颠覆存储库中找到 https://tpabbrevia.svn.sourceforge.net/svnroot/tpabbrevia/trunk. 。我已经接受了David Heffernan的建议,并添加了一个“ abcrtl.pas”单元,该单元在C ++构建器中编译时模仿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 compile也使用了它。

要亲自查看,只需下载后备箱(或只是“源”和“软件包”目录),请在Abdefine.inc的底部禁用{$ ifdef bcb}块,然后尝试编译C ++构建器“ Abbrevia .cbproj“项目。

有帮助吗?

解决方案

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

在C ++构建器版本中,您只需编译并链接foolib.c,就好像它是一个c文件(是!),在您使用BCC32创建.OBJ的程序的Delphi版本中,如所述,请使用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 在普通的帕斯卡尔中实施应该是非常常规的。

sprintf 在完全的一般性方面更加困难,但是您可能会发现它仅用于像整数这样的琐碎的东西。在这种情况下,您可以伪造C代码来调用专门为此的例行程序并琐碎地实施。

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

编辑3

我很快说话了吗?您可以拉出一个完美的服务 sprintf 从User32.dll出发,几乎所有流程都已经加载了。确保您挑选 wsprintfA 如果是您需要的ANSI版本。

编辑4

我注意到 _beginthreadex. 。您说这是在不同的Delphi单元中定义的。为了让编译器查看它,您需要在abctrl.pas中重新计算它,然后从那里调用Ablzma.pas中的真实版本。

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

有时,您会因包含.OBJ文件的顺序而打结,而解决方案是使用正向声明,但这是另一个故事。

其他提示

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

迟到,但更完整:crtl.dcu在d2005到xe2之前没有问题。

对于D6和D7,对Midaslib.dcu有一个依赖性。好吧,并非真的,DCU使用肮脏的用户分发。

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

unit midaslib;
interface
implementation
end.

现在,您可以使用CRTL.DCU而没有内部错误!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top