閉じる

2026年基準 C++ CMakeの使い方:ターゲットベースのビルド設定とパッケージ管理の要点

C++を用いたシステム開発において、ビルドシステムの選定はプロジェクトの成否を分ける極めて重要な要素です。

2026年現在、CMakeは単なるビルドツールを超え、依存関係の管理やテスト、パッケージ化までを統合する強力なエコシステムへと進化を遂げました。

本記事では、現代のC++開発で必須となる「ターゲットベース」の設計思想を中心に、最新のベストプラクティスを解説します。

特にパッケージ管理やC++20/23/26の標準化に伴うモジュール対応など、現場で即座に役立つテクニックを詳しく見ていきましょう。

モダンCMakeの根幹:ターゲットベースの設計思想

以前のCMakeでは、include_directoriesやadd_definitionsといったグローバルな命令を多用する手法が一般的でした。

しかし、現代的な「モダンCMake」においては、すべての設定を「ターゲット(Target)」という単位に紐付けることが推奨されています。

ターゲットベースの設計とは、実行ファイルやライブラリを一つのオブジェクトとして扱い、そのオブジェクトが必要とする情報を個別に定義する手法です。

このアプローチを採用することで、複雑な依存関係を持つ大規模プロジェクトでも、設定の衝突を避けつつ見通しの良いビルド構成を維持できます。

ターゲットには、コンパイルオプション、マクロ定義、インクルードパス、リンクすべきライブラリなどがカプセル化されます。

これにより、あるライブラリをリンクするだけで、そのライブラリが必要とするすべての設定が自動的に伝播する仕組みを構築可能です。

「グローバル変数を使わず、オブジェクト指向のようにビルドを記述する」という意識が、2026年のCMake使いには求められています。

可視性の制御:PUBLIC、PRIVATE、INTERFACE

ターゲットに対してプロパティを設定する際、最も重要なキーワードがPUBLIC、PRIVATE、INTERFACEの3つです。

これらを適切に使い分けることで、依存関係の影響範囲を厳密にコントロールできます。

PRIVATEは、そのターゲット自体のビルドには必要ですが、そのターゲットを利用する側には伝える必要がない設定に使用します。

INTERFACEは、ターゲット自体のビルドには不要ですが、そのターゲットをリンクする他のターゲットには必要な設定を定義します。

PUBLICは、自分自身と利用者の両方に必要な設定であり、最も頻繁に使用される設定です。

以下の表は、それぞれのキーワードによる伝播の違いをまとめたものです。

キーワード自分自身のビルドリンクする側への波及主な用途
PRIVATE適用される適用されない内部実装用ヘッダ、内部処理用のマクロ
INTERFACE適用されない適用されるヘッダのみのライブラリ、公開用ヘッダ
PUBLIC適用される適用される標準的なライブラリ、公開用インターフェース

2026年における標準的なプロジェクト構造

保守性の高いC++プロジェクトを構築するためには、CMakeLists.txtの配置とディレクトリ構造を標準化することが重要です。

一般的には、プロジェクトのルートに全体の管理を行うCMakeLists.txtを置き、ソースコードやテスト、外部ライブラリをサブディレクトリに分離します。

特にsrcディレクトリ内に各モジュールごとのCMakeLists.txtを配置する構成が、現在の主流となっています。

text
project_root/
├── CMakeLists.txt          (ルート設定)
├── CMakePresets.json       (ビルド設定のプリセット)
├── cmake/                  (自作のモジュールやユーティリティ)
├── include/                (公開ヘッダ)
├── src/                    (ソースコード本体)
│   ├── app/
│   │   ├── CMakeLists.txt
│   │   └── main.cpp
│   └── math_lib/
│       ├── CMakeLists.txt
│       └── calculator.cpp
├── tests/                  (テストコード)
└── extern/                 (外部依存関係)

ルートのCMakeLists.txtでは、プロジェクト全体に共通する最低要件やプロジェクト名を定義します。

2026年においては、CMake 3.25以上、あるいは最新の機能を活用するためにCMake 3.30以上を要求することが一般的です。

CMake
# 2026年時点での推奨最低バージョン
cmake_minimum_required(VERSION 3.30)

# プロジェクトの基本定義
project(ModernCppProject
    VERSION 1.2.0
    DESCRIPTION "A modern C++ project example"
    LANGUAGES CXX
)

