这里不是比较automake和cmake,但在工作当中,当一个三方库(sse_pb
)既有动态库,又有静态库时,我们使用-lsse_pb
连接时,系统会默认使用动态库,但我们需要优先使用静态库链接时, automake方式比较简单,但对于cmake,这里提供3种办法:
1.使用GCC编译参数
我们可以使用GCC的编译参数-Wl,-Bstatic
和-Wl,-Bdynamic
来实现指定优先静态编译:
find_package(PkgConfig)
pkg_check_modules(brpc REQUIRED IMPORTED_TARGET brpc)
pkg_search_module(sse_pb REQUIRED sse_pb)
add_library(basic_search SHARED)
target_link_libraries(basic_search
PRIVATE
basic_search_common
basic_search_util
...
PUBLIC
PkgConfig::brpc
-Wl,-Bstatic
${sse_pb_LIBRARIES}
-Wl,-Bdynamic
)
值得注意的是 pkg_check_modules
会将 pc 文件内的链接 -lsse_pb
预先生成 /usr/lib64/libsse_pb.so
形式,导致即使添加GCC参数也不会生效。所以正确的方式是使用 pkg_search_module
来生成cmake的宏变量,一般存在两组值:
-
用于普通情况,
pkg-config
在使用--libs
选项调用时提供的信息,如<XXX> = <prefix>
-
用于
pkg-config
在额外添加--static
选项调用时提供的信息 (<XXX> = <prefix>_STATIC
)
对应的宏变量有下列这些:
<XXX>_FOUND:如果模块存在,则设置为 1
<XXX>_LIBRARIES:只有库 (没有 "-l")
<XXX>_LINK_LIBRARIES:库及其绝对路径
<XXX>_LIBRARY_DIRS:库的路径 (没有 "-L")
<XXX>_LDFLAGS:所有必需的链接器标志
<XXX>_LDFLAGS_OTHER:所有其他链接器标志
<XXX>_INCLUDE_DIRS:预处理器标记'-I'(没有'-I')
<XXX>_CFLAGS:所有必需的 cflags
<XXX>_CFLAGS_OTHER:其他编译器标志
<YYY>_VERSION:模块版本
<YYY>_PREFIX:模块的前缀目录
<YYY>_INCLUDEDIR:包含模块的目录
<YYY>_LIBDIR:模块的 Lib 目录
如上述 ${sse_pb_LIBRARIES}
的设置,就是将 sse_pb 库以静态优先的方式链接起来。
2.使用CMAKE_FIND_LIBRARY_SUFFIXES
我们还可以使用 find_library
,通过改变查找 .a
文件的顺序来获得静态文件优先规则,如下所示:
if (WIN32 OR MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
elseif (UNIX)
# 仅查找静态库,强制后缀为 .a
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
# 如果只是优先查找静态库,保证 .a 后缀在前面即可,把默认的后缀加上
# set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
find_library(sse_pb_lib sse_pb)
target_link_libraries(basic_search
${sse_pb_lib}
)
3.写死路径
在这种 set_property
方式下,主要依赖路径:
add_library(sse_pb STATIC IMPORTED)
set_property(TARGET sse_pb PROPERTY IMPORTED_LOCATION /path/to/libsse_pb.a)
target_link_libraries(basic_search sse_pb)
其中 /path/to/libsse_pb.a
从上可以看出,最灵活也是最优雅的还是第一种方式,可以依赖pkg-config建立很好的环境变量,从而进行静态编译。