CMakeを使ってビルドする(3)
前々回の記事(CMakeを使ってビルドする(1))では、プロジェクト直下にのみソースファイルが存在するケースを用いて、基本的なCMakeLists.txt
の書き方をまとめました。
プロジェクトが大きくなると多数のサブディレクトリが作られ、その中にソースファイルが配置されることも多くなってきます。今回は、そのようなサブディレクトリが存在するケースについて、CMakeLists.txt
の書き方をまとめてみました。
単純なケースでのCMakeLists.txt
の書き方はこちら。
Generator-Expressionsについてはこちら。
サブディレクトリを含むときのCMakeLists.txtの書き方
想定しているディレクトリ構成
今回は以下のようなプロジェクトのディレクトリ直下にソースファイルとサブディレクトリfunc1
が置かれているケースを考え、main.cpp
とfunc1/func1.cpp
からtest1
をビルドするとします。
project1/
|- main.h
|- main.cpp
|- CMakeLists.txt
|- func1/
|- func1.h
|- func1.cpp
|- CMakeLists.txt
|- build/ (ビルド用のディレクトリ)
CMakeLists.txt
はディレクトリに1つ必要なので、ルートディレクトリの他にfunc1
の中にも作成しておきます。
サブディレクトリのファイルからライブラリを作成する場合
CMakeLists.txt
cmake_minimum_required(VERSION 3.8) project(test1 CXX) add_subdirectory(func1) add_executable(test1 main.cpp) target_link_libraries(test1 PRIVATE func1)
func1/CMakeLists.txt
cmake_minimum_required(VERSION 3.8) add_library(func1 STATIC func1.cpp)
CMakeLists.txt
3行目のadd_subdirectory()
ここでfunc1
以下をビルドの対象に加えます。次のような書式で記述します。対象に加えたディレクトリにもCMakeLists.txt
が必要です。
add_subdirectory(ディレクトリ [EXCLUDE_FROM_ALL])
EXCLUDE_FROM_ALL
はデフォルトターゲット(all
)から除外するときに指定します。
CMakeLists.txt
5行目のtarget_link_libraries()
add_executable()
で作成した実行ファイルにライブラリをリンクします。次のような書式で記述します。
target_link_libraries(ターゲット名 [PRIVATE|PUBLIC|INTERFACE] ライブラリ ...)
PRIVATE
, PUBLIC
, INTERFACE
のキーワードはオプションの有効な範囲を示すために使われます。ターゲット自身に有効な設定の場合にはPRIVATE
かPUBLIC
を、ターゲットに依存する他のターゲットに有効なものはINTERFACE
かPUBLIC
を指定します。
キーワード | ターゲット自身のビルドに必要 | ターゲットに依存するターゲットのビルドに必要 |
---|---|---|
PRIVATE | 〇 | × |
PUBLIC | 〇 | 〇 |
INTERFACE | × | 〇 |
詳細は公式ドキュメントを参照してください。
func1/CMakeLists.txt
2行目のadd_library()
ライブラリファイルを作成します。次のような書式で記述します。
add_library(ライブラリ名 [STATIC|SHARED|MODULE] 依存ファイル ...)
作成するライブラリの種類によってSTATIC
,SHARED
,MODULE
のキーワードを切り替えます。このコマンドの便利な点は静的ライブラリ(*.a
, *.lib
など)と動的ライブラリ(*.so
, *.dll
など)を簡単に切り替えられる点です。各キーワードの違いについて以下にまとめました。
キーワード | 生成されるライブラリの種類 |
---|---|
STATIC | 静的ライブラリ |
SHARED | プログラム実行時にロードされる動的ライブラリ |
MODULE | 必要な時にロードする動的ライブラリ |
詳細は公式ドキュメントを参照してください。
実際のビルド例(Windows + GCC + Make)
>cd build
>cmake -G "MinGW Makefiles" ..
(略)
>make all
[ 25%] Building CXX object func1/CMakeFiles/func1.dir/func1.cpp.obj
[ 50%] Linking CXX static library libfunc1.a
[ 50%] Built target func1
[ 75%] Building CXX object CMakeFiles/test1.dir/main.cpp.obj
[100%] Linking CXX executable test1.exe
[100%] Built target test1
このようにライブラリ(libfunc1.a
)が生成された上で、test1.exe
がビルドされています。
サブディレクトリのファイルからライブラリを作成しない場合
上記の方法で困ることは少ないと思いますが、ライブラリが必要ないのにもかかわらず、いちいちライブラリを作成するのがムダと思うこともあります。通常このような場合は、オブジェクトファイルを直接リンクするはずです。では、CMakeでこれを実現するにはどうすればよいのでしょうか。
オブジェクトライブラリ
CMakeには「オブジェクトライブラリ」というものがあり、オブジェクトファイルを直接リンクする場合には、これを使用します。ライブラリと名前がついていますが、ライブラリファイルは生成せず、CMake上でオブジェクトファイルのリストをライブラリのように扱えるようにする機能です。
実際に作成したCMakeLists.txt
とfunc1/CMakeLists.txt
を見てみます。
CMakeLists.txt
cmake_minimum_required(VERSION 3.8) project(test1 CXX) add_subdirectory(func1) add_executable(test1 main.cpp $<TARGET_OBJECTS:func1>)
func1/CMakeLists.txt
cmake_minimum_required(VERSION 3.8) add_library(func1 OBJECT func1.cpp)
CMakeLists.txt
4行目のadd_executable()
ここでGenerator-Expressionsがでてきました。$<TARGET_OBJECTS:オブジェクトライブラリ名>
とすることで、オブジェクトライブラリに設定されたオブジェクトファイルのリストを得ることができます。
func1/CMakeLists.txt
2行目のadd_library()
add_library()
にOBJECT
をつけることで、指定されたソースから生成されるオブジェクトファイルのリストをオブジェクトライブラリとして扱えるようになります。詳細は公式ドキュメントを参照してください。
実際のビルド例(Windows + GCC + Make)
>cd build
>cmake -G "MinGW Makefiles" ..
(略)
>make all
[ 33%] Built target func1
Scanning dependencies of target test1
[100%] Built target test1
確かにライブラリが作成されていません。出力もスッキリしています。
まとめ
今回は、プロジェクトのディレクトリ内にさらにサブディレクトリが存在するケースに対応するCMakeLists.txt
の書き方についてまとめると以下のようになります。
- 各ディレクトリに
CMakeLists.txt
を作成する - サブディレクトリの
CMakeLists.txt
ではadd_library()
を記述する - プロジェクト直下の
CMakeLists.txt
では- サブディレクトリを追加するために
add_subdirectory()
を記述する - ライブラリをリンクする場合は
target_link_libraries()
を記述する - オブジェクトファイルをリンクする場合は、
add_executable()
に$<TARGET_OBJECTS:...>
を追加する
- サブディレクトリを追加するために
ディスカッション
コメント一覧
まだ、コメントがありません