# C++標準の指定(C++23をデフォルトとする例)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# サブディレクトリの追加
add_subdirectory(src/math_lib)
add_subdirectory(src/app)

ターゲットベースの設定:具体的な記述方法

次に、ライブラリと実行ファイルを定義し、それらを結びつける具体的なコード例を見てみましょう。

ここでは、math_libというスタティックライブラリを作成し、それをappという実行ファイルで利用する構成を想定します。

ライブラリの定義 (src/math_lib/CMakeLists.txt)

ライブラリ側では、ソースファイルを指定し、インクルードパスをターゲットに紐付けます。

target_include_directoriesを使用する際、ビルド時とインストール時でパスを分けるのがモダンな作法です。

CMake
# ライブラリターゲットの作成
add_library(math_lib STATIC
    calculator.cpp
)

# インクルードディレクトリの設定
# PUBLICを指定することで、このライブラリをリンクする側にもパスが通る
target_include_directories(math_lib
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../include>
        $<INSTALL_INTERFACE:include>
)

# コンパイルオプションの設定
target_compile_options(math_lib
    PRIVATE
        $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
        $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic -Werror>
)

実行ファイルの定義 (src/app/CMakeLists.txt)

実行ファイル側では、どのターゲットに依存しているかを記述するだけで、インクルードパスなどの設定を継承できます。

CMake
# 実行ファイルターゲットの作成
add_executable(app
    main.cpp
)

# 依存ライブラリのリンク
# これにより、math_libのPUBLICプロパティがすべて適用される
target_link_libraries(app
    PRIVATE
        math_lib
)

このように記述することで、appターゲットはmath_libがどこに配置されているかを詳細に知る必要がなくなります。

「何を使いたいか」を宣言するだけで、「どうビルドするか」をCMakeが自動的に解決してくれるのです。

2026年のパッケージ管理:FetchContentとvcpkgの使い分け

C++の長年の課題であったパッケージ管理は、CMakeの機能強化と外部ツールの普及によって大幅に改善されました。

現在、主要な選択肢は「FetchContent」と「vcpkg(あるいはConan)」の2つに集約されています。

FetchContentによる軽量な依存解決

CMake 3.11で導入されたFetchContentは、ビルド時にGitリポジトリなどから直接ソースコードをダウンロードし、プロジェクトに組み込む機能です。

小規模なライブラリや、特定のバージョンをプロジェクトに固定したい場合に非常に便利です。

2026年では、単にfind_packageを試すだけでなく、存在しない場合に自動で取得するような構成も一般化しています。

CMake
include(FetchContent)

# nlohmann_jsonをGitHubから取得する例
FetchContent_Declare(
    json
    GIT_REPOSITORY https://github.com/nlohmann/json.git
    GIT_TAG        v3.11.3
)

# 依存関係を確定させ、プロジェクトに組み込む
FetchContent_MakeAvailable(json)

# 利用時はターゲットをリンクするだけ
target_link_libraries(app PRIVATE nlohmann_json::nlohmann_json)

vcpkgによる本格的なパッケージ管理

プロジェクトが大規模になり、OpenCVやQt、Boostといった巨大なライブラリを扱う場合は、Microsoftが主導するvcpkgが最も有力な選択肢です。

vcpkgはCMakeの「ツールチェーンファイル」として統合され、従来のfind_packageをそのまま利用できる点が大きなメリットです。

プロジェクトルートにvcpkg.json(マニフェストファイル)を置くことで、依存関係を宣言的に記述できます。

JSON
{
  "name": "modern-cpp-project",
  "version-string": "1.2.0",
  "dependencies": [
    "fmt",
    "range-v3",
    "benchmark"
  ]
}

ビルド時には、CMakeのオプションとしてCMAKE_TOOLCHAIN_FILEを指定するだけで、自動的に依存ライブラリのインストールとリンクが行われます。

CMake Presetsによる開発環境の共通化

複数のプラットフォームや異なるコンパイル設定(Debug/Release)を管理するのは、従来非常に煩雑な作業でした。

これを解決するために導入されたのがCMakePresets.jsonであり、2026年ではプロジェクトの必須ファイルとなっています。

