とにかくCMAKE_MODULE_PATHを指定する必要がある場合、find_package()はどのように使用しますか?


167

CMakeを使用して、クロスプラットフォームのビルドシステムを動作させようとしています。現在、ソフトウェアにはいくつかの依存関係があります。自分でコンパイルして、システムにインストールしました。

インストールされたいくつかのサンプルファイル:

-- Installing: /usr/local/share/SomeLib/SomeDir/somefile
-- Installing: /usr/local/share/SomeLib/SomeDir/someotherfile
-- Installing: /usr/local/lib/SomeLib/somesharedlibrary
-- Installing: /usr/local/lib/SomeLib/cmake/FindSomeLib.cmake
-- Installing: /usr/local/lib/SomeLib/cmake/HelperFile.cmake

CMakeは、ファイルfind_package()を開きFind*.cmake、システム上のライブラリを検索して、いくつかの変数を定義するを持っていますSomeLib_FOUND

私のCMakeLists.txtには次のようなものが含まれています。

set(CMAKE_MODULE_PATH "/usr/local/lib/SomeLib/cmake/;${CMAKE_MODULE_PATH}")
find_package(SomeLib REQUIRED)

最初のコマンドは、CMakeがの後に検索する場所を定義し、が見つかる場所のFind*.cmakeディレクトリを追加したので、期待どおりに機能します。SomeLibFindSomeLib.cmakefind_package()

しかし、find_package()存在する理由の1つは、非クロスプラットフォームのハードコードされたパスから離れることです。

これは通常どのように行われますか?のcmake/ディレクトリをSomeLibプロジェクトにコピーして、CMAKE_MODULE_PATH相対的に設定する必要がありますか?


そのパターンは私には非常に奇妙なようです。CMakeを使用するライブラリは、このように「検索」モジュールを公開することは想定されていません。その「SomeLib」を見つける方法をどのように思いついたのですか?そして、それはどのlibですか?
SirDarius

2
同様のことがcmake.org/Wiki/…でも行われています。そして、それはOGREです。
MarcDefiant 2013

2
あなたがリンクするセクションはこれについて言及しています:「CMake(現在)はそれを出荷しないので、あなたはプロジェクト内でそれを出荷する必要があります。」これは私が(参照LibYAMLを見つけるためにflvmetaでやっていることであるgithub.com/noirotm/flvmeta/tree/master/cmake/modulesを)。モジュールパスは、プロジェクト内のこのディレクトリを指します。
SirDarius 2013

3
通常、FindXXXモジュールをプロジェクトにコピーし、CMAKE_MODULE_PATHを設定します(これらのモジュールがもちろんCMakeに存在しない場合)。他のプロジェクトでもこのパターンを何度も見ました
szx

回答:


214

コマンドにfind_packageは、ModuleモードとConfigモードの2つのモードがあります。Module実際にConfigモードが必要なときにモードを使用しようとしています。

モジュールモード

Find<package>.cmakeプロジェクト内にあるファイル。このようなもの:

CMakeLists.txt
cmake/FindFoo.cmake
cmake/FindBoo.cmake

CMakeLists.txt コンテンツ:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(Foo REQUIRED) # FOO_INCLUDE_DIR, FOO_LIBRARIES
find_package(Boo REQUIRED) # BOO_INCLUDE_DIR, BOO_LIBRARIES

include_directories("${FOO_INCLUDE_DIR}")
include_directories("${BOO_INCLUDE_DIR}")
add_executable(Bar Bar.hpp Bar.cpp)
target_link_libraries(Bar ${FOO_LIBRARIES} ${BOO_LIBRARIES})

CMAKE_MODULE_PATH高い優先度を持っており、あなたが標準書き換える必要があるときに便利かもしれFind<package>.cmakeファイルを。

設定モード(インストール)

<package>Config.cmake外部にありinstall 、他のプロジェクトのコマンドによって生成されたファイル(Fooたとえば)。

foo 図書館:

> cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Foo)

add_library(foo Foo.hpp Foo.cpp)
install(FILES Foo.hpp DESTINATION include)
install(TARGETS foo DESTINATION lib)
install(FILES FooConfig.cmake DESTINATION lib/cmake/Foo)

設定ファイルの簡略版:

> cat FooConfig.cmake 
add_library(foo STATIC IMPORTED)
find_library(FOO_LIBRARY_PATH foo HINTS "${CMAKE_CURRENT_LIST_DIR}/../../")
set_target_properties(foo PROPERTIES IMPORTED_LOCATION "${FOO_LIBRARY_PATH}")

デフォルトでは、CMAKE_INSTALL_PREFIXディレクトリにインストールされたプロジェクト:

> cmake -H. -B_builds
> cmake --build _builds --target install
-- Install configuration: ""
-- Installing: /usr/local/include/Foo.hpp
-- Installing: /usr/local/lib/libfoo.a
-- Installing: /usr/local/lib/cmake/Foo/FooConfig.cmake

設定モード(使用)

インポートされたターゲットfind_package(... CONFIG)に含めるために使用:FooConfig.cmakefoo

> cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Boo)

# import library target `foo`
find_package(Foo CONFIG REQUIRED)

add_executable(boo Boo.cpp Boo.hpp)
target_link_libraries(boo foo)
> cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON
> cmake --build _builds
Linking CXX executable Boo
/usr/bin/c++ ... -o Boo /usr/local/lib/libfoo.a

インポートされたターゲットは高度に構成可能であることに注意してください。私の答えを見てください。

更新


