CMake基礎 #2 - バージョン, オプション, インストール

Last Edited: 1/24/2025

このブログ記事では、CMakeにおけるバージョン、オプション、インストール他について紹介します。

DevOps

前回の記事では、小規模で基本的なプロジェクト用の CMakeLists.txt ファイルのセットアップ方法を解説しました。 今回は、大規模なプロジェクトをセットアップする際により重要となるバージョン、オプション、インストールについて説明します。

バージョン

大規模なプロジェクトを扱う場合、さまざまなバージョンを配布することがあります。プロジェクトにバージョンを割り当てるには、project 引数を使用して、 例えば project(Project VERSION 1.0) のように記述します。CMakeLists.txt に設定したバージョンをソースコードから参照できるようにするため、 CMake によって ProjectConfig.h という設定ファイルを生成させることができます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(PROJECT VERSION 1.0)
 
configure_file(ProjectConfig.h.in ProjectConfig.h)
 
add_executable(${PROJECT_NAME} main.cc)
 
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR})

configure_file を使用して、ProjectConfig.h をビルドディレクトリ内に ProjectConfig.h.in から生成します。 このファイルを target_include_directories を用いてインクルードします。ProjectConfig.h.in では以下のようにバージョン情報を取得できます。

ProjectConfig.h.in
#define PROJECT_VERSION_MAJOR "@Project_VERSION_MAJOR@" // if version is 1.0, major is 1.
#define PROJECT_VERSION_MINOR "@Project_VERSION_MINOR@" // if version is 1.0, minor is 0.

ソースコードでは ProjectConfig.h を参照し、マクロとして定義されたこれらの変数にアクセスできます。

#include <iostream>
#include <ProjectConfig.h>
 
int main(int argc, char* argv[]) {
 
    std::cout << argv[0] << " Version: " << 
    PROJECT_VERSION_MAJOR << "." << PROJECT_VERSION_MINOR << std::endl;
 
    return 0;
};

オプション

大規模なプロジェクトでは、オプションのライブラリを利用することで追加機能を実装する場合があります。 その際、ユーザーにライブラリや追加機能を利用するかどうかを選択させることができます。 例えば、C++ の通常の加算よりも高速に動作する魔法のような add 関数を提供する <Addition.h> を考えます。 このライブラリを使用するかどうかのオプションを以下のように設定できます。

CMakeLists.txt
option(USE_ADDITION "A magical library for optimizing addition." ON)
 
if (USE_ADDITION)
    add_subdirectory(Addition)
    list(APPEND OPTIONAL_LIBS Addition)
    list(APPEND OPTIONAL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/Addition/include)
endif ()
 
target_link_libraries(${PROJECT_NAME} LibraryA ${OPTIONAL_LIBS})
 
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/LibraryA/include ${OPTIONAL_INCLUDE_DIRS})

option を利用して変数 USE_ADDITION をデフォルトで ON に設定し、USE_ADDITION が有効であればライブラリを追加するかどうかを判断します。 USE_ADDITION は、ProjectConfig.h.in 内で #define USE_ADDITION と定義し、ソースコードで利用できます。

#include <iostream>
#include <ProjectConfig.h>
 
#ifdef USE_ADDITION
    #include <Addition.h>
#endif
 
int main(int argc, char* argv[]) {
 
#ifdef USE_ADDITION
    std::cout << "Using Addition Library: 1+2=" << add(1, 2) << std::endl;
#elif
    std::cout << "Using Normal Addition 1+2=" << 1+2 << std::endl;
#endif
 
    return 0;
};

実行可能ファイルとライブラリの検索

実行可能ファイルやライブラリをコードベース内で設定し、開発者やユーザーにデバイス上でインストールしてもらうのではなく、 すでにインストールされているものを利用する前提で構築できます。特に Git のような多くの人がすでにインストールしている大規模な実行ファイルやライブラリ (Gitは DevOps シリーズで解説予定)については、プロジェクトディレクトリに含めるのではなく、ユーザーのコンピュータにインストール済みの Git を使用することが望ましいです。 必要な実行可能ファイルがインストールされていることを確認し、パスを取得するために、以下のように find_program を使用できます。

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
 
