KAGURA実験室

KAGURA開発者の個人ブログ

CMakeの便利機能 configure

f:id:nkshigeru:20190117001841j:plain
このイラストはフィクションであり、実在の人物とは関係ありません。一切関係ありません。

「こんなことできたらいいな」というとき、実装自体はそんなに難しくなくても、製品に組み込むとなるとそう簡単ではないことがあります。本当に有用なものか自信がなかったり、バージョン間の互換性を考えると慎重にならざるを得なかったり・・・。

とりあえず実装してみて、使うかどうかは後から決めたい。そんなとき、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」を実行すると、追加したオプションのチェックボックスが表示されます。

f:id:nkshigeru:20190103231944p:plain
ENABLE_FEATURE_XYZのチェックボックスをOn/Offできる

Config.h.inはCMake独特の形式で、以下のようにします。

// Config.h.in
#cmakedefine ENABLE_FEATURE_XYZ

CMakeで「Generate」を実行すると、Config.hが生成されます。チェックのOn/OffによってConfig.hの結果が変わります。

f:id:nkshigeru:20190104000629p:plain
ENABLE_FEATURE_XYZがOnのとき
f:id:nkshigeru:20190104000633p:plain
ENABLE_FEATURE_XYZがOffのとき

ヘッダーファイルはコンパイルしないので、add_executableコマンドにConfig.hを追加する必要はありませんが、追加するとVisual Studioのファイル一覧に表示されるので便利です。 f:id:nkshigeru:20190103235657p:plain

最初はフォルダ構造を理解するのが難しいかもしれません。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)環境でも同じようなことができるようになります。