1. 首先是當(dāng)前這個例子中要用到的一些命令
1.1. add_library
添加一個lib到工程中,指定這個lib的源文件
函數(shù)定義
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
<name>是目標(biāo)庫的名字,這個名字在工程內(nèi)全局唯一,最終編譯出來的目標(biāo)文件名字取決于目標(biāo)平臺(比如說lib<name>.a或<name>.lib)
STATIC, SHARED, 或MODULE用來指定要創(chuàng)建的lib的類型。
-
STATIC, 代表靜態(tài)鏈接庫,編譯的時候link到工程中; -
SHARED,代表動態(tài)鏈接庫,運行時候加載; -
MODULE,是一些插件,運行時候使用dlopen-like的功能進(jìn)行動態(tài)加載;
EXCLUDE_FROM_ALL 會在目標(biāo)文件上設(shè)置相應(yīng)的屬性(執(zhí)行默認(rèn)make的時候,這個目標(biāo)文件會被排除在外,不被編譯)
add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED
[GLOBAL])
一個Imported Lib目標(biāo)代表一個工程外部的庫文件,當(dāng)前這個工程內(nèi)滅有命令來編譯這個庫,并且這個庫的IMPORT屬性是true。
沒有設(shè)置GLOBAL的時候,這個目標(biāo)名稱的作用域只在創(chuàng)建它的目錄以及子目錄;設(shè)置了之后,全局可見。
NOTE: Imported Target通常代表一個工程的一個依賴,一般只能作為諸如
target_link_libraries()這樣命令的右值,不能修改
add_library(<name> OBJECT <src>...)
創(chuàng)建一個特殊的“object library” 目標(biāo)。這種庫只編譯源文件生成目標(biāo)文件,但是不把這些目標(biāo)文件打包進(jìn)一個lib。當(dāng)其他的庫或者目標(biāo)文件要使用這些目標(biāo)文件的時候,會以這樣的形式來添加,objlib是這個庫的名字
add_library(... $<TARGET_OBJECTS:objlib> ...)
add_executable(... $<TARGET_OBJECTS:objlib> ...)
add_library(<name> INTERFACE [IMPORTED [GLOBAL]])
創(chuàng)建一個Interface庫,一個INTERFACE庫不會直接創(chuàng)建編譯目標(biāo)文件,即使這個庫可以設(shè)置一些屬性并且可以被installed,exported和imported。通常來說使用set_property(),target_link_libraries(INTERFACE), target_include_directories(INTERFACE),target_compile_options(INTERFACE)和target_compile_definitions(INTERFACE)這些函數(shù)來設(shè)置INTERFACE_*屬性,然后這個庫可以像其他庫一樣作為target_link_libraries()命令的參數(shù)。
這里還可以通過設(shè)置IMPORTED標(biāo)志來生成一個INTERFACE imported Target,表示這個庫文件在工程外。
1.2. target_include_directories
target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
指定編譯目標(biāo)文件的時候需要包含的路徑和內(nèi)容, <target> 必須是一個已經(jīng)通過諸如 add_executable()或者add_library()函數(shù)創(chuàng)建了的目標(biāo),并且不是一個標(biāo)注成IMPORTED目標(biāo)。
INTERFACE, PUBLIC 和 PRIVATE這些關(guān)鍵字用來指定后面這些參數(shù)的作用范圍。PUBLIC和INTERFACE的條目會產(chǎn)生目標(biāo)對象的INTERFACE_INCLUDE_DIRECTORIES屬性(也就是說添加了的公共默認(rèn)搜索路徑),后面的參數(shù)定義了包含路徑。
指定的包含路徑可以是絕對路徑也可以是相對路徑,重復(fù)調(diào)用相同的<target>會把這些條目按次序添加到對象上。如果指定了SYSTEM屬性,則意味著這個路徑是一個系統(tǒng)路徑
target_include_directories 的參數(shù)可以使用“生成表達(dá)式”,語法是$<...>。
包含路徑的使用要求對于build樹和instal樹通常是不太一樣的。BUILD_INTERFACE 和 INSTALL_INTERFACE 生成表達(dá)式可以用來描述不同的使用要求。
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
$<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
)
2. 實例
- 首先看一下當(dāng)前工程的目錄
.
├── CMakeLists.txt
├── include
│ └── Logger.hpp
└── src
└── Logger.cpp
很簡單的一個工程,提供了spdlog的一個簡單封裝,其他文件要使用日志功能的時候只要包含Logger.hpp頭文件就可以了。
- 下面是CMakeLists.txt文件
set(module_name logger)
project(${module_name} CXX)
message(STATUS "Configuring ${module_name}")
set(sources
src/Logger.cpp
)
set(headers
include/Logger.hpp
)
#依賴開源的interface庫spdlog,添加一個interface類型的庫目標(biāo)
add_library(spdlog INTERFACE)
#給這個interface庫添加屬性,也就是這個spdlog的頭文件的相對路徑
target_include_directories(
spdlog
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../../externals/spdlog/include>"
)
#spdlog依賴的線程庫
find_package(Threads)
#添加要編譯的logger庫
add_library(${module_name} ${sources} ${headers})
target_link_libraries(${module_name} spdlog ${CMAKE_THREAD_LIBS_INIT})
#和之前一樣,指定需要包含的路徑(這個時候spdlog庫里面已經(jīng)包含了spdlog的頭文件搜索路徑了,所以當(dāng)前這個logger庫就不用額外指定了)
target_include_directories(
${module_name}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
)
- 使用logger庫的主工程
這個cmake只要把logger庫link進(jìn)來就可以了,logger庫內(nèi)的頭文件搜索路徑都被一并繼承了。
set(module_name sctp_proxy)
project(&{module_name} CXX)
add_subdirectory(libs)
add_executable(${module_name} main.cpp)
target_link_libraries(${module_name} logger)