在'cmake'中使用'pkg-config'的正确方法是什么?

apeeds0o  于 2022-11-11  发布在  其他
关注(0)|答案(6)|浏览(845)

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

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)
参考:

4szc88ey

4szc88ey1#

首先,呼叫:

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内置了该命令|私人|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/latest/module/FindPkgConfig.html

njthzxwz

njthzxwz2#

如果您以非常普通的方式使用cmake和pkg-config,则此解决方案有效。
但是,如果您有一个库存在于某个开发目录中(例如/home/me/hack/lib),那么使用此处所示的其他方法将无法配置链接器路径。在典型安装位置下找不到的库将导致链接器错误,例如/usr/bin/ld: cannot find -lmy-hacking-library-1.0。此解决方案修复了这种情况下的链接器错误。
另一个问题可能是pkg-config文件没有安装在正常位置,需要在运行cmake时使用PKG_CONFIG_PATH环境变量添加项目的pkg-config路径(请参阅其他有关此问题的堆栈溢出问题)。
使用IMPORTED_TARGET是解决上述问题的关键。此解决方案是this earlier answer的改进,并可归结为工作的CMakeLists.txt的最终版本:

cmake_minimum_required(VERSION 3.14)
project(ya-project C)

# the `pkg_check_modules` function is created with this call

find_package(PkgConfig REQUIRED) 

# these calls create special `PkgConfig::<MODULE>` variables

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 PUBLIC
        PkgConfig::MY_PKG
        PkgConfig::YOUR_PKG)

请注意,target_link_libraries不仅仅是更改链接器命令,它还传播指定目标的其他PUBLIC属性,如编译器标志、编译器定义、包含路径等,因此,请谨慎使用PUBLIC关键字。

6bc51xsx

6bc51xsx3#

很少有人只需要与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的自我回答。

von4xj4u

von4xj4u4#

大多数可用的答案都无法为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::命名空间下的所有内容都可用。这是所有需要的,也是所有 * 应该 * 需要的。

sczxawaw

sczxawaw5#

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

sycxhyv7

sycxhyv76#

如果您也希望从库中添加定义,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})

相关问题