パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.6.3.6(15)
Code::Blocksをビルドする

統合開発環境Code::Blocksを自分でビルドする手順を説明し、カスタマイズを可能にする。

本サイトは配布されるインストーラでCode::Blocksを導入した。Code::Blocksは高機能ながらいくつかの不具合を抱え、特に日本語対応が不十分にある。本項目はCode::Blocksをソースコードからビルド方法を説明し、機能改良やバグ修正を可能にする。バージョン20.03を前提に記述する。

ソースコード

ダウンロード

リンク先からアーカイブファイルcodeblocks-20.03.tar.xzあるいはcodeblocks-20.03.tar.bz2をダウンロードする。後述するがtar.xz版は解凍できない場合がある。

ディレクトリ配置

ビルドは配布インストーラから導入済みのCode::Blocksで行い、すなわち一つのパソコンが二つ以上のCode::Blocksを持つ。導入済みを"インストールCode::Blocks"、そこでビルドしたCode::Blocksを"ビルドCode::Blocks"と区別する。後者は組み合わせるオプションの違いで複数存在する。

目的 ディレクトリ
Code::Blocksワーク C:\Users\user\MinGW\CB_Work
展開 C:\Users\user\MinGW\CB_Work\codeblocks-20.03
ビルド C:\Users\user\MinGW\CB_Work\codeblocks-20.03\src

codeblocks-20.03.tar.xzあるいはcodeblocks-20.03.tar.bz2をCode::BlocksワークディレクトリにおいてMSYS2コマンドラインツールtarで解凍する。ビルドは展開ディレクトリのsrcサブディレクトリで行う。srcはメインプログラムのソースコードをsrcサブディレクトリに収め、srcという名称のディレクトリが二つ存在し混乱しやすい。本項目での相対パスはビルドディレクトリ(C:\Users\user\MinGW\CB_Work\codeblocks-20.03\src)からとする。

user@THINKPAD-L430 MINGW64 /c/Users/user/MinGW/CB_Work
$ tar xvf codeblocks-20.03.tar.xz
...

不明の理由でtar.xz解凍がハングアップする場合があり、サイト作成者の環境ではパソコン2台のうち1台でハングアップした。ハングアップした1台もtar.bz2なら同手順で問題なく解凍できた。

展開されるファイルには多様なビルド用ファイルが含まれるが、本サイトはインストールCode::BlocksでビルドするためCode::Blocks用ファイル(*.workspace、*.cbp、update*.bat)以外の記述は省く。32ビット/64ビット、およびリンクするwxWidgetsライブラリバージョンをオプションとして選択し、その組み合わせを"組み合わせバージョン"と呼ぶ。

ディレクトリ ファイル 内容
...\codeblocks-20.03 ... ...
├ src *.workspace ワークスペース
││ *.cbp codeblocks.exe/.dllビルド用プロジェクト
││ update*.bat アップデートバッチ
││ ... ...
│├ src *.cpp, *.h codeblocks.exeビルド用ソースコード/インクルード
││︙ ... ...
│├ sdk *.cpp, *.h codeblocks.dllビルド用ソースコード/インクルード
││︙ ... ...
│├ plugins
││├ abbriviations *.cpp, *.h abbreviations.dllビルド用ソースコード/インクルード
││︙ ... ...
││└ contrib
││ ├ AutoVersioning *.cbp AutoVersioning.dllビルド用プロジェクト
││ ││ *.cpp, *,h AutoVersioning.dllビルド用ソースコード/インクルード
││ │︙ ... ...
││ ︙ ... ...
│├ tools
││├ Addr2LineUI *.cbp Addr2LineUI.exeビルド用プロジェクト
││││ *.cpp, *.h Addr2LineUI.exeビルド用ソースコード/インクルード
│︙︙︙ ... ...

ある組み合わせバージョンのビルドで直接操作するファイルはビルドディレクトリのワークスペース二つとアップデートバッチ一つで、ワークスペースの組み合わせバージョンはサフィックスXXXで、アップデートバッチはYYYで識別する。ワークスペースがビルドするプロジェクトファイル(*.cbp)はサブディレクトリを含めに多数配置されるが、全てにXXXで識別する組み合わせバージョンが存在する。一部のプロジェクトは専用アップデートバッチを持つが、これもYYYで識別する。ビルドディレクトリのアップデートバッチは専用と区別するため"アップデートバッチ(メイン)"として参照する。ビルドはYYYで識別するサブディレクトリへ出力して、異なる組み合わせバージョンの出力が共存できる。

名称 ファイル 説明
CodeBlocksワークスペース CodeBlocksXXX.workspace アプリケーションとコアプラグインをビルドして開発ディレクトリへ出力する。
ContribPluginsワークスペース ContribPluginsXXX.workspace コントリビュートプラグインをビルドして開発ディレクトリへ出力する。
アップデートバッチ(メイン) updateYYY.bat リソースファイルを開発ディレクトリへ配置する。開発ディレクトリを出力ディレクトリへコピーする。
アーキテクチャ wxWidgetsバージョン XXX YYY
32ビット 2.8.X
3.0.X _wx30 30
3.1.X _wx31 31
64ビット 3.0.X _wx30_64 30_64
3.1.X _wx31_64 31_64

