Error While Linking Multiple C Object files in Delphi 2007
Asked Answered
N

1

5

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.
Numerical answered 9/1, 2011 at 7:37 Comment(2)
My guess: "b_function()" or "c_function()" is not found in any of the three object files. You assume the problem's related to linking multiple object files and you proved you can link one file. Did you try linking, for example, only "b.obj" and only importing "b_function()"?Shapeless
Maybe this article by Rudy Velthuis could help: rvelthuis.de/articles/articles-cobjs.htmlBentlee
C
10

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: https://mcmap.net/q/394663/-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

[DCC Error] Unit1.pas(1): E2065 Unsatisfied forward or external declaration: '_a'

you simply add, in the implementation section of the unit, a declaration like so:

procedure _a; external;

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!

Cadastre answered 9/1, 2011 at 7:38 Comment(6)
Thank you very much. I guess the single pass linker is the problem. I am linking over 30 Objects which aren't stand alone. So i will have to reorder my Object files or put then in a single file.Numerical
@Numerical I'd be interested to hear how you get on. Pedantically, I think that it is the compiler that is single pass rather than the linker and my instincts tell me that this is a compiler issue rather than a linker issue, but I'm only guessing at this!Cadastre
@Numerical I found another Stack Overflow question that covers this ground: #3228627Cadastre
@Numerical see Edit 3 above for yet another way around this problem.Cadastre
@david. Thanks. I have tried your Edit3. It fix the error, But gives a new error while calling that function. Kernel: RegisterWaitForInputIdle. Check my Edit on the Question.Numerical
@Numerical That's really a new question. Please can you post it as such.Cadastre

© 2022 - 2024 — McMap. All rights reserved.