CMake

ビルドツールC/C++クロスプラットフォームプロジェクト管理設定生成

ビルドツール

CMake

概要

CMakeは、クロスプラットフォーム対応の無料でオープンソースのソフトウェア開発ツールファミリーです。コンパイラに依存しない方法でビルドプロセス、テスト、パッケージングを管理・自動化します。Bill Hoffman氏らによって2000年に開発が開始され、C/C++プロジェクトのビルドシステム生成において事実上の標準となっています。Make、Ninja、Visual Studio、Xcodeなど様々なネイティブビルドツールに対応し、複雑なプロジェクト構成から大規模な企業級アプリケーションまで幅広くサポートしています。

詳細

主要機能

  • クロスプラットフォーム対応: Windows、Linux、macOS、Unix系システムで動作
  • ビルドシステム生成: Make、Ninja、Visual Studio、Xcodeプロジェクトを生成
  • 多言語サポート: C、C++、Fortran、C#、Java、Pythonなどに対応
  • 依存関係管理: 自動的なライブラリ検出と依存関係解決
  • テスト統合: CTestによる包括的なテストフレームワーク
  • パッケージング: CPackによるクロスプラットフォームインストーラー作成
  • IDE統合: 主要IDE(Visual Studio、Qt Creator、CLion等)での優れたサポート

アーキテクチャ

CMakeListsファイルによる宣言的な設定から、ターゲットプラットフォーム用のネイティブビルドスクリプトを生成。設定、生成、ビルドの3フェーズで動作し、out-of-sourceビルドをサポート。

エコシステム

find_packageシステムによる豊富なライブラリサポート、vcpkgやConanなどのパッケージマネージャーとの統合、GitHub ActionsやGitLab CIでの標準的な使用。

メリット・デメリット

メリット

  • 業界標準: C/C++開発において最も広く使用されるビルドツール
  • クロスプラットフォーム: 単一の設定で複数プラットフォームに対応
  • 豊富なIDE統合: 主要IDEでの優れたサポートと IntelliSense
  • 強力なライブラリ検出: find_packageによる自動ライブラリ検出
  • 成熟したエコシステム: 20年以上の開発実績と豊富なドキュメント
  • 企業での採用: KDE、LLVM、OpenCV、Qt等の大規模プロジェクトで使用
  • 継続的統合: CI/CDパイプラインとの優れた統合

デメリット

  • 学習コスト: 独自の構文と概念の理解が必要
  • 設定の複雑さ: 大規模プロジェクトでは設定が複雑になる
  • デバッグの困難さ: 生成されたビルドスクリプトの問題追跡が困難
  • パフォーマンス: 非常に大規模なプロジェクトでは設定時間が長い
  • バージョン互換性: 古いバージョンとの互換性問題
  • モダンツールとの競合: RustのCargo、GoのModulesなど言語特化ツールの台頭

参考ページ

書き方の例

インストールと基本セットアップ

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install cmake

# CentOS/RHEL/Fedora
sudo yum install cmake
# または
sudo dnf install cmake

# macOS (Homebrew)
brew install cmake

# Windows (Chocolatey)
choco install cmake

# バージョン確認
cmake --version

# 基本的なプロジェクト作成
mkdir my-project
cd my-project
mkdir build

基本的なCMakeLists.txt

# CMakeの最小バージョン指定
cmake_minimum_required(VERSION 3.20)

# プロジェクト名と使用言語
project(MyProject
    VERSION 1.0.0
    DESCRIPTION "Sample C++ project with CMake"
    LANGUAGES CXX
)

# C++標準の設定
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# 実行ファイルの作成
add_executable(my_app
    src/main.cpp
    src/utils.cpp
)

# ヘッダーファイルのディレクトリ指定
target_include_directories(my_app PRIVATE
    include
)

# ビルドとインストール
# mkdir build && cd build
# cmake ..
# cmake --build .
# または make

ライブラリの作成と使用