ビルド構成

ソースコード同梱のドキュメント(...\BUILD)に従えばビルドは以下の手順になる。ただし本サイトのインストールCode::Blocksは必要な設定を欠いてそのままではビルドできない。

  1. インストールCode::BlocksでCodeBlocksワークスペースを開きAllバーチャルターゲットを選択して[Build|Build workspace]する。
  2. インストールCode::BlocksでContribPluginsワークスペースを開きAllバーチャルターゲットを選択して[Build|Build workspace]する。
  3. インストールCode::Blocksを閉じて、ビルドディレクトリでアップデートバッチを実行する。

CodeBlocksワークスペース(CodeBlocksXXX.workspace)およびContribPluginsワークスペース(ContribPluginsXXX.workspace)は50個以上のサフィックスXXXを持つプロジェクトファイル(*.cbp)で構成される。二つのワークスペースは多数の*.cbpを共通に持つ。各プロジェクトはオブジェクトファイル(*.o)をオブジェクトディレクトリ(.objsYYY)に出力し、ビルド出力を開発ディレクトリ(develYYY)に出力する。ビルド出力は実行形式(*.exe)、DLL(*.dll)、スタティックリンクライブラリ(*.a)のいずれかで、*.aは中間生成物で*.exeまたは*.dllにリンクされる。

アップデートバッチ(メイン)(updateYYY.bat)を実行するとdevelYYYにリソース(イメージなど)ファイルを配置してから、develYYYの内容全てを出力ディレクトリ(outputYYY)にコピーする。これはoutputYYYにコピーしたビルドCode::Blocksで再帰的にビルドすることを想定するものだが、この方法は混乱を招きかねないので本サイトは採らずインストールCode::Blocksでビルドする。updateYYY.batを実行せずともdevelYYYのビルドCode::Blocksは起動できるが、リソースを欠いて例えばいくつかのイメージを表示できない。plugins\contribのサブディレクトリに配置されるプラグインプロジェクトのいくつか(例えばcodesnippets)は専用のupdateYYY.batを持つが、こちらはポストビルドステップが自動実行する。

覚え書き
二つのワークスペースを構成するプロジェクトの多くが共通なので別々のワークスペースとする理由は見当たらない。develYYYの*.aは実行に不要だがoutputYYYへコピーされる。本サイトの運用にoutputYYYは不要だがdevelYYYにリソース配置するためupdateYYY.batは必ず実行する。

64ビットアーキテクチャでwxWidgetsバージョン3.1.Xをリンクする場合の各ファイルと出力ディレクトリを例示する。

ディレクトリ ファイル 内容
...\codeblocks-20.03
├ src CodeBlocks_wx31_64.workspace CodeBlocksワークスペース
││ ContribPlugins_wx31_64.workspace ContribPluginsワークスペース
││ CodeBlocks_wx31_64.cbp codeblocks.exe、codeblocks.dllビルド用プロジェクト
││ update31_64.bat アップデートバッチ(メイン)
│︙
│├ plugins
││︙
││└ contrib
││ ├ AutoVersioning AutoVersioning_wx31_64.cbp AutoVersioning.dllビルド用プロジェクト
││ ︙ ... ...
││ ├ codesnippets codesnippets_wx31_64.cbp codesnippets.dllビルド用プロジェクト
││ │ update31_64.bat codesnippets.dll用アップデートバッチ(専用)
││ ︙ ... ...
│├ tools
││├ Addr2LineUI Addr2LineUI_wx31_64.cbp Addr2LineUI.exeビルド用プロジェクト
│︙︙︙ ... ...
│├ .objs31_64 (*.o) (オブジェクト出力ディレクトリ)
│├ devel31_64 codeblocks.exe, codeblocks.dll メインプログラム実行形式とDLL
|││ *.exe, *.dll, *.a 実行形式、DLL、スタティックリンクライブラリ
|│└ share
|│ └ CodeBlocks *.zip リソースアーカイブ
|│  ├ plugins *.dll プラグインDLL
|│  ├ images (*.png) (イメージリソースディレクトリ)
|│  ︙ ... ...
|├ output31_64 codeblocks.exe, codeblocks.dll メインプログラム実行形式とDLL(devel31_64のコピー)
|︙︙ ... ...

普通なら異なるターゲットをビルドオプションの変更(デバッグビルドとリリースビルドなど)に用いるが、Code::Blocksをビルドするプロジェクトはこれに従わない。例えばCodeBlocksXXX.cbpの異なるターゲットはプロジェクトファイルの異なる部分集合から実行形式(*.exe)、DLL(*.dll)、スタティックリンクライブラリ(*.a)いずれかをビルドする。srcターゲットがcodeblocks.exeをビルドし、sdkターゲットがcodeblocks.dllをビルドし、この二つがCode::Blocksのメインプログラムである。グローバル変数cb_release_typeで全ビルドのコンパイルオプションを変更できるが、出力ディレクトリ(.objsYYY/develYYY/outputYYY)は変更されず上書きされてデバッグビルドとリリースビルドが共存できない。一方で異なる組み合わせバージョンは異なる*.cbpが異なるディレクトリに出力して問題なく共存できる。

