Cで作成されたLIBをMFCで使用したいがLNK2019が出る

[戻る]
ブヒブヒ 2009/08/25(火) 17:50:55
いつもお世話になっております。
ブヒブヒです。

開発環境 
WinXP Pro SP3
VC2005 SP1 MFC

VC++6.0でCとWin32APIで作成されたプログラムで
使用していたスタティックライブラリを
上記開発環境のプロジェクトで使用したいと考えております。
(ある計測機器をコントロールするためのライブラリで
ソースはありません。サポートもありません。)

ヘッダーファイル内の関数定義を
extern "C" { }で囲い、
ビルドが成功するところまで出来たのですが、
ヘッダー内の関数を呼び出すとLNK2019エラーが出てしまいます。

下記のようなソースとなっております。
AAA.hファイル内
-----------------------------
extern "C"
{
    extern int BBB(...);
    extern int CCC(...);
}
-----------------------------

XXX.cppファイル内
-----------------------------
#include "AAA.h"
#pragma comment( lib, "AAA.lib" )

// いろいろ宣言があって

void CXXXDlg::OnBnClickedButton1()
{
     BBB(...);
}
-----------------------------

エラーは下記のようになっております。
LNK2019: 未解決の外部シンボル _BBB が
関数 "public: void __thiscall CXXXDlg::OnBnClickedButton1(void)" 
(?OnBnClickedButton1@CXXXDlg@@QAEXXZ) で参照されました。


OnBnClickedButton1()内のBBB()関数をコメントアウトすると
問題なくビルドが成功します。

どのようにしたらBBB()関数を使用できるのでしょうか。
大変申し訳ありませんが
よろしくお願いいたします。
ブヒブヒ

仲澤@失業者 2009/08/25(火) 18:58:50
当該の「スタティックライブラリ」は、
関数「BBB()」を含む他のライブラリとリンクしてませんか?

wood 2009/08/26(水) 06:39:18
    extern int BBB(...);
    extern int CCC(...);
この2つの関数は外部参照として宣言されていることから
プロジェクトにリンクするライブラリ(LIB)はコンパイルオプションや
リンクオプションでライブラリ名はパスを含めきちんと追加されてますか?

tetrapod 2009/08/26(水) 08:30:57
リンカが正しく aaa.lib を見つけているかをチェック
aaa.lib 中の export symbol が _BBB であること (_BBB@0 等でないこと) を確認
dumpbin /exports aaa.lib

逆に _BBB@0 等であれば extern のやりかたが間違っているわけでそっちを修正

bun 2009/08/26(水) 09:33:35
少し細かく解説

> extern "C"
> {
>     extern int BBB(...);
>     extern int CCC(...);
> }
ということは、BBB(), CCC()関数の実体はここにはなく、参照のみだという
ことです。つまり、別の場所に実体が必要ということね。
そこはOK?

そして、
> LNK2019: 未解決の外部シンボル _BBB が
> 関数 "public: void __thiscall CXXXDlg::OnBnClickedButton1(void)" 
> (?OnBnClickedButton1@CXXXDlg@@QAEXXZ) で参照されました。
は、BBB()関数の実体が見つからないという話。

なので、AAA.lib 内に BBB()関数 がいるか確認してください。

で、確認方法が、
tetrapodさんの書かれているものになるのかな、たぶん。

ブヒブヒ 2009/08/26(水) 11:13:36
皆様
ありがとうございます。

お返事が遅れてしまい、申し訳ありません。
別のことに時間を取られていました。

tetrapodさんの方法でAAA.lib内を確認してみます。

よろしくお願いいたします。
ブヒブヒ

ブヒブヒ 2009/08/26(水) 16:13:16
皆様
お世話になっております。
ブヒブヒです。

dumpbin /export AAA.lib
を試してみました。

?TestFunc@@〜
?TestCheck@@〜
というのが表示されたので、
C言語で作成されたという条件が間違っておりました。
ご迷惑をおかけして申し訳ありませんでした。

しかし、AAA.hファイルに定義されている
BBB()やCCC()が出てきませんでした。

ライブラリファイルはAAA.libのみで他にはありません。
dumpbin /exportで表示されない関数もあるのでしょうか?


そして現在、AAA.hのexturn "C"を削除して
ビルドしようとしているのですが、

AAA.lib(YYY_1.obj) : error LNK2019: 未解決の外部シンボル
"public: void __thiscall CString::SetAt(int,char)"
(?SetAt@CString@@QAEXHD@Z) が「"AAA.lib内にある関数名"」で参照されました。

AAA.lib(YYY_2.obj) : error LNK2001: 外部シンボル
""public: void __thiscall CString::SetAt(int,char)"
(?SetAt@CString@@QAEXHD@Z)" は未解決です。

というようにCString::〜というエラーが30件以上、出てきました。

このエラーはどのようにしたら解消できるのでしょうか?
質問内容が件名から変わってしまいましたが
教えていただけないでしょうか。
よろしくお願いいたします。
ブヒブヒ

tetrapod 2009/08/26(水) 17:33:17
エラーメッセージが主張している、見つからないエラーになっているシンボルは
public: void __thiscall CString::SetAt(int, char) であるわけだ。
これは Visual Studio 6.0 のころの MFC 4.2 (MBCS) だよ。
ウチの手元の VS6.0 のライブラリディレクトリ上で dumpbin /all mfc42.lib したら
このシンボルがきっちり見つかった。