このファイルを使用することで、複雑なコマンドライン引数を入力することなく、誰でも同じ条件でビルドを開始できる環境を提供できます。

JSON
{
  "version": 6,
  "configurePresets": [
    {
      "name": "default",
      "displayName": "Default Config",
      "description": "Ninja generator with Clang",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_CXX_COMPILER": "clang++",
        "CMAKE_BUILD_TYPE": "Release"
      }
    }
  ]
}

開発者はターミナルで以下のコマンドを実行するだけで、設定からビルドまでを完了できます。

text
# 設定の適用
cmake --preset default

# ビルドの実行
cmake --build --preset default

これにより、VS CodeやCLion、Visual Studioといった主要なIDEとの親和性も飛躍的に向上しました。

C++20/23/26 モジュールへの対応

2026年において無視できないトピックが、C++20で導入された「モジュール(Modules)」への完全な移行です。

CMake 3.28以降、モジュールのサポートは安定期に入り、従来のヘッダファイルに代わる新しい分割コンパイル手法が一般化しています。

target_sourcesコマンドにCXX_MODULESというカテゴリを指定することで、CMakeは自動的にモジュールの依存関係を解析し、正しい順序でコンパイルを行います。

CMake
# C++モジュールを定義する例
add_library(core_module)

target_sources(core_module
    PUBLIC
        FILE_SET CXX_MODULES FILES
            core.ixx
)

target_compile_features(core_module PUBLIC cxx_std_23)

モジュールを使用することで、コンパイル時間の短縮だけでなく、マクロの汚染を防ぎ、より堅牢なAPI設計が可能になります。

CMakeによるモジュールサポートの成熟は、C++の近代化を強力に後押ししています。

自動テストの統合:CTestの活用

品質管理を自動化するために、CMakeに統合されたテストランナーであるCTestの活用は欠かせません。

add_testコマンドを使用することで、GoogleTestやCatch2といったテストフレームワークと連携したテストスイートを構築できます。

CMake
# テストの有効化
enable_testing()

# テスト用ターゲットの作成
add_executable(unit_tests test_main.cpp)
target_link_libraries(unit_tests PRIVATE math_lib GTest::gtest_main)

# テストの登録
add_test(NAME MyMathTest COMMAND unit_tests)

テストの実行は、ビルドディレクトリで以下のコマンドを入力するだけです。

text
ctest --output-on-failure

CI/CDパイプラインにおいても、この標準的なコマンドを利用することで、テスト結果の集計やレポート出力を容易に行うことができます。

インストールとパッケージング:CMakeの真骨頂

ビルドした成果物を配布可能な形にする「インストール」処理も、CMakeの重要な役割です。

installコマンドを適切に設定することで、ライブラリのバイナリ、ヘッダファイル、そして他のプロジェクトから再利用するための設定ファイルを自動生成できます。

CMake
# インストールルールの定義
install(TARGETS math_lib
    EXPORT MathLibTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

# ヘッダファイルのインストール
install(DIRECTORY include/ DESTINATION include)

# CMake用設定ファイルの書き出し
install(EXPORT MathLibTargets
    FILE MathLibConfig.cmake
    NAMESPACE MathLib::
    DESTINATION lib/cmake/MathLib
)

このように設定されたライブラリは、別のプロジェクトからfind_package(MathLib REQUIRED)とするだけで簡単に利用できるようになります。

自分たちで作ったライブラリを社内共通基盤として提供する際、このエクスポート設定の有無が使い勝手を大きく左右します。

まとめ

2026年におけるC++のCMake活用は、単なるビルドスクリプトの記述を超え、ソフトウェア全体のライフサイクルを管理するためのプラットフォームとなりました。

ターゲットベースの設計を徹底し、可視性を適切にコントロールすることで、複雑な依存関係に悩まされることはなくなります。

また、FetchContentやvcpkgによるモダンなパッケージ管理を取り入れ、CMake Presetsで環境を共通化することは、チーム開発の効率を劇的に向上させます。

C++20/23/26といった新しい言語仕様がもたらすモジュール化の恩恵も、最新のCMakeを使いこなすことで最大限に享受できるでしょう。

本記事で紹介したテクニックを自身のプロジェクトに適用し、より快適で堅牢なC++開発環境を手に入れてください。

URLをコピーしました!