Yine de CMAKE_MODULE_PATH belirtmeniz gerekiyorsa find_package () ne işe yarar?


167

CMake kullanarak çalışan bir çapraz platform oluşturma sistemi elde etmeye çalışıyorum. Şimdi yazılımın birkaç bağımlılığı var. Onları kendim derledim ve sistemime kurdum.

Yüklü bazı örnek dosyalar:

-- 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

Şimdi CMake, bir dosyayı find_package()açan Find*.cmakeve sistemdeki kütüphaneyi arayan ve SomeLib_FOUNDvb. Gibi bazı değişkenleri tanımlayan bir dosyaya sahiptir .

CMakeLists.txt dosyamda şöyle bir şey var:

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

İlk komut, CMake'in nerede aradığını tanımlar ve bulunabileceği Find*.cmakedizini ekledim , bu yüzden beklendiği gibi çalışır.SomeLibFindSomeLib.cmakefind_package()

Ancak bu biraz gariptir, çünkü find_package()var olmanın nedenlerinden biri, platforma olmayan sabit kodlu yollardan uzaklaşmaktır.

Bu genellikle nasıl yapılır? Ben kopya mı cmake/dizinini SomeLibbenim projeye ve set CMAKE_MODULE_PATHnispeten?


Bu desen bana çok garip geliyor. CMake kullanan kütüphanelerin 'find' modüllerini bu şekilde göstermeleri beklenmez. Bu "SomeLib" i bulmak için nasıl bir yol buldunuz? Ve bu hangi lib?
SirDarius

2
Benzer bir şey cmake.org/Wiki/… ' de yapılır . Ve bu OGRE.
MarcDefiant

2
Bağlantı verdiğiniz bölüm şu sözlerden bahseder: "CMake (şu anda) göndermediği için projenizde göndermeniz gerekir." Flvmeta'da LibYAML'i bulmak için yaptığım şey budur (bkz. Github.com/noirotm/flvmeta/tree/master/cmake/modules ). Modül yolu projemin içindeki bu dizine işaret ediyor.
SirDarius

3
Genellikle FindXXX modüllerini projeme kopyalarım ve CMAKE_MODULE_PATH ayarlıyorum (eğer bu modüller CMake'de mevcut değilse), bu modeli başka projelerde de birçok kez gördüm
szx

Yanıtlar:


214

Komutun find_packageiki modu vardır: Modulemod ve Configmod. ModuleGerçekten Configmoda ihtiyacınız olduğunda modu kullanmaya çalışıyorsunuz .

Modül modu

Find<package>.cmakedosyanın bulunduğu dahilinde projeniz. Bunun gibi bir şey:

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

CMakeLists.txt içerik:

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_PATHYüksek önceliğe sahip olduğunu ve standart Find<package>.cmakedosyayı yeniden yazmanız gerektiğinde yararlı olabileceğini unutmayın .

Yapılandırma modu (yükleme)

<package>Config.cmakedosya dışarıda bulunur ve install başka bir projenin komutuyla üretilir ( Fooörneğin).

foo kütüphane:

> 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)

Yapılandırma dosyasının basitleştirilmiş sürümü:

> 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}")

Varsayılan olarak CMAKE_INSTALL_PREFIXdizinde kurulu proje :

> 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

Yapılandırma modu (kullanım)

İçe aktarılan hedefe find_package(... CONFIG)dahil FooConfig.cmakeetmek için kullanın foo:

> 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

İçe aktarılan hedefin son derece yapılandırılabilir olduğunu unutmayın . Cevabımı gör .

Güncelleme


1
Cevabınız harika. Bununla birlikte, github'daki örnek IMO olabileceğinden daha karmaşıktır. Bir alt dizinin (modül) tek bir yapay nesneyi dışa aktardığı genel durumda, başlıklarla birlikte bir lib diyelim, özel * Config.cmake oluşturmanıza gerek yok. Sonuç olarak konfigürasyon önemli ölçüde azaltılabilir. Sanırım ben de benzer bir örnek yapacağım.
Dimitris

2
@Dimitris Evet, biraz basitleştirilebilir. Github örneğini güncelledim, bu yüzden şimdi kullanmıyor configure_package_config_file. Bu arada başka önerileriniz varsa bana çekme isteği gönderebilirsiniz.

1
@rusio İşte benim olduğu örnek . Monolitik yapıyı (kök klasördeki tüm modüller) veya otonom yapıları (her modül ayrı ayrı kurulmasını gerektirir) destekler.
Dimitris