VS6.0 付属の MFC4.2 と VS2005 付属の MFC8 はバイナリレベルでは非互換なので
リンクエラーになって当然だと思われる。

ということは・・・簡単な解決策は無い・・・なぁ。VS6.0 はあるのかな?ならば
VS2005 をあきらめてプロジェクト全体を VS6.0 でコンパイルするか
エラーになってるのが CString 関連だけなら自分で Wrapper 作るか
MFC4.2 の CString 系ソースを持ってきて VS2005 でコンパイルするか
当該ライブラリのソースをなんとしてでもげっちゅして VS2005 でコンパイルするか
その辺かな・・・

maru 2009/08/26(水) 18:27:40
VC6でDLLを作ってAAA.libをリンクする。
VC2005ではそのDLLを使用するってのは? つまりBBB(), CCC()のラッパー。
という手はどうですか?

関数名の衝突を避けるために、DLLでexportする関数名は変更する必要があるけど。

ブヒブヒ 2009/08/26(水) 20:05:49
tetrapodさん、maruさん
お返事ありがとうございます。

とりあえずVC6.0 MFCで動くようにしようと思い、
VC++6.0 SP6 MFCでプロジェクトを作成し、
ビルドする段階まできました。

リリースビルドは問題なくできるのですが、
デバッグビルドにすると下記のようなエラーが
たくさん出てしまいます。

libc.lib(crt0dat.obj) : error LNK2005: __cinit はすでに
libcmtd.lib(crt0dat.obj) で定義されています

libc.lib(crt0dat.obj) : error LNK2005: _exit はすでに
libcmtd.lib(crt0dat.obj) で定義されています

このエラーはどうやって解消するのでしょうか。
度々申し訳ありませんが
教えていただけないでしょうか。
よろしくお願いいたします。
ブヒブヒ

PS
Exe単体でなければいけないToolはVC6.0で。
機能提供や迅速なGUI作成が必要な場合はラッピングしたDLLで。
という方針で行きたいと思います。

tetrapod 2009/08/26(水) 20:29:36
それは FAQ なんで調べて味噌。まあ端的には
「デバッグモードにはデバッグモード用のライブラリをリンクする必要がある」
「リリースモードにはリリースモード用のライブラリをリンクする必要がある」
「デバッグとリリースを混在させてはダメ」
ということ。
当該計測機器ライブラリのデバッグモード用があるかどうか調べて、
・デバッグモードにはデバッグモードのライブラリを使う、か
・デバッグモードをあきらめてリリースモードでデバッグする、か
どっちか。

もうひとつ、スレッドモデルが違うとダメ。
libcmtd は LIBrary for C of Multi Thread - Debug の意味
libc は LIBrary for C (single thread without debug) の意味
やはり同じく、当該計測機器ライブラリのスレッドモデルを調べて、
・プロジェクトのコンパイルオプションをライブラリにあわせる、か
・プロジェクトのコンパイルオプションに適合するライブラリを使う、か
どっちか。

なので Visual C 用のライブラリは [MT/ST]+[Debug/Release] で4種類あるのが普通
気の利いたライブラリメーカなら4種類とも用意しているはず。
aaa.lib + aaamt.lib + aaad.lib + aaamtd.lib のように。
(順に、シングルスレッドリリース、マルチスレッドリリース、
シングルスレッドデバッグ、マルチスレッドデバッグ、用のライブラリ)
まずはその辺探してみるべし(俺たち読者には状況がわからんからな)

# 実はさらに STATIC/DYNAMIC 違いによって8種類あったりするのだが...

ブヒブヒ 2009/08/27(木) 11:37:54
[[解決]]
tetrapodさん、ありがとうございます。

申し訳ありません。
記述し忘れていたのですが
デバッグ用ライブラリとリリース用ライブラリの2つあります。
(正確にはデバッグとリリース用のライブラリ、計2つと
関数の簡易説明ドキュメント、現在使用しているCとWin32APIで作成された
ツールとプロジェクトを引き継ぎました)

プロジェクトの設定ダイアログの
C/C++のコード生成や
リンクのインプットで無視するライブラリの設定を
変更して試してみた結果。

リリースビルドでは
C/C++のコード生成でシングルスレッドでもマルチスレッドでも
ビルドが成功しました。

デバッグビルドでは
C/C++のコード生成でシングルスレッドでビルド成功。
マルチスレッドでlibcmt,libcpmtd,libcのライブラリを無視にすると
ビルドが成功しました。

これから装置をコントロールできるか確認します。

このあたりの設定は今まで全くいじったことがないので助かりました。
ありがとうございました。
ヘッポコプログラマ@ブヒブヒ

tetrapod 2009/08/27(木) 11:51:11
> マルチスレッドでlibcmt,libcpmtd,libcのライブラリを無視にすると
> ビルドが成功しました。
ビルドが成功しても *正しく動かない* からダメ。
伊達や酔狂で警告が出ているんぢゃないんだから無視しちゃ/させちゃダメ。

ブヒブヒ 2009/08/27(木) 14:21:40
tetrapodさん
ありがとうございます。
気をつけます。
ブヒブヒ

古いスレッドには追加発言できません。