CMake: ¿De qué sirve find_package () si necesita especificar CMAKE_MODULE_PATH de todos modos?

Estoy tratando de obtener un sistema de comstackción multiplataforma que funcione con CMake. Ahora el software tiene algunas dependencias. Los compilé yo mismo y los instalé en mi sistema.

Algunos archivos de ejemplo que se instalaron:

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

Ahora CMake tiene un find_package() que abre un archivo Find*.cmake y busca la biblioteca en el sistema y define algunas variables como SomeLib_FOUND etc.

Mi CMakeLists.txt contiene algo como esto:

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

El primer comando define dónde CMake busca después de Find*.cmake y agregué el directorio de SomeLib donde FindSomeLib.cmake se puede encontrar, por lo que find_package() funciona como se esperaba.

Pero esto es un poco extraño porque una de las razones por las que find_package() existe es alejarse de las rutas no codificadas de plataforma cruzada.

¿Cómo se hace esto usualmente? ¿Debo copiar el directorio cmake/ de SomeLib en mi proyecto y configurar el CMAKE_MODULE_PATH relativa?

Command find_package tiene dos modos: modo Module y modo Config . Está intentando usar el modo Module cuando realmente necesita el modo Config .

Modo de módulo

Find.cmake archivo Find.cmake ubicado dentro de tu proyecto. Algo como esto:

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

Contenido de 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}) 

Tenga en cuenta que CMAKE_MODULE_PATH tiene una alta prioridad y puede ser útil cuando necesite reescribir el archivo estándar Find.cmake .

Modo de configuración (instalar)

Config.cmake archivo Config.cmake ubicado fuera y producido por el comando de install de otro proyecto ( Foo por ejemplo).

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

Versión simplificada del archivo de configuración:

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

Por defecto, proyecto instalado en el directorio 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 

Modo de configuración (uso)

Utilice find_package(... CONFIG) para incluir FooConfig.cmake con foo objective importado:

 > 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 

Tenga en cuenta que el objective importado es altamente configurable. Ver mi respuesta

Actualizar

  • Ejemplo

¿Cómo se hace esto usualmente? ¿Debo copiar el directorio cmake/ de SomeLib en mi proyecto y configurar el CMAKE_MODULE_PATH de manera relativa?

Si no confías en CMake para tener ese módulo, entonces – sí, haz eso . Eso es lo que hago como alternativa.

Tenga en cuenta que los módulos FindFoo.cmake son cada uno una especie de puente entre la dependencia de la plataforma y la independencia de la plataforma: buscan en varios lugares específicos de la plataforma obtener rutas en variables cuyos nombres son independientes de la plataforma.

No necesita especificar la ruta del módulo per se. CMake se envía con su propio conjunto de scripts find_package incorporados, y su ubicación está en el valor predeterminado CMAKE_MODULE_PATH.

El caso de uso más normal para proyectos dependientes que han sido CMakeified sería usar el comando external_project de CMake y luego incluir el archivo Use [Project] .cmake del subproyecto. Si solo necesita el script Find [Project] .cmake, cópielo fuera del subproyecto y en el código fuente de su propio proyecto, y luego no necesitará boost el CMAKE_MODULE_PATH para encontrar el subproyecto a nivel del sistema.

Si está ejecutando cmake para generar SomeLib usted mismo (por ejemplo, como parte de un superconstructor), considere usar el Registro de paquetes de usuario . Esto no requiere rutas codificadas y es multiplataforma. En Windows (incluido mingw64) funciona a través del registro. Si examina cómo se construye la lista de prefijos de instalación mediante el modo CONFIG del comando find_packages () , verá que el Registro de paquetes de usuario es uno de los elementos.

Breve cómo hacerlo

Asocie los objectives de SomeLib que necesita fuera de ese proyecto externo agregándolos a un conjunto de exportación en los archivos CMakeLists.txt donde se crean:

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

Cree un archivo XXXConfig.cmake para SomeLib en su ${CMAKE_CURRENT_BUILD_DIR} y almacene esta ubicación en el Registro de paquetes de usuario agregando dos llamadas a exportar () al CMakeLists.txt asociado con SomeLib :

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

Emita su find_package(SomeLib REQUIRED) en el archivo CMakeLists.txt del proyecto que depende de SomeLib sin las “rutas no codificadas de plataforma dura” que CMAKE_MODULE_PATH con CMAKE_MODULE_PATH .

Cuando podría ser el enfoque correcto

Este enfoque es probablemente el más adecuado para situaciones en las que nunca usará su software aguas abajo del directorio de comstackción (por ej., Comstack de forma cruzada y nunca instala nada en su máquina, o está comstackndo el software solo para ejecutar pruebas en el directorio de comstackción), ya que crea un enlace a un archivo .cmake en su salida “comstackción”, que puede ser temporal.

Pero si en realidad nunca está instalando SomeLib en su flujo de trabajo, llamar a EXPORT(PACKAGE ) permite evitar la ruta codificada. Y, por supuesto, si está instalando SomeLib , probablemente conozca su plataforma, CMAKE_MODULE_PATH , etc., así que la excelente respuesta de @ user2288008 lo tendrá cubierto.