cmake_minimum_required(VERSION 3.20)
project(MathLibrary VERSION 2.1.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 静的ライブラリの作成
add_library(MathFunctions STATIC
    src/MathFunctions.cpp
    src/mysqrt.cpp
)

# ライブラリのヘッダーファイル
target_include_directories(MathFunctions
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        src
)

# 実行ファイルの作成
add_executable(calculator
    src/main.cpp
)

# ライブラリのリンク
target_link_libraries(calculator PRIVATE MathFunctions)

# オプション機能の追加
option(USE_MYMATH "Use tutorial provided math implementation" ON)

if(USE_MYMATH)
    target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
    
    # サブディレクトリの追加
    add_subdirectory(MathFunctions)
    
    list(APPEND EXTRA_LIBS MathFunctions)
endif()

target_link_libraries(calculator PUBLIC ${EXTRA_LIBS})

外部ライブラリの検出と使用

cmake_minimum_required(VERSION 3.20)
project(NetworkApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)

# 必須パッケージの検索
find_package(PkgConfig REQUIRED)
find_package(Threads REQUIRED)

# OpenSSLの検索
find_package(OpenSSL REQUIRED)
if(OPENSSL_FOUND)
    message(STATUS "OpenSSL found: ${OPENSSL_VERSION}")
endif()

# Boostライブラリの検索
find_package(Boost 1.70 REQUIRED 
    COMPONENTS 
        system 
        filesystem 
        network
        program_options
)

# curlライブラリの検索(pkg-configを使用)
pkg_check_modules(CURL REQUIRED libcurl)

# 実行ファイルの作成
add_executable(network_client
    src/main.cpp
    src/http_client.cpp
    src/ssl_utils.cpp
)

# インクルードディレクトリの指定
target_include_directories(network_client PRIVATE
    include
    ${Boost_INCLUDE_DIRS}
    ${CURL_INCLUDE_DIRS}
)

# ライブラリのリンク
target_link_libraries(network_client
    PRIVATE
        OpenSSL::SSL
        OpenSSL::Crypto
        Boost::system
        Boost::filesystem
        Boost::program_options
        ${CURL_LIBRARIES}
        Threads::Threads
)

# コンパイラ固有の設定
target_compile_options(network_client PRIVATE ${CURL_CFLAGS_OTHER})

モダンCMakeのベストプラクティス

cmake_minimum_required(VERSION 3.20)

project(ModernProject
    VERSION 1.2.3
    DESCRIPTION "Modern CMake project example"
    HOMEPAGE_URL "https://github.com/username/project"
    LANGUAGES CXX
)

# プロジェクト設定
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# ビルドタイプの設定
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

# コンパイラ設定
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")

# インターフェースライブラリ(ヘッダーオンリー)
add_library(project_options INTERFACE)
add_library(project_warnings INTERFACE)

# コンパイラ警告の設定
target_compile_options(project_warnings
    INTERFACE
        $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic>
        $<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wpedantic>
        $<$<CXX_COMPILER_ID:MSVC>:/W4>
)

# 機能テスト
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag("-std=c++20" COMPILER_SUPPORTS_CXX20)

if(NOT COMPILER_SUPPORTS_CXX20)
    message(FATAL_ERROR "Compiler does not support C++20")
endif()

# ライブラリターゲットの作成
add_library(core_lib
    src/core/engine.cpp
    src/core/renderer.cpp
    src/core/input.cpp
)

# ターゲットプロパティの設定
set_target_properties(core_lib PROPERTIES
    CXX_STANDARD 20
    CXX_STANDARD_REQUIRED ON
    POSITION_INDEPENDENT_CODE ON
)

# モダンターゲットベースの設定
target_include_directories(core_lib
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        src
)

target_link_libraries(core_lib
    PUBLIC
        project_options
        project_warnings
)

# 実行ファイルの作成
add_executable(main_app src/main.cpp)

target_link_libraries(main_app
    PRIVATE
        core_lib
        project_options
        project_warnings
)

# インストール設定
include(GNUInstallDirs)

install(TARGETS main_app core_lib
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

install(DIRECTORY include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

テストとCTest統合

# テストの有効化
enable_testing()

# Google Testの検索と設定
find_package(GTest REQUIRED)

# テスト実行ファイルの作成
add_executable(unit_tests
    tests/test_main.cpp
    tests/test_math.cpp
    tests/test_utils.cpp
)

target_link_libraries(unit_tests
    PRIVATE
        core_lib
        GTest::gtest
        GTest::gtest_main
        GTest::gmock
)

# テストの追加
add_test(NAME unit_tests COMMAND unit_tests)

# カスタムテストの追加
add_test(NAME quick_test
    COMMAND main_app --test-mode
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)

# テスト実行時の環境変数設定
set_tests_properties(unit_tests PROPERTIES
    ENVIRONMENT "DATA_DIR=${CMAKE_SOURCE_DIR}/test_data"
)

# カバレッジ測定(GCC/Clang)
option(ENABLE_COVERAGE "Enable coverage reporting" OFF)

if(ENABLE_COVERAGE)
    target_compile_options(core_lib PRIVATE --coverage)
    target_link_libraries(core_lib PRIVATE --coverage)
endif()

# テスト実行
# cmake --build . --target test
# または ctest
# ctest --verbose  # 詳細出力
# ctest -j 4       # 並列実行

クロスプラットフォーム設定

cmake_minimum_required(VERSION 3.20)
project(CrossPlatformApp LANGUAGES CXX)

# プラットフォーム検出
if(WIN32)
    message(STATUS "Building for Windows")
    set(PLATFORM_LIBS ws2_32 wsock32)
    set(PLATFORM_DEFINITIONS WIN32_LEAN_AND_MEAN NOMINMAX)
elseif(APPLE)
    message(STATUS "Building for macOS")
    set(PLATFORM_LIBS "-framework Foundation" "-framework CoreFoundation")
    set(PLATFORM_DEFINITIONS MACOS_BUILD)
elseif(UNIX)
    message(STATUS "Building for Linux/Unix")
    set(PLATFORM_LIBS pthread dl)
    set(PLATFORM_DEFINITIONS LINUX_BUILD)
endif()

# アーキテクチャ検出
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
    message(STATUS "64-bit build")
    set(ARCH_DEFINITIONS ARCH_64)
else()
    message(STATUS "32-bit build") 
    set(ARCH_DEFINITIONS ARCH_32)
endif()

# 実行ファイルの作成
add_executable(cross_app
    src/main.cpp
    src/platform_utils.cpp
)

# プラットフォーム固有の設定
target_compile_definitions(cross_app
    PRIVATE
        ${PLATFORM_DEFINITIONS}
        ${ARCH_DEFINITIONS}
)

target_link_libraries(cross_app
    PRIVATE
        ${PLATFORM_LIBS}
)

# Windows固有の設定
if(WIN32)
    set_target_properties(cross_app PROPERTIES
        WIN32_EXECUTABLE TRUE
    )
endif()

# リソースファイルの追加(Windows)
if(WIN32)
    target_sources(cross_app PRIVATE resources/app.rc)
endif()

パッケージング(CPack)

# CPackの設定
include(CPack)

set(CPACK_PACKAGE_NAME "MyApplication")
set(CPACK_PACKAGE_VENDOR "Company Name")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "My application description")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")

# インストーラーの設定
if(WIN32)
    set(CPACK_GENERATOR "NSIS;ZIP")
    set(CPACK_NSIS_DISPLAY_NAME "My Application")
    set(CPACK_NSIS_PACKAGE_NAME "MyApp")
    set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources/app.ico")
elseif(APPLE)
    set(CPACK_GENERATOR "DragNDrop;TGZ")
    set(CPACK_DMG_FORMAT "UDZO")
    set(CPACK_DMG_VOLUME_NAME "MyApplication")
else()
    set(CPACK_GENERATOR "DEB;RPM;TGZ")
    
    # DEBパッケージ設定
    set(CPACK_DEBIAN_PACKAGE_MAINTAINER "[email protected]")
    set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libstdc++6")
    
    # RPMパッケージ設定
    set(CPACK_RPM_PACKAGE_LICENSE "MIT")
    set(CPACK_RPM_PACKAGE_GROUP "Applications/Productivity")
endif()

# パッケージ作成
# cmake --build . --target package