在 Delphi 2007 中链接多个 C 对象文件时出错
我是德尔福新手。我试图在我的 Delphi 项目中添加 C 对象文件并直接链接它们,因为 Delphi 支持 C 对象链接。当我链接单个对象文件时,我得到了它的工作。但是当我尝试链接多个对象文件时,我收到错误“不满意的转发或外部声明”。我已经在 Delphi 2007 和 XE 中尝试过这个。那么我在这里做错了什么?
工作代码:
function a_function():Integer;cdecl;
implementation
{$Link 'a.obj'}
function a_function():Integer;cdecl;external;
end.
错误代码:
function a_function():Integer;cdecl;
function b_function();Integer;cdecl;
function c_function();Integer;cdecl;
implementation
{$LINK 'a.obj'}
{$LINK 'b.obj'}
{$LINK 'c.obj'}
function a_function():Integer;cdecl;external;
function b_function();Integer;cdecl;external;
function c_function();Integer;cdecl;external;
end.
I am new to delphi. I was trying to add C Object files in my Delphi project and link them directly since Delphi Supports C Object Linking. I got it working when i link a single Object file. But when i try to link multiple object files, i am getting error 'Unsatisfied forward or external declaration'. I have tried this in Delphi 2007 as well as XE.So what am i doing wrong here?
Working Code:
function a_function():Integer;cdecl;
implementation
{$Link 'a.obj'}
function a_function():Integer;cdecl;external;
end.
Error Code:
function a_function():Integer;cdecl;
function b_function();Integer;cdecl;
function c_function();Integer;cdecl;
implementation
{$LINK 'a.obj'}
{$LINK 'b.obj'}
{$LINK 'c.obj'}
function a_function():Integer;cdecl;external;
function b_function();Integer;cdecl;external;
function c_function();Integer;cdecl;external;
end.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
顺便说一句,@vcldeveloper 链接的文章对一些常见问题有很好的解释。在 Pascal 代码中提供缺失的 C RTL 函数的技巧非常出色,并且比尝试将必要的函数链接为 C 文件甚至 .obj 文件要快得多。
然而,我怀疑我知道这里发生了什么。我使用同样的方法,但实际上设备中有 100 多个 .obj 文件。我发现当我添加新的链接器错误时,我会得到与您相同的链接器错误。我解决这个问题的方法是尝试重新排序我的 $LINK 指令。我尝试一一添加新的 obj 文件,最终我总是能够解决这个问题。
如果您的 C 文件是完全独立的,那么您可以将每个文件放在不同的单元中,链接器将处理该问题。然而,我怀疑情况确实如此,而且我怀疑如果它们真的是独立的,那么这个问题就不会发生。另外,最好将 $LINK 指令放在一个单元中,以便需要提供的任何 RTL 函数都只能提供一次(它们需要与 $LINK 指令出现在同一单元中)。
链接器中的这种奇怪现象出现在 Delphi 6 中,并且出现在 Delphi 2010 中。
编辑 1:我现在意识到这个问题可能是由于 Delphi 使用单通道编译器造成的。我怀疑“缺少外部引用”错误是因为编译器按照 .obj 文件在单元中出现的顺序处理它们。
假设a.obj出现在b.obj之前,而a.obj调用b() b.obj中的函数。编译器在需要修复函数调用时不知道 b() 位于何处。当我有时间的时候,我会尝试测试这个假设是否至少是合理的!
最后,解决这个问题的另一个简单方法是将 ac、bc 和 cc 合并到一个 C 文件中,我相信这会绕过 OP 的这个问题。
编辑2:我发现了另一个涵盖这一点的Stack Overflow问题:stackoverflow.com/questions/3228127/why-does-the-order-of-linked-object-file-with-l-directive-matter
编辑3:我找到了另一种真正美妙的方法来解决这个问题。每次编译器抱怨时,
您只需在单元的实现部分中添加如下声明:
如果您希望从 Delphi 调用一个例程,那么您显然需要正确获取参数列表、调用约定等。否则,如果它是外部代码内部的例程,那么您可以忽略参数列表、调用约定等。
据我所知,这是导入以循环方式相互引用的两个对象的唯一方法。我认为以这种方式声明外部过程类似于进行前向声明。不同之处在于实现是由对象而不是 Pascal 代码提供的。
我现在已经能够在我的军械库中添加更多工具 - 感谢您提出问题!
As an aside, the article linked by @vcldeveloper has a good explanation of some of the common issues. The trick of providing missing C RTL functions in Pascal code is excellent and much quicker than trying to link in the necessary functions as C files, or even as .obj files.
However, I have a suspicion that I know what is going on here. I use this same approach but in fact have over 100 .obj files in the unit. I find that when I add new ones, I get the same linker error as you do. The way I work around this is to try re-ordering my $LINK instructions. I try to add the new obj files one by one and I have always been able, eventually, to get around this problem.
If your C files are totally standalone then you could put each one in a different unit and the linker would handle that. However, I doubt that is the case and indeed I suspect that if they really were standalone then this problem would not occur. Also, it's desirable to have the $LINK instructions in a single unit so that any RTL functions that need to be supplied can be supplied once and once only (they need to appear in the same unit as the $LINK instructions).
This oddity in the linker was present in Delphi 6 and is present in Delphi 2010.
EDIT 1: The realisation has now dawned on me that this issue is probably due to Delphi using a single pass compiler. I suspect that the "missing external reference" error is because the compiler processes the .obj files in the order in which they appear in the unit.
Suppose that a.obj appears before b.obj and yet a.obj calls a function in b() b.obj. The compiler wouldn't know where b() resides at the point where it needs to fixup the function call. When I find the time, I going to try and test if this hypothesis is at the very least plausible!
Finally, another easy way out of the problem would be to combine a.c, b.c and c.c into a single C file which would I believe bypass this issue for the OP.
Edit 2: I found another Stack Overflow question that covers this ground: stackoverflow.com/questions/3228127/why-does-the-order-of-linked-object-file-with-l-directive-matter
Edit 3: I have found another truly wonderful way to work around this problem. Every time the compiler complains
you simply add, in the implementation section of the unit, a declaration like so:
If it is a routine that you wish to call from Delphi then you clearly need to get the parameter list, calling conventions etc. correct. Otherwise, if it is a routine internal to the external code, then you can ignore the parameter list, calling conventions etc.
To the best of my knowledge this is the only way to import two objects that refer to each other in a circular manner. I believe that declaring an external procedure in this way is akin to making a forward declaration. The difference is that the implementation is provided by an object rather than Pascal code.
I've now been able to add a couple of more tools to my armory – thank you for asking the question!