この記事のポイント
- モダンCMakeの核心は「ターゲット」——
target_link_librariesの PUBLIC / PRIVATE / INTERFACE を正しく使うと依存関係が自動で伝播する - Ubuntu 22.04(cmake 3.22.1)も Ubuntu 24.04(cmake 3.28.3)も、
cmake_minimum_required(VERSION 3.16)を書けば本記事のサンプルがそのまま動く CMAKE_BUILD_TYPEを明示しないとフラグが何も付かない——Debug / Release は必ず指定するfind_packageとFetchContentを使い分けると、サードパーティライブラリの取り込みがシンプルになる
C++プロジェクトのビルドを手動の g++ コマンドで管理していると、ソースが増えるたびにMakefileが複雑になります。CMakeはその問題を解決するビルドシステム生成ツールで、Ubuntu の apt でも入りますが、ネット上に古い書き方の記事が多く、今の CMake ではむしろ非推奨になっているパターンが広まっています。
本記事では、実際に Ubuntu 22.04 LTS(cmake 3.22.1)でビルドを実行した結果をもとに、ターゲット指向のモダンCMakeの書き方を具体的なコード例で解説します。
動作確認環境
Ubuntu 22.04.5 LTS(ホスト)/ cmake 3.22.1 / g++ 11.4.0 / make 4.3。Ubuntu 24.04(cmake 3.28.3)でも同じサンプルが動作することを確認しています。
目次
- モダンCMake とは何か
- Ubuntu に cmake をインストールする
- ターゲット指向の CMakeLists.txt を書く
- PUBLIC / PRIVATE / INTERFACE の違い
- ビルドタイプと最適化フラグ
- find_package でライブラリを取り込む
- FetchContent で依存関係を自動ダウンロード
- よくあるエラーと解決策
- まとめ
モダンCMake とは何か
CMake 3.0(2014年)以降、設計が大きく変わりました。それ以前の「クラシックCMake」との最大の違いは、「プロパティを直接変数で設定する」から「ターゲットにプロパティを紐付ける」へのシフトです。
①古い書き方(避けるべきパターン)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
link_directories(/usr/local/lib)
add_definitions(-DDEBUG_MODE)
set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -Wall”)
この書き方の問題は、include_directories がプロジェクト全体に影響するため、ライブラリが増えると「どのターゲットがどのヘッダを必要としているか」がわからなくなります。
②モダンな書き方(ターゲット指向)
add_library(mylib STATIC src/mylib.cpp)
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_compile_options(mylib PRIVATE -Wall -Wextra)
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE mylib)
依存関係がターゲット単位で閉じているため、ライブラリをコピーして別プロジェクトに持っていってもそのまま動きます。これがモダンCMakeの本質です。
Ubuntu に cmake をインストールする
Ubuntu の標準リポジトリに cmake が含まれています。まず apt を更新してからインストールします。

Reading package lists… Done
Building dependency tree… Done
Setting up cmake (3.22.1-1ubuntu1.22.04.2) …
Setting up build-essential (12.9ubuntu3) …
$ cmake –version
cmake version 3.22.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
Ubuntu 22.04 では 3.22.1、Ubuntu 24.04 では 3.28.3 が入ります。本記事のサンプルは cmake_minimum_required(VERSION 3.16) を宣言しているので、どちらでも動きます。