1
@Dimitris Tamam, şimdi anlıyorum. Genellikle "optimize ettiğiniz" dosya find_dependency gibi ekstra şeyler yüklemek için kullanılır . Başlamak için iyi bir şablon olduğunu düşünüyorum, bu yüzden aslında kullanılmasa bile saklayacağım. Kodun geri kalanı daha basit görünüyor çünkü sürüm, dll için dışa aktarma, mizanpajla bin/lib(çalıştırılabilir dosyayı yüklemeye çalışın ve pencerelerde çalıştırın) gibi bazı işlevler eksik . Ve ad alanları çok güzel görünüyor, bu yüzden onları da tutacağım :) Ayrıca monolithicderleme ekledim .

1
Örneklerinizin her biri bana çok yardımcı oldu. İkinize de teşekkürler!
zmb

2

Kendiniz cmakeüretmeye çalışıyorsanız SomeLib(bir süper yapının parçası olarak söyleyin), Kullanıcı Paketi Kayıt Defterini kullanmayı düşünün . Bu sabit kodlanmış yollar gerektirmez ve çapraz platformdur. Windows'ta (mingw64 dahil) kayıt defteri aracılığıyla çalışır. Yükleme önekleri listesinin find_packages () komutunun CONFIGmodu tarafından nasıl oluşturulduğunu incelerseniz , Kullanıcı Paketi Kayıt Defteri'nin öğelerden biri olduğunu görürsünüz.

Kısa nasıl yapılır

SomeLibİhtiyaç duyduğunuz hedefleri CMakeLists.txt, oluşturuldukları dosyalarda bir dışa aktarma kümesine ekleyerek bu harici projenin dışında ilişkilendirin :

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

Bir oluşturma XXXConfig.cmakeiçin dosya SomeLibonun içinde ${CMAKE_CURRENT_BUILD_DIR}ve iki çağrı ekleyerek Kullanıcı Paketi Sicil içinde bu konuma depolamak ihracat () için CMakeLists.txtilişkili SomeLib:

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

Senin Sayı find_package(SomeLib REQUIRED)içinde Commmand CMakeLists.txtbağlıdır projenin dosyası SomeLibile müdahalesi "sert kodlu yolları olmayan çapraz platform" olmadan CMAKE_MODULE_PATH.

Ne zaman doğru yaklaşım olabilir

Bu yaklaşım muhtemelen yazılımınızı derleme dizininin aşağısında asla kullanmayacağınız durumlar için en uygunudur (örneğin, çapraz derleme yaparsınız ve makinenize hiçbir şey yüklemezsiniz veya yazılımı yalnızca testleri çalıştırmak için oluşturursunuz build dizini), "build" çıktısında geçici olabilen bir .cmake dosyasına bir bağlantı oluşturduğundan.

Ancak SomeLib, iş akışınıza gerçekten hiç yüklemiyorsanız, çağrı EXPORT(PACKAGE <name>)yapmak sabit kodlu yoldan kaçınmanıza olanak tanır. Ve tabii ki, eğer kuruyorsanız SomeLib, muhtemelen platformunuzu CMAKE_MODULE_PATHvb. Biliyorsunuzdur , bu yüzden @ user2288008'in mükemmel cevabı sizi ele alacaktır.


1

Modül yolunu kendiniz belirtmeniz gerekmez . CMake, kendi yerleşik find_package komut dosyalarıyla birlikte gönderilir ve konumları varsayılan CMAKE_MODULE_PATH konumundadır.

CMakeified olan bağımlı projeler için daha normal kullanım durumu, CMake'nin external_project komutunu kullanmak ve sonra alt projeden [Project] .cmake dosyasını kullanmak olacaktır. Yalnızca Find [Project] .cmake komut dosyasına ihtiyacınız varsa, alt projeden kendi projenizin kaynak koduna kopyalayın ve alt projeyi sistem düzeyinde bulmak için CMAKE_MODULE_PATH değerini artırmanız gerekmez.


12
their location is in the default CMAKE_MODULE_PATHvarsayılan CMAKE_MODULE_PATHolarak boş

@ User2288008'in 2018'deki yorumunu onaylayabilir CMAKE_MODULE_PATH. Windows'ta boş.
Jeroen

Projenizle birlikte gönderilen modüller için projeye özgü bir değişkendir. "Varsayılan olarak boştur, proje tarafından ayarlanması amaçlanmıştır." cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
Farway

1

Bu genellikle nasıl yapılır? cmake/SomeLib dizinini projeme kopyalamalı ve CMAKE_MODULE_PATH değerini nispeten ayarlamam gerekir mi?

CMake'in bu modüle sahip olduğuna güvenmiyorsanız, - evet, bunu - bir çeşit yapın:find_SomeLib.cmake ve bağımlılıklarını cmake/dizininize kopyalayın . Bunu bir yedek olarak yapıyorum. Gerçi çirkin bir çözüm.

FindFoo.cmakeModüllerin her birinin platforma bağımlılık ile platformdan bağımsızlık arasında bir tür köprü olduğunu unutmayın - adları platformdan bağımsız olan değişkenlerde yollar elde etmek için platforma özgü çeşitli yerlere bakarlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.