从`cmake`使用`pkg-config`的正确方法是什么?

问题描述 投票:56回答:5

在网上四处看看我看到了很多这样的代码:

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)

target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS}
target_link_libraries(app ${SDL2_LIBRARIES})

然而,这似乎是错误的方式,因为它只使用包含目录和库,但忽略了定义,库路径和pkg-config可能返回的其他标志。

这样做的正确方法是什么,并确保pkg-config返回的所有编译和链接标志都被编译的app使用?有没有一个命令来实现这一点,即像target_use(app SDL2)

参考:

cmake pkg-config
5个回答
1
投票

下面看到的其他方法无法为在典型安装位置(例如/ usr / lib)下找不到的那些共享库配置链接器路径。生成的链接器错误是/usr/bin/ld: cannot find -llibrary-1.0。对于我的情况,也没有安装pkg-config文件,并且使用PKG_CONFIG_PATH环境变量添加了项目的pkg-config路径。这是一个工作的CMakeLists.txt的简化版本:

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)

42
投票

首先,电话:

include(FindPkgConfig)

应替换为:

find_package(PkgConfig)

find_package()调用更灵活,允许使用REQUIRED这样的选项,这些选项可以自动执行include()手动执行的操作。

其次,应尽可能避免手动调用pkg-config。 CMake附带了丰富的软件包定义,可以在Linux下的/usr/share/cmake-3.0/Modules/Find*cmake中找到。这些为用户提供了更多选项和选择,而不是对pkg_search_module()的原始调用。

至于上面提到的假设target_use()命令,CMake已经以PUBLIC | PRIVATE | INTERFACE的方式内置了。像target_include_directories(mytarget PUBLIC ...)之类的调用将导致include目录自动用于使用mytarget的每个目标,例如target_link_libraries(myapp mytarget)。但是,这种机制似乎只适用于在CMakeLists.txt文件中创建的库,而不适用于使用pkg_search_module()获取的库。可能会使用调用add_library(bar SHARED IMPORTED),但我还没有调查过。

至于主要问题,这在大多数情况下适用:

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

SDL2_CFLAGS_OTHER包含成功编译所需的定义和其他标志。然而,标志SDL2_LIBRARY_DIRSSDL2_LDFLAGS_OTHER仍被忽略,不知道这会成为一个问题的频率。

更多文档在这里http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html


7
投票

很少人只需要与SDL2链接。目前流行的答案使用pkg_search_module()来检查给定的模块并使用第一个工作模块。

您更有可能想要与SDL2和SDL2_Mixer以及SDL2_TTF等进行链接... pkg_check_modules()会检查所有给定的模块。

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

免责声明:如果我有足够的街头信誉和stackoverflow,我会简单地评论一下Grumbel的自我回答。


2
投票

大多数可用的答案都无法配置pkg-config库的标头。在冥想Documentation for FindPkgConfig后,我想出了一个解决方案,提供了那些:

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

(相应地用你的目标代替<my-target>和代替<some-lib>的任何库。)

IMPORTED_TARGET选项似乎是关键,并使PkgConfig::命名空间下的所有内容都可用。这就是所需要的,也应该是所有需要的。


0
投票
  1. 没有像target_use这样的命令。但我知道有几个项目已经为内部使用编写了这样的命令。但是每个项目都希望传递额外的标志或定义,因此将它放在一般的CMake中是没有意义的。没有它的另一个原因是像Eigen这样的C ++模板库,没有库,但你只有一堆包含文件。
  2. 所描述的方式通常是正确的。某些库可能会有所不同,那么你必须添加_LDFLAGS_CFLAGS。没有target_use的另一个原因。如果它不适合您,请询问有关SDL2或您想要使用的任何库的新问题。

-3
投票

如果您还想从库中添加定义,那么add_definitions指令就在那里。可以找到文档here,以及添加编译器标志的更多方法。

以下代码片段使用此指令将GTKGL添加到项目中:

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})
© www.soinside.com 2019 - 2024. All rights reserved.