PROFESSINAL CMAKE : A PRACTICAL GUIDEとは
CMake参考書紹介(2022年時点)という記事で,この電子書籍を読んでクロスプラットフォームの環境構築ができたということが書いてありました.
これを受けて,試しに無料で公開されている部分を読んで要約してみたというものです.
この本は全部で7パートから構成されており,そのうち1パート目が無料で公開されています.
その無料で公開されている部分の各チャプターに何が書いてあるのかをメモの代わりに要約しています.
概要を理解し読む気を起こすための記事なので,きちんとした内容は実際にこの公開されているものを読みに行ってください.
その3
その3では,Chapter4をまとめます.
ここでは,CMakeのライブラリについて説明しています.
Chapter 4. Building Simple Targets
以前の章では,add_executable()を使ってシンプルなビルドをする例を示した.
この賞では,この関数にオプションを追加して様々なプラットフォームに対応する方法を説明する.
CMakeの特徴はライブラリのリンクを管理できることだ.
static, shared, module, frameworkなどのライブラリをサポートしている.
このChapterでは,主にそれらの機能を説明する.
4.1 Executables
以下がadd_executable()のすべてのコマンドだ.
add_executable(targetName [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...]
)
-
WIN32
Windows GUIアプリを作成する際のコマンドである.
なので実際,WinMain()が実行ファイルになる.
他のプラットフォームでは,WIN32のコマンドは無視される. -
MACOSX_BUNDLE
これは,MacOSやIOSをビルドするためのコマンドである.
CMakeは,基本的なバンドルのためのInfo.plistを生成する.
詳細は,Section 25.2で説明する.
他のプラットフォームでは,MACOSX_BUNDLEは無視される. -
EXCLUDE_FROM_ALL
基本的には,すべてのターゲットがビルドされる.
しかし,デベロッパーツールなどたまにしか必要ないものもある.
その場合,このコマンドを付けるとビルドから除外される.
加えて,実行ファイルを作るのではなく既存の実行ファイルに一種の参照を加えることもできる.
これについては,Chapter 19で説明する.
以下は本Chapterの例である.
# Main GUI app, built as part of the default "ALL" target
add_executable(MyApp WIN32 MACOSX_BUNDLE
main.cpp
widgets.cpp
)
# Helpful command-line tools, not built by default
add_executable(checker checker.cpp EXCLUDE_FROM_ALL)
add_executable(reporter reporter.cpp EXCLUDE_FROM_ALL)
以下の命令では,MyAppのみビルドされる.
cmake --build /path/to/build
以下の命令では,checkerもビルドされる.
cmake --build /path/to/build --target checker
4.2 Defining Libraries
CMakeでは,add_library()を使ってライブラリを定義する.
これにより,環境に寄らず同じコードでライブラリを定義できる.
add_library(targetName [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...]
)
targetNameとEXCLUD_FROM_ALLの働きはadd_executable()と同じ働きである.
対応するライブラリは,static, shared, moduleの三種類である.
-
STATIC
Windowsでは,targetName.lib, Unix系ではlibtargetName.aが出力される -
SHARED
Windowsでは,targetName.dll, Mac系では,libtargetName.dylib,Unix系ではlibtargetName.soが出力される.
詳しくは,Section 25.3 "Frameworks"で説明する. -
MODULE
直接リンクするのではなく,実行時に動的にロードされるコンポーネント.
ライブラリの種類は,指定する必要はない.
特に必要なければ指定せず,CMakeコマンドの引数にすべきだ.
以下で,-DBUILD_SHARED_LIBS=YESとするとSHARDになる.
そうでなければ,STATICになる.
cmake -DBUILD_SHARED_LIBS=YES -B /path/to/build
4.3 Linking Targets
CMakeでは,ライブラリのリンク関係を記述することができる.
その記述例は以下の通りである.
target_link_libraries(targetName
<PRIVATE|PUBLIC|INTERFACE> item1 [item2 ...]
[<PRIVATE|PUBLIC|INTERFACE> item3 [item4 ...]]...
)
ここでは,ライブラリAとBの関係性を例に挙げて説明する.
-
PRIVATE
プライベートは,AはBを内部実装して使うことを意味する.
(おそらく,C++における内部結合の使い方である) -
PUBLIC
パブリックは,AはBを内部的に使うだけでなく,Bをインターフェイスとしても使う.
この場合,AはBに完全に依存する.
(おそらく,C++の外部結合の使い方である) -
INTERFACE
インタフェイスは,AがBを内部的に使うのではなく,インターフェイスのみ使う.
後のChapterで他にもtarget_…()というコマンドが出てくる.
これらは,依存関係の追加情報として,ヘッダーのパス,コンパイルの定義などのオプションを追加できる.
これらの機能は,CMake 2.8.11 - 3.2で追加された.
3.12以前のCMakeを使う場合は,ライブラリのディレクトリに縛りがあるので注意が必要だ.
4.4 Linking Non-targets
ここまでのCMakeは,CMake内でリンクをしてきた.
一方,CMakeのtarget_link_libraries()はさらに柔軟にライブラリのリンクができる.
- Full path to a library file
CMakeはリンカーコマンドにライブラリファイルを追加する.
これにより,ライブラリのファイルが変わった時CMakeはそのターゲットを自動で再リンクする. - Plain library name
パスを指定しないで,ライブラリ名を指定するとそのライブラリを探しに行く.
これは推奨されないときもあり,詳細はSection18.1で説明する. - Link flag
-で始まる-lか-framework以外は,リンカコマンドに追加するフラグとして働く.
使わない方が良い.
4.5 Old-style CMake
古いCMakeの解説なので省略する.
使用しない方がいいらしい.
4.6 Recommended Practices
ターゲット名はプロジェクト名と関係する必要はない.
また,ターゲット名とプロジェクト名はほぼ変わらないので変数にしない方が良い.
(変えるとそれに依存するものが影響を受ける)
以下に悪い例と良い例を示す
# BAD: Don't use a variable to set the project name, set it directly
set(projectName MyExample)
project(${projectName})
# BAD: Don't set the target name from the project name
add_executable(${projectName} ...)
# GOOD: Set the project name directly
project(MyProj)
# BAD: Don't set the target name from the project name
add_executable(${PROJECT_NAME} ...)
# GOOD: Set the project name directly
project(MyProj)
# GOOD: Target name is independent of the project name
add_executable(MyThing ...)
ライブラリのターゲットにlibと付けるとWindows以外の環境で最初にlibとついてダサくなる.
(liblibsomething...みたいなw)
STATICとSHAREDのコマンドは,そのライブラリがどちらかで決まり出ない限り使わない.
ビルド時のBUILD_SHARED_LIBSで指定できる.
古いCMake構文だとすべてpublicになっていたので,target_link_libraries()を呼ぶときはpoblic, private, interfaceを指定する.
このキーワードを記述すると,後にターゲット間の依存関係をどう処理するかに強い影響を与える.
感想
一部,なじみの無い概念がでてきてわからなかった(INTERFACEの概念など).
わかる人で間違えていたら遠慮なく指摘してほしい.