21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CMakeとIDEを連携させる

Last updated at Posted at 2018-11-29

はじめに

私は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/
       ...
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(myproj CXX)
# ...
add_subdirectory(src)
# ...
src/CMakeLists.txt
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_sourcesadd_subdirectoryを組み合わせて使えば、親ディレクトリで定義したターゲットに対して、子ディレクトリ以下のファイルを再帰的に後から追加していくことが可能となります。
これらのコマンドを使って以下のようにスクリプトを書き換えました。

/---
  |---CMakeLists.txt
  |
  |---include/
  |     |---CMakeLists.txt
  |     |---dir1/
  |     |---dir2/
  |    ...
  |
  |---src/
        |---CMakeLists.txt
        |---dir1/
        |     |---CMakeLists.txt
        |    ...
        |
        |---dir2/
       ...
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(myproj CXX)
# ...
add_library(mylib)
add_subdirectory(include)
add_subdirectory(src)
target_include_directories(mylib PUBLIC include)
# ...
src/CMakeLists.txt
add_subdirectory(dir1)
add_subdirectory(dir2)
# ... 同様に子ディレクトリを追加
src/dir1/CMakeLists.txt
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).

target_sources: CMake Documentation

ん?相対パスを渡すと現在のサブディレクトリに対する相対パスとして解釈される?怪しげな文言が…。でもサブディレクトリで加えているから問題ないはずじゃね?と思ったら、先ほど示したブログで

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を使って絶対パスで指定したら、今度はちゃんとビルドできました。つまり以下のようにしないとダメ:

src/dir1/CMakeLists.txt
target_sources(mylib
  PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
    # ... 同様にソースファイルを追加
)

CMake 3.13〜

CMake3.13からはポリシーCMP0076を使って自動的に絶対パスへ変更することができるようになりました。すなわち、

CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(myproj CXX)
# CMP0076を有効化
cmake_policy(SET CMP0076 NEW)
# ...

としておけば、

src/dir1/CMakeLists.txt
target_sources(mylib
  PRIVATE
    file1.cpp
    file2.cpp
    # ... 同様にソースファイルを追加
)

として問題なくビルドできます。

21
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?