-
-
Notifications
You must be signed in to change notification settings - Fork 86
CMakeを使用した実行手順
以下、yumetodoさんによる解説。
cmakeの3.10.0以降というわりと新しめのが必要です。これはVS2017以降での/std:
に対応するためです。
MSVC standard version switches (#16482) · Issues · CMake / CMake · GitLab
aptとかyumとかで落ちてくるのだと古いかもしれません。公式サイトから拾ってきてください。linuxでインストールするときはporgを使うとなんちゃってパッケージ管理ができてよいです。Windowsではmsys2のpacmanかchocolateyで入れると良いです。
DungeonTemplateLibrary/
に移動します。
mkdir build
cd build
cmake ..
make ci
でサンプルのコンパイル&実行ができます。コンパイルだけしたい場合はmake sample
です。
WindowsのMSYS2環境下ではcmakeのオプションに-G "MSYS Makefiles"
が必要です。
makeには必要に応じて-j4
などをつけて並列化してください。自分の環境では3倍も時間が短縮できました。
特にWindowsだとGNU Makeがちょっと遅いのでかわりにNinjaを使って
mkdir build
cd build
cmake -G "Ninja" ..
ninja ci -j4
などとできます。
Release buildがしたい場合はcmakeに-DCMAKE_BUILD_TYPE=Release
を渡してください。
標準C++のバージョンを変えたい場合はDCMAKE_CXX_STANDARD=14
とかしてください。14
より前を入れるとエラーになるようにしています。何も渡さないといい感じに新しいやつを使うようになっています(C++20は勝手には有効になりません)C++11も使いたいという場合は/cmake/modules/DecideCXXStandard.cmake
の
if(CMAKE_CXX_STANDARD LESS 14)
message(FATAL_ERROR "Specify C++14 or later")
endif()
をいじってください。
gccじゃなくてclangが使いたいんじゃ、という場合はcmakeに-DCMAKE_CXX_COMPILER=clang++
を渡してください。
msvcがいいんじゃって場合はcmake-guiからいい感じにやってください(説明放棄。Clang CodeGenやfafnirで入れたclangを呼び出す場合も
-T
で当該toolset名を渡してください。自分はやってないけど動くんじゃないですかね?
使う機会があるかは謎ですが一応make install
できるようになっています。prefixはcmakeに-DCMAKE_INSTALL_PREFIX=/path/to/prefix
を渡してください。
この項はcmakeの公式documentを参考に読みすすめてください。
cmakeの構築の方針ですが、まずライブラリはxxx-config.cmake
を提供するべし、という最近の原則に則っています。ナニソレオイシイノという場合は
お手軽な xxx-config.cmake の作成方法
を参照してください。
ただ、ヘッダーオンリーなので自動生成はかえって面倒だなと思っていたところ、C++の単体テストフレームワークであるiutest https://github.com/srz-zumix/iutest がいい感じにしていたので採用しました。
xxx-config.cmake
、つまり今回はdtl-config.cmake
を手動で書くのですが、これがメンテナンスされているという保証が必要です。今回で言えば、サンプルコードをビルドする時のinclude pathの設定を多少冗長でもわざわざこれを利用して設定するようにします。
まず
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER)
のようにしてシステムに既にインストールされているDTLを見ないようにした上で、
find_path(DTL_ROOT_DIR
NAMES include/DTL.hpp
HINTS
${CMAKE_CURRENT_SOURCE_DIR}/../../../
NO_DEFAULT_PATH
)
DTLのporject rootを探し(set(DTL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../)
で良かった気もするが一応)
set(DTL_DIR ${DTL_ROOT_DIR})
list(APPEND CMAKE_PREFIX_PATH ${DTL_ROOT_DIR})
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../)
list(APPEND CMAKE_PREFIX_PATH ${DTL_ROOT_DIR}/cmake/modules)
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/modules)
list(APPEND CMAKE_MODULE_PATH ${DTL_ROOT_DIR}/cmake/modules)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake/modules)
find_package(DTL REQUIRED)
のようにdtl-config.cmake
を呼び出してDTL_INCLUDE_DIR
変数にinclude dirが入るようにしました。
cmakeの変数のスコープはかなりアクロバティックで、原則directoryごとにスコープがあります。 ref: CMake: 変数のスコープ - Qiita
今回
- Sample
- DTL
- Shape
- Storage
- DTL
のような階層構造になっているので、これに合わせるために各directoryにCMakeLists.txt
を作成し、add_subdirectory
で下のdirectoryを指定するようにしています。
原則project rootのCMakeLists.txt
をみてコンパイルしますが(上の手順もそれで解説している)、一応それぞれ独立して動けるようにはなっているはずです(非推奨)。
これは出力ファイルがないので話が簡単で、add_custom_target
のCOMMAND
にadd_executable
で指定した名前${target}
を指定するだけで実行してくれます。あとは
add_custom_target(sample_DTL_Shape)
add_custom_target(run_sample_DTL_Shape)
として、
add_dependencies(sample_DTL_Shape
${target}
)
add_dependencies(run_sample_DTL_Shape
run_${target}
)
でグループ化しています。上の階層でもadd_custom_target
でターゲットをグループ化することで最終的にsample
とrun_sample
に集約されて、将来testが書かれることを想定してこれとまとめるためのci
を用意しています(ci
は今の所run_sample
しか実行しない)
これは実行時に出力ファイルがあります。
幸いにして出力ファイルが1つだけだったので良かったですが、これが複数あったら生成ファイルをmake clean
に引っ掛けるために血反吐を吐きつつ汚いハックが必要でした。
でどうしたかというと
add_custom_target(run_${target}
SOURCES ${output_name}
COMMENT "Execute produced executable."
)
add_custom_command(
OUTPUT ${output_name}
COMMAND ${target}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${target}
)
のようにadd_custom_target
とadd_custom_command
の合わせ技で乗り切っています。
ref: CMake: カスタムターゲットによるグループ化 - Qiita
あとは上と同じですね。
ところで${output_name}
はどうやって生成しているのでしょうか?
FileXXX.cpp
というファイルをコンパイルして実行するとfile_sample.xxx
が生成されるという規則性を利用します(このための #17 )
string(REGEX REPLACE "File([A-Z]+)" "file_sample.\\1" output_name_base ${target})
string(TOLOWER ${output_name_base} output_name)
つまり正規表現でXXX
を引っ張って、次に小文字に変換しています。一行で書けそうな気もしますが、私の技術力では無理です(ぇ。
Copyright (c) 2018-2021 As Project.
Distributed under the Boost Software License, Version 1.0.(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)