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.txt3行目のadd_subdirectory()
ここでfunc1以下をビルドの対象に加えます。次のような書式で記述します。対象に加えたディレクトリにもCMakeLists.txtが必要です。
add_subdirectory(ディレクトリ [EXCLUDE_FROM_ALL])EXCLUDE_FROM_ALLはデフォルトターゲット(all)から除外するときに指定します。
CMakeLists.txt5行目のtarget_link_libraries()
add_executable()で作成した実行ファイルにライブラリをリンクします。次のような書式で記述します。
target_link_libraries(ターゲット名 [PRIVATE|PUBLIC|INTERFACE] ライブラリ ...)PRIVATE, PUBLIC, INTERFACEのキーワードはオプションの有効な範囲を示すために使われます。ターゲット自身に有効な設定の場合にはPRIVATEかPUBLICを、ターゲットに依存する他のターゲットに有効なものはINTERFACEかPUBLICを指定します。
| キーワード | ターゲット自身のビルドに必要 | ターゲットに依存するターゲットのビルドに必要 |
|---|---|---|
| PRIVATE | 〇 | × |
| PUBLIC | 〇 | 〇 |
| INTERFACE | × | 〇 |
詳細は公式ドキュメントを参照してください。
func1/CMakeLists.txt2行目の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.txt4行目のadd_executable()
ここでGenerator-Expressionsがでてきました。$<TARGET_OBJECTS:オブジェクトライブラリ名>とすることで、オブジェクトライブラリに設定されたオブジェクトファイルのリストを得ることができます。
func1/CMakeLists.txt2行目の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:...>を追加する
- サブディレクトリを追加するために




ディスカッション
コメント一覧
まだ、コメントがありません