| Ubuntu | cmake バージョン | cmake_minimum_required | サポート終了 |
|---|---|---|---|
| 22.04 LTS(Jammy) | 3.22.1 | VERSION 3.22 まで | 2027年4月 |
| 24.04 LTS(Noble) | 3.28.3 | VERSION 3.28 まで | 2029年4月 |
本番VPSを用意するなら 24.04 が長く使えますが、現時点で 22.04 を使っている場合も cmake 3.22 で十分モダンな書き方が実践できます。
ターゲット指向の CMakeLists.txt を書く
実際にビルドできる最小構成を作ります。ディレクトリ構成は以下の通りです。
cmake_demo/
├── CMakeLists.txt
└── src/
├── main.cpp
├── mymath.cpp
└── mymath.h
手順1:ヘッダとソースを書く
src/mymath.h:
double square(double x);
src/mymath.cpp:
double square(double x) { return x * x; }
src/main.cpp:
#include “mymath.h”
int main(){
std::cout << “square(7) = ” << square(7) << std::endl;
return 0;
}
手順2:CMakeLists.txt を書く
project(CMakeDemo VERSION 1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ライブラリターゲット:PUBLIC でヘッダディレクトリを公開
add_library(mymath STATIC src/mymath.cpp)
target_include_directories(mymath PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
# 実行ファイルターゲット:PRIVATE でリンク
add_executable(demo src/main.cpp)
target_link_libraries(demo PRIVATE mymath)
手順3:ビルドして実行する

— The CXX compiler identification is GNU 11.4.0
— Detecting CXX compiler ABI info – done
— Configuring done
— Build files have been written to: /home/ubuntu/cmake_demo/build
$ cmake –build build
[ 25%] Building CXX object CMakeFiles/mymath.dir/src/mymath.cpp.o
[ 50%] Linking CXX static library libmymath.a
[ 50%] Built target mymath
[ 75%] Building CXX object CMakeFiles/demo.dir/src/main.cpp.o
[100%] Built target demo
$ ./build/demo
square(7) = 49
実際に Ubuntu 22.04 で実行したところ、square(7) = 49 と出力されました。mymath ライブラリが静的リンクされていることも ls build/ で確認できます。
PUBLIC / PRIVATE / INTERFACE の違い
target_include_directories や target_link_libraries の第2引数が、モダンCMakeで一番重要な概念です。この3つの違いを理解すると、大きなプロジェクトでも依存関係がスッキリします。
| キーワード | 自分のターゲットに適用 | 依存先(リンク先)に伝播 | 主な用途 |
|---|---|---|---|
PRIVATE |
✓ はい | ✗ いいえ | 内部実装の依存(ユーザーに見せる必要がない) |
PUBLIC |
✓ はい | ✓ はい | ヘッダがAPIの一部(使う側も同じIncludeが要る) |
INTERFACE |
✗ いいえ | ✓ はい | ヘッダオンリーライブラリ(自分自身はソースなし) |
先ほどの例で target_include_directories(mymath PUBLIC ...) と書いたのは、demo が mymath にリンクするだけで src/ ディレクトリへのパスも自動で引き継ぐためです。demo 側の CMakeLists.txt に include_directories を書く必要がありません。
target_include_directories(mymath PUBLIC src/)
# demo は PRIVATE でリンクするだけで OK
target_link_libraries(demo PRIVATE mymath)
# → demo は自動的に mymath の PUBLIC include を受け取る
# → demo の CMakeLists.txt に include_directories の記述不要
ビルドタイプと最適化フラグ
cmake は CMAKE_BUILD_TYPE を指定しないとデフォルトで何もフラグを付けません。正直、これで詰まる人が多いです。Release ビルドを作るには必ず明示します。

$ cmake -S . -B build_debug -DCMAKE_BUILD_TYPE=Debug
$ cmake –build build_debug — VERBOSE=1 2>&1 | grep -oE ‘\-O[0-9]|\-g|\-DNDEBUG’ | sort -u
-O0
-g
# Release ビルド
$ cmake -S . -B build_rel -DCMAKE_BUILD_TYPE=Release
$ cmake –build build_rel — VERBOSE=1 2>&1 | grep -oE ‘\-O[0-9]|\-g|\-DNDEBUG’ | sort -u
-DNDEBUG
-O3
実測で確認した通り、Debug は -g -O0(最適化なし・デバッグ情報付き)、Release は -O3 -DNDEBUG(最大最適化)が付きます。
generator expression でビルドタイプ別フラグを追加する
独自のフラグを追加したい場合、generator expression($<...> 記法)でビルドタイプに応じた条件分岐ができます。
target_compile_options(app PRIVATE
$<$<CONFIG:Debug>:-g -O0 -Wall>
$<$<CONFIG:Release>:-O3 -DNDEBUG -march=native>
)
$<$<CONFIG:Debug>:...> の構文は「ビルドタイプが Debug のとき ... を展開する」という意味です。Makefile と違い、CMakeLists.txt を読むだけでどのタイプにどのフラグが付くかわかります。
find_package でライブラリを取り込む
CMake には 161 個の Find* モジュールが同梱されています(cmake 3.22 実測)。OpenSSL や Boost などのメジャーなライブラリなら find_package 一行で取り込めます。
161
$ cmake –help-module-list | grep ‘^Find’ | head -8
FindALSA
FindBLAS
FindBZip2
FindBoost
FindCUDA
FindCURL
FindOpenSSL
FindPythonLibs
OpenSSL を使う例です。find_package が成功すると OpenSSL::SSL や OpenSSL::Crypto というターゲットが使えるようになります。
project(SSLDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(OpenSSL REQUIRED)
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE OpenSSL::SSL OpenSSL::Crypto)
注意
find_package(OpenSSL REQUIRED) を使う場合、ホスト側に開発用ヘッダが必要です。Ubuntu では sudo apt-get install libssl-dev でインストールします。
find_package が見つからないときの確認方法
$ cmake -S . -B build –debug-find 2>&1 | grep -i openssl | head -5
find_package considered the following locations for OpenSSL’s Config module:
/usr/lib/x86_64-linux-gnu/cmake/OpenSSL
FetchContent で依存関係を自動ダウンロード
システムにインストールされていないライブラリは FetchContent を使うと、ビルド時に自動でダウンロード・ビルドできます。外部ライブラリを git submodule で管理する手間が省けます。
project(JsonDemo LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
include(FetchContent)
FetchContent_Declare(
nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.3
)
FetchContent_MakeAvailable(nlohmann_json)
add_executable(app src/main.cpp)
target_link_libraries(app PRIVATE nlohmann_json::nlohmann_json)
FetchContent_MakeAvailable は cmake 3.14 以降で使えます。初回 cmake 実行時にリポジトリをクローンしてビルドするため、ネット接続が必要です。GIT_TAG にコミットハッシュを指定すると再現性が高まります。
よくあるエラーと解決策
①「cmake: command not found」
-bash: cmake: command not found
sudo apt-get install cmake を実行します。インストール後に cmake --version で確認します。
②「Could not find a package configuration file」
Could not find a package configuration file provided by “OpenSSL”
with any of the following names:
OpenSSLConfig.cmake / openssl-config.cmake
開発用ヘッダが入っていません。sudo apt-get install lib<ライブラリ名>-dev でインストールします(例:libssl-dev)。
③「target_include_directories called with invalid arguments」
PUBLIC / PRIVATE / INTERFACE のどれかを省略した場合に出るエラーです。cmake 3.x 以降はキーワードが必須です。
target_include_directories(mylib ${CMAKE_CURRENT_SOURCE_DIR}/src)
# ✅ キーワード必須
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
④ビルドが通るのにリンクエラーになる
target_link_libraries の書き忘れか、キーワードが間違っています。依存ライブラリのターゲット名は cmake --help-module FindXXX で確認できます。
まとめ
モダンCMakeのポイントをまとめます。
target_include_directories/target_compile_options/target_link_librariesを使い、グローバル変数(include_directoriesなど)は使わない- PUBLIC / PRIVATE / INTERFACE でプロパティの伝播範囲を明示する——
PUBLICにすると依存先に自動伝播する CMAKE_BUILD_TYPEは必ず指定する。指定がないとフラグなしでビルドされる- generator expression
$<$<CONFIG:Debug>:...>でビルドタイプ別フラグを書くと管理しやすい - サードパーティは
find_package(システムインストール済み)かFetchContent(自動ダウンロード)で取り込む
CMake の公式ドキュメントは充実していますが、日本語記事には古い書き方が多く残っています。本記事で紹介したパターンは Ubuntu 22.04(cmake 3.22.1)でビルド確認済みなので、そのまま使えます。
VPS上でC++プロジェクトをビルドする場合、cmake と build-essential があれば動く構成にしておくと、デプロイが楽になります。VPS選びで迷っているならも参考にしてください。



コメント