在网上四处看看我看到了很多这样的代码:
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)
?
参考:
下面看到的其他方法无法为在典型安装位置(例如/ 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)
首先,电话:
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_DIRS
和SDL2_LDFLAGS_OTHER
仍被忽略,不知道这会成为一个问题的频率。
更多文档在这里http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html
很少人只需要与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的自我回答。
大多数可用的答案都无法配置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::
命名空间下的所有内容都可用。这就是所需要的,也应该是所有需要的。
target_use
这样的命令。但我知道有几个项目已经为内部使用编写了这样的命令。但是每个项目都希望传递额外的标志或定义,因此将它放在一般的CMake中是没有意义的。没有它的另一个原因是像Eigen这样的C ++模板库,没有库,但你只有一堆包含文件。_LDFLAGS
或_CFLAGS
。没有target_use
的另一个原因。如果它不适合您,请询问有关SDL2或您想要使用的任何库的新问题。如果您还想从库中添加定义,那么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})