メインコンテンツに移動

CMake

CMakeは, VTKと呼ばれる可視化ソフトウェアを開発しているKitWare社が, VTKと共に開発したビルドツールです.VTK以外でも強力であるということで, Linux/Mac/Windows全てで動作するという条件では,まあ我慢できるビルドツールではないでしょうか.

最初の0歩

CMakeを使うには, 特定のフォルダー構造が必要です.すなわち

  • CMakeLists.txt
  • ソースファイル(例えば src とか lib とか)
    • 必要ならばサブフォルダー
  • ビルド用フォルダー(build とか Linux とか)

という感じです.というわけですから, CMakeFiles.txtがあるフォルダーでコンパイルするには

mkdir build
cd build
cmake ..
make

と入力するわけです.すると,貴方が書くよりも遥かにマトモなMakefileをcmakeが書いてくれます.


さいしょの一歩

となるとCMakeLists.txtをどう書けばよいのかにゃ.となるわけです.一例を示う:

cmake_minimum_required(VERSION 3.9)
#必ず最初に!!!プロジェクトと利用言語を宣言
project(BGK CXX)
#言語標準を指定するのよ. 分からんかったら黙って次の通りかけ
set(CMAKE_CXX_STANDARD 17)          # C++17
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)            # C99
set(CMAKE_C_STANDARD_REQUIRED ON)
#もしライブラリーを利用するなら
#     みんな大好きBoost
find_package(Boost 1.70.0 REQUIRED COMPONENTS date_time filesystem .... program_options )
set(Boost_USE_SHARED_LIBS ON)
include_directories( ${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
#       微積分とか常微分方程式とかするならGSL
find_package(GSL)
#       可視化とかするならVTK
find_package(VTK)
include(${VTK_USE_FILE})
#        並列計算するならMPI
find_package(MPI)
#省略不可:あなたが作成するターゲットについて記述!
add_executable(test_SD
     test_SD/SDA.cpp test_SD/spherical_design.cpp
     lib/sql.cpp lib/util.cpp
     )
target_link_libraries(test_SD
     cryptopp mysqlpp log4cplus
     boost_coroutine boost_filesystem boost_program_options
     boost_system boost_thread boost_timer
     gsl gslcblas
     )

これくらいなら見たらわかるわな.青字がプロジェクト, 赤字が各ターゲットについて書く.だから,ユーザーで色々変わるところは青のプロジェクト名と,赤字部分:

add_executable(お前の実行ファイル名 それを構成するソースファイルたち)
target_link_libraries(お前の実行ファイル名 それに必要なライブラリーたち)

だけだろう.コンパイルは:

cd asshole <-- コンパイル用フォルダーに移動して
cmake ..   <-- これで Makefileが作られる
     正常なら, The CXX compiler identification is Intel 16 とか出てくる.
make test_SD <--- これで test_SD が作成される
Scanning dependencies of target BGK
[ 13%] Building CXX object CMakeFiles/BGK.dir/BGK/case.cpp.o
...

文句あっか?ねえよな.Makefileよりも格段に単純である.

  • おっとCMakeLists.txt書き間違ったわ
    • →ビルドフォルダー作り直した方が,精神衛生に良い.
  • %表示なんかいらねえから, 何を実行しているか示せ,という場合には make VERBOSE=1 ... と起動すれば良い.

コンパイルオプション

これは

set(CMAKE_CXX_FLAGS "-Ofast")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -qopenmp")
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -qopenmp")
set(CMAKE_EXE_LINKER_FLAGS "-Ofast")
set(CMAKE_SHARED_LINKER_FLAGS "-Ofast")
set(CMAKE_STATIC_LINKER_FLAGS "-Ofast")

どすえ. どれを使うかわ: cmake -DCMAKE_BUILD_TYPE=Release とかよろしおすな.

  • なんかコンパイルオプション効いてねえ・・・効いてねえぞ?
    • プロジェクト宣言より前に何を書いてもダメですよ.そいつらは,利きません.

コマンドを実行

ビルドでファイル, コピーしたいか,それ使うね add_custom_target だよ:

add_custom_target(installe
   DEPENDS my_program
   COMMAND "cp" "my_program" "/usr/local/sbin/"
)

これ依存解決ですだよ

あるターゲットだけ違うんだけど

あるターゲットでオプションが違う?それ心配ないね.これでよろしあるよ:

set_target_properties(ターゲット名 PROPERTIES
    COMPILE_FLAGS "追加オーダー"
    LINK_FLAGS        "追加オプション" )

追加オーダーだので,デフォルトのフラグに追加されるね.

あるファイルだけ違うんだけど

あるファイルでオプションが違う?追加ならできる:

set_source_files_properties(src/myprog.cpp PROPERTIES
    COMPILE_FLAGS "追加オーダー"
)

問題は,オプションの追加しかできないってことだ.例えばデフォルトで最適化しているとき,あるファイルを最適化しない(デフォルトのオプションを削除する),ということはできない.

なんかバグ回避とかで,最適化したくない場合もあるよね.それは, ソースコードで

#pragma optimize("",off)

で, 再びonにするまでを関数単位で最適化無効にできるよ.つまりoffになってから定義が始まった関数は, 最適化がなくなる.いや,無くなるのはちょいと,というばやい

#pragma optimization_level N

もある. これは pragma intel optimization_level とか pragma gcc optimization_level でもよいのだが,最適化無効ではなく最適化レベルをNにする.

If文など

使う

Package検索を使う

有名なライブラリーは, Package検索者を用いて,ライブラリーを探し出すことができます.

BOOST

find_package(Boost 1.69.0 REQURED COMPONENTS あんたの必要なコンポ) で ${Boost_INCLUDE_DIR) $(Boost_LIBRARY_DIRS) を設定してくれます.あ,1.69.0 というのは最低必要バージョンなのです)

MPI

find_package(MPI) で ${MPI_CXX_INCLUDE_DIRS}, ${MPI_CXX_COMPILE_FLAGS}, ${MPI_CXX_LINK_FLAGS} ${MPI_CXX_LIBRARIES} が設定されます.ので,全てに適用するなら

set(CMAKE_CXX_FLAGS "-qopenmp ..... ${MPI_CXX_COMPILE_FLAGS})
set(CMAKE_EXE_LINKER_FLAGS "${MPI_CXX_LINK_FLAGS}")
include_directories(.... ${MPI_CXX_INCLUDE_DIRS} ....)
target_link_libaries(..... ${MPI_CXX_LIBRARIES} ....)

という感じですね.

GSL

find_package(GSL)で, ${GSL_INCLUDE_DIRS}, ${GSL_LIBRARIES}, ${GSL_VERSION}がゲットできます.

CGAL

find_package(CGAL) で, ${CGAL_USE_FILE}  ${CGAL_LIBRARIES} がげっとできると期待したい.詳しくは神の方がよく知っていると思うぞ

VTK

find_package(VTK REQUIRED)で, ${VTK_USE_FILE}, ${VTK_LIBARIES} がゲットできます.最初のは

include(${VTK_USE_FILE})

をCMakeLists.txtに書けば, 諸般の設定をしてくれるみたいだぞ

他人の設定したオプションを知る

他の人が書いたCMakeLists.txtは,オプションがわかんねえです.そんなときには, ビルドしたフォルダーで

$ ccmake   .     (最後のピリオドを忘れないこと)

と入力すると,良いです.何が起こっているかが一覧されます:

クリックするとなぜか編集できたりします.でもよく見ると・・・CMakeLists.txt にあなたが設定した内容が反映されてない気がしてきます.これは下の「変数」を理解しなければなりません.

CMakeの変数たち

CMakeのフォルダーの構造は

  • CMakeLists.txt が存在する(親)フォルダー
  • ソースコードが入っているフォルダー 例えば src/, myLib/ DoomyPrg/, asshole_lib/...
  • Linux用のビルドフォルダー Linux/
  • Mac用のビルドフォルダー OSX/
  • Windows用のビルドフォルダー Windows/

という感じですね.で, Linux/ で cmake .. と入力すると, そこに CMakeCache.txt ができます.これはなんだというと,「デフォルト値」が設定されているんですね.で,ccmake は CMakeCache.txt を編集するものなのです.実際のコンパイルでは

  1. cmakeがシステムを調べてデフォルト値を設定(システムで適当そうな値)
  2. ccmake でユーザーが変更をしていれば適用 (つまりビルドフォルダー別に設定した値)
  3. CMakeLists.txt で設定した内容で上書き (CMakeLists.txtであんたが設定した内容)
  4. cmake -D変数=値 で設定したもので上書き (その時点のあんたの気分に依存する値)
  5. ここの状態でコンパイル

となります.だから ccmake で表示されているのは, cmakeが思うに,これで良いのでは?というオプションになっているのです.あんたが色々設定してコンパイルするときに何が使われているのか心配になるのであれば,CMakeLists.txt で

message("CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

と書けば, cmake のときに表示してくれるので少しは安心ですね.

特定のファイルだけテストしたい

make ターゲット のコマンドでは,全体のビルドを行います.これはプログラム開発中には面倒ですよね・・・今書いた奴テストしたい,ってのにいちいち全体ビルドでは時間の無駄です.そんな場合には, 

make -f CMakeFiles/プロジェクト.dir/build.make CMakeFiles/プロジェクト.dir/ターゲット/あんたのソースファイル.cpp.o

例: make -f CMakeFiles/BGK.dir/build.make CMakeFiles/BGK.dir/BGK/reg.cpp.o

でコンパイルだけしてくれます.