CMakeLists.txtとは?C/C++プロジェクトのビルドを自動化する設定ファイル完全ガイド

プログラミング・IT

「C++のプロジェクトが大きくなって、コンパイルが面倒…」
「WindowsでもLinuxでもMacでも動くプログラムを作りたいけど、どうすれば?」

C/C++でプログラミングをしていると、必ず出てくるのがビルド(コンパイル)の管理という課題です。

その解決策として広く使われているのがCMake(シーメイク)というツールと、その設定ファイルであるCMakeLists.txtです。

この記事では、CMakeLists.txtとは何か、どう書けばいいのか、そして実際のプロジェクトでどう使うのかを、初心者の方にも分かりやすく解説します。

難しいビルドシステムの話を、実例を交えながら説明していきますね。

C/C++開発を効率化したい方は、ぜひ最後までお読みください!

スポンサーリンク
  1. CMakeとは?基本を理解しよう
    1. CMakeの定義
    2. なぜCMakeが必要なのか?
    3. CMakeが解決する問題
  2. CMakeLists.txtとは?
    1. CMakeLists.txtの定義
    2. Makefileとの違い
    3. 基本的なワークフロー
  3. 最もシンプルなCMakeLists.txt
    1. Hello World プログラム
    2. ビルド方法
    3. 各行の意味
  4. よく使うCMakeコマンド
    1. プロジェクト設定
    2. ターゲット追加
    3. ファイル収集
    4. ディレクトリ指定
    5. ライブラリのリンク
    6. C++標準の指定
    7. コンパイルオプション
  5. 実践的なCMakeLists.txt
    1. 例1:複数ファイルのプロジェクト
    2. 例2:ライブラリを含むプロジェクト
    3. 例3:外部ライブラリの使用
  6. 変数とオプション
    1. 変数の定義
    2. よく使う変数
    3. オプションの定義
    4. メッセージ出力
  7. 条件分岐とループ
    1. if文
    2. プラットフォーム判定
    3. foreach ループ
  8. ビルドタイプの設定
    1. ビルドタイプの指定
    2. ビルドタイプごとの設定
  9. よくあるエラーと解決方法
    1. エラー1:「CMake Error: The source directory does not exist」
    2. エラー2:「Could not find a package configuration file」
    3. エラー3:「No CMAKE_CXX_COMPILER could be found」
    4. エラー4:ヘッダーファイルが見つからない
    5. エラー5:未定義参照エラー
  10. CMakeのベストプラクティス
    1. 1. ソース外ビルドを使う
    2. 2. target_xxx を使う
    3. 3. PUBLICとPRIVATEを使い分ける
    4. 4. モダンCMake(3.0以降)を使う
    5. 5. ファイルリストは明示的に
  11. 実際のプロジェクト例
    1. プロジェクト構造
    2. ルートのCMakeLists.txt
  12. よくある質問と回答
    1. Q. CMakeとMakeの違いは?
    2. Q. CMakeLists.txtはどこに置けばいい?
    3. Q. Windowsでも使えますか?
    4. Q. CMakeのバージョンはどれを使えばいい?
    5. Q. find_packageが失敗します
    6. Q. ビルドディレクトリを削除してもいい?
    7. Q. CMakeとCMakeLists.txtのバージョンは合わせる必要がある?
  13. まとめ:CMakeLists.txtでビルドを自動化

CMakeとは?基本を理解しよう

CMakeLists.txtを理解する前に、まずCMakeについて知る必要があります。

CMakeの定義

CMake(シーメイク)とは、C/C++プロジェクトのビルドプロセスを管理するためのツールです。

正式名称:

  • Cross-platform Make(クロスプラットフォーム メイク)
  • 「クロスプラットフォーム」= どんなOSでも動く

開発:

  • Kitware社が開発
  • オープンソース
  • 2000年から開発開始

なぜCMakeが必要なのか?

C/C++のプログラムは、ソースコードをコンパイルして実行ファイルにする必要があります。

小さなプログラムなら:

g++ main.cpp -o program

これだけで済みます。

