はじめに
私はCMakeを使って研究用の自作ライブラリをビルドしているのですが、普段IDE(Visual Studio, Xcode, Code::Blocksなど)を使っている学生が使いやすいようにCMakeをIDEと連携させる方法を調べて試したので、ここにまとめておきます。
CMakeにIDEのプロジェクトファイルを生成させる方法
CMakeにはbuild system generatorを指定するオプション-G
があります。
$ cmake -G <generator> -S . -B build
CMake Documentation >> cmake(1)
CMake Documentation >> cmake-generators(7)
Code::Blocks
プロジェクトのルートディレクトリ下で以下のコマンドを打ち込めば<project>.cbp
が生成されます。
$ cmake -G "CodeBlocks - Unix Makefiles" -S . -B build
Unix Makefiles
の部分は、他のgeneratorに差し替え可能です。
CMake Documentation >> cmake-generators(7) >> CodeBlocks
Sublime Text 2
Sublime Text 2の場合は
$ cmake .. -G "Sublime Text 2 - Unix Makefiles" -S . -B build
Code::Blocksと同様に、Unix Makefiles
の部分は、他のgeneratorに差し替え可能です。
CMake Documentation >> cmake-generators(7) >> Sublime Text 2
Xcode
XcodeもCode::Blocksと同様にコマンドラインからプロジェクトファイルを作成できます。
$ cmake -G Xcode -S . -B build
Visual Studio
Visual Studioの場合はVisual Studio上で目的のプロジェクトフォルダを開けばIDE上で操作できます。
CMakeを使ってVisual Studioのプロジェクトファイルを生成することもできます。
$ cmake -G "Visual Studio 17 2022" -S . -B build
Documentation >> cmake-generators(7) >> Visual Studio 17 2022
はまったところ
ヘッダーファイルがプロジェクトツリーに表示されない
はじめにCode::Blocksのプロジェクトファイルを生成してみたところ、ソースファイルはプロジェクトのツリーに表示されるのに、ヘッダーファイルは表示されませんでした。(ビルドはできましたが。)
調べると、ヘッダーファイルをCMakeのターゲットのソースとして加えないとIDEのプロジェクトツリーに正しく表示されないということがわかりました。
file(GLOB)
を使わずにヘッダー/ソースファイルをターゲットに追加する
つい最近知ったCMakeスクリプトを作成する際のガイドラインに、IDEを使う場合はfile(GLOB)
を使うべきではないというものがあったので、この機会にfile(GLOB)
を使わないようにスクリプトを書きなおそうとしました。
書き直す前のプロジェクトはこんな感じ:
/---
|---CMakeLists.txt
|
|---include/
| |---dir1/
| |---dir2/
| ...
|
|---src/
|---CMakeLists.txt
|---dir1/
|---dir2/
...
cmake_minimum_required(VERSION 3.0)
project(myproj CXX)
# ...
add_subdirectory(src)
# ...
file(GLOB_RECURSE SRC_FILES "*.cpp")
add_library(mylib ${SRC_FILES})
target_include_directories(mylib
PUBLIC ${PROJECT_SOURCE_DIR}/include
)
# ... 以下色々設定
CMake 3.12まで
ぱっと調べて出てきた方法は、ソースファイルとヘッダーファイルごとに変数を作成してファイルを追加していく方法なのですが、変数を使い過ぎないというガイドラインがあるので、この方法はよろしくありません。代わりにtarget_sources
を使うという方法を見つけました。
target_sources
とadd_subdirectory
を組み合わせて使えば、親ディレクトリで定義したターゲットに対して、子ディレクトリ以下のファイルを再帰的に後から追加していくことが可能となります。
これらのコマンドを使って以下のようにスクリプトを書き換えました。
/---
|---CMakeLists.txt
|
|---include/
| |---CMakeLists.txt
| |---dir1/
| |---dir2/
| ...
|
|---src/
|---CMakeLists.txt
|---dir1/
| |---CMakeLists.txt
| ...
|
|---dir2/
...
cmake_minimum_required(VERSION 3.0)
project(myproj CXX)
# ...
add_library(mylib)
add_subdirectory(include)
add_subdirectory(src)
target_include_directories(mylib PUBLIC include)
# ...
add_subdirectory(dir1)
add_subdirectory(dir2)
# ... 同様に子ディレクトリを追加
target_sources(mylib
PRIVATE
file1.cpp
file2.cpp
# ... 同様にソースファイルを追加
)
include
ディレクトリ以下でもsrc
ディレクトリと同様に子ディレクトリとヘッダーファイルを追加しています。
ところがビルドするとtarget_sources
を使って追加したファイルが見つからない_というエラーが出てビルドできませんでした。なぜだろうと思ってドキュメントをよく読むと、
Specify sources to use when compiling a given target. Relative source file paths are interpreted as being relative to the current source directory (i.e. CMAKE_CURRENT_SOURCE_DIR).
ん?相対パスを渡すと現在のサブディレクトリに対する相対パスとして解釈される?怪しげな文言が…。でもサブディレクトリで加えているから問題ないはずじゃね?と思ったら、先ほど示したブログで
In the target_sources() command above, each of the sources is prefixed by the directory of the CMakeLists.txt file. This is necessary because the list of source files that are added to a target are interpreted by CMake as being relative to the directory in which the target is defined (i.e. where the add_library() call is made).
Enhanced source file handling with target_sources() by Craig Scott
相対パスって__ターゲットを定義したディレクトリに対する相対パス__かよ!target_sources
を行っているディレクトリじゃないのねorz
というわけで、CMAKE_CURRENT_SOURCE_DIR
を使って絶対パスで指定したら、今度はちゃんとビルドできました。つまり以下のようにしないとダメ:
target_sources(mylib
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
# ... 同様にソースファイルを追加
)
CMake 3.13〜
CMake3.13からはポリシーCMP0076を使って自動的に絶対パスへ変更することができるようになりました。すなわち、
cmake_minimum_required(VERSION 3.13)
project(myproj CXX)
# CMP0076を有効化
cmake_policy(SET CMP0076 NEW)
# ...
としておけば、
target_sources(mylib
PRIVATE
file1.cpp
file2.cpp
# ... 同様にソースファイルを追加
)
として問題なくビルドできます。