Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

40
31

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 5 years have passed since last update.

[CMake] ライブラリを自動的に探すFind<package>.cmakeのテンプレート

Last updated at Posted at 2018-11-27

はじめに

修正:<package>-config.cmakeが得られる場合はそちらを使うようにという点を追記(@yumetodo さんありがとうございます。)

CMakeには自身のプロジェクトに属していないライブラリを自動的に検索してくれる便利なコマンドfind_packageがあります。
例えばBoostライブラリを自作プログラムで使っている場合、

cmake_minimum_required(VERSION 3.8.2)
project(find_package_example CXX)
find_package(Boost REQUIRED)
add_executable(foo foo.cpp)
target_link_libraries(foo
  Boost::boost
  )

とすればfooをコンパイルする際にBoostライブラリのヘッダーファイルがインクルードされます。

非常に便利なのですが、全てのライブラリに対してfind_packageを使えるわけではありません。
このコマンドを使うには、目的のライブラリを検索するロジックを示すFind<package>.cmakeまたは<package>Config.cmake/<lower-case-package>-config.cmakeがなければいけません。

参考記事:find_packageの動作

基本的にC/C++ライブラリの作成側がこれらのスクリプトを提供するべきです。
CMakeが<package>-config.cmakeを自動作成する機能を提供していますので、そちらを使いましょう。

参考記事:お手軽な xxx-config.cmake の作成方法

ただ提供されていない場合は自作する必要があります。
ここに必要最小限の要素に絞ったFind<package>.cmakeのテンプレートを載せておきますので、参考にしてください。
より細かく設定したい場合(プラットフォームやバージョンを考慮するなど)は、CMake自身が提供するスクリプト(例えばFindPNG.cmake)を参考にしてください。

参考:C++Now 2017: Daniel Pfeifer “Effective CMake"

Find<package>.cmakeを作成したら、CMAKE_MODULE_PATHにそのスクリプトを置いてあるディレクトリを追加します。

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} <path-to-dir>)

これだけでfind_package(<package>)が使えるようになります。
例えば下の例のスクリプトを使うと

# プロジェクトのルートディレクトリ下にあるcmakeというディレクトリに
# FindGMP.cmakeを置き、そのディレクトリを登録
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)

# ライブラリを検索
find_package(GMP REQUIRED)

add_executable(myapp main.cpp)
# myappにGMPをリンク
target_link_libraries(myapp GMP::GMP)

とできるようになります。

自作したFind<Package>.cmakegithubにアップしていますので、自由に利用してください。現在利用可能なパッケージは以下の通りです。

  • CGAL(The Computational Geometry Algorithms Library)
  • GMP(The GNU Multiple Precision Arithmetic Library)
  • MPFR(The GNU MPFR Library)
  • Microsoft GSL
  • Spdlog

テンプレート

必要最低限のコマンドからなるFind<package>.cmakeは以下のとおりです。

find_path(<package>_INCLUDE_DIR ...)
find_library(<package>_LIBRARY ...) # ヘッダーのみのライブラリの場合は不要
mark_as_advanced(
  <package>_INCLUDE_DIR
  <package>_LIBRARY     # ヘッダーのみのライブラリの場合は不要
  )

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(<package>
  REQUIRED_VARS
    <package>_INCLUDE_DIR
    <package>_LIBRARY      # ヘッダーのみのライブラリの場合は不要
  )

if(<package>_FOUND AND NOT TARGET <package>::<package>)
  add_library(<package>::<package> UNKNOWN IMPORTED)
  set_target_properties(<package>::<package> PROPERTIES
    IMPORTED_LINK_INTERFACE_LANGUAGES ["C"|"CXX"]  # ヘッダーのみのライブラリの場合は不要
    IMPORTED_LOCATION "${<package>_LIBRARY}"       # ヘッダーのみのライブラリの場合は不要
    INTERFACE_INCLUDE_DIRECTORIES "${<package>_INCLUDE_DIR}"
    )
endif()

以下の例ではUNIXのみ考慮しています。

コンパイル済みライブラリ

例えばGMPライブラリを探すスクリプトは以下の通りになります。

FindGMP.cmake
# インクルードディレクトリのパスをgmp.hを頼りに検索する
find_path(GMP_INCLUDE_DIR gmp.h
  # 検索するパス
  PATHS
    # 環境変数GMP_ROOTまたはGMP_INCLUDE_DIRが存在したらそこを検索
    ENV GMP_ROOT
    ENV GMP_INCLUDE_DIR
    # CMakeの変数としてGMP_ROOTが定義されていたらそこを検索
    ${GMP_ROOT}
    /usr
    /usr/local
  PATH_SUFFIXES
    include
  )
# ライブラリへのパスをライブラリ名を元に検索する
find_library(GMP_LIBRARY
  NAMES
    gmp
  PATHS
    ENV GMP_ROOT
    ENV GMP_LIB_DIR
    ${GMP_ROOT}
    /usr
    /usr/local
  PATH_SUFFIXES
    lib
  )
