誰にも見えないブログ

雑なメモ。まとまってない文章等

cmake tutorialその1:プロジェクトバージョン設定、C++規格指定、out-of-sourceビルド

  • 環境
    • ubuntu 18.04
    • cmake 3.16.0-rc3
    • g++ 7.4.0

公式チュートリアルを進めたときの作業記録というかコメンタリー的なものをを適当にブログに起こした。

cmake.org

  • とりあえず「A Basic Starting Point (Step 1)」を全部読んだ。


  • cmake概略
    • 2019年11月時点最新バージョン3.16
    • メタビルドシステム
    • CMakeLists.txtファイルに書いた独自DSLを解釈しそれぞれのプラットフォーム用のビルドファイルmake,visual studio,xcodeを作成する
    • プロジェクトの依存関係やテストの構成なども記述できるのでCLionというIEDはcmake対応前提な作りになっている
    • C++の(メタ)ビルドシステムとして2019年時点で支配的な位置を占めている
      • 仕事でC++書くなら知らないとお話にならないレベル(個人の感想、っていうか俺が今そんなかんじw)
      • アカデミアとかだとまだまだ慣れていない人も多いらしく、今勉強しておいて身につけておくと重宝されるかも。
    • バージョンごとに作法が違うので最低でも3.1以降のやり方を身につけると良さそう。
  • tutorial
    • 公式(再掲)

cmake.org

  • CGold:英語で公式tutorialの足りない部分が補完できる資料

cgold.readthedocs.io

  • 日本語のわかりやすいもの

kamino.hatenablog.com

ステップ1基本

  • A Basic Starting Pointの内容です

  • 以下の内容のCMakeLists.txtを用意します

# 利用するcmakeのバージョン設定
cmake_minimum_required(VERSION 3.10)

#プロジェクト名の設定
project(Tutorial)

#ビルド対象のソースの指定
add_executable(Tutorial tutorial.cxx)
  • command()的なシンタックスのものを"コマンド"という。
    • cmakeを解説する資料での"コマンド"という単語はCMakeLists.txtファイル中に記載するものなのか、shellで叩くものなのか、文脈で区別する必要があるので注意
      • こういうの割と混乱の元
  • cmakeコマンドは大文字、小文字を無視する
    • project(Tutorial)ともPROJECT(Tutorial)ともかける。

  • ビルド対象のC++ソースtutorial.cxx:github
    • 平方根をもとめる簡単なプログラム
// A simple program that computes the square root of a number
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
  if (argc < 2) {
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

  // convert input to double
  const double inputValue = atof(argv[1]);

  // calculate square root
  const double outputValue = sqrt(inputValue);
  std::cout << "The square root of " << inputValue << " is " << outputValue
            << std::endl;
  return 0;
}

プロジェクトへのバージョン番号設定とヘッダファイルへのバージョン情報の書き込み

  • Adding a Version Number and Configured Header Fileの内容です
  • プロジェクトにバージョン番号の追加
    • CMakeListsに以下を記載
# set the project name and version
project(Tutorial VERSION 1.0)
  • バージョン番号はCMakeListsからC++ソースコードconfigure_file()で渡すことが出来ます
configure_file(TutorialConfig.h.in TutorialConfig.h)
  • TutorialConfig.h.inの場所を指定します
    • この設定はCMakeListsの末尾に指定する必要があります。*1
      • 末尾じゃないとビルドできなかった。理由は謎。
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )
  • 設定ファイルTutorialConfig.h.inを作ります
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
  • .h.inファイルの@Tutorial_VERSION_MAJOR@,@Tutorial_VERSION_MINOR@をビルド時にcmakeが書き換えた.hファイルを作成する
$ cat TutorialConfig.h
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0

どのC++規格を利用するのか指定

  • Specify the C++ Standardの内容です
  • CMakeLists.txtに以下を書き足すことでC++11を使うことを明示します
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

初ビルド

  • ビルドの前に最終的なファイル構成、ファイル内容を確認します
  • ファイル
step1/
├── CMakeLists.txt
├── TutorialConfig.h.in
└── tutorial.cxx
  • ファイル内容
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.10)

# set the projetct name
project(Tutorial VERSION 1.0)

configure_file(TutorialConfig.h.in TutorialConfig.h)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

