VC PlusPlus:Link Error LINK2019 未解決のシンボル…で参照されました。 対処方法 新しいページはコチラ
提供: yonewiki
(→2.C言語とC++言語の混在による呼び出し関数の互い違い) |
(→知っていた方が良い小技) |
||
49行: | 49行: | ||
以下のようなコマンドを打つと生成できます。必ずしも出力できるわけではありません。dllを生成したプログラム側で__declspec(dllexport)というような宣言をしてあるものに限ります。 | 以下のようなコマンドを打つと生成できます。必ずしも出力できるわけではありません。dllを生成したプログラム側で__declspec(dllexport)というような宣言をしてあるものに限ります。 | ||
+ | |||
+ | defファイルの中身は自動で適切に生成されることもありますが、以下のような形式に整理しないといけない場合もあります。 | ||
+ | |||
+ | 以下はwintab32.dllっていうファイルから作ったdefファイルの抜粋です。 | ||
+ | <syntaxhighlight2 lang="text"> | ||
+ | Dump of file wintab32.dll | ||
+ | |||
+ | File Type: DLL | ||
+ | |||
+ | Section contains the following exports for Wintab32.dll | ||
+ | |||
+ | 00000000 characteristics | ||
+ | 59BBE69A time date stamp Fri Sep 15 23:41:30 2017 | ||
+ | 0.00 version | ||
+ | 20 ordinal base | ||
+ | 1184 number of functions | ||
+ | 54 number of names | ||
+ | |||
+ | ordinal hint RVA name | ||
+ | |||
+ | 25 0 000079E1 Sync | ||
+ | 22 1 00006235 WTClose | ||
+ | 60 2 000089CC WTConfig | ||
+ | 81 3 000033C3 WTDataGet | ||
+ | (省略) | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | というように吐き出された時のname欄が関数名でSyncとかWTCloseってのがソレにあたる。関数名には@が入ったりもします。 | ||
+ | |||
+ | <syntaxhighlight2 lang="text"> | ||
+ | LIBRARY (ファイル名(拡張子を省く)) | ||
+ | EXPORTS | ||
+ | (関数名) | ||
+ | (関数名) | ||
+ | (関数名) | ||
+ | (関数名) | ||
+ | </syntaxhighlight2> | ||
+ | |||
+ | コマンドは | ||
<syntaxhighlight2 lang="bash"> | <syntaxhighlight2 lang="bash"> | ||
dumpbin.exe /EXPORT (DLLライブラリファイル名or(完全パスor相対パス)\DLLライブラリファイル名) > (ライブラリ名と同じ名前).def | dumpbin.exe /EXPORT (DLLライブラリファイル名or(完全パスor相対パス)\DLLライブラリファイル名) > (ライブラリ名と同じ名前).def | ||
123行: | 162行: | ||
− | かなり、わけわからん@@とかYXPAとかどっから来たん?ってなると思います。そもそもマングリングってなんかヤラシイ名前で恥ずかしい(Embarrass) | + | かなり、わけわからん@@とかYXPAとかどっから来たん?ってなると思います。そもそもマングリングってなんかヤラシイ名前で恥ずかしい(Embarrass)わ。とか言っている日本人のなんと多いことか。そうです。チコちゃんはマングリングが何なのかしっています。 |
129行: | 168行: | ||
− | + | 装飾。英語のmanglingは日本語で修飾という意味です。マングリ返しとは関係ないし、ペロペロしたりもしません。チコちゃんは5歳なのにC++のマングリングまで知っているなんて、マングリ返しでもされたことをあるのかなぁ?「ませてはいませんて」そうなんです。C++では同一の関数名を名前空間を変更することによって定義できます。namespase ですね。だったり、オーバーロードという多重定義によって、引数が違うだけの関数名との切り分けも考慮した命名規則があります。命名規則は別の場所で解説するとして、元の名前がきちんとわかるようにわかりにくく修飾されています。元の名前は以下のようなundnameコマンドで確認できます。 | |
<syntaxhighlight2 lang="text"> | <syntaxhighlight2 lang="text"> | ||
145行: | 184行: | ||
ちなみに | ちなみに | ||
− | + | Sample.h | |
<syntaxhighlight2 lang="cpp"> | <syntaxhighlight2 lang="cpp"> | ||
#ifdef __cplusplus | #ifdef __cplusplus | ||
151行: | 190行: | ||
#endif | #endif | ||
− | void zcalloc(void *,unsigned int,unsigned int); | + | void __cdecl zcalloc(void * vValue, unsigned int uiValue, unsigned int uiValue2); |
#ifdef __cplusplus | #ifdef __cplusplus | ||
} | } | ||
#endif | #endif | ||
− | <syntaxhighlight2> | + | </syntaxhighlight2> |
+ | |||
+ | のように記述することでC++言語を使っている場合にC言語の関数形式に必ず変更するという定義が出来ます。まぁC言語に対応するとか、割かし難しい場合もあります。__cdeclキーワードは、dllに関数を書き出す時に必要になるもので、libファイルにはすべてが書き出されます。 | ||
+ | |||
+ | |||
+ | その場合は、参照するライブラリそのものをC++言語に作り替えるという方法があります。これは流石に面倒です。もう一つは、呼び出している関数を自前で再定義して使うという方法もあります。この場合、C言語で書かれたライブラリのプロジェクトの中にある特定プログラムファイルをSample.cというのをコピーして同じディレクトリにおいて、Sample.cとSample.cppが同じディレクトリに存在する状態になります。Sample.cやSample.cppに変更が発生した場合は両方を修正しなければならなくなります。 | ||
+ | |||
+ | |||
+ | そしてSample.hとSample.cppを自分が開発を進めているプロジェクトに取り込みます。インクルードパスの解決をしている場合は、Sample.hはプロジェクトに追加する必要はないかもしれません。なのでしっかりとSample.cppをプロジェクトに追加します。ヘッダファイルはSample.cpp内で#include "Sample.h"となっているなら、プロジェクトのプロパティのC/C++の項目の全般のところにある追加のインクルードファイルパスにSample.hがあるところを相対パスで指定します。必ずセットで移動する仕組みの関係になっていればです。一緒には動かさない。参照するライブラリ群は常に同じなら絶体パスで指定すると良いでしょう。であれば、本来ならばインクルードは#include <Sample.h>のように記述する方法をとるといいのかもしれません。元のファイルとの関係もあるので、あまり変更しない方がいいと思うので、"Sample.h"のような記述でインクルードするもの有りだとは思います。ちなみに<Sample.h>のようになっていれば、プロジェクトのプロパティのVCディレクトリという欄の追加のインクルードの方にパスを記述します。リンカエラーが何が参照できなかったかというヒントは表示されるので名前マングリング処理されたエラーが表示されても冷静に対処できるはずです。名前マングリングがややこしさを増殖させて感じてしまいがちですが、名前マングリングが起こることが分かっていれば、正確に何がどこに無くてエラーなのかっていうのは探知できると思います。 | ||
+ | |||
+ | |||
+ | C言語からC++言語に変更するには、ファイルの拡張子の変更だけで済む場合もありますが、関数の引数の型定義が、外出しになっている以下のように記述された関数 | ||
+ | |||
+ | Sample.c | ||
+ | <syntaxhighlight2 lang="c"> | ||
+ | |||
+ | void zcalloc(vValue, uiValue, uiValue2) | ||
+ | void * vValue, | ||
+ | unsigned int uiValue, | ||
+ | unsigned int uiValue2 | ||
+ | { | ||
+ | … | ||
+ | } | ||
+ | </syntaxhighlight2> | ||
+ | を | ||
+ | |||
+ | Sample.cpp | ||
+ | <syntaxhighlight2 lang="cpp"> | ||
+ | |||
+ | void zcalloc(void * vValue, unsigned int uiValue, unsigned int uiValue2) | ||
+ | { | ||
+ | … | ||
+ | } | ||
+ | </syntaxhighlight2> | ||
+ | と、こんな感じに修正する必要があります。メンドクサイ。 | ||
+ | |||
+ | |||
+ | このような不具合は同じプロジェクト内でlibを参照する場合でも同じです。プロジェクト内で半分引用したりした場合は、それ以外のコードを元々のライブラリを参照するようになっていて、半分引用してプロジェクト内では、Cの規約で呼び出されるように関係性が保たれていて引用したプロジェクトは問題なくビルド出来ます。しかし、そのプロジェクトに依存している中心的役割のプロジェクトからはC++の規約で引用したプロジェクトのlibを参照するようになっていれば、さらに引用元の関数を参照する際に、リンクエラーが発生します。さっきまでうまく行ってたのに依存してる関数だけリンクエラーとか意味わかんねぇっていう気分になります。実にややこしいことです。 | ||
+ | |||
+ | |||
+ | これが、C++とCの混合によるリンクエラーの仕組みです。要するに?なんとかして合わせろ!っていう事しか言えません。しかもC言語をC++言語に書き直したりする道を選んだときは、C言語独自に許された記法もあるので、割かしメンドクサイ変更をしつつ、あたらしく作ったCppファイルをメンテしないと駄目なこともあります。しっかりライブラリの設定をしたのにリンクエラーがでるときは、たぶん、こういう感じのリンクエラーが一番多いと思います。 | ||
[[VC PlusPlus]]に戻る | [[VC PlusPlus]]に戻る |