5

私はデルファイに不慣れです。DelphiはCオブジェクトリンクをサポートしているため、DelphiプロジェクトにCオブジェクトファイルを追加して直接リンクしようとしていました。単一のオブジェクトファイルをリンクすると、機能するようになりました。しかし、複数のオブジェクトファイルをリンクしようとすると、「Unsatisfied forwardorexternaldeclaration」というエラーが発生します。XEだけでなくDelphi2007でもこれを試しましたが、ここで何が間違っているのでしょうか。

作業コード:

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.
4

1 に答える 1

8

余談ですが、@ vcldeveloperによってリンクされた記事には、いくつかの一般的な問題についての適切な説明があります。Pascalコードで欠落しているCRTL関数を提供するトリックは、必要な関数をCファイルまたは.objファイルとしてリンクしようとするよりも優れており、はるかに高速です。

しかし、私はここで何が起こっているのかを知っているのではないかと疑っています。私はこれと同じアプローチを使用していますが、実際にはユニットに100を超える.objファイルがあります。新しいものを追加すると、あなたと同じリンカーエラーが発生することがわかりました。これを回避する方法は、$LINK命令を並べ替えてみることです。私は新しいobjファイルを1つずつ追加しようとしていますが、最終的には常にこの問題を回避することができました。

Cファイルが完全にスタンドアロンである場合は、それぞれを異なるユニットに配置すると、リンカーがそれを処理します。しかし、それが事実であるとは思えません。実際、それらが実際にスタンドアロンである場合、この問題は発生しないと思います。また、$ LINK命令を単一のユニットに入れて、提供する必要のあるRTL関数を1回だけ提供できるようにすることが望ましいです($ LINK命令と同じユニットに表示する必要があります)。

リンカーのこの奇妙な点は、Delphi 6に存在し、Delphi2010にも存在します。

編集1:この問題はおそらくシングルパスコンパイラを使用しているDelphiが原因であることに気づきました。「外部参照がありません」というエラーは、コンパイラが.objファイルをユニットに表示される順序で処理するためだと思われます。

a.objがb.objの前に表示されていても、a.objがb()b.objの関数を呼び出しているとします。コンパイラーは、関数呼び出しを修正する必要があるポイントでb()がどこにあるかを知りません。時間を見つけたら、この仮説が少なくとももっともらしいかどうかを試してみます。

最後に、この問題を解決するもう1つの簡単な方法は、ac、bc、およびccを1つのCファイルに結合することです。これにより、OPでこの問題を回避できると思います。

編集2:私はこの地面をカバーする別のスタックオーバーフローの質問を見つけました:stackoverflow.com/questions/3228127/why-does-the-order-of-linked-object-file-with-l-directive-matter

編集3:私はこの問題を回避するための別の本当に素晴らしい方法を見つけました。コンパイラが文句を言うたびに

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

ユニットの実装セクションに、次のような宣言を追加するだけです。

procedure _a; external;

Delphiから呼び出したいルーチンの場合は、パラメータリスト、呼び出し規約などを正しく取得する必要があります。それ以外の場合、それが外部コードの内部のルーチンである場合は、パラメーターリスト、呼び出し規約などを無視できます。

私の知る限り、これは、循環的に相互に参照する2つのオブジェクトをインポートする唯一の方法です。このように外部手続きを宣言することは、前方宣言をすることに似ていると思います。違いは、実装がPascalコードではなくオブジェクトによって提供されることです。

これで、武器庫にさらにいくつかのツールを追加できるようになりました。質問していただきありがとうございます。

于 2011-01-09T10:11:51.840 に答える