一般C/C++语言的编译,我还是喜欢使用automake,虽然它缺少通配符的支持,但其支持Makefile的原生语法以及一旦生成了Makefile,在任意有Makefile的目录修改Makefile.am之后都可以直接make;且结合libtool之后,动态库和静态库可以随心编译;这个是cmake不能比的,但cmake也有其优点,比如通配等。
这里不是比较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的宏变量,一般存在两组值:
对应的宏变量有下列这些:
<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)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".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建立很好的环境变量,从而进行静态编译。