C++
CMake

CMakeの使い方(その3)

はじめに

CMakeを使い始めて色々と学んだことを少しずつまとめています。今までの記事はこちら:

今回はビルドに必要なライブラリを自動的にインストールする機能の紹介です。個人的に最もCOOLだと思った機能です。

ステップ6:ライブラリを自動ダウンロード&ビルド

実行ファイルをビルドするために、デフォルトでインストールされていないライブラリが必要だとします。CMakeにはビルドに必要なライブラリを自動的にダウンロードしてビルドするExternalProject_Add関数があります。

ExternalProject_Add関数の基本

ExternalProject_Add(<target name> [<option> ...])

非常に多くのオプションがあるので、詳しくはドキュメントをあたってください。ここではよく使うものだけ紹介します。

GitHub等からダウンロードしてライブラリをビルドする場合

例えばGoogleTestを自動的にダウンロード&ビルドしたいとすると、こんな感じの書き方になります。

# ExternalProject_Addを使えるようにするためのおまじない
include(ExternalProject)

# GoogleTestをビルドするディレクトリを指定
#(ここではビルドディレクトリ内のgtest)
set(GTEST_BUILD_DIR ${CMAKE_BINARY_DIR}/gtest)
# GoogleTestをインストールするディレクトリを指定
# (ここではプロジェクトルートディレクトリ内のgtest)
set(GTEST_INSTALL_DIR ${CMAKE_SOURCE_DIR}/gtest)
# GoogleTestのヘッダファイルがあるディレクトリ
set(GTEST_INCLUDE_DIR ${GTEST_INSTALL_DIR}/include)
# GoogleTestの静的ライブラリがあるフォルダ
set(GTEST_LIB_DIR ${GTEST_INSTALL_DIR}/lib)

# GoogleTestはpthreadが必要なのでCMakeに探してもらう
find_package(Threads REQUIRED)

# GoogleTestを外部プロジェクトとして追加
ExternalProject_Add(googletest
        # ダウンロードするURLを指定
        URL https://github.com/google/googletest/archive/release-1.8.0.tar.gz
        # GoogleTestをビルドするディレクトリを指定
        PREFIX ${GTEST_BUILD_DIR}
        # GoogleTestをダウンロードして解凍した後、cmakeを実行するときに渡される引数
        # この例の場合、自分で`cmake -DCMAKE_INSTALL_PREFIX=...`とするのと同じ
        # cmakeで元々定義されている変数(CMAKE_CXX_FLAGS)やライブラリで定義されている
        # 変数を使用可能。引数の頭に`-D`をつけて与えることを忘れずに!
        CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${GTEST_INSTALL_DIR}
    )

# GoogleTestにgtestという名前をつけ、外部の(=このプロジェクトでビルド方法を定義しない)
# 静的ライブラリとして登録
add_library(gtest IMPORTED STATIC GLOBAL)
# gtestに対応する静的ライブラリのファイルとその依存ライブラリpthreadを指定
set_target_properties(gtest PROPERTIES
    IMPORTED_LOCATION ${GTEST_LIB_DIR}/libgtest.a
    IMPORTED_LINK_INTERFACE_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}
)

# gtest_mainも必要な場合はadd_libraryからset_target_propertiesまでの
# gtestをgtest_mainに書き換えて追加する

それぞれのライブラリで独自に指定している変数を知りたければ、それぞれのライブラリのルートディレクトリでcmake -Lとすれば表示されます。

add_library(gtest ...)としたことで、実行ファイルへ簡単にリンクできます:

add_executable(<target> <sources>)
target_link_libraries(<target> gtest)

共有ライブラリの場合はSTATICSHAREDに変えてあげましょう。
また、GTEST_BUILD_DIRGTEST_INSTALL_DIRキャッシュ変数にすれば、cmake -Lとしたときやccmakeを使ってconfigureするときに変数が表示されるようになります:

set(GTEST_INSTALL_DIR ${CMAKE_SOURCE_DIR}/gtest CACHE PATH "GoogleTest install directory")

ダウンロードするがビルド等は必要ない場合(ヘッダーのみのライブラリ)

C++ではテンプレートを使ったヘッダーのみのライブラリがあります。

これらのライブラリの場合は、ダウンロードしたらビルドせずにヘッダファイルのみ特定のディレクトリにコピーさせたいので、次のように書くことになります。

# Eigenのビルド・インストール・インクルードディレクトリを定義
set(EIGEN_BUILD_DIR   ${CMAKE_BINARY_DIR}/eigen)
set(EIGEN_INSTALL_DIR ${CMAKE_SOURCE_DIR}/eigen)
set(EIGEN_INCLUDE_DIR ${EIGEN_INSTALL_DIR}/include)

# Eigenを外部プロジェクトとして追加
ExternalProject_Add(
    eigen
    URL http://bitbucket.org/eigen/eigen/get/3.3.4.tar.gz
    PREFIX ${EIGEN_BUILD_DIR}
    # CMakeのconfigureは必要ないので空白("")を与えることで何もさせない
    CONFIGURE_COMMAND ""
    # ビルドも不要
    BUILD_COMMAND ""
    # インストールも不要
    INSTALL_COMMAND ""
    # テストも不要
    TEST_COMMAND ""
    )

# Eigenをダウンロードして解凍してできるフォルダを得る
ExternalProject_Get_Property(eigen SOURCE_DIR)

# 上で得たフォルダ内の指定ディレクトリの中身を別のフォルダ内にコピーする
# この場合${SOURCE_DIR}/Eigen --> ${EIGEN_INCLUDE_DIR}/Eigenへとコピーされる
ExternalProject_Add_Step(
    # 対象の外部プロジェクト
    eigen
    # 実行する操作
    copySource
    # 対象ディレクトリ
    WORKING_DIRECTORY ${SOURCE_DIR}
    # コマンド
    COMMAND ${CMAKE_COMMAND} -E copy_directory Eigen ${EIGEN_INCLUDE_DIR}/Eigen
    COMMENT "Copying headers to ${EIGEN_INCLUDE_DIR}/Eigen"
    )

# あとはインクルードディレクトリとして登録するだけ
include_directories(SYSTEM ${EIGEN_INCLUDE_DIR})