none
VC++ exeファイルのサイズについて

    質問

  • お世話になります。VisualStudio2017にて作成されるexeファイルのサイズについてご教示ください。

    ●質問

    VC++6.0で製造したソースを、VC++2017へ移行しました。

    作成されたexeファイルを確認したところ、6.0では600KB程度でしたが、2017(.Net)では4800KBに膨れ上がりました。

    6.0と同サイズとまではいかなくても、せめて2000KB以内には収めたいと思っているのですが、何か方法はないでしょうか?

    なお、exeファイルは64bit環境で動作するように、ソリューションプラットフォームを"x64"に設定しています。

    ●試したこと

    プロジェクトのプロパティから最適化を行うように設定してみたのですが、ファイルサイズは変わりませんでした。

    ●環境

    Windows10、VisualStudio2017

    2018年10月30日 1:22

回答

  • ライブラリを静的リンクしてませんでしょうか。
    コンパイルオプションの「ランタイムライブラリ」が
    「/MT」(マルチスレッド)になっていたら
    「/MD」(マルチスレッドDLL)にします。

    その他では、

    1.インライン化されないように、なるべく
      クラスメンバ関数の実装は、*.cppに移動する。
    2.文字列リテラル等はリソースにする。
      (自動的に圧縮してくれるオプションもありますけど、念のため)
    3.デバッグ情報は無しにする

    などは、試してみる価値があるかもしれません。
    (追記)上記3項については、佐祐理さんから「効果はない」とのご指摘をうけています。併せて検討してください。
    2018年10月30日 1:42

