¿Cuál es la forma correcta de usar `pkg-config` de` cmake`?
(6)
-
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. -
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 tenertarget_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})