# advancedモードでない限り変数の存在を隠す
mark_as_advanced(GMP_INCLUDE_DIR GMP_LIBRARY)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GMP
  REQUIRED_VARS
    GMP_INCLUDE_DIR
    GMP_LIBRARY
  )

# GMPが見つかり、かつGMP::GMPが定義されていない場合
if(GMP_FOUND AND NOT TARGET GMP::GMP)
  # GMP::GMPというターゲット名でGMPライブラリを定義
  # UNKNOWN = STATIC/SHAREDかはまだ不明
  # IMPORTED = このプロジェクトに属さないターゲット
  add_library(GMP::GMP UNKNOWN IMPORTED)
  set_target_properties(GMP::GMP PROPERTIES
    # C言語、C++なら"CXX"とする
    IMPORTED_LINK_INTERFACE_LANGUAGES "C"
    IMPORTED_LOCATION "${GMP_LIBRARY}"
    INTERFACE_INCLUDE_DIRECTORIES "${GMP_INCLUDE_DIR}"
    )
endif()

ヘッダーのみのライブラリ

例えばEigenライブラリを探すスクリプトは以下のとおりです。
(CMakeを使ってEigenライブラリをインストールすると、Eigen3Config.cmakeが自動作成されるので、本当は作る必要はありません。)

FindEigen.cmake
find_path(EIGEN_INCLUDE_DIR Eigen/Core
  PATHS
    ENV EIGEN_ROOT
    ENV EIGEN_INCLUDE_DIR
    ${EIGEN_ROOT}
    /usr
    /usr/local
  PATH_SUFFIXES
    include
  )
mark_as_advanced(EIGEN_INCLUDE_DIR)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Eigen
  REQUIRED_VARS EIGEN_INCLUDE_DIR
  )

if(Eigen_FOUND AND NOT TARGET Eigen::Eigen)
  # EigenはヘッダーのみのライブラリなのでINTERFACEキーワードを指定する
  add_library(Eigen::Eigen INTERFACE IMPORTED)
  set_target_properties(Eigen::Eigen PROPERTIES
    INTERFACE_INCLUDE_DIRECTORIES "${EIGEN_INCLUDE_DIR}"
    )
  # set_target_propertiesのかわりにtarget_include_directoriesを使ってもOK
  # target_include_directories(Eigen::Eigen INTERFACE ${EIGEN_INCLUDE_DIR})
endif()
40
31
5

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

@shohirose's pickup articles

shohirose

@shohirose(広瀬 翔)

2015年8月からテキサス大学オースティン校の石油工学科博士課程に留学し、2019年12月にPhDを取得しました。現在は東京に住んで東京本社で働いています。専門は貯留層工学、フラクチャー力学、数値計算あたりです。プログラミング言語はc++, matlab, pythonを主に使用しています。

Linked from these articles

Comments

yumetodo
@yumetodo

なおxxx-config.cmakeを吐かせて別途Findxxx系書くなとのお達しが出ている模様。

1
shohirose
@shohirose(広瀬 翔)

@yumetodo さん
教えてくださりありがとうございます。そんな通達が出ていたのですね。知らなかった…:sweat:
確認ですが、それはCMakeを使ってビルドしているプロジェクトの場合ですよね?

0
yumetodo
@yumetodo

find()から捜索されるときに結果としてFindxxxが使われると、ですね。

CMake Error at CMakeLists.txt:34 (find_package):
  By not providing "FindIUTEST.cmake" in CMAKE_MODULE_PATH this project has
  asked CMake to find a package configuration file provided by "IUTEST", but
  CMake did not find one.
  Could not find a package configuration file provided by "IUTEST" with any
  of the following names:
    IUTESTConfig.cmake
    iutest-config.cmake
  Add the installation prefix of "IUTEST" to CMAKE_PREFIX_PATH or set
  "IUTEST_DIR" to a directory containing one of the above files.  If "IUTEST"
  provides a separate development package or SDK, be sure it has been
  installed.

こういうの

0
shohirose
@shohirose(広瀬 翔)

私も昨晩初めてFindxxxを書いていたとき同じエラーメッセージが出ました。
それは結局スクリプトのミスが原因だとわかったのですが、yumetodoさんの場合はスクリプト単純で問題なさそうですし何ででしょう???

0
shohirose
@shohirose(広瀬 翔)
(Edited)

@yumetodo さん
今気づいたんですが、iutestはヘッダーのみで、かつこのプロジェクトのライブラリですよね?
find_packageを使わず、Microsoft/GSLのようにadd_libraryを使えばいいような気が…

iutest/CMakeLists.txt
add_library(IUTEST INTERFACE)
target_include_directories(IUTEST
  INTERFACE include
  )
1

Let's comment your feelings that are more than good

Qiita Advent Calendar is held!

Qiita Advent Calendar is an article posting event where you post articles by filling a calendar 🎅

Some calendars come with gifts and some gifts are drawn from all calendars 👀

Please tie the article to your calendar and let's enjoy Christmas together!

40
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address