finm137.wiki
CMakeLists.txt
最終更新:
kemonowikii
-
view
概要
CMakeとは、C++などのプロジェクトをビルドするための設定を管理するツールである。
CMake自体がコンパイラではなく、
- どのソースコードを使うか
- どのライブラリをリンクするか
- どのincludeフォルダを見るか
- C++17 / C++20など何の規格を使うか
- Windows / Linux / Raspberry Pi Picoなど、どの環境向けにビルドするか
などを指定し、Visual StudioやNinja、Makeなどのビルドシステム用ファイルを生成する。
C++である程度大きなソフトを作る場合、
ソースファイルを1個ずつ手動でコンパイルするより、
CMakeを使用してプロジェクト全体を管理した方が楽になる。
ソースファイルを1個ずつ手動でコンパイルするより、
CMakeを使用してプロジェクト全体を管理した方が楽になる。
主に使用するファイルは以下。
- CMakeLists.txt
- C++ソースコード
- C++ヘッダ
- 外部ライブラリ
基本的にはプロジェクト最上位に
「CMakeLists.txt」
を置く。
「CMakeLists.txt」
を置く。
例:
RABBE_AI_BEAST_Studio/ ├─ CMakeLists.txt ├─ src/ │ ├─ main.cpp │ ├─ app/ │ │ ├─ Application.cpp │ │ └─ Application.h │ └─ render/ │ ├─ Renderer.cpp │ └─ Renderer.h └─ third_party/
最初に覚えること
CMakeは大雑把に言うと、
「何を作るか」
「どのファイルを使うか」
「何を接続するか」
「どのファイルを使うか」
「何を接続するか」
を書く。
最初は以下だけ覚えればよい。
- cmake_minimum_required()
- project()
- set()
- add_executable()
- target_include_directories()
- target_link_libraries()
- add_subdirectory()
- find_package()
- option()
- if()
最小構成
まずはmain.cppだけをexeにする最小構成。
CMakeLists.txt
cmake_minimum_required(VERSION 3.20)
project(MyApp)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(MyApp
src/main.cpp
)
これだけでもCMakeプロジェクトとして成立する。
各項目の意味は以下。
cmake_minimum_required
使用するCMakeの最低バージョンを指定する。
cmake_minimum_required(VERSION 3.20)
意味:
「CMake 3.20以上を使用してください」
CMake公式でもトップレベルのCMakeLists.txt冒頭で指定することが推奨されている。
基本的にproject()より前に記述する。
project
プロジェクト名を指定する。
project(RABBE_AI_BEAST_Studio)
少し詳しく書く場合:
project(RABBE_AI_BEAST_Studio
VERSION 0.1.0
LANGUAGES CXX
)
VERSION
- ソフトのバージョン
LANGUAGES CXX
- C++を使うという意味
set
変数へ値を入れる。
C++でいう変数代入に近い。
例:
set(CMAKE_CXX_STANDARD 20)
これは
CMAKE_CXX_STANDARD = 20
と考えると分かりやすい。
独自変数も作れる。
set(APP_NAME RABBE_AI_BEAST_Studio)
使用時:
add_executable(${APP_NAME}
src/main.cpp
)
複数ファイルをまとめることも可能。
set(SOURCES
src/main.cpp
src/app/Application.cpp
src/render/Renderer.cpp
)
add_executable(RABBE_AI_BEAST_Studio
${SOURCES}
)
「set = ファイルを追加する命令」ではなく、
「名前付きの値やリストを保存する命令」
と覚える。
「名前付きの値やリストを保存する命令」
と覚える。
C++バージョン指定
C++20を使用する場合。
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF)
CMAKE_CXX_STANDARD
- C++規格
CMAKE_CXX_STANDARD_REQUIRED
- 指定した規格を必須にする
CMAKE_CXX_EXTENSIONS
- コンパイラ独自拡張を使うか
C++17なら
set(CMAKE_CXX_STANDARD 17)
でよい。
exeを作成する
add_executable
実行ファイルを作る。
add_executable(MyApp
src/main.cpp
)
複数ファイルも追加可能。
add_executable(MyApp
src/main.cpp
src/Application.cpp
src/Renderer.cpp
)
CMake公式では、add_executable()で指定した名前がビルド対象のターゲット名になる。
ヘッダーファイルを読ませる
target_include_directories
include検索パスを追加する。
target_include_directories(MyApp PRIVATE
src
)
これにより、
#include "app/Application.h"
のようなincludeが使いやすくなる。
新規開発では古い
include_directories()
より、
target_include_directories()
の使用が推奨されている。
PRIVATE
- このターゲット自身だけで使う
PUBLIC
- このターゲットと、それを利用する側も使う
INTERFACE
- 利用する側だけ使う
初心者はまずPRIVATE中心でよい。
ライブラリを接続する
target_link_libraries
外部ライブラリをリンクする。
例:
target_link_libraries(MyApp PRIVATE
glfw
)
複数指定可能。
target_link_libraries(MyApp PRIVATE
glfw
assimp
OpenGL::GL
)
CMake公式では、
target_link_libraries()でadd_executable()やadd_library()で作成済みのターゲットにライブラリを接続する。
target_link_libraries()でadd_executable()やadd_library()で作成済みのターゲットにライブラリを接続する。
古い
link_libraries()
より、
target_link_libraries()
を使用した方がよい。
サブフォルダを追加する
add_subdirectory
別フォルダにあるCMakeプロジェクトを追加する。
例:
add_subdirectory(third_party/glfw)
add_subdirectory(third_party/assimp)
glfwフォルダやassimpフォルダ内にも
CMakeLists.txtが存在する場合に使える。
CMakeLists.txtが存在する場合に使える。
その後、
target_link_libraries(MyApp PRIVATE
glfw
assimp
)
のように接続する。
インストール済みライブラリを探す
find_package
PCにインストール済みのパッケージを探す。
OpenGLの場合。
find_package(OpenGL REQUIRED)
target_link_libraries(MyApp PRIVATE
OpenGL::GL
)
REQUIREDを指定すると、
見つからなかった場合にCMake設定を失敗させる。
見つからなかった場合にCMake設定を失敗させる。
ON / OFF設定を作る
option
機能をON/OFFできる設定を作れる。
例:
option(RABBE_ENABLE_VRM
"Enable VRM support"
ON
)
option(RABBE_ENABLE_FBX
"Enable FBX support"
ON
)
option(RABBE_ENABLE_PYTHON
"Enable Python runtime"
ON
)
使用例:
if(RABBE_ENABLE_VRM)
add_subdirectory(src/vrm)
endif()
これにより、
「VRMあり版」
「VRMなし軽量版」
「VRMなし軽量版」
などを同じコードから作成可能。
if文
CMakeにも条件分岐がある。
if(RABBE_ENABLE_VRM)
message(STATUS "VRM enabled")
endif()
OFFの場合:
if(NOT RABBE_ENABLE_VRM)
message(STATUS "VRM disabled")
endif()
コマンドラインから設定を渡す
CMakeでは-Dを使って変数を外部から指定できる。
例:
cmake -S . -B build -DRABBE_ENABLE_VRM=ON
これは
RABBE_ENABLE_VRM = ON
をCMakeへ渡している。
公式ドキュメントでは
- D<変数>=<値>
でCMake Cacheへ値を作成・更新できる。
例:
cmake -S . -B build -DRABBE_ENABLE_CUDA=ON
cmake -S . -B build -DRABBE_ENABLE_CUDA=OFF
Raspberry Pi Picoの例
例えば同じC++コードをPicoとPico 2で使いたい場合。
Pico:
cmake -S . -B build -DPICO_BOARD=pico
Pico 2:
cmake -S . -B build -DPICO_BOARD=pico2
ソース本体を書き直さなくても、
CMake変数だけで対象ハードを切り替えられる場合がある。
CMake変数だけで対象ハードを切り替えられる場合がある。
CMakeの強みが分かりやすい例。
ソースフォルダとビルドフォルダ
CMakeではソースコードと生成ファイルを分けるのが基本。
例:
MyApp/ ├─ CMakeLists.txt ├─ src/ └─ build/
設定:
cmake -S . -B build
- S
- ソースフォルダ
- B
- ビルドフォルダ
この場合
- S .
= 現在のフォルダ
- B build
= buildフォルダへ生成
buildフォルダが存在しなければ、CMakeが作成できる。
ビルドする
設定完了後。
cmake --build build
これでコンパイルする。
基本手順:
cmake -S . -B build
cmake --build build
Releaseビルド
Visual Studio系などでは、
cmake --build build --config Release
Debugの場合:
cmake --build build --config Debug
CMake Cache
CMakeは設定を
build/CMakeCache.txt
へ保存する。
例えば
RABBE_ENABLE_VRM:BOOL=ON
などが記録される。
一度指定したoptionはCacheに残るため、
CMakeLists.txt側の初期値を変更しても、
以前のbuildフォルダでは値が残る場合がある。
CMakeLists.txt側の初期値を変更しても、
以前のbuildフォルダでは値が残る場合がある。
変更する場合:
cmake -S . -B build -DRABBE_ENABLE_VRM=OFF
または必要に応じてbuildフォルダを作り直す。
実践:RABBE AI BEAST Studio
例えば初期版。
cmake_minimum_required(VERSION 3.20)
project(RABBE_AI_BEAST_Studio
VERSION 0.1.0
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF)
option(RABBE_ENABLE_VRM
"Enable VRM support"
ON
)
option(RABBE_ENABLE_FBX
"Enable FBX support"
ON
)
option(RABBE_ENABLE_PYTHON
"Enable Python runtime"
ON
)
find_package(OpenGL REQUIRED)
add_subdirectory(third_party/glfw)
add_executable(RABBE_AI_BEAST_Studio
src/main.cpp
src/app/Application.cpp
src/render/Renderer.cpp
)
target_include_directories(RABBE_AI_BEAST_Studio PRIVATE
src
)
target_link_libraries(RABBE_AI_BEAST_Studio PRIVATE
glfw
OpenGL::GL
)
if(RABBE_ENABLE_FBX)
add_subdirectory(third_party/assimp)
target_link_libraries(RABBE_AI_BEAST_Studio PRIVATE
assimp
)
target_sources(RABBE_AI_BEAST_Studio PRIVATE
src/import/FBXImporter.cpp
)
endif()
if(RABBE_ENABLE_VRM)
target_sources(RABBE_AI_BEAST_Studio PRIVATE
src/import/VRMImporter.cpp
)
endif()
おすすめファイル構造
RABBE_AI_BEAST_Studio/ │ ├─ CMakeLists.txt │ ├─ src/ │ ├─ main.cpp │ │ │ ├─ app/ │ │ ├─ Application.cpp │ │ └─ Application.h │ │ │ ├─ render/ │ │ ├─ Renderer.cpp │ │ └─ Renderer.h │ │ │ └─ import/ │ ├─ VRMImporter.cpp │ ├─ VRMImporter.h │ ├─ FBXImporter.cpp │ └─ FBXImporter.h │ ├─ third_party/ │ ├─ glfw/ │ ├─ assimp/ │ └─ pybind11/ │ └─ build/
よく使う構文一覧
| 構文 | 役割 |
| cmake_minimum_required() | CMake最低バージョン |
| project() | プロジェクト作成 |
| set() | 変数や一覧を保存 |
| option() | ON/OFF設定作成 |
| add_executable() | exe作成 |
| add_library() | ライブラリ作成 |
| target_sources() | ソース追加 |
| target_include_directories() | includeパス追加 |
| target_link_libraries() | ライブラリ接続 |
| add_subdirectory() | 別CMakeプロジェクト追加 |
| find_package() | パッケージ探索 |
| if() | 条件分岐 |
| message() | ログ表示 |
messageでデバッグ
CMake実行中にメッセージを表示できる。
message(STATUS "VRM enabled")
変数確認:
message(STATUS "C++ standard = ${CMAKE_CXX_STANDARD}")
例えば、
if(RABBE_ENABLE_VRM)
message(STATUS "VRM support: ON")
else()
message(STATUS "VRM support: OFF")
endif()
CMake設定トラブル時に便利。
依存関係の管理
C++ではコードが正常でも、
外部ライブラリのバージョン不一致でエラーになることがある。
外部ライブラリのバージョン不一致でエラーになることがある。
例:
- GLFWバージョン違い
- Assimp DLL違い
- Pythonバージョン違い
- pybind11とPythonの組み合わせ違い
- llama.cpp API変更
- CUDAバージョン違い
- x86とx64の混在
- Debug DLLとRelease DLLの混在
そのため、
動作確認済みバージョンを固定するのが安全。
動作確認済みバージョンを固定するのが安全。
例:
third_party/ ├─ glfw/ ├─ assimp/ ├─ pybind11/ └─ llama.cpp/
毎回最新バージョンへ更新するより、
動作した構成を保存しておく方が安定する。
動作した構成を保存しておく方が安定する。
おすすめ攻略手順
CMake初心者は、
最初から大量のライブラリを追加しない方がよい。
最初から大量のライブラリを追加しない方がよい。
攻略順:
- STEP1
main.cppだけでビルド
- STEP2
GLFW追加
- STEP3
OpenGL追加
- STEP4
Renderer追加
- STEP5
Assimp追加
- STEP6
VRM / glTF追加
- STEP7
pybind11 / Python追加
- STEP8
llama.cpp追加
- STEP9
CUDA追加
1個追加するたびにビルド確認する。
エラーが出た場合、
「直前に追加した依存関係」
を疑いやすくなる。
「直前に追加した依存関係」
を疑いやすくなる。
ありがちな失敗
CMakeLists.txtが見つからない
- Sで指定したフォルダに
CMakeLists.txtが存在するか確認する。
ライブラリが見つからない
add_subdirectory()のパス、
find_package()、
ライブラリのインストール状況を確認。
find_package()、
ライブラリのインストール状況を確認。
ヘッダーが見つからない
target_include_directories()を確認。
リンクエラー
target_link_libraries()を確認。
ヘッダーは読めているのに
unresolved external symbol
などが出る場合、
ライブラリのリンク不足が候補。
ライブラリのリンク不足が候補。
設定変更したのに反映されない
CMakeCache.txtに以前の設定が残っている可能性あり。
- Dで明示的に指定するか、
buildフォルダを作り直して確認。
Debugでは動くがReleaseで動かない
Debug / Releaseで異なるDLLやライブラリを使っていないか確認。
Windowsでは特に注意。
x64とx86
64bitアプリに32bitライブラリを混ぜると正常にリンクできない。
基本的にRABBE AI BEAST Studioなら
x64へ統一するのが分かりやすい。
x64へ統一するのが分かりやすい。
初心者向け覚え方
CMakeは、
set() =値を覚えさせる
add_executable() =exeを作る
target_include_directories() =ヘッダーを探す場所
target_link_libraries() =ライブラリを接続
add_subdirectory() =別フォルダのCMakeも使う
option() =機能ON/OFF
-D =外から設定を渡す
と覚えるとよい。
まとめ
CMakeはC++そのものを書くツールではなく、
C++プロジェクト全体のビルド方法を管理するためのツール。
C++プロジェクト全体のビルド方法を管理するためのツール。
小規模では
main.cpp CMakeLists.txt
だけでも使用可能。
大規模になると、
- C++
- OpenGL
- GLFW
- Assimp
- Python
- llama.cpp
- CUDA
- VRM
- FBX
など多数の依存関係をまとめる役割を持つ。
特に重要なのは、
「ソースコード本体をできるだけ変更せず、
CMake設定でビルド対象や機能を切り替えられる」
CMake設定でビルド対象や機能を切り替えられる」
という点。
同一ソースから
- 軽量版
- CUDA版
- VRM版
- FBX版
- Python Agent版
- フル版
などを作れるように設計すると、
大型C++プロジェクトでも管理しやすくなる。
大型C++プロジェクトでも管理しやすくなる。