でも、大きなプロジェクトになると:

  • ファイルが数十個、数百個
  • ライブラリの依存関係
  • コンパイルオプションが複雑
  • 複数のOS(Windows、Linux、Mac)に対応

手動では無理!

ここでCMakeの出番です。

CMakeが解決する問題

問題1:プラットフォームの違い

  • Windows:Visual Studio、MSVC
  • Linux:Makefile、GCC
  • Mac:Xcode、Clang

CMakeの解決策:
一つのCMakeLists.txtから、各プラットフォーム用のビルドファイルを自動生成!

問題2:複雑な依存関係

  • main.cppがutil.hを使う
  • util.cppがmath_lib.aを使う
  • どの順番でコンパイル?

CMakeの解決策:
依存関係を自動で解決!

問題3:ライブラリの管理

  • OpenCVを使いたい
  • Boostを使いたい
  • どこにインストールされている?

CMakeの解決策:
自動でライブラリを探して設定!

CMakeLists.txtとは?

いよいよ本題です。

CMakeLists.txtの定義

CMakeLists.txtとは、CMakeに対して「どうビルドするか」を指示する設定ファイルです。

ファイル名:

  • 必ず「CMakeLists.txt」(大文字小文字を区別)
  • プロジェクトのルートディレクトリに置く

役割:

  • プロジェクトの構造を定義
  • コンパイルオプションを指定
  • ライブラリの依存関係を記述
  • ビルドターゲットを定義

Makefileとの違い

よく比較されるのがMakefileです。

Makefile:

  • 直接ビルドコマンドを実行
  • プラットフォーム依存
  • Linuxでは便利、Windowsでは使いづらい

CMakeLists.txt:

  • ビルドファイル(Makefileなど)を生成する
  • プラットフォーム非依存
  • どのOSでも使える

つまり:
CMakeは「Makefileを作るツール」なんです。

基本的なワークフロー

CMakeLists.txt を書く
    ↓
cmake コマンドを実行
    ↓
Makefile(またはVisual Studioプロジェクト)が生成される
    ↓
make コマンド(またはビルドボタン)でコンパイル
    ↓
実行ファイルが完成

最もシンプルなCMakeLists.txt

実際のコード例を見ていきましょう。

Hello World プログラム

ソースコード(main.cpp):

#include <iostream>

int main() {
    std::cout << "Hello, CMake!" << std::endl;
    return 0;
}

CMakeLists.txt:

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

# プロジェクト名を定義
project(HelloWorld)

# 実行ファイルを作成
add_executable(hello main.cpp)

これだけです!

ビルド方法

ステップ1:ビルドディレクトリを作成

mkdir build
cd build

ステップ2:CMakeを実行

cmake ..

ステップ3:ビルド

make

ステップ4:実行

./hello

出力:

Hello, CMake!

各行の意味

cmake_minimum_required(VERSION 3.10)

  • 必要なCMakeのバージョンを指定
  • 古いCMakeでは動かないことを防ぐ

project(HelloWorld)

  • プロジェクトの名前を設定
  • この名前は後で使える

add_executable(hello main.cpp)

  • 実行ファイル「hello」を作成
  • ソースファイルは「main.cpp」

よく使うCMakeコマンド

CMakeLists.txtで頻繁に使うコマンドを紹介します。

プロジェクト設定

cmake_minimum_required()

cmake_minimum_required(VERSION 3.15)

必須コマンド。最小バージョンを指定します。

project()

project(MyProject VERSION 1.0 LANGUAGES CXX)

プロジェクト名、バージョン、使用言語を指定します。

ターゲット追加

add_executable()

add_executable(my_program main.cpp utils.cpp)

実行ファイルを作成します。

add_library()

# 静的ライブラリ
add_library(mylib STATIC lib.cpp)

# 共有ライブラリ
add_library(mylib SHARED lib.cpp)

ライブラリを作成します。

ファイル収集

file(GLOB …)

file(GLOB SOURCES "src/*.cpp")
add_executable(my_program ${SOURCES})

複数のファイルを自動で収集します。

ただし注意:
GLOBは推奨されません(ファイルを追加してもCMakeが気づかない)。明示的にファイルを列挙する方が良いです。

