CMake
ビルドツール
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