1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
Microsoft (R) Incremental Linker Version 12.00.40629.0 Copyright (C) Microsoft Corporation. All rights reserved. LIBCMT.lib(crt0dat.obj) : error LNK2005: __amsg_exit already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crt0dat.obj) : error LNK2005: __cexit already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crt0dat.obj) : error LNK2005: __exit already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crt0dat.obj) : error LNK2005: __initterm_e already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crt0dat.obj) : error LNK2005: _exit already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(invarg.obj) : error LNK2005: __invoke_watson already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(winapisupp.obj) : error LNK2005: ___crtSetUnhandledExceptionFilter already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(winapisupp.obj) : error LNK2005: ___crtTerminateProcess already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(winapisupp.obj) : error LNK2005: ___crtUnhandledException already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crtheap.obj) : error LNK2005: __calloc_crt already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(hooks.obj) : error LNK2005: "void __cdecl terminate(void)" (?terminate@@YAXXZ) already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_a already defined in MSVCRT.lib(cinitexe.obj) LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_z already defined in MSVCRT.lib(cinitexe.obj) LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_a already defined in MSVCRT.lib(cinitexe.obj) LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_z already defined in MSVCRT.lib(cinitexe.obj) LIBCMT.lib(errmode.obj) : error LNK2005: ___set_app_type already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(winxfltr.obj) : error LNK2005: __XcptFilter already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(mlock.obj) : error LNK2005: __lock already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(mlock.obj) : error LNK2005: __unlock already defined in MSVCRT.lib(MSVCR120.dll) LIBCMT.lib(wsetloca.obj) : error LNK2005: __configthreadlocale already defined in MSVCRT.lib(MSVCR120.dll) LINK : warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NODEFAULTLIB:library LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library main.exe : fatal error LNK1169: one or more multiply defined symbols found |
上のようなエラーがどうして起こるのかの話。ただしどこからはじめても要素が絡み合ってまとまらないので適当に書く。
コンパイルフェーズ
ソースコードからどのように最終成果物のexeやdllが生成されるか?libは最終成果物というよりも開発途上物と呼ぶべきもの(一般ユーザに配布するわけじゃないから)。
1、ソースファイルから*.objをつくる。
clコマンドでつくる。/cをつくるとコンパイルだけしてリンクしない。ここで/MDや/MTの指定ができる。デフォルトは/MT。デバッグの話を混ぜるとさらに複雑になるので省略。マルチスレッドも省略(今はほとんどマルチスレッド)。
/MTや/MDはCRT(Cランタイムライブラリ(printf()とか))の扱いを決める。ほとんどのプログラムがCRTをつかう。CRTはmain()を呼んだり、__argcをつくったりするのでないと大変。
/MTを指定すると、スタティックライブラリのCRTを使うことを指定する。これは最終成果物のexeやdllにCRTの実装が入ることを意味する。clで*.objをつくった際、このobjにはリンカーへの指示としてLIBCMT.libとともにリンクするよう伝えるように書き込まれる。libコマンドで*.libをつくる際にも同じ情報が書き込まれる。後々linkで最終成果物を作るときにLIBCMT.libがコピー(みたいに)される。
プロジェクトがいくつものライブラリをリンクする際(外部ライブラリも含めて)すべて/MTで統一されていれば、リンクエラーは起きない(VCのバージョンが違う場合はどうなるか知らない)。すべての*.objや*.libがLIBCMT.libとリンクしてほしいと指示しているので。
/MDを使ってobjをつくるとCRTのダイナミックライブラリとリンクしたいことを指示する。objやlibにはmsvcrt.libとリンクするように指示される。msvcrt.libはインポートライブラリで実装はmsvcrtXXX.dllにある。
link時に/MTと/MDが混在しているとLIBCMT.libとmsvcrt.libが両方指定されて、この2つは元は同じもののはずだから(ソースコードレベルでは)同じシンボルを持ち、上記のようなエラーが発生する。よって上記のようなエラーが出た場合には、/MTや/MDを直すべきのはず。
シナリオ
ただ難しいのはあるソースから作られるものはexeとdllとlibがあって、dllをつくるときもlibができて、dllをつくるときの/MTや/MDをどうするのがいいのかということになると思う。
自分が作るのがexeで使うスタティックライブラリが/MTで作られていたなら自分も/MTにするしかない(はず)。しかしちなみにC++/CLIでは/MDしか許されないのでこれができない。
自分が作るのがスタティックライブラリのときはどうなるだろうか。/MTを指定すると、自分を使う人にも/MTを使ってほしいことになる。/MDを指定すると自分を使う人にも/MDを使ってほしいことになる?(はず)
さらに難しいのがdllをつくるときに外部ライブラリも必要な場合どうなるのかということだ。MSのドキュメントにはit is not recommended to link statically to the CRT in a DLL unless the consequences of this are specifically desired and understoodと書かれているので/MDを使うことになるが、その外部ライブラリが/MTなら自分も/MTにするしかなくそうなった場合いったい何が起こるのか。簡単に言うとMSが推奨してない/MTでdllをつくってそのdllつかうexeをコンパイルしたり実行したときどうなるのかの問題。
よくわからないが結論
スタティックライブラリを作るときは/MTを使う。DLLをつくるときは/MDをつかう。
しかしこうなると2つのライブラリを自分のexeに取り込みたいとき、そしてその2つがスタティックライブラリとDLLしか提供していない場合に、どちらも取り込むということができなくなるのではないか?
よってライブラリ作成者はスタティックバージョンとDLLバージョンの両方を用意するのが普通ということになるのだろうか。
LoadLibraryはどうなる
LoadLibraryが失敗するとき、シンボルが見つからないからとか言うエラーはよく見るが、シンボルが重複しているからというのは見たことがない。もしかして2重に持つのだろうか?(上記のような矛盾の場合)もしそうなら上で書いたできないの内いくつかは解決するはず。