Programing/Tool/CMake/Guides/Tutorial

Last-modified: Fri, 10 Nov 2023 11:42:45 JST (169d)
Top > Programing > Tool > CMake > Guides > Tutorial

CMake Tutorialの簡易翻訳

はじめに

本チュートリアルは、一般的なビルドシステムの問題をCMakeで対処するのに役立つガイドを提供します。
本チュートリアルのドキュメントとサンプルコードは、CMakeソースコードのHelp/guiede/tutorialにあります。
サンプルコードは、ステップ毎のサブディレクトリに分割して格納されています。

Step1.基本

  • 基本プロジェクト
    最も基本的な、ソースコードから実行ファイルをビルドするプロジェクトです。
    このような単純なプロジェクトの場合、必要なのはたった3行の CMakeLists.txt ファイルのみです。
    次のような CMakeLists.txt ファイルをディレクトリに作成します。
    1. cmake_minimum_required(VERSION 3.10)
    2.  
    3. # プロジェクト名を指定
    4. project(Tutorial)
    5.  
    6. # 実行ファイルを追加
    7. add_executable(Tutorial tutorial.cxx)

バージョン番号と設定用ヘッダファイルの追加

  • バージョン番号の追加
    実行ファイルとプロジェクトにバージョン番号を追加します。
    1. cmake_minimum_required(VERSION 3.10)
    2.  
    3. # プロジェクト名とバージョンの指定
    4. project(Tutorial VERSION 1.0)
  • 設定用ヘッダファイルの生成
    設定したバージョン番号をソースコードに渡すためのヘッダファイルを生成します。
    configure_fileコマンドを使用することで、テンプレートファイル(TutorialConfig.h.in)内にCMakeLists.txtで定義した変数の内容を埋め込んで、ヘッダファイル(TutorialConfig.h)を生成します。
    1. configure_file(TutorialConfig.h.in TutorialConfig.h)
  • 検索パスの追加
    設定用ヘッダファイルはバイナリツリーに書き込まれます。
    そのため、ヘッダファイルを #include で検索するためには、パスのリストに追加する必要があります。
    CMakeLists.txt の最後に次の行を追加します。
    1. target_include_directories(Tutorial PUBLIC
    2.                            "${PROJECT_BINARY_DIR}"
    3.                            )
  • テンプレートファイル
    設定用ヘッダファイル(TutorialConfig.h)の元となるテンプレートファイル(TutorialConfig.h.in)を作成します。
    1. // チュートリアル用の設定済みオプション
    2. #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
    3. #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
    CMakeがこのヘッダーファイルを生成すると、@Tutorial_VERSION_MAJOR@ と @Tutorial_VERSION_MINOR@ が変数値に置き換えられます。
  • ソースファイルの変更
    tutorial.cxxを変更して、設定用ヘッダーファイル(TutorialConfig.h)をインクルードします。
    以下のように実装することで実行可能ファイルの名前とバージョン番号を出力できます。
    1.   if (argc < 2) {
    2.     // report version
    3.     std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
    4.               << Tutorial_VERSION_MINOR << std::endl;
    5.     std::cout << "Usage: " << argv[0] << " number" << std::endl;
    6.     return 1;
    7.   }

C++規格への対応

  • コードの修正
    tutorial.cxx内のatofをstd::stodに置き換えて、C++11規格の機能を追加します。
    同時に#include <cstdlib>を削除します。
    1.   const double inputValue = std::stod(argv[1]);
  • CMakeLists.txtの修正
    C++11規格を使用する場合、CMakeコード上でも明示的に指定する必要があります。
    特定のC++規格に対応する最も簡単な方法は、CMAKE_CXX_STANDARD変数を使用する方法です。
    このチュートリアルでは、CMakeLists.txtファイルの CMAKE_CXX_STANDARD変数を11に設定し、CMAKE_CXX_STANDARD_REQUIREDをTrueに設定します。
    add_executableの呼び出し前にCMAKE_CXX_STANDARD宣言を必ず追加してください。
    1. cmake_minimum_required(VERSION 3.10)
    2.  
    3. # プロジェクト名とバージョンの指定
    4. project(Tutorial VERSION 1.0)
    5.  
    6. # C++規格の指定
    7. set(CMAKE_CXX_STANDARD 11)
    8. set(CMAKE_CXX_STANDARD_REQUIRED True)

ビルドとテスト

