しゃけのブログ

某大学院で研究している人の備忘録

CMakeのチュートリアルをやる(Step1)

CMake Tutorial

CMakeをC++プロジェクトなどで使うことは多いのですが、付け焼刃の知識しかなくて正しい書き方がいまだにわからない... なので初心に戻って、CMakeの公式が作ったチュートリアルをやっていこうと思います。

この記事はその時のメモみたいなものです。

参考はこちら。 チュートリアルの元となるプロジェクトファイルたちもここからダウンロードできます。

CMake Tutorial — CMake 3.25.0-rc3 Documentation

Step1: 標準的なプロジェクトの作成

次の要素が含まれている。

  • 自作のヘッダーファイルをインクルードするための設定
  • 実行ファイルの作り方
  • バージョン情報を付加したヘッダーファイルの自動生成

ファイルとしては、上のURLからダウンロードしたCMAKE-x.xx.x-RC3-TUTORIAL_SOURCEのStep1を参照しています。

目的

tutorial.cxxをCMakeLists.txtを使ってコンパイルする。

最小構成:実行ファイルを作る

CMakeLists.txtの最小構成だろうと思われるものを作って、そこから付け加えていく流れでまとめます。

tutorial.cxxをコンパイルしてTutorialという名前の実行ファイルを作るCMakeLists.txtは次の通り:

cmake_minimum_required(VERSION 3.10)

project(Tutorial VERSION 1.0)

add_executable(Tutorial tutorial.cxx)

cmake_minimum_required

cmake_minimum_required(VERSION 3.10) のように必要とされる最小のcmakeバージョンを指定できます。

私のcmakeはバージョン3.16.3だったので、cmake_minimum_required(VERSION 3.17)としてみたら、ちゃんと次のエラーが出た。

CMake Error at CMakeLists.txt:2 (cmake_minimum_required):
  CMake 3.17 or higher is required.  You are running version 3.16.3

project

project(Tutorial VERSION 1.0)のようにプロジェクト名と、バージョン情報を付加できます。

CMakeが自動生成する変数の名前が プロジェクトでつけた名前_...のようになる。また${PROJECT_NAME}でプロジェクト名を参照できます。

バージョン情報はあってもなくてもいいみたいですが、つけておくとTutorial_VERSION_MAJORTutorial_VERSION_MINORという変数が自動生成されて、にそれぞれ1と0が入るみたい。

add_executable

add_executable(Tutorial tutorial.cxx)

コンパイルの対象となるソースファイル(tutorial.cxx)を指定して実行ファイル(Tutorial)を作ります。 ターゲット(生成される実行ファイル名)はプロジェクト名と同じじゃなくてもいい。

機能追加1:C++バージョンの指定

CMake

cmake_minimum_required(VERSION 3.10)

project(Tutorial VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

add_executable(Tutorial tutorial.cxx)

CMAKE_CXX_STANDARD CMAKE_CXX_STANDARD_REQUIRED

set(XXX YYY)というコマンドを使うことで、YYYという値を持つXXXという変数を定義することができます。

そして、set(CMAKE_CXX_STANDARD 11)のようにすることで、ビルドに使うC++バージョンを設定できます。

また、set(CMAKE_CXX_STANDARD_REQUIRED True)としておくとC++11が使えない環境でのビルドにエラーを出すことができるようです。

※ 実行ファイルを作るadd_executableより前に指定する必要がある

チュートリアルでは、C++11にしかない機能がコンパイルできるようになることを確認しています。

補足:target_compile_features

上の変数を直接いじる方法以外に、最近のCMakeではtarget_compile_features(Tutorial PUBLIC cxx_std_11)C++バージョンを指定するやり方が主流のようです。

この機能によって、プロジェクトごとではなくターゲットごと(実行ファイルとかライブラリごと)にC++のバージョンを設定できるので使いやすい。

(もしかしてこのチュートリアル古い...???)

このPUBLICについては一旦考えずに次に進めましょう。

機能追加2: プロジェクトのバージョン情報をヘッダファイルからソースファイルへ教示

CMakeLists.txtで定義した変数の情報をソースファイルへ流す機能として、ソースファイルがインクルードするヘッダファイルへバージョン情報を自動で書き込む機能を追加します。

cmake_minimum_required(VERSION 3.10)

project(Tutorial VERSION 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

configure_file(TutorialConfig.h.in TutorialConfig.h)

add_executable(Tutorial tutorial.cxx)

target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")

configure_file

configure_file(TutorialConfig.h.in TutorialConfig.h)

TutorialConfig.h.inは事前に用意する次のようなファイル。

#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

ここで、@Tutorial_VERSION_MAJOR@など見慣れない書き方がされているが、ここはCMakeによって後で書き直される部分を明示しています。

configure_fileはこのようなヘッダファイルのひな型に対して、現在までに定義された変数を使ってC++のためのヘッダファイルを生成します。

この例では、Tutorial_VERSION_MAJORTutorial_VERSION_MAJORproject(Tutorial VERSION 1.0)コマンドによって1と0になっているので、 次のようなヘッダファイルが生成されると考えることができます。

#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0

実際、ビルドを走らせるとビルドフォルダ内に、この内容のTutorialConfig.hというファイルが生成されます。

target_include_directories

target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")

一旦、PUBLICという単語は忘れる(後できっと説明される)。

このコマンドによって、add_executableを実行したときに、ソースファイルがヘッダファイルをインクルードするときに探索するディレクトリを指定することができます。

${PROJECT_BINARY_DIR}変数はCMakeが自動生成してくれるもので、ビルドファイルを指し示します。

今回、ヘッダファイルはソースファイルと同じディレクトリではなく、ビルドフォルダ内に自動生成されるので、このような探索するディレクトリを明示する必要があります。

そして、このヘッダファイルをソースファイルからインクルードすれば、バージョン情報をmain関数から参照してprintすることができますね。

#include "TutorialConfig.h"

...
    std::cout << "Version: " << 
        Tutorial_VERSION_MAJOR << "." << Tutorial_VERSION_MINOR << std::endl;
...