cmake pkg-config

¿Cuál es la forma correcta de usar `pkg-config` de` cmake`?



(6)

  1. No existe un comando como target_use . Pero conozco varios proyectos que han escrito dicho comando para su uso interno. Pero cada proyecto quiere pasar banderas o definiciones adicionales, por lo que no tiene sentido tenerlo en general CMake. Otra razón para no tenerlo son las bibliotecas con plantillas de C ++ como Eigen, no hay una biblioteca, pero solo tiene un montón de archivos de inclusión.

  2. La forma descrita es a menudo correcta. Puede ser diferente para algunas bibliotecas, entonces tendrá que agregar _LDFLAGS o _CFLAGS . Una razón más para no tener target_use . Si no funciona para usted, haga una nueva pregunta específica sobre SDL2 o cualquier biblioteca que quiera usar.

Mirando alrededor de la red, he visto muchos códigos como este:

include(FindPkgConfig) pkg_search_module(SDL2 REQUIRED sdl2) target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS} target_link_libraries(app ${SDL2_LIBRARIES})

Sin embargo, esa parece ser la forma incorrecta de hacerlo, ya que solo usa los directorios y bibliotecas de inclusión, pero ignora las definiciones, las rutas de la biblioteca y otros indicadores que pkg-config puede devolver.

¿Cuál sería la forma correcta de hacer esto y garantizar que todos los indicadores de compilación y enlace devueltos por pkg-config sean utilizados por la app compilada? ¿Y hay un solo comando para lograr esto, es decir, algo como target_use(app SDL2) ?

árbitro:


Es raro que solo sea necesario vincular con SDL2. La respuesta actualmente popular usa pkg_search_module() que verifica los módulos dados y usa el primero que funciona.

Es más probable que desee vincular con SDL2 y SDL2_Mixer y SDL2_TTF, etc. ... pkg_check_modules() comprueba todos los módulos dados.

# sdl2 linking variables find_package(PkgConfig REQUIRED) pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf SDL2_mixer SDL2_image) # your app file(GLOB SRC "my_app/*.c") add_executable(my_app ${SRC}) target_link_libraries(my_app ${SDL2_LIBRARIES}) target_include_directories(my_app PUBLIC ${SDL2_INCLUDE_DIRS}) target_compile_options(my_app PUBLIC ${SDL2_CFLAGS_OTHER})

Descargo de responsabilidad: simplemente habría comentado la respuesta de Grumbel si tuviera suficientes créditos callejeros con .


La mayoría de las respuestas disponibles no pueden configurar los encabezados para la biblioteca pkg-config . Después de meditar en la FindPkgConfig me ocurrió una solución que también proporciona:

include(FindPkgConfig) if(NOT PKG_CONFIG_FOUND) message(FATAL_ERROR "pkg-config not found!" ) endif() pkg_check_modules(<some-lib> REQUIRED IMPORTED_TARGET <some-lib>) target_link_libraries(<my-target> PkgConfig::<some-lib>)

( Sustituya su objetivo en lugar de <my-target> y cualquier biblioteca en lugar de <some-lib> , en consecuencia ) .

La opción IMPORTED_TARGET parece ser clave y hace que todo esté disponible en el espacio de nombres PkgConfig:: . Esto era todo lo que se requería y también todo lo que debía exigirse.


Otros métodos que se ven aquí no pueden configurar las rutas de enlace para las bibliotecas que no se encuentran en las ubicaciones de instalación típicas. Si existe una biblioteca en algún directorio de desarrollo (como / home / me / hack / lib), el error resultante del enlazador sería /usr/bin/ld: cannot find -lmy-hacking-library-1.0 .

Otro problema podría ser que los archivos pkg-config no están instalados en el lugar normal, y las rutas de pkg-config para el proyecto deben agregarse utilizando la variable de entorno PKG_CONFIG_PATH (consulte otras preguntas sobre el desbordamiento de pila al respecto).

La solución se reduce a esta versión de un CMakeLists.txt en funcionamiento:

cmake_minimum_required(VERSION 3.14) project(ya-project C) find_package(PkgConfig REQUIRED) pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET any-package) pkg_check_modules(YOUR_PKG REQUIRED IMPORTED_TARGET ya-package) add_executable(program-name file.c ya.c) target_link_libraries(program-name PkgConfig::MY_PKG PkgConfig::YOUR_PKG)


Primero de, la llamada:

include(FindPkgConfig)

debe reemplazarse con:

find_package(PkgConfig)

La llamada find_package() es más flexible y permite opciones como REQUIRED , que hacen cosas automáticamente que uno tendría que hacer manualmente con include() .

En segundo lugar, se debe evitar llamar manualmente pkg-config cuando sea posible. CMake viene con un amplio conjunto de definiciones de paquetes, que se encuentran en Linux en /usr/share/cmake-3.0/Modules/Find*cmake . Estos proporcionan más opciones y opciones para el usuario que una llamada sin procesar a pkg_search_module() .

En cuanto al comando target_use() hipotético mencionado, CMake ya lo tiene incorporado de alguna manera con PUBLIC | PRIVATE | INTERFACE. Una llamada como target_include_directories(mytarget PUBLIC ...) hará que los directorios de inclusión se usen automáticamente en cada destino que use mytarget , por ejemplo, target_link_libraries(myapp mytarget) . Sin embargo, este mecanismo parece ser solo para bibliotecas creadas dentro del archivo CMakeLists.txt y no funciona para bibliotecas adquiridas con pkg_search_module() . La llamada add_library(bar SHARED IMPORTED) podría usarse para eso, pero aún no lo he add_library(bar SHARED IMPORTED) .

En cuanto a la pregunta principal, esto aquí funciona en la mayoría de los casos:

find_package(PkgConfig REQUIRED) pkg_check_modules(SDL2 REQUIRED sdl2) ... target_link_libraries(testapp ${SDL2_LIBRARIES}) target_include_directories(testapp PUBLIC ${SDL2_INCLUDE_DIRS}) target_compile_options(testapp PUBLIC ${SDL2_CFLAGS_OTHER})

El SDL2_CFLAGS_OTHER contiene definiciones y otros indicadores necesarios para una compilación exitosa. Sin SDL2_LIBRARY_DIRS banderas SDL2_LIBRARY_DIRS y SDL2_LDFLAGS_OTHER todavía se ignoran, ni idea de con qué frecuencia eso se convertiría en un problema.

Más documentación aquí http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html


Si también desea agregar definiciones desde la biblioteca, la instrucción add_definitions está ahí para eso. La documentación se puede encontrar here , junto con más formas de agregar indicadores de compilación.

El siguiente fragmento de código utiliza esta instrucción para agregar GTKGL al proyecto:

pkg_check_modules(GTKGL REQUIRED gtkglext-1.0) include_directories(${GTKGL_INCLUDE_DIRS}) link_directories(${GTKGL_LIBRARY_DIRS}) add_definitions(${GTKGL_CFLAGS_OTHER}) set(LIBS ${LIBS} ${GTKGL_LIBRARIES}) target_link_libraries([insert name of program] ${LIBS})