cmakeもしくはcmake-guiを実行して、プロジェクトを構成し、選択したビルドツールでビルをします。

  • ビルドディレクトリの作成
    コマンドから CMakeソースコードの Help/guide/tutorial ディレクトリに移動し、ビルドディレクトリを作成します。
    1. mkdir Step1_build
  • CMakeの実行
    次に、ビルドディレクトリに移動し、CMake を実行してプロジェクトを構成し、ビルドシステムを生成します。
    1. cd Step1_build
    2. cmake ../Step1
  • ビルド
    ビルドシステムを呼び出して、実際にプロジェクトをコンパイル/リンクします。
    1. cmake --build .
  • 動作確認
    最後にビルドしたTutorialコマンドを動作確認しましょう。
    1. Tutorial 4294967296
    2. Tutorial 10
    3. Tutorial

Step2.ライブラリ追加

プロジェクトにライブラリを追加します。
このライブラリには、数値の平方根を計算する独自の実装が含まれています。
このライブラリを追加することで、実行ファイルはライブラリが提供する実装を使用できます。

このチュートリアルでは、ライブラリを MathFunctions というサブディレクトリに置いています。
サブディレクトリには、ヘッダーファイル MathFunctions.h とソースファイル mysqrt.cxx が含まれています。

次の1行の CMakeLists.txt ファイルを MathFunctions ディレクトリに追加します。

  1. add_library(MathFunctions mysqrt.cxx)

To make use of the new library we will add an add_subdirectory() call in the top-level CMakeLists.txt file so that the library will get built. We add the new library to the executable, and add MathFunctions as an include directory so that the mqsqrt.h header file can be found. The last few lines of the top-level CMakeLists.txt file should now look like:

  1. # add the MathFunctions library
  2. add_subdirectory(MathFunctions)
  3.  
  4. # add the executable
  5. add_executable(Tutorial tutorial.cxx)
  6.  
  7. target_link_libraries(Tutorial PUBLIC MathFunctions)
  8.  
  9. # add the binary tree to the search path for include files
  10. # so that we will find TutorialConfig.h
  11. target_include_directories(Tutorial PUBLIC
  12.                           "${PROJECT_BINARY_DIR}"
  13.                           "${PROJECT_SOURCE_DIR}/MathFunctions"
  14.                           )

Now let us make the MathFunctions library optional. While for the tutorial there really isn’t any need to do so, for larger projects this is a common occurrence. The first step is to add an option to the top-level CMakeLists.txt file.

  1. option(USE_MYMATH "Use tutorial provided math implementation" ON)
  2.  
  3. # configure a header file to pass some of the CMake settings
  4. # to the source code
  5. configure_file(TutorialConfig.h.in TutorialConfig.h)

This option will be displayed in the cmake-gui and ccmake with a default value of ON that can be changed by the user. This setting will be stored in the cache so that the user does not need to set the value each time they run CMake on a build directory.

The next change is to make building and linking the MathFunctions library conditional. To do this we change the end of the top-level CMakeLists.txt file to look like the following:

  1. if(USE_MYMATH)
  2.   add_subdirectory(MathFunctions)
  3.   list(APPEND EXTRA_LIBS MathFunctions)
  4.   list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
  5. endif()
  6.  
  7. # add the executable
  8. add_executable(Tutorial tutorial.cxx)
  9.  
  10. target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
  11.  
  12. # add the binary tree to the search path for include files
  13. # so that we will find TutorialConfig.h
  14. target_include_directories(Tutorial PUBLIC
  15.                            "${PROJECT_BINARY_DIR}"
  16.                            ${EXTRA_INCLUDES}
  17.                            )

Note the use of the variable EXTRA_LIBS to collect up any optional libraries to later be linked into the executable. The variable EXTRA_INCLUDES is used similarly for optional header files. This is a classic approach when dealing with many optional components, we will cover the modern approach in the next step.

The corresponding changes to the source code are fairly straightforward. First, in tutorial.cxx, include the MathFunctions.h header if we need it:

  1. #ifdef USE_MYMATH
  2. #  include "MathFunctions.h"
  3. #endif

Then, in the same file, make USE_MYMATH control which square root function is used:

  1. #ifdef USE_MYMATH
  2.   const double outputValue = mysqrt(inputValue);
  3. #else
  4.   const double outputValue = sqrt(inputValue);
  5. #endif

Since the source code now requires USE_MYMATH we can add it to TutorialConfig.h.in with the following line:

  1. #cmakedefine USE_MYMATH

Exercise: Why is it important that we configure TutorialConfig.h.in after the option for USE_MYMATH? What would happen if we inverted the two?

Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool. Then run the built Tutorial executable.

Now let’s update the value of USE_MYMATH. The easiest way is to use the cmake-gui or ccmake if you’re in the terminal. Or, alternatively, if you want to change the option from the command-line, try:

  1. cmake ../Step2 -DUSE_MYMATH=OFF

Rebuild and run the tutorial again.

Which function gives better results, sqrt or mysqrt?