*.cbpのwxWidgetsライブラリ指定はグローバル変数wxYYYで行い各組み合わせバージョンはインストールCode::Blocksの同一グローバル変数セットに共存できる。ただし本サイトの標準カスタマイズはこれら(およびcb_release_typeなど)を定義していない。*.cbpは全てバーチャルターゲットAllを持ち、Allは必要なターゲット(ほとんど全て)をビルドする。

アーキテクチャ wxWidgets グローバル変数
32ビット 2.8.X wx
3.0.X wx30
3.1.X wx31
64ビット 3.0.X wx30_64
3.1.X wx31_64

ビルド環境の構築

本サイトの標準カスタマイズはソースコード添付のCode::Blocksプロジェクトファイルに対応できない。またプロジェクトファイルもデバッグビルドとリリースビルドを同じ出力ディレクトリに上書きしてしまう。そこで以下の方法を採る。

  • インストールCode::Blocksに新たなパーソナリティを追加して専用のカスタマイズを施す。
  • プロジェクトファイル(*.cbp)とアップデートバッチを修正してデバッグビルドとリリースビルドで出力ディレクトリを変える。

ビルドはwxWidgetsライブラリを必要とし、これはモノリシック、ダイナミックリンクでなければならない。MSYS2の導入するwxWidgetsは非モノリシックなので使えない。本項目はソースコードからビルドしたwxWidgets利用を前提とし、wxWidgetsディレクトリもこれに従う。アップデートバッチ(メイン)といくつかのプロジェクトのポストビルドステップはzipアーカイバを利用するが、本サイトはMSYS2版zipを導入するため実引数に与えるパス名デリミタをMSYS2準拠の/に変更する。この変更はグロッビング(ワイルドカードによるファイル名補完)に必要だが見た目の混乱を避けるためzipに渡す全てのパス名で行う。

Code::Blocksのパーソナリティ追加

Code::Blocksの各種設定はC:\Users\user\AppData\Roaming\CodeBlocksディレクトリに保存される。デフォルトはdefault.confだが、別ファイルを指定して異なった各種設定の下に起動する事ができる。こういった異なる各種設定をパーソナリティと呼び、パーソナリティは起動時コマンドラインの--personalityオプションで指定する。パーソナリティはステータスバー右端の言語設定(国旗アイコン)の左に表示される。

以下はインストールCode::BlocksをCB_Workパーソナリティで起動する。これが新しいパーソナリティであればC:\Users\user\AppData\Roaming\CodeBlocksにCB_Work.confを初期設定で作成し、そうでなければCB_Work.confを読み込んで起動する。Code::Blocksのビルドはこのパーソナリティで行う。

C:\Users\user>"C:\Program Files\CodeBlocks\codeblocks.exe" --personality="CB_Work"

実際の運用はショートカットを作成してスタートメニューなどに登録するべきであろう。インストールCode::BlocksもビルドCode::Blocksも同じディレクトリの*.confを読み込むため、運用に一定の注意を必要とする。以降のインストールCode::Blocks設定は全てCB_Workパーソナリティで行う。

グローバル変数定義

デバッグビルドとリリースビルドはグローバル変数セットで切り替える。

インストールCode::BlocksをCB_Workパーソナリティで起動してカスタマイズする。[Settings|Global variables]の[Global Variable Editor]ダイアログ[New]ボタンで新しいグローバル変数セットを作成し、それぞれのグローバル変数を定義する。以下は最も汎用的な設定で、想定される組み合わせバージョンの全てに対応する。グローバル変数セットdebug32、release32、debug64、release64を作成し、それぞれにグローバル変数を定義し、定義の無いメンバは空白のままに残す。boostはプロジェクトの一つ(plugins\contrib\NassiShneiderman\NassiShneiderman.cbp)がライブラリ参照するために必要で、本サイトはMSYS2でboostライブラリを導入したためmingwと同じになるが、これを別(例えば自分でビルドしたもの)とするには書き換える。cb_release_typeはコンパイル時オプションでデバッグ/リリースビルドを切り替え、suffixメンバは本サイトが独自定義するもので出力ディレクトリを切り替える。mingwはmingw32/mingw64サブシステムディレクトリを指定する。wxYYY(wxやwx30など)は各wxWidgetsバージョンのインストールディレクトリを指定し、releaseメンバとrelease_nodotメンバはバージョン依存文字列に使用する。