ディレクトリ指定

include_directories()

include_directories(include)

ヘッダーファイルの検索パスを追加します。

target_include_directories()(推奨)

target_include_directories(my_program PUBLIC include)

特定のターゲットに対してのみ、インクルードパスを設定します。

ライブラリのリンク

target_link_libraries()

target_link_libraries(my_program pthread)

ライブラリをリンクします。

C++標準の指定

set(CMAKE_CXX_STANDARD …)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

C++17を使用することを指定します。

コンパイルオプション

target_compile_options()

target_compile_options(my_program PRIVATE -Wall -Wextra)

コンパイラの警告オプションなどを追加します。

実践的なCMakeLists.txt

実際のプロジェクトで使える例を見てみましょう。

例1:複数ファイルのプロジェクト

ディレクトリ構造:

MyProject/
├── CMakeLists.txt
├── main.cpp
├── utils.cpp
└── utils.h

CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0)

# C++17を使用
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 実行ファイルを作成
add_executable(my_program 
    main.cpp
    utils.cpp
)

# 警告オプションを追加
target_compile_options(my_program PRIVATE
    -Wall
    -Wextra
    -pedantic
)

例2:ライブラリを含むプロジェクト

ディレクトリ構造:

MyProject/
├── CMakeLists.txt
├── app/
│   ├── main.cpp
│   └── CMakeLists.txt
└── lib/
    ├── mylib.cpp
    ├── mylib.h
    └── CMakeLists.txt

ルートのCMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(MyProject VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)

# サブディレクトリを追加
add_subdirectory(lib)
add_subdirectory(app)

lib/CMakeLists.txt:

# ライブラリを作成
add_library(mylib STATIC
    mylib.cpp
)

# インクルードディレクトリを公開
target_include_directories(mylib PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}
)

app/CMakeLists.txt:

# 実行ファイルを作成
add_executable(my_program
    main.cpp
)

# ライブラリをリンク
target_link_libraries(my_program PRIVATE mylib)

例3:外部ライブラリの使用

CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(ImageProcessor)

set(CMAKE_CXX_STANDARD 17)

# OpenCVを探す
find_package(OpenCV REQUIRED)

# 実行ファイルを作成
add_executable(image_app main.cpp)

# OpenCVのインクルードディレクトリを追加
target_include_directories(image_app PRIVATE ${OpenCV_INCLUDE_DIRS})

# OpenCVライブラリをリンク
target_link_libraries(image_app PRIVATE ${OpenCV_LIBS})

変数とオプション

CMakeLists.txtでは、変数やオプションを使えます。

変数の定義

set()

set(MY_SOURCES main.cpp utils.cpp)
set(MY_HEADERS utils.h)

add_executable(my_program ${MY_SOURCES})

よく使う変数

プロジェクト情報:

${PROJECT_NAME}           # プロジェクト名
${PROJECT_VERSION}        # バージョン
${CMAKE_PROJECT_NAME}     # トップレベルプロジェクト名

ディレクトリ:

${CMAKE_SOURCE_DIR}       # トップレベルのソースディレクトリ
${CMAKE_BINARY_DIR}       # トップレベルのビルドディレクトリ
${CMAKE_CURRENT_SOURCE_DIR}  # 現在のソースディレクトリ
${CMAKE_CURRENT_BINARY_DIR}  # 現在のビルドディレクトリ

コンパイラ:

${CMAKE_CXX_COMPILER}     # C++コンパイラのパス
${CMAKE_CXX_FLAGS}        # C++コンパイルフラグ

オプションの定義

option()

option(BUILD_TESTS "Build test programs" ON)

if(BUILD_TESTS)
    add_subdirectory(tests)
endif()

使い方:

cmake .. -DBUILD_TESTS=OFF

メッセージ出力

message()

message(STATUS "Building project: ${PROJECT_NAME}")
message(WARNING "This is a warning")
message(FATAL_ERROR "This stops CMake")

条件分岐とループ

CMakeLists.txtは、プログラミング言語のように条件分岐やループが使えます。

