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つは、クロスプラットフォームではないハードコーディングされたパスから逃れるためであるため、これはちょっと奇妙です。
これは通常どのように行われますか? SomeLib
のcmake/
ディレクトリをプロジェクトにコピーし、CMAKE_MODULE_PATH
を相対的に設定する必要がありますか?
コマンド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)
を使用して、インポートしたターゲットfoo
にFooConfig.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 を参照してください。
更新
これは通常どのように行われますか? SomeLibの
cmake/
ディレクトリをプロジェクトにコピーし、CMAKE_MODULE_PATHを相対的に設定する必要がありますか?
CMakeがそのモジュールを持っていると信じていない場合は、-はい、それを行います-並べ替え:find_SomeLib.cmake
とその依存関係をcmake/
ディレクトリにコピーします。それが私がフォールバックとして行うことです。しかし、それはい解決策です。
FindFoo.cmake
モジュールは、それぞれプラットフォーム依存とプラットフォーム非依存の架け橋であることに注意してください。プラットフォームに依存しないさまざまな場所を見て、名前がプラットフォーム非依存の変数のパスを取得します。
モジュールパス自体を指定するためにneedを使用しないでください。 CMakeには独自の組み込みfind_packageスクリプトセットが付属しており、それらの場所はデフォルトのCMAKE_MODULE_PATHにあります。
CMake化された依存プロジェクトのより一般的な使用例は、CMakeのexternal_projectコマンドを使用し、サブプロジェクトのUse [Project] .cmakeファイルを含めることです。 Find [Project] .cmakeスクリプトだけが必要な場合は、サブプロジェクトから自分のプロジェクトのソースコードにコピーします。システムレベルでサブプロジェクトを見つけるためにCMAKE_MODULE_PATHを増やす必要はありません。
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.cmake
にSomeLib
の${CMAKE_CURRENT_BUILD_DIR}
ファイルを作成し、SomeLib
に関連付けられたCMakeLists.txt
に export() の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の優れた答えでカバーできます。