project(PROJECT VERSION 1.0)
 
find_program(GIT_EXECUTABLE git)
 
if (GIT_EXECUTABLE)
    message(STATUS "Git found at: ${GIT_EXECUTABLE}")
else ()
    message(FATAL_ERROR "Git not found")
endif ()

find_program は、実行可能ファイルが存在するかを確認し、その完全なパスを取得します。message を使って、 実行可能ファイルが見つかったかどうかを通知できます。ライブラリについては、以下のように find_library を使用して、 必要な数学ライブラリ libm.so のパスを確認します。

CMakeLists.txt
find_library(MATH_LIBRARY m)
if (MATH_LIBRARY)
    message(STATUS "Math library found: ${MATH_LIBRARY}")
else ()
    message(FATAL_ERROR "Math library not found")
endif ()
target_link_libraries(${PROJECT_NAME} PRIVATE ${MATH_LIBRARY})

ライブラリには Find<name>.cmake ファイルが設定されている場合があり、これを使って find_package を利用することで、 ライブラリのパスと、通常必要となる追加情報を取得できます。例えば、FindGit.cmake を使用して、 実行可能ファイルのパスやインストールされている Git のバージョンを取得できます。

CMakeLists.txt
find_package(Git)
if (GIT_FOUND)
    message("Git found: ${GIT_EXECUTABLE}, Version: ${GIT_VERSION_STRING}")
    execute_process(COMMAND ${GIT_EXECUTABLE} init)
else ()
    message(FATAL_ERROR "Git not found")
endif ()

上記の例では、さらに execute_process を使用して、find_package で取得したパスを使って実行可能ファイルを実行しています。 大規模なライブラリを作成する際には、簡単にライブラリにアクセスできるように Find<name>.cmake ファイルを設定することをお勧めします。

インストール

大規模なプロジェクトをビルドした後、それを配布し、ユーザーや開発者がコンピュータにインストールできるようにする必要があります。 CMake と install を使用してこれを行うことができますが、CMake の背景知識がない初心者にとっては、CMake を使用してビルドする方法を学ぶ必要があります。 このプロセスを簡素化するために、readme.md に以下のようなドキュメントを含めることができます。

readme.md
To install the project, you need to install CMake and Git and run the following commands:
 
    cmake -S . -DUSE_ADDITION=ON -B build
    cd build
    sudo make install

これらの詳細を隠すために、configure.shbuild.shinstall.sh のようなシェルスクリプトを作成し、 それぞれに上記のコマンドを含めてユーザーに実行させることもできます。ただし、このアプローチでも、 初心者やコマンドラインを使用した経験がないユーザーにとっては依然として複雑かもしれません。 そのため、CPack を使用することで、どの OS でも簡単にインストールできるインターフェースをユーザーに提供できます。 これを利用するには、以下の行を追加するだけです。

CMakeLists.txt
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_VERSION_MAJOR "${Project_VERSION_MAJOR}")
set(CPACK_VERSION_MINOR "${Project_VERSION_MINOR}")
include(CPack)

CPack を利用するには、License.txt ファイルをルートディレクトリに設定する必要があります。 ビルドディレクトリに移動し、cpack を実行してプロジェクトをコンパイルします。 Linux では、Project--Linux.tar.gzProject--Linux.tar.Z ファイルがビルドディレクトリに作成され、 それらと一緒に生成される Project--Linux.sh を実行することでインストールできます。CPack には GUI を設定するためのものなど、 多くの設定オプションがありますが、ここでは CPack の基本的な使用方法を説明しました。

結論

この記事では、バージョンとオプションの設定方法、およびライブラリの検索方法とインストールの設定について解説しました。 CMake の関数に関するさらなる情報については、お使いのバージョンの公式ドキュメントを参照することをお勧めします。

リソース