web-dev-qa-db-ja.com

CMake:とにかくCMAKE_MODULE_PATHを指定する必要がある場合、find_package()の用途は何ですか?

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)

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

ただし、find_package()が存在する理由の1つは、クロスプラットフォームではないハードコーディングされたパスから逃れるためであるため、これはちょっと奇妙です。

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

131
MarcDefiant

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

モジュールモード

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

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ファイルは、outsideにあり、他のプロジェクトの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)を使用して、インポートしたターゲットfooFooConfig.cmakeを含めます。

> 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

インポートされたターゲットはhighly構成可能であることに注意してください。 answer を参照してください。

更新

167
user2288008

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

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

FindFoo.cmakeモジュールは、それぞれプラットフォーム依存とプラットフォーム非依存の架け橋であることに注意してください。プラットフォームに依存しないさまざまな場所を見て、名前がプラットフォーム非依存の変数のパスを取得します。

1
einpoklum

モジュールパス自体を指定するためにneedを使用しないでください。 CMakeには独自の組み込みfind_packageスクリプトセットが付属しており、それらの場所はデフォルトのCMAKE_MODULE_PATHにあります。

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

1
zjm555

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

簡単なハウツー

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

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

XXXConfig.cmakeSomeLib${CMAKE_CURRENT_BUILD_DIR}ファイルを作成し、SomeLibに関連付けられたCMakeLists.txtexport() の2つの呼び出しを追加して、この場所をユーザーパッケージレジストリに保存します。

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

SomeLibに依存しているプロジェクトのCMakeLists.txtファイルでfind_package(SomeLib REQUIRED)コマンドを発行します。これには、CMAKE_MODULE_PATHをいじる「クロスプラットフォーム以外のハードコードパス」はありません。

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

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

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

1
Ryan Feeley