#add the executable
add_executable(Tutorial tutorial.cxx)

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )
  • TutorialConfig.h.in
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
  • tutorial.cxx
// A simple program that computes the square root of a number
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include "TutorialConfig.h"

int main(int argc, char* argv[])
{
  if (argc < 2) {
    // report version
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

  // convert input to double
  const double inputValue = atof(argv[1]);

  // calculate square root
  const double outputValue = sqrt(inputValue);
  std::cout << "The square root of " << inputValue << " is " << outputValue
            << std::endl;
  return 0;
}

ビルド(out of source build)

├── Step1_build  ←ここでビルド
└── step1        ←こっちはビルド時に汚さない!
    ├── CMakeLists.txt
    ├── TutorialConfig.h.in
    └── tutorial.cxx
  • 以下のコマンドを実行すると実行ファイルが作られます
mkdir Step1_build
cd Step1_build
cmake ../Step1
cmake --build .
  • cmakeコマンドを2回実行していることに注目してください。
    • 1回目のコマンドcmake ../Step1でビルドに必要なMakefileやバージョン情報を記載した.hファイルを作っています。
    • 2回目のコマンドcmake --build .で下位のビルドシステム(今回はmake)を使って実行ファイルを作っています。
  • cmake --build .実行前後のディレクトリを見比べてみます

    • ★が付いているのがcmake --buildによって作られたファイルです
$ tree
.
├── CMakeCache.txt
├── CMakeFiles
│   ├── 3.16.0-rc3
│   │   ├── CMakeCCompiler.cmake
│   │   ├── CMakeCXXCompiler.cmake
│   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   ├── CMakeSystem.cmake
│   │   ├── CompilerIdC
│   │   │   ├── CMakeCCompilerId.c
│   │   │   ├── a.out
│   │   │   └── tmp
│   │   └── CompilerIdCXX
│   │       ├── CMakeCXXCompilerId.cpp
│   │       ├── a.out
│   │       └── tmp
│   ├── CMakeDirectoryInformation.cmake
│   ├── CMakeOutput.log
│   ├── CMakeTmp
│   ├── Makefile.cmake
│   ├── Makefile2
│   ├── TargetDirectories.txt
│   ├── Tutorial.dir
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── link.txt
│   │   └── progress.make
│   ├── cmake.check_cache
│   └── progress.marks
├── Makefile
├── TutorialConfig.h
└── cmake_install.cmake

8 directories, 27 files
.
├── CMakeCache.txt
├── CMakeFiles
│   ├── 3.16.0-rc3
│   │   ├── CMakeCCompiler.cmake
│   │   ├── CMakeCXXCompiler.cmake
│   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   ├── CMakeSystem.cmake
│   │   ├── CompilerIdC
│   │   │   ├── CMakeCCompilerId.c
│   │   │   ├── a.out
│   │   │   └── tmp
│   │   └── CompilerIdCXX
│   │       ├── CMakeCXXCompilerId.cpp
│   │       ├── a.out
│   │       └── tmp
│   ├── CMakeDirectoryInformation.cmake
│   ├── CMakeOutput.log
│   ├── CMakeTmp
│   ├── Makefile.cmake
│   ├── Makefile2
│   ├── TargetDirectories.txt
│   ├── Tutorial.dir
│   │   ├── ★CXX.includecache
│   │   ├── DependInfo.cmake
│   │   ├── build.make
│   │   ├── cmake_clean.cmake
│   │   ├── ★depend.internal
│   │   ├── depend.make
│   │   ├── flags.make
│   │   ├── link.txt
│   │   ├── progress.make
│   │   └── ★tutorial.cxx.o
│   ├── cmake.check_cache
│   └── progress.marks
├── Makefile
├── ★Tutorial
├── TutorialConfig.h
└── cmake_install.cmake

8 directories, 31 files
  • もちろん新規に作られたTutorialファイルが実行ファイルです。
  • build中のstdioのログ
Scanning dependencies of target Tutorial
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
  • 実行結果
$ ./Tutorial 1024
The square root of 1024 is 32
  • Versionの表示
$ ./Tutorial 
./Tutorial Version 1.0
Usage: ./Tutorial number

*1:Add the following lines to the end of the CMakeLists.txt file: