VC++の使い方

VC++の使い方 > VC++ Tips > 軽い実行可能ファイルの作り方
このページの内容
設定の保存について
ファイルサイズ = 4KB×n
ランタイムライブラリを使うな
エントリポイントの変更
結果→1KB
参考URL
ありがたいスポンサー様
All About ソフトウエアエンジニア
ネットで8%割引!自動車保険はアメリカンホーム・ダイレクト
人生の「チャンス」と「ピンチ」にモビット!
保険料が一生上がらない、保険料最大50%割引の一生涯の医療保険!

設定の保存について

VC++6.0 でアプリケーションを作成すると、何にもしない実行可能ファイルでも 40KB になってしまいます。これってすごい無駄な気がしますよね…。

ここでは、実行可能ファイルのサイズをダイエットする方法を解説します。

ファイルサイズ = 4KB×n

VC++6.0は、デフォルトでファイルのサイズを 4KB(4096byte) の整数倍になるように調整します。このようにしないと、Windows98 が実行ファイルを正しくモメリキャッシュできないようです。しかし、オンラインソフトとして公開する場合は、ダウンロードにかかる時間を少なくしたいのも事実です。また、これから NT系の OS が増えてくることを考えると、この機能は無駄な気もします。

ファイルサイズが 4KB の整数倍にならないようにするには、リンカオプションで/OPT:NOWIN98を指定して下さい。ソースのどこかに

#pragma comment(linker, "/opt:nowin98")

と書いても同様の効果が得られます。

ランタイムライブラリを使うな

ランタイムライブラリとはprintfやatoiなどのよく知られた関数群です。WindowsのAPI群はDLLとして提供されていますが、ランタイムライブラリは提供されていません。アプリケーション中でランタイムライブラリを使用すると、ランタイムライブラリをスタティックリンクします。つまり、実行可能ファイルの中にランタイムライブラリが埋め込まれるのです。ランタイムライブラリのサイズは 20KB もあるので、ランタイムライブラリを使わないだけで、20KBのダイエットに成功します。

幸い、ランタイムライブラリの機能の大半は、APIで提供されているるようです。窓プログラミングをする場合は、ランタイムライブラリを使わなくてもプログラミングできるでしょう。例えば、文字列操作系のstrcpyはlstrcpyとして提供されています。ただし、マルチスレッドなプログラミングをする場合は、ランタイムライブラリを使わざるをえないようです。

VC++は自動的にランタイムライブラリをリンクします。ランタイムライブラリをリンクしないようにするには、以下のように設定して下さい。このように設定すれば、間違ってランタイムライブラリをリンクしてしまったときに、リンクエラーになるので分かりやすいでしょう。

libc.libを強制的にリンクしない
libc.libを強制的にリンクしない

また、ソースに

#pragma comment(linker, "/nodefaultlib:\"libc.lib\"")

と書いても同様の効果が得られます。

エントリポイントの変更

libc.libを明示的にリンクしないように宣言しましたが、実はこのままでは次のようなエラーが出てしまいます。

LINK : error LNK2001: 外部シンボル "_WinMainCRTStartup" は未解決です

_WinMainCRTStartup関数は、WinMainを呼び出す関数です。じゃ、_WinMainCRTStartup関数は誰が呼び出すかというと、.EXEファイルの開始アドレス(エントリポイント)が_WinMainCRTStartup関数に設定されているため自動的に呼び出されます。そして、_WinMainCRTStartupはランタイムライブラリに含まれているのです。ということで、ランタイムライブラリをリンクしようとしたが、libc.lib はリンクしないようリンカオプションで設定されていたため、エラーが起きたんですね。

どうしたらよいかというと、開始アドレス(エントリポイント)をWinMain関数に設定してやればいいのです。

エントリポイントをWinMainに変更
エントリポイントをWinMainに変更

もしくは、ソースに

#pragma comment(linker, "/entry:\"WinMain\"")

と書いても同様の効果が得られます。


ただし、このように設定した弊害として、_WinMainCRTStartupが設定してくれていたはずのWinMain関数の引数が正しく設定されません。といっても、HINSTANCE はGetModuleHandleで、コマンドライン引数はGetCommandLineで取得できますが。

また、Debugビルドする場合にはリンクエラーが出ます。これに関しては、下の参考URLの1つ目をご覧下さい。

結果→1KB

以下のようなソースを当方の環境でビルドしてみると1KBとなりました。めでたしめでたし。

#include <windows.h>
#pragma comment(linker, "/nodefaultlib:\"libc.lib\"")
#pragma comment(linker, "/entry:\"WinMain\"")
#pragma comment(linker, "/opt:nowin98")

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, 
                    LPSTR lpCmdLine, int intShowCmd)
{
	return 0;
}

参考URL