やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

ライブラリ化せずに分割する方法

ライブラリ化するとファイルサイズが肥大化した。 そこで、ライブラリ化せずに分割する方法を探した。

入手

方法 GitHub MEGA
.lib分離 GitHub MEGA
VC++proj内分割 GitHub MEGA
ディレクトリ分割 GitHub MEGA

前回、.libに分割して実装した。 今回は同じソースコードを.libに分割しない方法で分割してみた。 すると.libファイル分のファイルサイズが丸々なくなった。 理由はわからない。 ファイルを軽くしたいなら.lib化せず、exeプロジェクトに含めたほうがいい。

ライブラリ化の問題

ライブラリ化するとファイルサイズが一気に肥大化する。

ライブラリにせず、別のプロジェクトにすることはできない。 VC++でプロジェクト作成すると、プロジェクト単位でバイナリファイルを作成しようとする。 Winアプリ、コンソールアプリ、静的ライブラリ、動的ライブラリ、いずれかを作成してしまう。

対策

1つのWinアプリプロジェクトで、アプリ機能ごとにフォルダ分けする。

前々から気に食わなかったディレクトリ構成

  • プロジェクト
    • ソースファイル
    • ヘッダファイル
    • リソースファイル
    • 外部依存関係

VC++でプロジェクトを作成すると、こんな感じでファイルが分けられる。 これが気に食わない。

ソースファイルとヘッダファイルの部分が嫌。 こんな分け方じゃ、規模が大きくなったときにまったく意味がない。

こんな感じにしたい

アプリ機能ごとに分離したい。 とりあえず、前回のプロジェクトを参考にすると、以下のように分けたい。

  • プロジェクト(Windowsアプリ)
    • Main
      • Program.cpp
      • Window1
        • Window1.h
        • Window1.cpp
        • Initialize
          • InitializeWndProc.h
          • InitializeWndProc.cpp
        • Keyboard
          • KeyboardWndProc.h
          • KeyboardWndProc.cpp
    • Framework
      • MultiWindow
        • IWndProc.h
        • WndProcMapper.h
        • WndProcMapper.cpp
        • WndClassRegister.h
        • WndClassRegister.cpp
      • PartWndProc
        • IPartWndProc.h
        • Window.h
        • Window.cpp

方法を考えてみた

方法1

すべてWindowsアプリのプロジェクト配下に入れてしまい、プロジェクトのディレクトリ構成だけ変えてしまう方法がある。

メリット

  • 参照設定が一切不要
  • ファイルサイズが肥大するライブラリを作らずに済む

問題1

ファイルシステム上のディレクトリ構造と一致しない。

ファイラでプロジェクトファイルをみたら全部一つのディレクトリ内にあるから探すのに苦労する。 いちいち重たいIDEを起動せねばディレクトリ構成がわからない。 すでに完成したプロジェクトで、ちょっと中身を見たいときはテキストエディタで開きたい。 でも、フォルダ構成がないからごちゃ混ぜになってファイルを探すのが大変。

問題2

ファイル名が重複せぬよう工夫を強いられる。

問題3

1ディレクトリに含められるファイルの上限内である必要がある。

NTFSは無制限っぽいが、USBメモリに入れるならFAT32の上限65534にひっかかる可能性もある。 ふつう、そんなにたくさんファイルを作らないから問題にはならないだろうけど。

oshiete.goo.ne.jp

方法2

ファイルシステム上のディレクトリ構成もあわせて分割する。

メリット

ファイルシステム上も同様のディレクトリ構成でファイルを探せる。

問題1

参照設定が面倒。 アプリ機能が追加されると、その都度、参照設定も追加せねばならない。

問題2

分類なんて曖昧なもの。 そのうち整合性がとれなくなったりしてやり直したりすることがよく起こる。 その都度、ファイルシステム上の構造を変えたり、インクルードパス文字列を生成して設定することになる。

問題3

コンパイラにインクルードするヘッダを参照するパスを渡す必要がある。

しかし、多すぎるとコマンドプロンプトの文字数制限にひっかかる可能性がある。 Windows2000だと2047文字、XP以降だと8191文字。

指標

規模における分割の指標

コード量が多すぎると見づらくなる。小分けにしたい。 分ける単位と量の指標を考えてみた。 あくまで上限の指標。実際はもっと小さくなると思う。

単位 最大値
1ファイル 1class
1ファイル 300行
1ディレクト 1機能
1ディレクト 8class
1ディレクト 8ディレクト
1ディレクト 4階層
1プロジェクト 1Windowsアプリ
1プロジェクト 1Consoleアプリ
1プロジェクト 16参照ライブラリ
1ソリューション 4プロジェクト

1プロジェクト8ディレクトリ4階層。 1prj = 84 = 4096 dir 1dir = 8class * 300行 = 2400行 1prj = 4096 dir * 2400行 = 9830400行

1class300行以内

  • 1classをヘッダ(.h)とソース(.cpp)に分離した場合
  • 各ファイルが300行以内であればいい
  • 1classのヘッダ(.h)とソース(.cpp)の合計が300行を超えてもかまわない

参照ライブラリ

  • C++C#と違い、ライブラリ化してもヘッダファイルが必要
  • 1ファイルにまとめられないから、ライブラリ化のメリットが下がる
  • 何かの拍子にヘッダファイルを削除したら使えなくなってしまう
  • ディレクトリ構成や参照設定も考える必要がある

ユーザとデベロッパの都合

開発では小分けにしたほうが好都合。 開発やテストがしやすい。

でも、エンドユーザに配布するときはexeファイルひとつにまとめたほうが好都合。 間違って削除したり変更したりできてしまうことを防ぎたい。

この辺、どうするのがいいんだろう。 そもそも何が好都合かなんてケースバイケースか。

exeだけにしてアップデートやロールバックまでユーザが制御できるのが一番いいのだけど。 もはやライブラリの話を超えてしまうか。

再利用性における分割の指標

再利用できそうな部分はライブラリ化する。

  • 実装の抽象化(フレームワーク
    • Windowsプログラミングの抽象化
    • アプリ機能の抽象化
    • 外部ソフトウェア連携の抽象化
  • アプリ機能の一部(ライブラリ)

プロジェクトのソースコードは大きく分けて以下の3つに分けたい。

分類名 内容
Main 本プロジェクト固有の実装
Library 本プロジェクト固有の機能の実装
Framework 本プロジェクトが利用する抽象化のための実装

ただしLibraryはMainの一部ならMainに含めたほうがわかりやすいかもしれない。

ファイルサイズ

分割方法 exeファイルサイズ Window1.lib MultiWindowCreatorClass.lib PartWndProcClass.lib
.lib分割 19 2189 1729 752
VC++prj内分割 19 - - -
ディレクトリ分割 19 - - -

.libに分割すると、.lib分だけ増えている。 .libに分割せずexeだけの場合でも、同じソースコードなのに…。 なぜ.libに分けるとこんなにファイルサイズに差が出るのか。

所感

ぜんぜんまとまらない記事になった。 ライブラリのことなど諸々をよくわかっていないからかもしれない。

分割する方法の是非はともかく、単にフォルダ分けすることができるとわかった。 それだけでも収穫。

.libや.dllの話はかなり難しそう。 もっと調べる必要がある。