グローバル変数 メンバ debug32 release32 debug64 release64
boost base C:\msys64\mingw32 C:\msys64\mingw64
cb_release_type base -g -O2 -g -O2
suffix d r d r
mingw base C:\msys64\mingw32 C:\msys64\mingw64
wx base [wxWidgetsバージョン2.8.Xインストールディレクトリ]
lib $(#wx)\my_builds
\debug32_monodll\lib
$(#wx)\my_builds
\release32_monodll\lib
$(#wx)\my_builds
\debug64_monodll\lib
$(#wx)\my_builds
\release64_monodll\lib
release 2.8
release_nodot 28
wx30 base [wxWidgetsバージョン3.0.Xインストールディレクトリ]
lib $(#wx30)\my_builds
\debug32_monodll\lib
$(#wx30)\my_builds
\release32_monodll\lib
$(#wx30)\my_builds
\debug64_monodll\lib
$(#wx30)\my_builds
\release64_monodll\lib
release 3.0
release_nodot 30
wx31 base [wxWidgetsバージョン3.1.Xインストールディレクトリ]
lib $(#wx31)\my_builds
\debug32_monodll\lib
$(#wx31)\my_builds
\release32_monodll\lib
$(#wx31)\my_builds
\debug64_monodll\lib
$(#wx31)\my_builds
\release64_monodll\lib
release 3.1
release_nodot 31
wx30_64 base [wxWidgetsバージョン3.0.Xインストールディレクトリ]
lib $(#wx30_64)\my_builds
\debug32_monodll\lib
$(#wx30_64)\my_builds
\release32_monodll\lib
$(#wx30_64)\my_builds
\debug64_monodll\lib
$(#wx30_64)\my_builds
\release64_monodll\lib
release 3.0
release_nodot 30
wx31_64 base [wxWidgetsバージョン3.1.Xインストールディレクトリ]
lib $(#wx31_64)\my_builds
\debug32_monodll\lib
$(#wx31_64)\my_builds
\release32_monodll\lib
$(#wx31_64)\my_builds
\debug64_monodll\lib
$(#wx31_64)\my_builds
\release64_monodll\lib
release 3.1
release_nodot 31

32ビット/64ビット設定が混在し32ビットビルドはdebug32/release32セット、64ビットビルドはdebug64/release64セットを使う。例えばCodeBlocks_wx31_64.workspaceをdebug32セットでビルドするとエラーとなる。debug32/release32セットに64ビット用グローバル変数(wx30_64、wx31_64)は不要で、逆にdebug64/release64セットに32ビット用グローバル変数(wx、wx30、wx31)は不要だが、未定義ではプロジェクトを開く際などに[Global Variable Editor]ダイアログが定義を強要して面倒なのでダミーを定義しておく(すなわち何でも構わない)。従って運用に照らし必要な設定のみ行う方が安心で、本サイトも実際は以下のように64ビットwxWidgetsバージョン3.1.4を前提にdebug64/release64セットのみ定義してwx31_64以外のwxYYYを省略する。

グローバル変数 メンバ debug64 release64
boost base C:\msys64\mingw64
cb_release_type base -g -O2
suffix d r
mingw base C:\msys64\mingw64
wx31_64 base C:\wxWidgets\wxWidgets-3.1.4
lib $(#wx31_64)\my_builds\debug64_monodll\lib $(#wx31_64)\my_builds\release64_monodll\lib
release 3.1
release_nodot 31

デバッガ定義とコンパイラ定義

デバッガとコンパイラをmingwグローバル変数で定義して32ビット/64ビットが自動的に切り替わるようにする。

[Setting|Debugger]で[Debugger settings]ダイアログ左側ツリービューで[GDB/CDB debugger|Default]ノードを選択して以下に設定する。[...|Executable path]入力テキストボックスはキー入力に問題があるので設定をコピーアンドペーストする

設定 Default
Executable path $(#mingw.bin)\gdb.exe
Arguments
Debugger Type GDB

[Settings|Compiler]で[Global compiler settings]ダイアログの[Global compielr settings]ページを開く。[...|Selected compiler]でGNU GCC Compilerを選択しデフォルトコンパイラになっている事を確認する。[...|Toolchain executables]を以下に設定する。コンパイラファイル名に32ビット/64ビット共通名を選択している。

設定 GNU GCC Compiler
Compiler's installation directory $(#mingw)
Program Files C compiler gcc.exe
C++ compiler g++.exe
Linker for dynamic libs g++.exe
Linker for static libs ar.exe
Debugger GDB/CDB debugger : Default
Resource compiler windres.exe
Make program mingw32-make.exe

環境変数PATHの追加

MSYS2版zipアーカイバを利用するためPATHを追加する。[Settings|Environment]の[Environment settings]ダイアログ[Environment variables]ページで、[Select/Create/Clone/Remove envvar - set]defaultのまま[Add]を押して追加する。

PATH=%PATH%;C:\msys64\usr\bin

プロジェクトファイルとアップデートバッチの修正

64ビットwxWidgets3.4.1(XXXが_wx31_64、YYYが31_64)用ファイルを例として説明するが、他の組み合わせバージョン用ファイルについてはXXXとYYYを読み替える。全てのプロジェクトファイル(*.cbp)と全てのアップデートバッチ(メインおよび専用update31_64.bat)、およびビルドディレクトリのupdate.batに以下を施す。作業は膨大なので自動化するバッチファイルを最後に提示する。

*.cbpのwxWidgets設定は本サイトがビルドしたwxWidgetsと異なるため修正する。

  • [Project|Build options]の[Project build options]ダイアログ左側ツリービュー全ノードの[Linker settings]ページで以下を行う。
    • ライブラリファイルwxmsw$(WX_VERSION)$(WX_SUFFIX)をwx_mswu-$(#wx31_64.release).dllに書き換える。
  • [Project|Build options]の[Project build options]ダイアログ左側ツリービュー全ノードの[Search directories]ページで以下を行う。
    • [Compiler]と[Resoruce compiler]の探索パス$(#WX31_64.lib)\gcc_dll$(WX_CFG)\msw$(WX_SUFFIX)を$(#wx31_64.lib)\wx\include\msw-unicode-$(#wx31_64.release)に書き換える。
    • [Linker]の探索パス$(#WX31_64.lib)\gcc_dll$(WX_CFG)を$(#wx31_64.lib)に書き換える。

ビルドCode::Blocksのデバッグ/リリースを共存させるため*.cbpを修正する。出力ディレクトリ名の末尾にcb_release_type.suffixグローバル変数を加え、デバッグ用(例えばdevel31_64d)とリリース用(devel31_64r)の出力ディレクトリを変更する。

  • [Project|Properties]の[Project/targets options]ダイアログ[Builds targets]の全ターゲットで以下を行う。
    • [Output filename]のパスが含むdevel31_64をdevel31_64$(#cb_release_type.suffix)に書き換える。
    • [Objects output dir]の.objs31_64を.objs31_64$(#cb_release_type.suffix)に書き換える。
  • [Project|Build options]の[Project build options]ダイアログ左側ツリービュー全ノードの[Pre/post build steps]ページで以下を行う。
    • [Pre-build steps]あるいは[Post-build steps]で出力ディレクトリ(devel31_64、.objs31_64、output31_64)を参照していたら末尾に$(#cb_release_type.suffix)を書き加える。
    • [Pre-build steps]あるいは[Post-build steps]でアップデートバッチupdate31_64.batを参照していたらupdate31_64$(#cb_release_type.suffix).batに書き換える。
覚え書き
[Objects output dir]のグローバル変数設定には後述のバグに留意の事。

zip実引数パスデリミタを変更するため*.cbpを修正する。zip実行はポストビルドステップだけだが念のためプレビルドステップも加える。

  • [Project|Build options]の[Project build options]ダイアログ左側ツリービュー全ノードの[Pre/post build steps]ページで以下を行う。
    • [Pre-build steps]あるいは[Post-build steps]でzip実行していたら実引数パスデリミタを\から/に変更する。

全てのupdate31_64.batからデバッグ/リリースビルド用のupdate31_64d.bat/update31_64r.batを作成する。アップデートバッチは二つの方法で書かれているためそれぞれに異なる処理を施す。

  • update31_64.batが31_64を実引数としてupdate.batをコールして実際の処理はupdate.batが行う場合、31_64d/31_64rでコールするバッチファイルを作成する。
  • update31_64.batの中にdevel31_64やoutput31_64が書き込まれている場合、devel31_64d/devel31_64rやoutput31_64d/output31_64rに書き換えたバッチファイルを作成する。

ビルドディレクトリupdate.batのzip実引数パスデリミタを変更する。アップデートバッチ(メイン)(ビルドディレクトリupdate31_64d.bat/update31_64r.bat)はこれを31_64d/31_64rでコールするだけなので修正する必要はない。

  • zipはローカル環境変数ZIPCMDに代入されているので%ZIPCMD%実行全て実引数パスデリミタを\から/に変更する。

自動処理はpreprocess_common.batバッチファイルとpreprocess.batバッチファイルをビルドディレクトリに置いてそこで実行する。preprocess_common.batはビルドディレクトリupdate.batを修正し、これは組み合わせバージョンに依存せず一度だけ実行する。その他はpreprocess.batの実引数に必要な組み合わせバージョンを1個以上指定して実行する。実引数は基本YYYだが32ビットwxWidgets2.8.Xは空白文字列なので28とし、すなわち28、30、30_64、31、31_64のいずれかである。

preprocess_common.bat

@rem Modify .\update.bat to change path delimier from \ to / in arguments
@rem passed to MSYS2 zip. We don't need enabledelayedexpansion.
@rem Note that sed output is postprocessed by unix2dos to replace LF with
@rem CRLF, otherwise the batch would have strange behaviour.
@setlocal
@set PATH=C:\msys64\usr\bin;%PATH%
@set _FILE=update.bat
@set _SCRIPT=%~dp0_script.sed
@echo /^^\s*set\s+CB_DEVEL_RESDIR\s*=/a set CB_DEVEL_RESDIR_SLASH=%%CB_DEVEL_RESDIR:\\=\/%%> %_SCRIPT%
@rem @echo /^^\s*"?\s*%%ZIPCMD%%\s*"?/,/^>\s*nul\s*$/{s/\\/\//gi>> %_SCRIPT%
@echo /^^\s*"?\s*%%ZIPCMD%%\s*"?/,/[^^^^]$/{s/\\/\//gi>> %_SCRIPT%
@echo s/%%CB_DEVEL_RESDIR%%/%%CB_DEVEL_RESDIR_SLASH%%/gi}>> %_SCRIPT%
@if not exist %_FILE%_backup copy %_FILE% %_FILE%_backup > nul
@echo Modify %_FILE% ...
@sed -E -i -f %_SCRIPT% %_FILE%
@unix2dos -q %_FILE%
@del %_SCRIPT%
@exit /b

preprocess.bat

@rem Modify files in the current and descendant directories for CB to built
@rem with multiple configurations. Project files [Project]XXX.cbp (*.cbp) are
@rem modified and update batch files updateYYYr.bat/updateYYYd.bat for
@rem debug/release builds are created from updateYYY.bat.
@setlocal enabledelayedexpansion
@set PATH=C:\msys64\usr\bin;%PATH%
@set _IDS_LIST=, 28, 30, 30_64, 31, 31_64,
@set _IDS=
@for %%i in (%*) do @if not "!_IDS_LIST:, %%i,=!"=="%_IDS_LIST%" set _IDS=!_IDS! %%i
@if "%_IDS%"=="" (
echo.
echo Provide WX version IDs that CB to build uses.
echo Usage: %~n0 ID1 [ID2 [ID3 ... ]]
echo Where IDx is either%_IDS_LIST:~1,-1%.
exit /b 1
)
@set _CBP_SCRIPT_TEMPLATE=%~dp0_cbp_script_template.sed
@set _SCRIPT=%~dp0_script.sed
@rem Create a template of a sed script file to modify *.cbp. #YYY# will be
@rem substituted with the actual YYY. "|" must be escaped by "^" on echo and
@rem the both must be escaped for an assignment, so that you need "^^^|".
@rem The "setlocal enabledelayexpansion" requires "!" escaped at delayed
@rem expansion after static parsing, so that you need "^^!".
@set _LIB_REGEX=\$\‍(#WX#YYY#(\.lib\‍)^^^|\‍)[\/]lib)[\/]gcc_dll\$\‍(WX_CFG\‍)
@echo s/%_LIB_REGEX%[\/]msw\$\‍(WX_SUFFIX\‍)/\$\‍(#wx#YYY#.lib\‍)\\wx\\include\\msw-unicode-\$\‍(#wx#YYY#\.release\‍)/gi> %_CBP_SCRIPT_TEMPLATE%
@echo s/%_LIB_REGEX%/\$\‍(#wx#YYY#\.lib\‍)/gi>> %_CBP_SCRIPT_TEMPLATE%
@echo s/wxmsw\$\‍(WX_VERSION\‍)\$\‍(WX_SUFFIX\‍)/wx_mswu-\$\‍(#wx#YYY#\.release\‍).dll/gi>> %_CBP_SCRIPT_TEMPLATE%
@set _FILE_REGEX=(devel^^^|\.objs^^^|update^^^|output)#YYY#
@echo /%_FILE_REGEX%\$/^^!s/%_FILE_REGEX%/\0\$\‍(#cb_release_type\.suffix\‍)/gi>> %_CBP_SCRIPT_TEMPLATE%
@rem Add to the template a command to change path delimiter from \ to / in
@rem arguments passed to MSYS2 zip in Pre/post build steps.
@echo /^^\s*^<Add (before^|after)=(^"\s*zip^|('\s*cmd\s+\/c\s+^&quot;^|^"\s*cmd\s+\/c)\s*cd\s.*^&amp;\s*zip\s+)/s/\\/\//gi>> %_CBP_SCRIPT_TEMPLATE%
@rem Define any XXX to find directories containing *.cbp to modify. Because
@rem *.cbp for ID=28 has no XXX at all, there is no other way to find it than
@rem relying on another *.cbp having XXX.
@set _XXX_TO_FIND_CBP=_wx31
@rem Because update batch files are classified into two groups by their
@rem different processing ways, you cannot process them automatically by
@rem traveling directories. Instead such two directory lists are created that
@rem you will process them for each list. _UPDATE_BAT_DIR_LIST_1 contains
@rem directories where an update batch file calls update.bat with an argument
@rem YYY. _UPDATE_BAT_LIST_2 contains directories where an update batch file
@rem has YYY written in.
@set _UPDATE_BAT_DIR_LIST_1=
@set _UPDATE_BAT_DIR_LIST_1=%_UPDATE_BAT_DIR_LIST_1% .
@set _UPDATE_BAT_DIR_LIST_1=%_UPDATE_BAT_DIR_LIST_1% plugins\contrib\DoxyBlocks
@set _UPDATE_BAT_DIR_LIST_1=%_UPDATE_BAT_DIR_LIST_1% plugins\contrib\SpellChecker
@set _UPDATE_BAT_DIR_LIST_1=%_UPDATE_BAT_DIR_LIST_1% plugins\contrib\ThreadSearch
@set _UPDATE_BAT_DIR_LIST_2=
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\codesnippets
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\FortranProject
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\IncrementalSearch
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\lib_finder
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\ToolsPlus
@set _UPDATE_BAT_DIR_LIST_2=%_UPDATE_BAT_DIR_LIST_2% plugins\contrib\wxSmith
@rem Main loop for given WX version IDs.
@for %%i in (%_IDS%) do @(
rem ID=28 has neither XXX nor YYY.
set _XXX=_wx%%i
set _YYY=%%i
if "%%i"=="28" (
set _XXX=
set _YYY=
)
echo.
echo Process CB projects of which WX version ID is %%i^(XXX=!_XXX!,YYY=!_YYY!^).
echo.
rem Modify [Project]XXX.cbp.
sed -E -e s/#YYY#/!_YYY!/gi %_CBP_SCRIPT_TEMPLATE% > %_SCRIPT%
for /r %%f in (*%_XXX_TO_FIND_CBP%.cbp) do @(
set _FILE=%%f
set _FILE=!_FILE:%_XXX_TO_FIND_CBP%.cbp=!!_XXX!.cbp
if exist !_FILE! (
echo Modify !_FILE:%CD%\=! ...
if not exist !_FILE!_backup copy !_FILE! !_FILE!_backup > nul
sed -E -i -f %_SCRIPT% !_FILE!
)
)
rem Create updateYYYd.bat/updateYYYr.bat from updateYYY.bat for
rem debug/release builds. Note that sed output is postprocessed by
rem unix2dos to replace LF with CRLF, otherwise the batch would have
rem strange behaviour.
for %%d in (%_UPDATE_BAT_DIR_LIST_1%) do @(
set _FILE=%%d\update!_YYY!.bat
if exist !_FILE! (
echo Create %%d\update!_YYY![d^|r].bat ^(calls update.bat^) ...
for %%t in (d r) do @(
echo @call update.bat !_YYY!%%t> %%d\update!_YYY!%%t.bat
)
)
)
for %%d in (%_UPDATE_BAT_DIR_LIST_2%) do @(
set _FILE=%%d\update!_YYY!.bat
if exist !_FILE! (
echo Create %%d\update!_YYY![d^|r].bat ^(from update!_YYY!.bat^) ...
for %%t in (d r) do @(
sed -E -e "s/^(devel^|output^)!_YYY!/\0%%t/gi" !_FILE! | unix2dos > %%d\update!_YYY!%%t.bat
)
)
)
)
@del %_CBP_SCRIPT_TEMPLATE%
@del %_SCRIPT%
@exit /b
覚え書き
上のpreprocess.batをコピーアンドペーストで利用するとエラーとなる場合がある。ソースに"\‍("あるいは"\‍)"が含まれると不明の理由で文字間にゼロ幅接合子"&zwj;"が追加されていて、ペースト先のエディタによっては不正となる。
覚え書き
*.cbpポストビルドステップのzip実行に二つの方法が確認されている。
zip -<option> subdir2\subsubdir2\output.zip subdir1\subsubdir1\subsubsubdir1\*.png
cmd /c "cd subdir1\subsubdir1 & zip -<option> ..\..\subdir2\subsubdir2\output.zip subsubsubdir1\*.png"
第二の方法はcdコマンド実引数にもパスデリミタが現れるがこれをsedユーティリティの修正から除外するのは難しい。一般にウィンドウズコマンドツールでデリミタ/を使えないが幸いcdは許容するので一緒に修正する。GnuWin32のzipならグロッビングでもウィンドウズパスデリミタを正しく認識してそもそも修正不要なのだが。

アップデートバッチのメニュー登録

ドキュメント(...\BUILD)はアップデートバッチの実行前に必ずCode::Blocksを閉じるとするが、outputYYYにコピーしたビルドCode::Blocksで再帰的にビルドすることを想定するためで本サイトはインストールCode::Blocksでビルドしてその制約は無い。Toolsメニューにビルドディレクトリupdate.batを登録して組み合わせバージョンYYYを実引数に渡す。[Tools|Configure tools]で[User-defined tools]ダイアログ[Add]で新しく登録するが、[Tools+|Configure tools]でも構わない。

プロパティ 内容
Name Run update batch
Executable cmd /c update
Parameters [[print(ReplaceMacros(_T("$(WORKSPACE_FILENAME)")).BeforeLast('.').AfterFirst('_').AfterFirst('x'))]]$(#cb_release_type.suffix)
Working directory $(WORKSPACE_DIR)
Launching options Launch tool hidden with standard output redirected

[Tools|Run update batch]はワークスペースファイル名からYYYを推定してアップデートバッチを実行する。

ビルドと実行

ビルド環境が正しく構築されている事を前提にインストールCode::BlocksでCode::Blocksをビルドする。本サイトはビルド環境の汎用性にできる限りの注意を払ったものの実際にビルドしたのは64ビットwxWidgets3.1.4だけで、他の組み合わせバージョンは確認していない。このビルドは追加設定とパッチ当てを必要とし、これは別項目のソースコードで説明する。

デバッグビルド

最初にデバッグビルド(debug64)する。

  1. インストールCode::BlocksをCB_Workパーソナリティで起動する。
  2. [File|Open]でCodeBlocks_wx31_64.workspaceワークスペースを開く。
  3. [Settings|Global variables]の[Global Variable Editor]ダイアログ[Current Set]でdebug64を選択する。
  4. [Build|Build workspace]する。エラーに適切なパッチを当てる。
  5. [File|Open]でContribPlugins_wx31_64.workspaceワークスペースを開く。
  6. [Build|Build workspace]する。
  7. [File|Open]でCodeBlocks_wx31_64.workspaceを開き直す。
  8. 一度実行確認する。[Build|Run]の[Select target]ダイアログでsrcターゲット選択を確認して[OK]すればビルドCode::Blocksは起動するがいくつかの不具合を生じる。
    • [Management]ウィンドウ[Projects]ページなどのアイコンが正しく表示されない。
    • [Settings|Environment]などは多くの警告を発し、無視してダイアログ表示すると左側ペインのイメージが全く表示されない。
  9. [Tools|Run update batch]でアップデートバッチを実行する。
  10. [Build|Run]で起動し、イメージが正しく表示されるのを確認する。
覚え書き
[Build|Run]はビルドCode::Blocksをdebugパーソナリティで起動するため、defaultパーソナリティやCB_Workパーソナリティへの影響を心配せずに色々な事を試せる。ただし新たに作成されるdebugパーソナリティは初期設定なので本サイトの標準カスタマイズと異なり不具合となる可能性がある。これを避けるにはあらかじめC:\Users\user\AppData\Roaming\CodeBlocksディレクトリのdefault.confをdebug.confにコピーしておく。

リリースビルド

引き続きリリースビルド(release64)するが、グローバル変数セットを変更する以外はデバッグビルドと変わらない。

  1. [File|Close workspace]でワークスペースを一度閉じる。
  2. [File|Open]でCodeBlocks_wx31_64.workspaceを開く。
  3. [Settings|Global variables]の[Global Variable Editor]ダイアログ[Current Set]でrelease64を選択する。
  4. [Build|Build workspace]する。
  5. [File|Open]でContribPlugins_wx31_64.workspaceワークスペースを開く。
  6. [Build|Build workspace]する。
  7. [File|Open]でCodeBlocks_wx31_64.workspaceを開き直す。
  8. [Tools|Run update batch]でアップデートバッチを実行する。
  9. [Build|Run]で起動確認する。
覚え書き
ワークスペースを一度閉じて開き直すのは[Object output dir]のグローバル変数に関するバグ対策である。[Project|Properties]の[Project/target options]ダイアログ[Builds targets]ページの設定にグローバル変数を用いる場合、ほとんどは値の変更を即座に反映するが[Object output dir]だけは前にビルドした時の値を維持して変更されず、変更にはプロジェクトを一度非アクティブにしなければならない。Code::Blocksのビルドはワークスペース単位で行うためほとんどの場合にプロジェクトは非アクティブ/再アクティブしてこのバグが現れる可能性は低いが、念のためワークスペースごと開き直す。

デバッグ追跡

せっかくCode::Blocksのデバッグビルドに成功したのだからデバッグ追跡してみよう。例えばトップレベルウィンドウの構築からwxWidgetsのwxFrameコンストラクタへ追跡する。

CodeBlocks_wx31_64.workspaceワークスペースを開き直しグローバル変数debug64セットを選択する。Code::Blocks wx3.1.x (64bit)プロジェクト(CodeBlocks_wx31_64.cbp)、src\app.cppのCodeBlocksApp::InitFrame関数でトップレベルウィンドウのMainFrameクラスインスタンスを構築(new)する行にテキストカーソルを置いて[Debug|Toggle breakpoint]でブレークポイントを設定する。[Debug|Start / Continue]でデバッガをスタートしてビルドCode::Blocksを実行すれば設定したブレークポイントで停止する。[Debug|Step into]するとMainFrame::MainFrameに飛ぶ。さらに[Debug|Step into]で基底クラスコンストラクタwxFrame::wxFrameを追跡しようとするが、実引数処理が先に来るためwxString::FromAsciiを追跡するので[Debug|Step out]してFrame::Frameに戻る。再度[Debug|Step into]すれば引き続き実引数処理としてwxStringコンストラクタを追跡して[Debug|Step out]でFrame::Frameに戻る。もう一度[Debug|Step into]してようやくwxFrame::wxFrameを追跡し、[Debug|Next line]の繰り返しで内部フローをステップ確認できる。[Debug|Start / Continue]で通常実行を再開する。

覚え書き
デバッガ上のプログラム実行は通常より当然ながら遅い。Code::Blocksは大規模なプログラムであるためデバッグ実行は予想以上の時間がかかりハングアップしているかに見えるが慌てない。