當使用CMake來生成編譯腳本時,如果需要鏈接其他庫文件,一般使用target_link_libraries,如:
target_link_libraries(master
flatbuffers
mariadbclient
ssl
crypto
dl
rt
pthread
resolv
z
)
默認情況下,這個是鏈接動態庫的。不過很多時候為了方便部署,需要靜態鏈接部分靜態鏈庫,有幾種方式可以試下:
- 直接寫死靜態庫的完整路徑
target_link_libraries(master
/usr/local/lib/libflatbuffers.a
)
- 自動查找靜態庫
上面直接寫死庫文件的完整路徑,可移植性大打折扣。CMake的好處本身就是跨平台的,各個平台的庫文件路徑不一樣,可以使用find_library
來獲取完整路徑。不過find_library
默認情況下是優先查找動態庫的,需要改一下
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(FLATBUFFERS_LIB flatbuffers)
target_link_libraries(master
${FLATBUFFERS_LIB}
)
# 當然,這個可能更簡單,只是也不跨平台罷了
find_library(FLATBUFFERS_LIB libflatbuffers.a)
- 直接指定庫文件后綴或者名字
target_link_libraries(master
libflatbuffers.a
)
# 或者
target_link_libraries(master
flatbuffers.a
)
上面的寫法都會查找靜態庫,只不過不跨平台(win下后綴是.lib)。
- 使用編譯參數
target_link_libraries(master
-Wl,-Bstatic
flatbuffers
-Wl,-Bdynamic
)
target_link_libraries
里是可以加編譯參數的。在庫名字的前后,可以直接指定編譯參數強制使用靜態庫,只不過同樣不跨平台,畢竟GCC和MSBuild的參數可差遠了。
總而言之,目前官方是沒有直接提供一個優先鏈接靜態庫
的選項,比較推薦的是修改find_library
優先級的方式,畢竟還有if else控制一下,可以處理跨平台的情況。但很多情況下跨平台也不一定是跨編譯器,比如我一般寫的Linux下的程序,到win下是用mingw編譯器,所以全部都用.a
后綴是沒有問題的。
target_link_libraries
會影響依賴它的目標編譯參數
Library dependencies are transitive by default with this signature. When this target is linked into another target then the libraries linked to this target will appear on the link line for the other target too.
add_library(lua_flatbuffers STATIC ${SRC_LIST})
target_link_libraries(lua_flatbuffers flatbuffers)
target_link_libraries(master
lua_flatbuffers
flatbuffers.a
ssl
)
上面這個例子,編譯lua_flatbuffers
這個靜態庫的時候,依賴flatbuffers
。而master
依賴lua_flatbuffers
,此時CMake會自動把lua_flatbuffers
的依賴flatbuffers
自動加到master
去。即原本master
的參數為-Wl,-Bstatic lua_flatbuffers -lflatbuffers -Bdynamic -lssl
,現在卻變成了-Wl,-Bstatic lua_flatbuffers -lflatbuffers -Bdynamic -lssl -lflatbuffers
,后面多了一個-lflatbuffers
。即使master
的庫里強制指定靜態庫,但由於lua_flatbuffers
使用的是動態庫,所以最終master
使用的也是動態庫。
這個問題讓我查了很久,可以強制清空lua_flatbuffers
的INTERFACE_LINK_LIBRARIES來解決
set_target_properties(lua_flatbuffers PROPERTIES INTERFACE_LINK_LIBRARIES "")
如果編譯出現問題,cmake
之后可以用make VERBOSE=1
來編譯程序,各種參數一清二楚,方便查找問題
-o /home/test/code/MServer/server/bin/master -Wl,-Bstatic -llua -luuid -lflatbuffers -lmariadbclient -lmongoc-static-1.0 -lbson-static-1.0 -lsasl2 -Wl,-Bdynamic -Wl,-Bstatic -lz -Wl,-Bdynamic -lssl -lcrypto -ldl -lrt -lpthread -lresolv