/MD と /MTの話

上のようなエラーがどうして起こるのかの話。ただしどこからはじめても要素が絡み合ってまとまらないので適当に書く。

コンパイルフェーズ

ソースコードからどのように最終成果物の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重に持つのだろうか?(上記のような矛盾の場合)もしそうなら上で書いたできないの内いくつかは解決するはず。

落としたrubyが走り出さない

落としたruby2.4.2がWindowsXPで動かない。

仕方ないのでビルドしたついでにアップロード。vc9,32bit。XP以上で動くはず。2000でもvc9ランタイムがあれば動くはず。vc6ではビルドできなかった。

https://onedrive.live.com/?id=F0D9DDC561F5CF32%212276&cid=F0D9DDC561F5CF32

MSIのエラーを調べる

1,tmpフォルダを削除
%tmp%をできるだけ削除。ここにログが作れられる。

2,レジストリを設定してログを出力するようにする。

3,インストールを実行してログを出力

4,%tmp%の中でエラーを検索
“return value 3″で内容検索をする。

5,レジストリを元に戻す。

cpp/cliでCLRのatexit

AppDomainのProcessExitでできそう。

C++でbreakできるブロック

これだとfalseが定数だと警告が出る。

無限ループはしたくない。

何故か警告が出ないが1が気になる。

警告warning C4065: switch statement contains ‘default’ but no ‘case’ labels おしい。

結局完璧なやり方がない。lambdaには直接コールは今のところないし、大げさすぎる。

Visual StudioでForm1.hを外部からリネームしたらデザイナーが起動できない

上はForm1.hForm1.ja-JP.resxForm1.resXをそれぞれFormMainに変えてプロジェクトに追加したときのdiff。直すにはFormMainにFileType=”3″を加えて下にリソースを置けばいいようだ。

下は成功図