CMake使用conan包时链接顺序指定

CMake使用conan包时链接顺序指定

问题

1
2
3
4
add_library(discoverplugin SHARED ${ALL_SOURCE})
conan_cmake_run(CONANFILE conanfile.txt
BASIC_SETUP CMAKE_TARGETS)
target_link_libraries(discoverplugin CONAN_PKG::landiscover rt dl m pthread stdc++fs)

conan包landiscover是一个静态库,且内部使用了标准库std::filesystem的相关功能。构建出discoverplugin动态库之后,发现找不到std::filesystem相关符号,但是我已经在target_link_libraries加入了stdc++fs,而且它还是最后一个,怎么可能找不到呢?

分析

在builddir/discoverplugin/src/CMakeFiles/discoverplugin.dir/link.txt找到链接器命令行,发现rt dl m pthread stdc++fs的链接在conan包中库之前。这就奇怪了,我明明将这几个库写在了后面,为什么会这样呢?

所有的一切都很正常,除了CONAN_PKG::landiscover这个conan包是从外面引入的,问题很有可能出现在它上面。在builddir/discoverplugin/src/conanbuildinfo.cmake找到CONAN_PKG::landiscover包相关设定如下:

1
2
add_library(CONAN_PKG::landiscover INTERFACE IMPORTED)
set_property(TARGET CONAN_PKG::ZeusFoundation PROPERTY INTERFACE_LINK_LIBRARIES .......) # 很多生成表达式,都是在拼路径这里就不详细展开了

这里我们注意到包CONAN_PKG::landiscover是通过add_library添加进来的,而且用了两个个看起来有些不同寻常的选项参数INTERFACEIMPORTED,查阅CMake的文档看下CMake怎么说.

Creates an Interface Library. An INTERFACE library target does not compile sources and does not produce a library artifact on disk. However, it may have properties set on it and it may be installed and exported. Typically, INTERFACE_* properties are populated on an interface target using the commands:

具有INTERFACE类型的目标,并不会真的从源码构建为一个动态库或静态库,但是它却能像一个普通的的动态库静态库一样调用以下方法:

1
2
3
4
5
6
7
set_property()
target_link_libraries(INTERFACE)
target_link_options(INTERFACE)
target_include_directories(INTERFACE)
target_compile_options(INTERFACE)
target_compile_definitions(INTERFACE)
target_sources(INTERFACE)

An IMPORTED target represents a pre-existing dependency. Usually such targets are defined by an upstream package and should be treated as immutable. After declaring an IMPORTED target one can adjust its target properties by using the customary commands such as target_compile_definitions(), target_include_directories(), target_compile_options() or target_link_libraries() just like with any other regular target.

具有IMPORTED类型的目标代表了一个已经存在的依赖关系,通常这样的目标是上游包定义的,也可理解为预编译二进制文件,但是我们能像普通的目标一样用以下方法对目标的属性进行修改:

1
2
3
4
target_compile_definitions()
target_include_directories()
target_compile_options()
target_link_libraries()

解决

1
2
3
4
5
conan_cmake_run(CONANFILE conanfile.txt
BASIC_SETUP CMAKE_TARGETS)
# 解决链接器依赖顺序导致有符号没有链接到的问题
target_link_libraries(CONAN_PKG::landiscover INTERFACE rt dl m pthread stdc++fs)
target_link_libraries(${LIBNAME} CONAN_PKG::landiscover)

给库CONAN_PKG::landiscover添加链接依赖即可,如此CMake生成的链接器命令行在库CONAN_PKG::landiscover后会链接rt dl m pthread stdc++fs

参考


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!