CMakeの便利機能 configure
「こんなことできたらいいな」というとき、実装自体はそんなに難しくなくても、製品に組み込むとなるとそう簡単ではないことがあります。本当に有用なものか自信がなかったり、バージョン間の互換性を考えると慎重にならざるを得なかったり・・・。
とりあえず実装してみて、使うかどうかは後から決めたい。そんなとき、CMakeの機能が使えます。
configure
同じソースコードで機能XYZの有効/無効を切り替えたい場合、機能XYZを実装しているところを#ifdef~#endifで囲ったりします。
// main.cpp #include <iostream> #include "Config.h" int main() { #ifdef ENABLE_FEATURE_XYZ std::cout << "xyz" << std::endl; #endif std::cout << "Hello" << std::endl; return 0; }
こうすれば、ENABLE_FEATURE_XYZ
というマクロを定義するかどうかで、挙動を変えられます。
ここでは、その定義をConfig.hというファイルに分けることにします。
// Config.h #define ENABLE_FEATURE_XYZ
機能XYZを有効にするかどうか、ビルドする人の気分(?)で簡単に変えられたら便利です。そこで、Config.hの生成をCMakeにお願いします。
# CMakeLists.txt cmake_minimum_required (VERSION 3.0) project(hello) # ビルドする人が設定できるオプションを追加する option(ENABLE_FEATURE_XYZ "機能XYZを有効にする" ON) # Config.h.inからConfig.hを生成する configure_file( "${PROJECT_SOURCE_DIR}/Config.h.in" "${PROJECT_BINARY_DIR}/Config.h" ) # 生成されたConfig.hをC++ソースから読み込むため include_directories("${PROJECT_BINARY_DIR}") add_executable(hello main.cpp "${PROJECT_BINARY_DIR}/Config.h" )
CMakeで「Configure」を実行すると、追加したオプションのチェックボックスが表示されます。
Config.h.inはCMake独特の形式で、以下のようにします。
// Config.h.in
#cmakedefine ENABLE_FEATURE_XYZ
CMakeで「Generate」を実行すると、Config.hが生成されます。チェックのOn/OffによってConfig.hの結果が変わります。
ヘッダーファイルはコンパイルしないので、add_executableコマンドにConfig.hを追加する必要はありませんが、追加するとVisual Studioのファイル一覧に表示されるので便利です。
最初はフォルダ構造を理解するのが難しいかもしれません。PROJECT_SOURCE_DIRとPROJECT_BINARY_DIRの違いに注意してください。
- source <== PROJECT_SOURCE_DIR
|- CMakeLists.txt
|- main.cpp
|- Config.h.in
|- build/ <== PROJECT_BINARY_DIR ・・・自分で設定した任意の場所。sourceの中とは限らない
|- hello.sln (プロジェクトファイルなど)
|- Config.h
何が嬉しいのか?
なぜこんな回りくどいことをするのでしょうか。Config.hを直接変更したらいいのでは?
一時的なビルドの設定のために、いちいちソースコードを変更していると、他の変更と一緒にgitなどにコミットしてしまうかもしれません。Config.hを自動生成すれば、ソースコードの変更履歴を汚さずに済みます。
Unix系の環境では、そのためにconfigureスクリプトが用意されていたり、autotools系のツールを使ったりすることが多いですが、CMakeを使うと、Windows(Visual Studio)環境でも同じようなことができるようになります。