xmake是一個基於Lua的輕量級現代化c/c++的項目構建工具,主要特色是:語法簡單易上手,提供更加可讀的項目維護,實現跨平臺行爲一致的構建體驗。c++
本文主要詳細講解下,若是在一個項目中維護和生成多個目標文件的生成,以及它們之間的依賴關係設置。git
xmake的概念定義裏,一個獨立的項目工程可能會有多個子工程組織在一塊兒,每一個子工程對應只能生成一個惟一的目標文件,例如:可執行程序,靜態庫或者動態庫等。github
而這裏所說的每一個子工程就是xmake裏面所說的target
,字面意思就是目標子工程
。工具
所以每一個子工程,咱們均可以經過新增一個target在xmake.lua裏面維護,例如:ui
target("test1") set_kind("binary") add_files("src/test1/*.c") target("test2") set_kind("binary") add_files("src/test2/*.c")
上面咱們就定義了兩個獨立的子工程目標,編譯時候會生成兩個互不依賴的可執行文件。lua
暫時先不談target間的依賴問題,若是咱們有許多通用設置,每一個target下都得設置一遍,那會很是冗餘,也很差維護。設計
所以,咱們能夠把這些配置移到target域的外面,也就是根做用域中去設置,這樣對當前xmake.lua以及全部子xmake.lua中的target都會生效,例如:code
add_links("tbox") add_linkdirs("lib") add_includedirs("include") target("test1") set_kind("binary") add_files("src/test1/*.c") target("test2") set_kind("binary") add_files("src/test2/*.c")
好比這兩target都須要連接tbox庫,放置在外層根域設置,test1和test2都能加上對應links。繼承
那若是某個target須要用到另一個tatget生成的靜態庫,應該怎麼配置呢?接口
一種方式就是經過add_linkdirs
和add_links
手動指定對應target最後生成的目錄庫所在目錄,而後把連接加上。
target("foo") set_kind("static") add_files("foo/*.c") add_defines("FOO") target("test1") set_kind("binary") add_includedirs("foo/inc") add_links("foo") add_linkdirs("$(buildir)") add_files("test1/*.c") add_defines("FOO") target("test2") set_kind("binary") add_includedirs("foo/inc") add_links("foo") add_linkdirs("$(buildir)") add_files("test2/*.c") add_defines("FOO")
上述配置中,test1和test2都會用到libfoo庫,而且須要獲取到libfoo庫的頭文件路徑,庫路徑和連接,而且在使用過程當中還須要額外設置-DFOO
宏定義開關才行。
看上去沒啥,其實這麼寫有兩個問題:
那有沒有更加簡單可靠的配置方式呢,其實咱們只須要add_deps
來對target間配置上依賴關係便可。
target("foo") set_kind("static") add_files("*.c") add_defines("FOO", {public = true}) add_includedirs("foo/inc", {public = true}) target("test1") set_kind("binary") add_deps("foo") add_files("test1/*.c") target("test2") set_kind("binary") add_deps("foo") add_files("test2/*.c")
對比下,test1和test2的配置,是否是精簡了好多?僅僅經過add_deps("foo")
就繼承了libfoo的全部導出設置:linkdirs, links, includedirs以及defines
其中target自身生成的庫默認就會自動導出連接設置,而includedirs和defines經過設置public屬性,咱們也將它們標記爲導出,這樣能夠被test目標繼承到。
而且,如今有了依賴關係,xmake在編譯的時候,會自動處理這些target之間的編譯順序,保證不會出現連接的時候,libfoo庫尚未生成的問題。
根據上文所說,target會自動繼承依賴目標中的配置和屬性,不須要額外調用add_links
, add_linkdirs
和add_rpathdirs
等接口去關聯依賴目標了。
而且繼承關係是支持級聯的,例如:
target("library1") set_kind("static") add_files("*.c") add_includedirs("inc") -- 默認私有頭文件目錄不會被繼承 add_includedirs("inc1", {public = true}) -- 此處的頭文件相關目錄也會被繼承 target("library2") set_kind("static") add_deps("library1") add_files("*.c") target("test") set_kind("binary") add_deps("library2")
上面的配置中,test依賴library2,而後library2又依賴library1,那麼經過add_deps
僅僅添加library2的依賴,test就能夠完整繼承整個依賴鏈上的全部導出設置。
那若是咱們不想繼承依賴target的任何配置,如何操做呢?
add_deps("dep1", "dep2", {inherit = false})
經過顯式設置inherit配置,來告訴xmake,這兩個依賴的配置是否須要被繼承,若是不設置,默認就是啓用繼承的。
上文,咱們還經過 add_includedirs("inc1", {public = true})
, 設置public爲true, 將includedirs的設置公開給其餘依賴的子target繼承。
目前對於target的編譯連接flags相關接口設置,都是支持繼承屬性的,能夠人爲控制是否須要導出給其餘target來依賴繼承,目前支持的屬性有:
屬性 | 描述 |
---|---|
private | 默認設置,做爲當前target的私有配置,不會被依賴的其餘target所繼承 |
public | 公有配置,當前target,依賴的子target都會被設置 |
interface | 接口設置,僅被依賴的子target所繼承設置,當前target不參與 |
這個其實參考借鑑了cmake的設計,目前xmake中只要跟target相關的全部編譯連接設置接口,都是支持可見性導出的,例如:add_includedirs
, add_defines
, add_cflags
等等。
關於這塊的詳細信息,能夠看下:https://github.com/xmake-io/x...
原文:https://tboox.org/cn/2019/12/...
我的主頁
我的項目