if文

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    message(STATUS "Debug build")
    add_definitions(-DDEBUG)
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
    message(STATUS "Release build")
    add_definitions(-DNDEBUG)
else()
    message(STATUS "Unknown build type")
endif()

プラットフォーム判定

if(WIN32)
    message(STATUS "Building for Windows")
    add_definitions(-DWINDOWS)
elseif(UNIX)
    message(STATUS "Building for Unix-like system")
    if(APPLE)
        message(STATUS "Building for macOS")
    else()
        message(STATUS "Building for Linux")
    endif()
endif()

foreach ループ

set(MY_FILES file1.cpp file2.cpp file3.cpp)

foreach(FILE ${MY_FILES})
    message(STATUS "Processing ${FILE}")
endforeach()

ビルドタイプの設定

DebugビルドとReleaseビルドを使い分けられます。

ビルドタイプの指定

# デフォルトのビルドタイプを設定
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")

コマンドラインで指定:

cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake .. -DCMAKE_BUILD_TYPE=Release

ビルドタイプごとの設定

# Debugビルドの設定
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")

# Releaseビルドの設定
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")

よくあるエラーと解決方法

実際に使っていると、エラーに遭遇することがあります。

エラー1:「CMake Error: The source directory does not exist」

原因:
CMakeのパスが間違っている

解決策:

# 正しい例
cd build
cmake ..

# 間違った例
cmake .  # これはダメ

エラー2:「Could not find a package configuration file」

エラーメッセージ例:

Could not find a package configuration file provided by "OpenCV"

原因:
外部ライブラリがインストールされていない、またはCMakeが見つけられない

解決策:

ライブラリをインストール:

# Ubuntu/Debian
sudo apt-get install libopencv-dev

# macOS
brew install opencv

パスを指定:

cmake .. -DOpenCV_DIR=/path/to/opencv

エラー3:「No CMAKE_CXX_COMPILER could be found」

原因:
C++コンパイラがインストールされていない

解決策:

Linux:

sudo apt-get install build-essential

macOS:

xcode-select --install

Windows:

  • Visual Studioをインストール
  • または MinGW-w64

エラー4:ヘッダーファイルが見つからない

エラー:

fatal error: myheader.h: No such file or directory

原因:
インクルードパスが設定されていない

解決策:

