CMakeで外部ライブラリを導入する方法とその違いについて

◎ 本記事は「CMake講座」シリーズの第5回です。
前回 -> 【第4回】CMakeでビルドタイプとコンパイルオプションを管理しよう!〜Debug/Releaseの理解〜
次回 ->【第6回】CMakeで自作ライブラリをパッケージ化しよう!〜Config / Targets / Version の生成〜

○ シリーズ全体の構成はこちら: CMake講座トップページ

【第5回】CMakeで外部ライブラリを導入しよう!〜find_package / FetchContent / add_subdirectory / ExternalProject_Add〜

前回は、CMakeでビルドタイプやコンパイルオプションを管理する方法を学びました。
今回は実践的なテーマとして、「外部ライブラリの導入方法」を解説します。

C++の開発では、標準ライブラリだけでなく、他人が作った便利なライブラリを活用することが多くあります。
CMakeには、それらを安全かつ再利用しやすく取り込むための機能が標準で備わっています。


1. 外部ライブラリ導入の主な4つの方法

方法用途特徴
find_package()システムにインストール済みのライブラリを利用最も基本的で高速。環境依存がある
add_subdirectory()同梱ライブラリを組み込みソース同梱型に向く
FetchContent外部リポジトリを自動ダウンロード依存解決が容易。モダンCMakeで推奨
ExternalProject_Add()独立した外部プロジェクトをビルドビルドを完全に分離。高度な制御が可能

2. find_package — 既存ライブラリを利用する

find_package() は、既にシステムにインストールされているライブラリをCMakeが自動的に検出し、利用可能にする仕組みです。

例:Eigen3(行列演算ライブラリ)を使う

sudo apt install libeigen3-dev

まずはライブラリをシステムにインストールします。
この時に、cmakeのビルドシステムに対応している多くのライブラリは、
自動的に XXXTargets.cmake XXX-config.cmake といったファイルをインストールします。
これによって以下のように find_package() でパッケージを検索できるようになります。

cmake_minimum_required(VERSION 3.10)
project(UseEigen LANGUAGES CXX)

find_package(Eigen3 REQUIRED)

add_executable(App main.cpp)
target_link_libraries(App PRIVATE Eigen3::Eigen)

find_package(Eigen3 REQUIRED) で、CMakeが /usr/lib/cmake/Eigen3/ などを探索します。
Eigen3::Eigen は「インポートターゲット」と呼ばれる特別な名前で、 CMakeが自動的に include パスやコンパイル設定を適用します。


インポートターゲットの名前を調べるには?

多くのライブラリは、find_package() の後に「パッケージ名::ターゲット名」の形式で提供されます。 たとえば Eigen3::Eigenfmt::fmtspdlog::spdlog のような形です。

どんなターゲットが定義されているかを調べたい場合は、CMakeが生成するログを見るのが確実です。

  • ターミナル出力で「-- Found Eigen3: ...」と表示される行を確認
  • /usr/lib/cmake/Eigen3/Eigen3Targets.cmake などのファイルを開く
  • target_link_libraries() に渡すターゲット名が add_library(... IMPORTED) の形で定義されている

3. add_subdirectory — ソースを直接同梱する

add_subdirectory(lib/mylib)
add_subdirectory(app)

リポジトリにライブラリのソースコードを含める場合は、add_subdirectory() を使うのが最もシンプルです。

project_root/
├── lib/
│   └── mylib/
│       ├── CMakeLists.txt
│       └── mylib.cpp
├── app/
│   └── main.cpp
└── CMakeLists.txt

# lib/mylib/CMakeLists.txt
add_library(MyLib mylib.cpp)
target_include_directories(MyLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

# app/CMakeLists.txt
add_executable(App main.cpp)
target_link_libraries(App PRIVATE MyLib)

◎ この方法は自作ライブラリやチーム内共有ライブラリに最適です。
PUBLIC を指定しているため、リンク先(App)にも自動的に include パスが伝わります。


4. FetchContent — Gitから自動取得する

CMake 3.11以降で導入された FetchContent は、外部リポジトリをビルド時に自動で取得する仕組みです。
依存関係を一括で管理でき、モダンCMakeでは主流の方法となっています。

例:GoogleTestを自動取得

include(FetchContent)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG release-1.14.0
)
FetchContent_MakeAvailable(googletest)

add_executable(App main.cpp)
target_link_libraries(App PRIVATE gtest_main)

初回ビルド時にCMakeが自動的にリポジトリをクローンし、 googletest のターゲット(gtest_main など)が利用可能になります。

FetchContent は内部的に add_subdirectory() を呼び出しており、 取得したソースをそのままプロジェクト内に組み込みます。


5. ExternalProject_Add — 独立ビルドとして外部ライブラリを構築する

ExternalProject_Add() は、外部のソースを「別プロジェクトとして完全に独立してビルド」するための機能です。 他の手法と違い、依存関係のビルドを明確に分離できるのが特徴です。

例:外部ツールを個別ビルド

include(ExternalProject)
ExternalProject_Add(MyExternalLib
  GIT_REPOSITORY https://github.com/example/libsample.git
  GIT_TAG main
  PREFIX ${CMAKE_BINARY_DIR}/external
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/external/install
)

◎ この方法は、外部プロジェクトを完全に別ディレクトリでビルド・インストールしたい場合に便利です。
たとえば大規模なC++アプリで、依存ライブラリのコンパイルを分離して管理するようなケースで用いられます。

ただし、ExternalProject_Add() では生成ターゲットを直接 target_link_libraries() に渡せないため、 リンクには明示的にビルド出力ディレクトリを指定する必要があります。
もしくは、プロジェクトとは完全に別の CMakeLists.txt からビルド、インストールすることで、
そのパッケージを自分のプロジェクト(App)から find_package() するという方法もあります。


6. どの方法を使えばいい?

状況推奨手法
OSパッケージとして提供find_package()
自作・チーム内ライブラリadd_subdirectory()
Gitリポジトリ依存FetchContent
完全独立ビルドが必要ExternalProject_Add()

7. 複合的に使う例

実際のプロジェクトでは、これらを組み合わせて利用することも一般的です。

find_package(fmt REQUIRED)
include(FetchContent)
FetchContent_Declare(spdlog
  GIT_REPOSITORY https://github.com/gabime/spdlog.git
  GIT_TAG v1.14.1
)
FetchContent_MakeAvailable(spdlog)

add_executable(App main.cpp)
target_link_libraries(App PRIVATE fmt::fmt spdlog::spdlog)

この例では、fmt はシステムライブラリとして利用し、 spdlog はFetchContentを使って自動ダウンロードしています。


8. まとめ

手法長所短所
find_package()高速・標準的環境依存
add_subdirectory()柔軟で簡単規模が大きいと管理が複雑
FetchContent依存解決が容易初回ビルドがやや重い
ExternalProject_Add()完全分離・自動構築直接リンクがやや煩雑

◎ CMakeでは、開発規模や目的に応じてライブラリ導入の手法を選ぶことができます。 単体アプリなら find_package()FetchContent、 大規模開発なら ExternalProject_Add() のような明示的管理が有効です。


9. 次回予告

次回は、「CMakeでインストール設定とパッケージ化を行う方法」を扱います。 install()CPack を使って、自作ライブラリを他プロジェクトに再利用できる形で配布する手順を学びます。

◇CMake基礎講座

(第4回:CMakeでビルドタイプとコンパイルオプションを管理しよう)
(第6回:CMakeで自作ライブラリをパッケージ化しよう)

CMake講座トップページに戻る