すべての返信

  • ライブラリを静的リンクしてませんでしょうか。
    コンパイルオプションの「ランタイムライブラリ」が
    「/MT」(マルチスレッド)になっていたら
    「/MD」(マルチスレッドDLL)にします。

    その他では、

    1.インライン化されないように、なるべく
      クラスメンバ関数の実装は、*.cppに移動する。
    2.文字列リテラル等はリソースにする。
      (自動的に圧縮してくれるオプションもありますけど、念のため)
    3.デバッグ情報は無しにする

    などは、試してみる価値があるかもしれません。
    (追記)上記3項については、佐祐理さんから「効果はない」とのご指摘をうけています。併せて検討してください。
    2018年10月30日 1:42
  • 過去にも実行ファイルのサイズがVS2017で大きくなるというスレッドがあったので参考用リンク。

    VS2017 v15.8.1 EXEファイルサイズが大きくなる

    2018年10月30日 1:52
  • 回答ありがとうございます。

    「ランタイムライブラリ」が「/MT」(マルチスレッド)になっていましたので「/MD」(マルチスレッドDLL)に変更してリビルドしてみたところ、以下のようなエラーが発生しました。

    「#error: Building MFC application with /MD[d] (DRT dll version) requires MFC Shared dll version.

     Please #define _AFXDLL or do not use /MD[d]」

    以下のURLを参考に、ランタイムライブラリの設定は「/MD」のままで「プロパティ > 構成プロパティ > 全般 > MFCの使用」を「共有DLLでMFCを使う」に変更してリビルドしてみたところ、exeファイルは387KBになりました。

     参考URL:http://gomi-box.hatenablog.com/entry/20101006/1286355611


    VB6時代のexeよりさらに小さくなるという結果に、驚きと「このexeファイル大丈夫だろうか」という不安が・・・。 (^-^;

    今回変更したプロパティの内容を確認しつつ、exeファイルも検証してみたいと思います。

    ありがとうございました。

    2018年10月30日 2:16
  • 回答ありがとうございます。

    そちらのページも参照していたのですが、「修正版を待つしかない」という結果になっていましたのでスルーしておりました・・・。(申し訳ありません・・・)

    今回exeファイルが膨れ上がった原因として、無関係(未使用)なライブラリがexeファイルに含まれている可能性は高いですね・・・。
    後学のために、リンク先のページの内容も読み込んで理解しておきたいと思います。
    ありがとうございました。


    2018年10月30日 2:26
  • 補足です。

    「共有DLLでMFCを使う」に変更されたということですが、こちらの設定で作成された exe は実行に別途 MFC の DLL が必要となります。Visual Studio 等が入っていない環境で動かす場合は、下記の Visual C++ ランタイムライブラリをインストールする必要があります。

    https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads

    2018年10月30日 2:41
  • ありがとうございます。

    VC++のランタイムライブラリは別途インストールするようにします。

    しかし、設定を変えるだけでexeファイルがこんなにスリムになるとは。

    いかにライブラリという余分な贅肉が付いているか分かりますね・・・。(必要なものではあるのですが)

    2018年10月30日 4:05
  • 1.インライン化されないように、なるべく
      クラスメンバ関数の実装は、*.cppに移動する。
    2.文字列リテラル等はリソースにする。
      (自動的に圧縮してくれるオプションもありますけど、念のため)
    3.デバッグ情報は無しにする

    どれも見当違いであまりEXEファイルサイズの削減には貢献しないと思います。

    1.について、Visual C++では/LTCG (Link-time Code Generation)によりコンパイル時の定義場所に関わらず、実行ファイル全体でインライン展開を試みます。
    2.について、/GF (Eliminate Duplicate Strings)により文字列リテラルは自動的に共有・削減されます。
    3.について、/Ziもしくは/ZIを使っていればデバッグ情報はpdbファイルに書かれ、EXEファイルにはpdbファイルパスが書かれるだけ、数十バイトの増分のはずです。今はあまり使われていない/Z7を使うとEXEファイルが肥大化します。

    2018年10月30日 5:28
  • オプションの設定によって、exeファイルのサイズに影響が出ますね・・・。
    参考にさせて頂きたいのですが、どなたか以下の環境・設定で動いている実績がある方はいらっしゃいませんか?

    ●環境
     Windows10(64bit)
    ●VisualStudioのバージョン
     VisualStudio2017(ソリューションプラットフォームは"x64")
    ●VisualStudioのプロジェクトの設定
     ①「構成プロパティ > C/C++ > コード生成 > ランタイム ライブラリ」を「マルチスレッドDLL(/MD)」に設定。
     ②「構成プロパティ > 全般 > MFCの使用」を「共有DLLでMFCを使う」に設定。
      (VC++のランタイムは別途インストール済)


    2018年10月30日 7:33
  • その設定で特に問題なく動いてます。

    最も、VC6世代のコードをそのままコンバートしたものではありませんので、環境として動作に問題はないという程度でしかありません。

    うまく動かないという場合はどこかにプログラム的なバグがあるということになります。

    VC6時代のソースコードと現在のソースコードの互換性は100%ではありません


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2018年10月31日 6:43
  • 手元のVS2017にはVC++2015とVC++2017が入れてあるので比較してみました。MFCダイアログアプリケーションで VC++2015: 450KB、VC++2017: 2500KB。

    いろいろ睨めっこしたんですが、MFCのソースコードdlgcore.cppのCWnd::CreateDlgIndirect()がAfxRegisterMFCCtrlClasses()を呼び出していることが原因でした。

    適当なcppファイルに

    void AfxRegisterMFCCtrlClasses() {}

    を書き加えたところ、不要なライブラリをリンクしなくなり、VC++2017: 434KB に削減できました。

    # static link(/MT)が前提の話題で、dynamic link(/MD)には関係ありません。

    2018年10月31日 7:39
  • とっちゃんさん、佐祐理さん、レスを頂きありがとうございます。
    また、返信が遅くなり大変申し訳ございません。

    ●とっちゃんさん、「その設定で特に問題なく動いてます。」とのことで 安心しました。
    ただ、やはり とっちゃんさんが仰っているとおりVC6と.Netのソースの互換性は100%ではないので、しっかりテストした方がよいですね…。
    ありがとうございます。

    ●佐祐理さん、色々と調べていただきありがとうございます。
    試してみた結果、最終的に2つ上で書いたVisualStudioのプロジェクトの設定に戻りました・・・。

    (確認した手順)
     ①こちらの環境でも、dlgcore.cppがAfxRegisterMFCCtrlClasses()を呼び出していることを確認しました。
     ②cppに以下を書き加えました。
    void AfxRegisterMFCCtrlClasses() {}


     ③プロジェクトの設定を、以下の状態に戻してリビルド。
      ・ランタイムライブラリは「/MT」(マルチスレッド)
      ・MFCの使用は「スタティックライブラリでMFCを使用する」

      →リビルドした結果、以下のエラーが発生しました。
       エラー LNK2005 "void __cdecl AfxRegisterMFCCtrlClasses(void)" (?AfxRegisterMFCCtrlClasses@@YAXXZ) は既に MainFrm.obj で定義されています。
       エラー LNK1169 1 つ以上の複数回定義されているシンボルが見つかりました。

     ④MFCの使用を「共有DLLでMFCを使う」に変更してリビルド
      →リビルドした結果、以下のエラーが発生しました。
       エラー C1189 #error:  Please use the /MD switch for _AFXDLL builds
     ⑤ランタイムライブラリを「/MD」(マルチスレッドDLL)に変更してリビルド。
      →エラーはなく、リビルドは正常に終了しました。
       なお、exeファイルのサイズは387KBでした。(上の回答で報告していたサイズと同じですね。)

    (参考にしたURL)
    https://social.msdn.microsoft.com/Forums/vstudio/ja-JP/c83113d2-ff99-42e2-b4e9-4e7ae1719472/mfc124341247312479124861245112483124631252212531124631237712427?forum=vcgeneralja

    ③のエラーが発生した時に上記のURLを見つけたのですが、その中で話題にあがっていた
     _AFX_NO_MFC_CONTROLS_IN_DIALOGS
    は、VC6、.Netのどちらのソースでも見つかりませんでした。


    2018年11月6日 6:07
  • エラー LNK2005

    MainFrm.cpp にも AfxRegisterMFCCtrlClasses() を書いていませんか?

    VC6でもそうですが、同じ関数を複数定義すると内容が一致していても、重複定義でリンクエラーになります。

    より正確(将来的にDLLを使う用意変更した場合を含む)を期すなら

    #ifndef _AFXDLL
    void AfxRegisterMFCCtrlClasses() {}
    #endif
    
    としておけば、DLLを使うように変更した場合にはいらない関数として定義されなくなります。

    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2018年11月6日 6:31
  • 返信いただき、ありがとうございます。

    > MainFrm.cpp にも AfxRegisterMFCCtrlClasses() を書いていませんか?
    確認しましたが、書いていませんでした・・・。

    > #ifndef _AFXDLL
    「_AFXDLLが定義されていない時」にifの中を通るのですね。勉強になります。


    2018年11月6日 7:22
  • おかしいですね。

    LNK2005 (とそれに付随するLNK1169) は、プロジェクト内のソースに同じ関数が複数ある場合に表示されるエラーなんですが?

    AfxRegisterMFCCtrlClasses() は、どこかのソースファイル(アプリケーションクラスのソースあたりが一番無難)に1つだけ定義されるようにしておく必要があります。

    そのあたりをもう一度細かく確認してみてください。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2018年11月6日 7:41
  • 今回作成したソリューションの中には見当たらなかったのですが、検索の方法が悪いのでしょうか?
     ・"AfxRegisterMFCCtrlClasses"をキーとして、検索する場所をソリューション全体として検索。
     ・ソリューションのソースファイルを、"AfxRegisterMFCCtrlClasses"をキーとしてテキストエディタでGrep検索。

    なお、外部依存関係の afxctrlcontainer.h に宣言がありました。
    VC++の知識が乏しく変なことを言っていたら申し訳ないのですが、
    外部依存関係のヘッダーもリビルド時に読み込まれて
    下記の宣言と 今回追加した宣言が重複しているのでしょうか・・・?


    void AfxRegisterMFCCtrlClasses();


    また、もう1点確認なのですが、
    ご教示頂いた下記の内容をMainFrm.cppに書いたのですが、記載する場所が間違っているのでしょうか?

    #ifndef _AFXDLL
    void AfxRegisterMFCCtrlClasses() {}
    #endif


    お時間をとらせて申し訳ありません。教えて頂けますと幸いです。

    2018年11月6日 10:40
  • この話題はMFCインクルード前に_AFX_NO_MFC_CONTROLS_IN_DIALOGSを定義することによって、static link時のファイルサイズを削減する機能についてコメントしています。ですので、大前提としてMFCインクルード前に_AFX_NO_MFC_CONTROLS_IN_DIALOGSを定義してください。
    2018年11月6日 12:09
  • https://blogs.msdn.microsoft.com/vcblog/2012/02/06/reducing-the-size-of-statically-linked-mfc-applications-in-vc11/

    こちらのページを参考に stdafx.hに以下を追加してみたのですが、エラーは変わらずでした・・・。

    #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS


    なお、以下の状態でリビルドしてみたところ、正常に終了してexeファイルが作成されました。
    exeファイルのサイズは1867KBでした。

    (ソースコード)
     ・上記の#defineの記述は残す。
     ・「void AfxRegisterMFCCtrlClasses() {}」はコメントアウト。

    (プロジェクトの設定)
     ・ランタイムライブラリは「/MT」(マルチスレッド)
     ・MFCの使用は「スタティックライブラリでMFCを使用する」
    2018年11月7日 1:03
  • いまいち理解されていないようなで、条件をまとめておきます。

    • コンパイルオプション/MT(もしくは/MTd)を選択する
    • 「スタティックライブラリでMFCを使用する」を選択する
    • MFC関連のヘッダーファイル(afx.hやafxXXX.h)を#includeするよりも前に #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS を記述する

    が基本の使い方です。その上で

    • Visual Studio 2017 v15.8に限り、CMFCApplication2App theApp;などtheAppオブジェクトを定義しているcppファイル内にvoid AfxRegisterMFCCtrlClasses() {}を記述する

    となります。15.7以前や今後リリースされる15.9以降ではこの記述は不要です。また記述するcppファイルは依存関係があるため、なるべく重要なコードが含まれているcppに記述する必要があります。これで動かない場合はそろそろリリースされるであろう15.9を待つのも一つの手かと。

    2018年11月7日 23:07
  • 何度もありがとうございます。

    環境は VisalStudio 2017 v15.2 ですので、まとめて頂いた条件の「基本の使い方」までを設定してリビルドしました。
    エラーは表示されず正常にexeファイルが作成されましたが、ファイルサイズは4800KBでした。

    v15.9 のリリースを待つか、プロジェクトの設定を変更するか・・・。(悩

    2018年11月8日 4:53