CMakeの基本的な使い方

CMakeの基本的な使い方

1. はじめに


自分の備忘録として、CMakeの基本的な使い方をまとめておきます。 普段利用するものの頻繁に書くものではないため、ゼロから書こうとするとあれ?って忘れている事が多いので。

作業スペースのカレントディレクトリにCMakeLists.txtを作成します。 ソースコードはsrcディレクトリ以下に配置しているものとします。

├── CMakeLists.txt
└── src/main.c
└── src/hoge.cc

まず、ごく基本的な例を以下に示します。

cmake_minimum_required(VERSION 3.10)
project(Project_name_free)
set(CMAKE_CXX_STANDARD 14)

find_package(PkgConfig)
pkg_check_modules(EGL REQUIRED egl)

add_executable(target_name src/main.c src/*.cc)
target_include_directories(target_name PRIVATE ${EGL_INCLUDE_DIRS})
target_link_libraries(target_name PRIVATE ${EGL_LIBRARIES})
target_compile_options(target_name PUBLIC ${EGL_CFLAGS} "-Wall")

2. プロジェクト設定


cmake_minimum_required コマンド

ビルドを実行するHost PC環境で必要になるCMakeの最低バージョンを指定します。

cmake_minimum_required(VERSION 3.10)

最新のCMakeの文法/コマンド等を利用していなければ、バージョン制約はほぼないと思います。 例えばUbuntu18.04のCMakeのバージョンが3.10のため、この辺のバージョンを指定しておけば良いと思います。


project コマンド

CMakeプロジェクト名を指定するために利用します。

project(Project_name_free)

指定した文字列がPROJECT_NAMEにセットされます。 オプションとして、VERSIONLANGUAGESがありますが単なる付加情報のため、 指定してもしなくても良いです。


CMAKE_CXX_STANDARD プロパティ

C++の場合、以下の様にビルド時に指定するC++標準バージョンを指定する事が出来ます。

set(CMAKE_CXX_STANDARD 14)

3. PkgConfigの利用


ビルド時のヘッダーファイルのインクルードやライブラリリンクオプションを簡易化するために、 pkg-configはほぼ必須だと思います。これをCMakeで利用する方法について説明します。


find_package コマンド

find_packageコマンドを利用すると、利用したいライブラリ (パッケージ) のライブラリパスや インクルードファイルパスなどを取得する事が可能です。

下記を実行すると、GTK2_INCLUDE_DIRSにインクルードファイルのパス、GTK2_LIBRARIESに ライブラリパスが自動で設定されます。

find_package(GTK2)

利用可能なモジュールは、cmake --help-module-listコマンドで表示される一覧で確認が可能です。 ただ、find_packageをサポートしているパッケージがまあまあない事があるので、その場合には後述の pkg_check_modulesコマンドを利用します。

なので、よくあるパターンとしては、以下の例の様にfind_packageコマンドはPkgConfigモジュールを 指定してそれが提供するpkg_check_modulesコマンドを利用するというやり方です。

find_package(PkgConfig)

pkg_check_modules コマンド

実際にはこのコマンドを多用すると思います。上記の様に、find_package(PkgConfig)を実行しておけば、 以下の様にpkg-configコマンドで取得できる情報を取得可能です。

第一引数は、適当なプレフィックス (XPREFIX) します。 第二引数は、REQUIREDQUIETを指定し、パッケージが必須の場合にはREQUIREDを指定し、 見つからなかった場合にエラーで止まる様にします。 第三引数は、利用したいpkg-configで指定するパッケージ名です。

pkg_check_modules(EGL REQUIRED egl)

コマンド実行で設定される変数は以下です。

<XPREFIX>_FOUND          ... set to 1 if module(s) exist
<XPREFIX>_LIBRARIES      ... only the libraries (w/o the '-l')
<XPREFIX>_LIBRARY_DIRS   ... the paths of the libraries (w/o the '-L')
<XPREFIX>_LDFLAGS        ... all required linker flags
<XPREFIX>_LDFLAGS_OTHER  ... all other linker flags
<XPREFIX>_INCLUDE_DIRS   ... the '-I' preprocessor flags (w/o the '-I')
<XPREFIX>_CFLAGS         ... all required cflags
<XPREFIX>_CFLAGS_OTHER   ... the other compiler flags

4. ターゲットの指定


ソースコード

add_executableコマンドを利用します。

add_executable(target_name src/main.c src/*.cc)

第一引数は、実行バイナリの名前を指定します。 第二引数以降に、ソースコードを指定します。ワイルドカード (*) も利用可能です。 なお、ソースコードのパスはCMakeLists.txtファイルが置いてあるパスからの相対パスとなります。


インクルードファイル

target_include_directoriesコマンドを利用します。 コンパイラに指定する-Iに繋がるコマンドです。

第一引数は、実行バイナリの名前を指定します。 第二引数は、PRIVATE/PUBLIC/INTERFACEのいずれかを指定します。 第三引数は、対象のインクルードファイルのパスを指定します。

target_include_directories(target_name PRIVATE ${EGL_INCLUDE_DIRS})

ところで、第二引数に指定しているPRIVATE, PUBLIC, INTERFACEは何でしょうか? 非常に分かり辛いですが、以下の様な感じで基本的に多いのはPRIVATEだと思います。


PRIVATE

ターゲットのみが必要とする場合に指定

PUBLIC

ターゲットとターゲットが依存するライブラリが必要とする場合に指定

INTERFACE

ターゲットが依存するライブラリのみ必要とする場合に指定


ライブラリ

target_link_librariesコマンドを利用します。 コンパイラに指定する-lに繋がるコマンドです。

target_link_libraries(target_name PRIVATE ${EGL_LIBRARIES})

5. ビルドオプションの指定


コンパイラに渡すオプションをtarget_compile_optionsを利用して指定する事が出来ます。

target_compile_options(target_name PUBLIC ${EGL_CFLAGS} "-Wall")

6. リンク


CMake