target_include_directories(my_program PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

エラー5:未定義参照エラー

エラー:

undefined reference to `my_function'

原因:
ライブラリがリンクされていない

解決策:

target_link_libraries(my_program PRIVATE mylib pthread)

CMakeのベストプラクティス

効果的なCMakeLists.txtを書くためのコツです。

1. ソース外ビルドを使う

悪い例:

cmake .
make

良い例:

mkdir build
cd build
cmake ..
make

ソースディレクトリを汚さないようにしましょう。

2. target_xxx を使う

古い書き方(非推奨):

include_directories(include)
link_libraries(pthread)

新しい書き方(推奨):

target_include_directories(my_program PRIVATE include)
target_link_libraries(my_program PRIVATE pthread)

ターゲットごとに設定する方が明確です。

3. PUBLICとPRIVATEを使い分ける

# PRIVATE: このターゲットだけが使う
target_include_directories(mylib PRIVATE src)

# PUBLIC: このターゲットと、これを使うターゲットも使う
target_include_directories(mylib PUBLIC include)

# INTERFACE: このターゲットは使わないが、これを使うターゲットが使う
target_include_directories(mylib INTERFACE interface)

4. モダンCMake(3.0以降)を使う

古いスタイル:

include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(my_program ${OpenCV_LIBS})

モダンスタイル:

find_package(OpenCV REQUIRED)
target_link_libraries(my_program PRIVATE OpenCV::OpenCV)

5. ファイルリストは明示的に

避けるべき:

file(GLOB SOURCES "*.cpp")

推奨:

set(SOURCES
    main.cpp
    utils.cpp
    helper.cpp
)

実際のプロジェクト例

総合的な例を見てみましょう。

プロジェクト構造

MyProject/
├── CMakeLists.txt
├── include/
│   └── myproject/
│       └── utils.h
├── src/
│   ├── main.cpp
│   └── utils.cpp
├── tests/
│   ├── CMakeLists.txt
│   └── test_utils.cpp
└── external/
    └── CMakeLists.txt

ルートのCMakeLists.txt

cmake_minimum_required(VERSION 3.15)

project(MyProject 
    VERSION 1.0.0
    DESCRIPTION "A sample CMake project"
    LANGUAGES CXX
)

# C++17を使用
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# ビルドタイプのデフォルト
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

# オプション
option(BUILD_TESTS "Build test programs" ON)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)

# ソースファイル
set(SOURCES
    src/main.cpp
    src/utils.cpp
)

# 実行ファイル
add_executable(${PROJECT_NAME} ${SOURCES})

# インクルードディレクトリ
target_include_directories(${PROJECT_NAME}
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# コンパイルオプション
target_compile_options(${PROJECT_NAME}
    PRIVATE
        $<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic>
        $<$<CXX_COMPILER_ID:MSVC>:/W4>
)

# 外部ライブラリ
add_subdirectory(external)

# テスト
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

# インストール設定
install(TARGETS ${PROJECT_NAME}
    RUNTIME DESTINATION bin
)

よくある質問と回答

Q. CMakeとMakeの違いは?

Makeは直接ビルドツール、CMakeはビルドファイル生成ツールです。

Make:

  • Makefileを読んで直接コンパイル
  • プラットフォーム依存

CMake:

  • CMakeLists.txtから Makefile(など)を生成
  • プラットフォーム非依存

Q. CMakeLists.txtはどこに置けばいい?

プロジェクトのルートディレクトリに置きます。

サブディレクトリにも置けます(add_subdirectoryで追加)。

Q. Windowsでも使えますか?

はい、使えます!

CMakeはWindowsでも動作し、Visual Studioのプロジェクトファイルを生成できます。

cmake .. -G "Visual Studio 17 2022"

Q. CMakeのバージョンはどれを使えばいい?

3.15以降を推奨します。

理由:

  • モダンCMakeの機能が使える
  • 多くのライブラリが対応している
  • セキュリティアップデートもある

Q. find_packageが失敗します

ライブラリが見つからない場合の対処法:

1. ライブラリをインストール

2. CMakeにパスを教える

cmake .. -DCMAKE_PREFIX_PATH=/path/to/library

3. 環境変数を設定

export CMAKE_PREFIX_PATH=/path/to/library

Q. ビルドディレクトリを削除してもいい?

はい、いつでも削除できます。

rm -rf build
mkdir build
cd build
cmake ..

ソースコードは影響を受けません。

Q. CMakeとCMakeLists.txtのバージョンは合わせる必要がある?

CMakeLists.txtで指定するのは「最小バージョン」です。

cmake_minimum_required(VERSION 3.15)

CMake 3.15以降なら動作します。より新しいバージョンでも問題ありません。

まとめ:CMakeLists.txtでビルドを自動化

CMakeLists.txtについて、基本から実用まで解説してきました。

この記事のポイント:

✓ CMakeLists.txtはCMakeの設定ファイル

✓ プラットフォーム非依存のビルドシステム

✓ 最小構成はcmake_minimum_required、project、add_executable

✓ target_xxxコマンドで明示的に設定するのが推奨

✓ 外部ライブラリはfind_packageで探す

✓ ソース外ビルド(buildディレクトリ)を使う

✓ 条件分岐やループも使える柔軟な設定が可能

最も大切なこと:

CMakeLists.txtは、クロスプラットフォーム開発には欠かせないツールです。

最初は複雑に見えますが、基本を押さえれば強力な味方になります。

今日から実践すること:

  1. 簡単なHello WorldプロジェクトでCMakeを試す
  2. 既存のプロジェクトにCMakeLists.txtを追加してみる
  3. 外部ライブラリを使うプロジェクトに挑戦
  4. GitHubの有名プロジェクトのCMakeLists.txtを読んでみる

C/C++開発が、CMakeLists.txtでもっと効率的になりますよ!

コメント

タイトルとURLをコピーしました