Qt Advent Calendar 2023にちょっと遅刻して投稿です。
QtでもCMakeを使いたい背景
Qt5の時代のビルドシステムは通常はqmake、またはモダンな環境を求めるならQbsという感じでしたが、2020年12月にリリースされたQt6からはCMakeが標準となり、過去の遺産を捨てつつ統一の方向へ向かっているようです。1
JetBrainsによる2023年のビルドシステムに関するアンケートから抜粋
JetBrainsの調査によるとCMakeが6割に届きそうだったのに2023年はちょっとだけ減っています。
とは言え2017年にはVisualStudioがトップでWindows依存度が高かった状況からは良くなっていますね。
昔はqmakeを使ったりQbsのモダンさに惹かれたりしましたが、今時のC++開発ではCMakeを使うのが良さそうだと思いCMakeの最新仕様をちゃんと勉強し始めています。
というわけでこの記事は
- チームの利点として、標準のCMake機能で構築することで各自が自由なIDEを利用できる (建前)
- Qtが快適なQtCreatorと好みのIDE2を両方使いたい (本音)
- あと、Qt以外のライブラリ管理はvcpkg使って、WindowsとMac対応して、テストやインストールもあるそこそこ複雑なプロジェクト管理したい
というだいぶ散らかった内容になります。
単に「VSCodeでCMakeを使いたい」とか「QtCreatorでCMakeを使いたい」だけであれば個別の解説を探した方が早いと思います。
CMakePresets.jsonによるビルド設定の共有
昔はなかった便利機能としてCMakeのプリセット機能があります。
CMakePresets.jsonを置いておくとビルド設定を共有できて、さらにCMakeUserPresets.jsonをgitignoreして置いておくと個別のビルド設定を書くことができます。3
- CMAKE_PREFIX_PATHでQtのパスを通す
- toolchainFileとしてvcpkgを指定する
- WindowsとMac(arm64,x64)
の条件だとこんな感じでしょうか。
"configurePresets": [
{
"name": "Default_Windows",
"hidden": true,
"displayName": "Windows default configuration",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"cacheVariables": {
"CMAKE_PREFIX_PATH": "$env{USERPROFILE}/Qt/6.6.1/msvc2019_64"
},
"toolchainFile": "$env{VCPKG_ROOT}/vcpkg/scripts/buildsystems/vcpkg.cmake"
},
{
"name": "Debug_Windows",
"inherits": "Default_Windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Release_Windows",
"inherits": "Default_Windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "Default_Mac",
"hidden": true,
"generator": "Ninja",
"displayName": "Mac default configuration",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_PREFIX_PATH": "~/Qt/6.6.1/macos"
},
"toolchainFile": "~/vcpkg/scripts/buildsystems/vcpkg.cmake"
},
{
"name": "Default_Mac_ARM64",
"hidden": true,
"inherits": "Default_Mac",
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "arm64"
}
},
{
"name": "Default_Mac_X64_On_ARM64",
"hidden": true,
"inherits": "Default_Mac",
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "x86_64",
"CMAKE_APPLE_SILICON_PROCESSOR": "x86_64",
"VCPKG_TARGET_TRIPLET": "x64-osx"
}
},
{
"name": "Debug_Mac_ARM64",
"inherits": "Default_Mac_ARM64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Release_Mac_ARM64",
"inherits": "Default_Mac_ARM64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "Debug_Mac_X64_On_ARM64",
"inherits": "Default_Mac_X64_On_ARM64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Release_Mac_X64_On_ARM64",
"inherits": "Default_Mac_X64_On_ARM64",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
また、CMakeでoptionを指定している場合は、
option(MY_BUILD_OPTION "Build Option" ON)
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"MY_BUILD_OPTION": "OFF"
}
のようにプリセットごとにON/OFFを切り替えられます。
VSCodeでの利用
CMake Toolsのプラグインを入れておいて、下の方に表示する設定にしておくと選べます。
長すぎるせいか最近の更新で表示設定しないと省略されるようになったかもしれません。左のアイコンにCMake用のやつがいるはずなので基本的な設定はそこからでもできると思います。
実行時にQtのバイナリを見つけられない場合はターミナルで
$env:Path = $env:Path+";C:\Qt\6.6.1\msvc2019_64\bin"
などとして通すと実行できます。
バージョンを複数使う場合は環境変数に追加したくないので手間だけど別途指定してます。もっと良いやり方があると嬉しいのですが。
QtCreatorでの利用
2022年11月ごろのバージョン9で対応しているようです。CMakePresets.jsonのほうはすでにバージョン6とかになっていて進化が早いので最新を使っておいた方がよいと思います。
この使い方で満足した場合は解説は終了です。
CMakePresets.jsonを読み込まずにQtCreatorのKitを使いたい
QtCreatorではQtのバージョンとビルド設定をKitという形で扱っており、これはこれで便利です。
Qtのバージョンが複数あって動作確認のために切り替えることが多くて、さらに今回考慮してませんがiOSなどのモバイル版があったりすると、バージョン管理複雑なのでこういう設定はありがたいです。
チームの全員がCMakePresets.jsonに慣れ親しんでいたら不要かもしれないのですが、やはりIDEの便利設定は楽なので使いたいです。リポジトリ上にCMakePresets.jsonはあるけど、手元ではQtCreatorの独自設定で行う方法を紹介します。
プロジェクト読み込み時
CMake側にプリセットがないときはKitの一覧が並んでいますが、プリセットがあると混合されてちょっとみづらくなります。一旦すべてのチェックを外して、必要なKitにチェックを入れると良いと思います。
Kitに紐付いたCMakeキャッシュ変数を設定する
設定のKitsからCMake Configurationという項目で初期変数を指定できます。
一番下にCMAKE_TOOLCHAIN_FILEを指定したところです。これでQtCreator上でこのバージョンのQtKitを選んだときはvcpkgにもパスが通ります。
プロジェクトごとの初期変数を確認
Kitに紐付けた設定がある場合はビルド設定ページのCMake Initial Configurationに追加されています。
ここではCMakeに渡す前のQtCreator側の変数の解釈とかが行われるようです。
Kitには紐付けずにプロジェクト単位で設定したい場合はここで追加できます。
追加後は下のRe-configure with Initial Parameters
ボタンを押す必要があります。
プロジェクトごとの現在の変数を確認
Initial ConfigurationはQtCreatorが管理してる変数で、CMakeに渡されたあとはCurrent Configurationになります。%{Qt:QT_INSTALL_PREFIX}などの変数は展開されていることがわかります。
オプションがある場合はここで変更することでプロジェクトごとの設定として適用できます。ここでも変更後はRun CMakeしないとキャッシュのせいで変更が適用されなかったりします。
カスタムターゲットやinstallの実行
VSCodeの方だとターゲットやinstallが一覧に出ていて選べるのですが、QtCreatorだと実行形式のみ良い感じに判別してくれてるので、逆に個別のターゲットをビルドしづらくなります。CMakePresets.jsonを使っていればビルドプリセットの方でターゲットを指定したプリセットも作れるようです。(あまりやってないので知らないけど)
ターゲットを指定
ちなみにデフォルトはallぽいですが、Current executableに変更しておくと最小ビルドで実行してくれるので便利です。
実行設定を増やす
複数の設定を切り替えたいときは増やすこともできます。
QtCreatorの場合は実行設定ページでDeploymentのところから設定を増やし、CMake installするステップを追加できます。また、任意のビルドターゲットの指定もできます。
実行するときにどの設定で実行するのかを選べるようになります。
例えば実行して開発するときと配布用のインストーラーを作成するときとでわけたりすると便利です。
まとめ
何を書きたいのか焦点がブレてる記事になってしまったんですが、CMakeプロジェクトをQtCreatorとVSCodeの両方で扱う上でのメモ書きみたいな感じでまとめました。他にも思い出したら追加していくかもしれません。
-
C++全体の傾向としてもVisualStudioもCMake対応を強化しているし、CLionもデフォルトにCMake採用していて、長かったビルドシステム戦国時代も終わるかもしれないし終わらないかもしれません。
まあ多分終わらないし、パッケージマネージャーとかテストフレームワークなども標準化は遠そうです ↩ -
CLionの場合のメモ。プリセットがある場合は自動で読み込んでくれるのですが、一旦CLionがDebugプリセットを用意する -> プリセットを読み込みましたのポップアップ -> 個別に有効にする、というステップでやや回りくどい気がします。MacなのにWindows用のものも候補に出てたりします。
あとQtが自動生成した大量のターゲットが同列に並ぶので見づらいです。
などが不満だったけど最新版ではほぼ直ってました。優秀なIDEだ。 ↩ -
これがないとprivate.cmakeみたいなのをgitignoreしてCMakeLists.txtからincludeするスクリプトを書いたりすることになります。C++を好きになる素質のある人はCMakeのゆるさは嫌いなことが多いので、そういうことを続けるとCMakeおじさんとして孤独に活躍することになります。標準化された方法があるって良いね。 ↩