1
あなたの答えは素晴らしいです。ただし、githubの例はIMOの場合よりも複雑です。サブディレクトリ(モジュール)が単一のアーティファクトをエクスポートする一般的なケースでは、ヘッダーと一緒にlibとしましょう。カスタム* Config.cmakeを生成する必要はありません。その結果、構成を大幅に削減できます。私も同じような例を作ろうと思います。
Dimitris 2015年

2
@Dimitrisはい、少し簡略化できます。githubの例を更新したので、を使用しませんconfigure_package_config_file。ちなみに、他に提案がある場合は、プルリクエストを送ってください。

1
@rusioこれが私のです。モノリシックビルド(ルートフォルダーのすべてのモジュール)または自律ビルド(各モジュールを個別にインストールする必要があります)をサポートしています。
Dimitris

1
@Dimitrisわかりました、わかりました。通常、「最適化して削除」したファイルは、find_dependencyなどの追加のものをロードするために役立ちます。開始するには良いテンプレートだと思うので、実際には使用されていない場合でもそれを保持します。コードの残りの部分は、バージョン、dllへのエクスポート、レイアウトbin/lib(実行可能ファイルをインストールしてWindowsで実行してください)などの一部の機能がないため、より単純に見えます。そして名前空間はとてもきれいに見えるので、私もそれらを保持します:)また、monolithicビルドを追加しました。

1
あなたのそれぞれの例は私にとって非常に役に立ちました。あなたがた両方に感謝します!
zmb 2015

2

自分自身cmakeを生成するために実行している場合SomeLib(たとえば、スーパービルドの一部として)、ユーザーパッケージレジストリの使用を検討してください。これはハードコーディングされたパスを必要とせず、クロスプラットフォームです。Windows(mingw64を含む)では、レジストリを介して動作します。インストールプレフィックスのリストがfind_packages()コマンドのCONFIGモードによってどのように構築されるかを調べると、ユーザーパッケージレジストリが要素の1つであることがわかります。

簡単なハウツー

作成SomeLibしたCMakeLists.txtファイルのエクスポートセットにターゲットを追加して、その外部プロジェクトの外部で必要なターゲットを関連付けます。

add_library(thingInSomeLib ...)
install(TARGETS thingInSomeLib Export SomeLib-export DESTINATION lib)

作成XXXConfig.cmakeのためのファイルをSomeLibその中${CMAKE_CURRENT_BUILD_DIR}との2つの呼び出しを追加することにより、ユーザーのパッケージレジストリでこの場所を保存)(輸出CMakeLists.txt関連付けられましたSomeLib

export(EXPORT SomeLib-export NAMESPACE SomeLib:: FILE SomeLibConfig.cmake) # Create SomeLibConfig.cmake
export(PACKAGE SomeLib)                                                    # Store location of SomeLibConfig.cmake

「非クロスプラットフォームのハードコードされたパス」を使用せずに依存するプロジェクトfind_package(SomeLib REQUIRED)CMakeLists.txtファイルでコマンドを発行します。SomeLibCMAKE_MODULE_PATH

それが正しいアプローチかもしれないとき

このアプローチは、ビルドディレクトリの下流でソフトウェアを使用しない(たとえば、クロスコンパイルしてマシンに何もインストールしない)場合や、テストを実行するためだけにソフトウェアをビルドする場合に最適です。ビルドディレクトリ)。「ビルド」出力に.cmakeファイルへのリンクが作成されるため、一時的な場合があります。

ただしSomeLib、ワークフローに実際にインストールすることがない場合は、呼び出しEXPORT(PACKAGE <name>)により、ハードコーディングされたパスを回避できます。そしてもちろん、をインストールしている場合はSomeLib、おそらくプラットフォームCMAKE_MODULE_PATHなどを知っているので、@ user2288008の優れた答えで対応できます。


1

モジュールパス自体を指定する必要ありません。CMakeには独自の組み込みのfind_packageスクリプトのセットが付属しており、その場所はデフォルトのCMAKE_MODULE_PATHにあります。

CMake化された依存プロジェクトのより一般的な使用例は、CMakeのexternal_projectコマンドを使用して、サブプロジェクトのUse [Project] .cmakeファイルを含めることです。Find [Project] .cmakeスクリプトだけが必要な場合は、それをサブプロジェクトから独自のプロジェクトのソースコードにコピーします。システムレベルでサブプロジェクトを見つけるためにCMAKE_MODULE_PATHを拡張する必要はありません。


12
their location is in the default CMAKE_MODULE_PATHデフォルトでCMAKE_MODULE_PATHは空です

@ user2288008の2018年のコメントを確認できますCMAKE_MODULE_PATH。Windowsでは空です。
Jeroen

これは、プロジェクトに付属するモジュール用のプロジェクト固有の変数です。「デフォルトでは空で、プロジェクトによって設定されることを意図しています。」cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
Farway

1

これは通常どのように行われますか?cmake/SomeLib のディレクトリをプロジェクトにコピーして、CMAKE_MODULE_PATHを相対的に設定する必要がありますか?

CMakeがそのモジュールを持っていると信頼していない場合は- はい、そうします-並べ替え:find_SomeLib.cmakeとその依存関係をcmake/ディレクトリにコピーします。それが私がフォールバックとしてやっていることです。しかし、それは醜い解決策です。

FindFoo.cmakeモジュールはそれぞれプラットフォーム依存とプラットフォーム非依存の間の一種の橋であることに注意してください-それらは名前がプラットフォームに依存しない変数のパスを取得するためにさまざまなプラットフォーム固有の場所を調べます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.