Version 15.24
「プロジェクトの設定」リンク編(1)
『【プロジェクトの設定】ダイアログ編、次は【リンク】ページね』
「このページでは、コンパイル後のオブジェクトファイルを結合して Exe
や DLLを作る【リンク】の設定を行います」
『コンパイルの次ってわけね』
「まずは【一般】ページから。【出力ファイル名】は、そのまま Exe や
DLL の出力先フォルダと出力ファイルの指定」
『ってことは、 Exe とかのファイル名ってここで好きに変えられるの?』
「そうだよ。たとえば、デバッグ用とリリース用とで出力先フォルダを変え
たり、さらにファイル名を変えたりできます」
『そか、プロジェクト単位、っていうか左上の【設定の対象】ごとに変えら
れるんだもんね』
「そういうこと。いろんな設定を試したい場合 Version 15.20 ( No.320 )
で説明した【構成】ダイアログを使っていくつも設定を作って、それぞれ
別のフォルダに出力したりファイル名を変えたりすればいいわけ」
『そうすればいろんな設定の Exe とかができるわけね』
「そういうこと。次の【オブジェクト/ライブラリ モジュール】は」
『はい! DLL 使う時に参照するライブラリファイルだね』
「 Version 15.07 ( No.307 ) から何度も使ってるね。ここで設定する以外
にも #pragma を使う方法とかもあるから」
『うん、それも教えてもらった』
「次の【デバッグ情報を生成する】は、これをオンにしないと
プログラムデータベース、つまり.pdbファイルが作られません」
『それって Version 15.19 ( No.319 ) で出てきた……げ、それがないと
デバッグできないんじゃん』
「そういうこと。だからデバッグ時には必ずオンにします」
『こういうのでオンオフできるんだ……』
「【デフォルト ライブラリをすべて無視】は、 Visual C++ と一緒に
インストールされたライブラリファイルを見るかどうか、っていう設定」
『んなの見なきゃだめじゃん』
「実際、これをオンにしてビルドするとリンクエラーになります」
『これ使うのってどういう時?』
「 Visual C++ 付属のライブラリを使用しない場合とかかな。全部自前で
作ったものを使う時には」
『これをオンにして、自分のライブラリファイルだけ見るわけね」
「次の【プロファイルを行う】は、これをオンにすると.mapファイルが作ら
れます」
『何そのファイル』
「このファイルについては【デバッグ】ページで説明します。問題は、実は
これ、オンにしても実際にはオンになりません」
『……どういうこと?』
「これをオンにして、たとえば上の【オブジェクト/ライブラリ モジュール】
の欄をクリックすると……」
『あれ?? 【インクリメンタル リンクを行う】になっちゃった』
「実はこれ、【プロファイルを行う】と【インクリメンタル リンクを行う】
が重なってるんです」
『重なってる!?』
「で、これは【インクリメンタル リンクを行う】の方が優先されちゃうか
ら、チェックをオンにしても【インクリメンタル リンクを行う】の方しか
オンになりません」
『ええー?』
「これは Visual C++6.0 のバグだね」
『パッチ当ててるのに直ってないし……』
「こういう場合は、下の【プロジェクト オプション】の欄で、
【プロファイルを行う】をチェックした時に指定されるオプション
【/profile】を書き込めばOK」
『あ、ここってもしかして【C/C++】ページと同じ?』
「そう。 Version 15.21 ( No.321 ) と同じように、このページでの設定は
下のこの【プロジェクト オプション】の文字列に置き換えられて、実際に
はリンカを実行する時のオプションとして指定されるんです」
『だから、上のチェックボックスが押せなくても、この欄で直接書いちゃえ
ばいいや、って話?』
「そういう話。どの欄がどのオプションか分かれば、その方が楽かもね」
『うーん……』
「で、最初は隠れている【インクリメンタル リンクを行う】は、その名の
通り【インクリメンタルリンク】を行います」
『なにそのリンク』
「たとえば、以下のプログラム」
// Main.cpp
#include <Windows.h>
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
int i = 100; // ここにブレークポイント。
return 0;
}
「ブレークポイントをセットして、ここで止めて」
『ほい止めた』
「その場で、 100 を 200 に変えて」
『へ? デバッグ中だよ!?』
「その、デバッグ中にプログラムの修正ができちゃうのが、
インクリメンタルリンク」
『そんなことできるんだ……』
「修正して保存したあと、ステップオーバーすると自動的にビルドされて、
そこからステップオーバーします。変数ウィンドウで見ると」
『ちゃんと i の中に 200 が入ってる!』
「デバッグ時にはオンがいいかな、便利だから」
『……でも、なんかちょっと不安かも』
「それはあるかも。確かに、うまくビルドできない時もあるから、一度止め
てから修正して、それからビルドした方がいいかな」
『やっぱね』
「最後の【MAP ファイルを生成する】も、【デバッグ】ページで」
『つかさっき言ってた .map ファイルってこれ?』
「そうこれ。これもデバッグのところでまとめて説明します」
『はーい』
「次は【アウトプット】ページ」
『う、ここは難しそう……』
「そうでもないよ。まず【ベース アドレス】だけど、これは
Version 8.03( No.145 ) で一度教えてます」
『え? 嘘!』
「この値は【ベースアドレス】、つまりアプリケーションのメモリの【基準
となるアドレス】を決めます。っていうよりは、単にインスタンスハンドル
の値を決めるもの、ってところかな」
『そういえばそうだった。ここでインスタンスハンドルの値を決めて、それ
がメモリの基準点、みたいになるんだったね』
「普段これは変える必要ないかな。次の【エントリポイント シンボル】は」
『ん? 確かエントリーポイントって WinMain() のことだよね』
「そう。 WinMain() に限らず、プログラムの〈最初に呼ばれる関数〉が
エントリーポイントです。ここで指定するのは、そのエントリーポイントの
関数名」
『え? じゃあ WinMain 以外の名前にできるの?』
「そういうこと。試しに【WinMainZ】を指定してビルドしてみて」
『あ、リンクエラー』
リンク中...
LINK : error LNK2001: 外部シンボル "_WinMainZ" は未解決です
Debug/BuildTest.exe : fatal error LNK1120: 外部参照 1 が未解決です。
link.exe の実行エラー
「そこで、実際に関数名を【WinMainZ】にしてみましょう」
// Main.cpp
#include <Windows.h>
int WINAPI WinMainZ
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
return 0;
}
『あ、通った!』
「まぁエントリーポイントの関数名を変える必要なんてないし、 MFC だと
もう決められてるからどうしようもないから」
『変える必要なしね』
「次の【スタック アロケーション】は、簡単に言うとローカル変数、つま
り関数内の変数を置いておくメモリのサイズ」
『関数内の変数、ってよーするにメンバ変数とかグローバル変数じゃない
変数ってことね』
「そういうこと。ちょっと試してみようか。まず、この中の【予約】の値を
【0x1000】にして」
『ほい』
「次にプログラムを以下のように修正して」
// Main.cpp
#include <Windows.h>
int WINAPI WinMain
( HINSTANCE p_hInstance
, HINSTANCE p_hPrevInstance
, LPSTR p_pchCmdLine
, int p_iCmdShow
)
{
char s[400000];
return 0;
}
「これをリビルド実行してみて」
『ほい。げ、エラーになった』
例外処理 (初回) は BuildTest.exe にあります:
0xC00000FD: Stack Overflow。
「これは、設定した【スタック アロケーション】、つまり〈ローカル変数
を置ける場所のサイズ〉よりも、ローカル変数の方が大きくなったから発生
したエラーです」
『ほー』
「デフォルトで 1MByte が設定されるから普段は設定を変える必要はないん
だけど、ものすごく変数のサイズが大きくなる場合には変えた方がいいか
な」
『そういう事ってあるの?』
「あんまりないかな。このエラーは、主に再帰呼び出しのプログラムミスで
発生することが多いかも」
『再帰呼び出しって Version 13.16 ( No.252 ) でやった、自分の関数を呼
び出すのだよね』
「そう。再帰呼び出しをして、それが無限ループすると変数が作られまくる
から」
『それで容量オーバーってわけね』
「それに、大きなデータって、たいがい最初はサイズが決まってないから、
new とか malloc() 使って確保するから」
『え? これって別なの?』
「そう、こういう動的にメモリを取得するものはこの設定とは関係ないか
ら」
『そっちで取得すれば問題ないわけね』
「話を戻して、今の【予約】欄の右にある【コミット】は、【予約】の分は
必要になったら確保するけど、【コミット】は最初から確保しておく分」
『最初からって、メモリそれだけ取ってたら無駄じゃない?』
「だからこれも普通は設定しないかな。というわけで次回に続く!」
『げ、こんな中途半端なところで!?』
/*
Preview Next Story!
*/
『なにこの中途半端さ!』
「この章はちょっとバランス悪いかも……」
『ま、今に始まったことじゃないけどさー』
「う”」
『というわけで次回』
< Version 15.25 「プロジェクトの設定」リンク編(2) >
「につづく!」
『このシリーズもいつまで続くのやら』
「意外と早く終わるかも」
『しんじらんなーい』