从“cmake”使用“pkg-config”的正确方法是什么?
我见过很多这样的代码:
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)
的命令?
参考:
I have seen a lot of code like this:
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS})
target_link_libraries(app ${SDL2_LIBRARIES})
However, that seems to be the wrong way about doing it, as it only uses the include directories and libraries, but ignores defines, library paths and other flags that might be returned by pkg-config
.
What would be the correct way to do this and ensure that all compile and link flags returned by pkg-config
are used by the compiled app
? And is there a single command to accomplish this, i.e., something like target_use(app SDL2)
?
ref:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
首先,调用:
应该替换为:
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 ...)
这样的调用将导致在使用mytarget
的每个目标中自动使用包含目录,例如target_link_libraries(myapp mytarget )
。但是,此机制似乎仅适用于在
CMakeLists.txt
文件中创建的库,不适用于通过pkg_search_module()
获取的库。调用add_library(bar SHARED IMPORTED)
可能用于此目的,但我还没有对此进行研究。至于主要问题,这在大多数情况下都有效:
SDL2_CFLAGS_OTHER
包含成功编译所需的定义和其他标志。然而,标志SDL2_LIBRARY_DIRS
和SDL2_LDFLAGS_OTHER
仍然被忽略,不知道这会成为一个问题的频率。更多文档请参见:CMake 文档 — FindPkgConfig。
First off, the call:
should be replaced with:
The
find_package()
call is more flexible and allows options, such asREQUIRED
, that do things automatically that one would have to do manually withinclude()
.Secondly, manually calling
pkg-config
should be avoided when possible. CMake comes with a rich set of package definitions, found on Linux under/usr/share/cmake-3.0/Modules/Find*cmake
. These provide more options and choice for the user than a raw call topkg_search_module()
.As for the mentioned hypothetical
target_use()
command, CMake already has that built-in in a way with PUBLIC|PRIVATE|INTERFACE. A call liketarget_include_directories(mytarget PUBLIC ...)
will cause the include directories to be automatically used in every target that usesmytarget
, e.g.,target_link_libraries(myapp mytarget)
.However, this mechanism seems to be only for libraries created within the
CMakeLists.txt
file and does not work for libraries acquired withpkg_search_module()
. The calladd_library(bar SHARED IMPORTED)
might be used for that, but I haven't yet looked into that.As for the main question, this here works in most cases:
The
SDL2_CFLAGS_OTHER
contains defines and other flags necessary for a successful compile. The flagsSDL2_LIBRARY_DIRS
andSDL2_LDFLAGS_OTHER
are however still ignored, no idea how often that would become a problem.More documentation here: CMake Documentation — FindPkgConfig.
现代 CMake 方法 - 使用
pkgconfig
结果导入目标如果您以非常正常的方式使用 cmake 和 pkg-config,则此解决方案有效。
但是,如果您的某个开发目录中存在一个库(例如
/home/me/hack/lib
),则使用此处看到的其他方法将无法配置链接器路径。在典型安装位置下找不到的库将导致链接器错误,例如/usr/bin/ld: 找不到 -lmy-hacking-library-1.0
。此解决方案修复了这种情况下的链接器错误。另一个问题可能是 pkg-config 文件没有安装在正常位置,并且需要在 cmake 运行时使用
PKG_CONFIG_PATH
环境变量添加项目的 pkg-config 路径(请参阅其他与此相关的堆栈溢出问题)。当您使用正确的 pkg-config 路径时,此解决方案也能很好地工作。使用
IMPORTED_TARGET
是解决上述问题的关键。此解决方案是对 这个早期答案 的改进,可归结为工作 CMakeLists.txt 的最终版本:注意:
target_link_libraries
的作用不仅仅是更改链接器命令。它还传播指定目标的其他 PUBLIC 属性,例如编译器标志、编译器定义、包含路径等,因此请谨慎使用 PUBLIC 关键字。IMPORTED_TARGET
需要 CMake 3.6 或更高版本。GLOBAL
扩展了MY_PKG
和YOUR_PKG
目标的定义范围。The modern-CMake approach - an imported target using
pkgconfig
resultsIf you're using cmake and pkg-config in a pretty normal way, this solution works.
If, however, you have a library that exists in some development directory (such as
/home/me/hack/lib
), then using other methods seen here fail to configure the linker paths. Libraries that are not found under the typical install locations would result in linker errors, like/usr/bin/ld: cannot find -lmy-hacking-library-1.0
. This solution fixes the linker error for that case.Another issue could be that the pkg-config files are not installed in the normal place, and the pkg-config paths for the project need to be added using the
PKG_CONFIG_PATH
environment variable while cmake is running (see other Stack Overflow questions regarding this). This solution also works well when you use the correct pkg-config path.Using
IMPORTED_TARGET
is key to solving the issues above. This solution is an improvement on this earlier answer and boils down to this final version of a working CMakeLists.txt:Notes:
target_link_libraries
does more than change the linker commands. It also propagates other PUBLIC properties of specified targets like compiler flags, compiler defines, include paths, etc., so, use the PUBLIC keyword with caution.IMPORTED_TARGET
requires CMake version 3.6 or later.GLOBAL
expands the scope of the definition of theMY_PKG
andYOUR_PKG
targets.大多数可用的答案都无法配置
pkg-config
库的标头。在思考 FindPkgConfig 文档之后,我想出了一个解决方案,它提供了还有:(用你的目标代替
并用任何库代替
, )IMPORTED_TARGET
选项似乎是关键,它使所有内容都可以在PkgConfig::
命名空间下使用。这就是所需要的一切,也是应该所需要的。Most of the available answers fail to configure the headers for the
pkg-config
library. After meditating on the Documentation for FindPkgConfig I came up with a solution that provides those also:(Substitute your target in place of
<my-target>
and whatever library in place of<some-lib>
, accordingly.)The
IMPORTED_TARGET
option seems to be key and makes everything then available under thePkgConfig::
namespace. This was all that was required and also all that should be required.很少有人只需要与 SDL2 链接。当前流行的答案使用
pkg_search_module()
它检查给定的模块并使用第一个工作模块。您更有可能想要与 SDL2 和 SDL2_Mixer 和 SDL2_TTF 等链接...
pkg_check_modules()
检查所有给定的模块。免责声明:如果我有足够的 stackoverflow 街头信誉,我会简单地评论 Grumbel 的自我回答。
It's rare that one would only need to link with SDL2. The currently popular answer uses
pkg_search_module()
which checks for given modules and uses the first working one.It is more likely that you want to link with SDL2 and SDL2_Mixer and SDL2_TTF, etc...
pkg_check_modules()
checks for all the given modules.Disclaimer: I would have simply commented on Grumbel's self answer if I had enough street creds with stackoverflow.
没有
target_use
这样的命令。但我知道有几个项目已经编写了这样的命令供其内部使用。但是每个项目都希望传递额外的标志或定义,因此在一般 CMake 中拥有它是没有意义的。不拥有它的另一个原因是像 Eigen 这样的 C++ 模板库,没有库,但你只有一堆包含文件。所描述的方式通常是正确的。对于某些库,它可能有所不同,那么您必须添加
_LDFLAGS
或_CFLAGS
。没有target_use
的又一个原因。如果它不适合您,请提出一个关于 SDL2 或您想要使用的任何库的新问题。There is no such command as
target_use
. But I know several projects that have written such a command for their internal use. But every project want to pass additional flags or defines, thus it does not make sense to have it in general CMake. Another reason not to have it are C++ templated libraries like Eigen, there is no library but you only have a bunch of include files.The described way is often correct. It might differ for some libraries, then you'll have to add
_LDFLAGS
or_CFLAGS
. One more reason for not havingtarget_use
. If it does not work for you, ask a new question specific about SDL2 or whatever library you want use.如果您还想从库中添加定义,可以使用
add_definitions
指令。可以在此处找到文档,以及添加编译器标志的更多方法。以下代码片段使用此指令将 GTKGL 添加到项目中:
If you are looking to add definitions from the library as well, the
add_definitions
instruction is there for that. Documentation can be found here, along with more ways to add compiler flags.The following code snippet uses this instruction to add GTKGL to the project: