CMakeでFetchContentとfind_packageを使い分ける目安
CMakeで外部ライブラリを使うとき、find_package() で探すのか、FetchContent で取ってくるのか迷うことがあります。
どちらが常に正しいというより、依存関係をどこで管理したいかで分けるのが分かりやすいです。
- すでに環境に入っているライブラリを使う ->
find_package() - プロジェクト側で取得元やバージョンを固定したい ->
FetchContent
公式ドキュメントでも、FetchContent と find_package() の関係は別々の仕組みとして扱われています。
https://cmake.org/cmake/help/latest/module/FetchContent.html
https://cmake.org/cmake/help/latest/command/find_package.html
find_packageを使う場合
find_package() は、インストール済みのパッケージを探すときに使います。
find_package(ZLIB REQUIRED)
add_executable(my_app
src/main.cpp
)
target_link_libraries(my_app
PRIVATE
ZLIB::ZLIB
)
この形は、OSのパッケージマネージャやvcpkg、Conan、SDKなどでライブラリを用意する場合に向いています。
プロジェクト側は「ZLIBが必要」とだけ書き、どこから持ってくるかは環境に任せます。
FetchContentを使う場合
FetchContent は、configure時に外部プロジェクトを取得して、メインのビルドに組み込むための仕組みです。
公式ドキュメントでは、FetchContent_Declare() で取得内容を定義し、FetchContent_MakeAvailable() で使える状態にする流れになっています。
https://cmake.org/cmake/help/latest/module/FetchContent.html
include(FetchContent)
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
FetchContent_MakeAvailable(fmt)
add_executable(my_app
src/main.cpp
)
target_link_libraries(my_app
PRIVATE
fmt::fmt
)
この形は、依存ライブラリの取得元やバージョンをプロジェクト内で固定したい場合に向いています。
ただし、configure時にネットワークアクセスが必要になる点は見ておく必要があります。
使い分けの目安
| 状況 | 使うもの |
|---|---|
| OSやSDKに入っているライブラリを使う | find_package() |
| CIや開発環境で同じバージョンを使いたい | FetchContent |
| クロスコンパイルでsysroot内のライブラリを使う | find_package() |
| 小さな依存をプロジェクトに固定したい | FetchContent |
| パッケージ管理ツールに任せたい | find_package() |
クロスコンパイルでは、基本的にターゲット用のライブラリをsysrootやSDKから探すことが多いため、find_package() の方が自然な場面が多いです。
一方で、ヘッダーオンリーに近いライブラリや、ターゲットごとの差が少ない依存なら FetchContent でも扱いやすいことがあります。
クロスコンパイル時に find_package() がホスト側を見に行く場合は、CMakeのクロスコンパイルでfind_packageがホストを見に行くときの設定 で探索先の設定を整理しています。
FetchContentで気をつけること
GIT_TAG には、ブランチ名よりもタグやコミットハッシュを指定します。
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
)
公式ドキュメントでも、外部から取得する内容について、ブランチ名よりハッシュの方が安全で期待した内容か確認しやすいという説明があります。
https://cmake.org/cmake/help/latest/module/FetchContent.html
ブランチ名を指定すると、同じCMake設定でも日によって取得される内容が変わる可能性があります。
find_packageとFetchContentを混ぜる場合
CMake 3.24以降では、FetchContent_Declare() に FIND_PACKAGE_ARGS などのオプションもあります。
FetchContent_Declare(
fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
GIT_TAG 10.2.1
FIND_PACKAGE_ARGS
)
ただ、最初からここまで使うと分かりにくくなります。
まずは次のどちらかに寄せる方が読みやすいです。
- 環境にあるものを使うなら
find_package() - プロジェクトで取ってくるなら
FetchContent
依存関係が増えてきたら、vcpkgやConanなどのパッケージ管理も含めて見直す形になります。
まとめ
外部ライブラリの扱いは、管理したい場所で分けます。
- 環境やSDKに任せるなら
find_package() - プロジェクト内で取得元とバージョンを固定するなら
FetchContent - クロスコンパイルではターゲット環境のライブラリを探すため、
find_package()を使う場面が多い FetchContentを使うなら、GIT_TAGは固定する
最初は混ぜすぎず、どちらで依存関係を管理するのかを明確にしておくのが扱いやすいです。


