Open xizhibei opened 3 years ago
请问作者, FooConfig.cmake的内容是靠 install(export) 自动生成的吗? 我想将这部分内容从手写改为cmake自动生成, 但是无法处理区分链接 动态库或静态库的需求, 导致只能手写Findxxx.cmake文件.
请问作者, FooConfig.cmake的内容是靠 install(export) 自动生成的吗? 我想将这部分内容从手写改为cmake自动生成, 但是无法处理区分链接 动态库或静态库的需求, 导致只能手写Findxxx.cmake文件.
不是,上面的例子是给第三方没有实现 cmake 支持的库写的,如果是自己的项目就参考 https://github.com/xizhibei/blog/issues/137 这个里面写的自动生成
拜读过 #137 ,但是那样生成的 cmake config 文件应该不支持区分静态库或者动态库, 而且动态库和静态库是两个 cmake config 文件. 不知作者是否有研究过如何将动态库和静态库合并导出一个 cmake config 文件让其他人引用? 目前我是手写的, 正在找有没有自动生成的方法.
大概明白你意思了,我说个我们自己使用的方式:
从 target 名称进行区分,比如静态库是 foo
而动态库是 fooShared
,这样的话,编译一次就可以自动生成一个 find config,不过你会导出名字变为 libfooShared.so
,想要统一的话,可以用 set_target_properties(fooShared PROPERTIES OUTPUT_NAME foo)
比如静态库是 foo 而动态库是 fooShared,这样的话,编译一次就可以自动生成一个 find config -- 请问这步是如何实现的? 我理解成是写成下面这样的代码, 这样会生成2个find config.
install(TARGETS foo EXPORT myfooLib)
install(EXPORT myfooLib)
install(TARGETS fooShared EXPORT myfooSharedLib)
install(EXPORT myfooSharedLib)
可以直接参考 #137 的导出部分来,我给个关键的部分
add_library(fooStatic STATIC foo.cpp)
set_target_properties(fooStatic PROPERTIES OUTPUT_NAME foo) # libfoo.a
add_library(fooShared SHARED foo.cpp)
set_target_properties(fooShared PROPERTIES OUTPUT_NAME foo) # libfoo.so
install(
TARGETS fooStatic fooShared
EXPORT Foo
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES
DESTINATION include)
install(
EXPORT Foo
FILE FooTargets.cmake
NAMESPACE Foo::
DESTINATION lib/cmake/Foo/)
在使用的时候:
find_package(Foo)
target_link_libraries(bar PUBLIC Foo::fooShared)
# 或者
target_link_libraries(bar PUBLIC Foo::fooStatic)
这两天我试了下, 按照您给的建议, 已经将动态库和静态库合一安装, 其他 project 也能正常引用到. 说来也巧, 真的是因为这篇文章独立的标题 我才能检索到这的, 再次感谢下.
另外, 关于安装部分有个问题想再请教下. 假设下面这种场景
我想了下, 要么停止 library A 的依赖库传染, 要么想办法把 target B 也传递给 binary B. 前者应该会导致依赖不完整,, 后者感觉应该是在您前面提到的 myLibConfig.cmake.in
做文章.
myLibConfig.cmake.in
中 include target B 的 cmake 文件, 让 binary B 也拥有这个 import target.hh,挺巧
你说这个问题没遇到过,目前除了你说的,没有更好的办法了
hh,挺巧
你说这个问题没遇到过,目前除了你说的,没有更好的办法了
周末检索各种资料确认了下, CMake官方的态度是这类第三方依赖应该downstream提前安装好, upstream在 myLibConfig.cmake.in
中写明依赖项即可.
根据我自己的工程实践, 觉得使用上还是麻烦了点, 尤其是一些闭源的场景. 目前的解决方案是在 myLibConfig.cmake.in
做文章, 根据需要导出的target清单自动重写了imported target的依赖, 感觉可以接受了.
不管怎样, 感谢作者的博客和答疑, 帮我解决了很大的困惑.
今天这篇文章算是对 【CMake 系列】(五)安装、打包与导出 的一个补充。其实我本打算跟上篇文章放在一起,毕竟都属于动态链接库相关的知识,但是这样一来就不容易被出现问题的同学们检索到了(才不是为了再水一篇文章 doge)。
问题的由来
是因为这个问题困扰了我不少时间,在好几个项目里面都遇到了这个问题。
那就是链接动态库的时候,编译出来的可执行文件会带有编译时的绝对路径,于是你将程序拷贝到其它地方运行的时候,必须把动态库放到绝对路径里面去,而不是放在系统里面相关的 lib 路径下面。
举一个例子,假如我们要实现一个
FooConfig.cmake
,这个库中既有静态库也有动态库,那么如果我们要在项目中使用,大概的实现方式是:将它命名为
FooConfig.cmake
然后放在位于项目根目录的 cmake 文件夹下,并且在项目中这样使用:最后,假如我们查找的库在
/path/to/foo/home
下面,那么我们用在项目中得到的结果会是这样的:这里就出现了绝对路径,当初这个问题折磨了我很久,一直以为是 RPATH 的问题,最后发现是 CMake 本身的问题。
如何解决
出现这个问题的原因就是库的 Package Find Config 不对,我研究了挺长时间,最后在官方的讨论中找到了原因以及答案:
IMPORTED_NO_SONAM
E 的属性;UNKNWON
类型的库;于是,将上面的代码改下即可: