xmake v2.5.1 發佈, 支持 Apple Silicon 並改進 C/C++ 包依賴管理

xmake 是一個基於 Lua 的輕量級跨平臺構建工具,使用 xmake.lua 維護項目構建,相比 makefile/CMakeLists.txt,配置語法更加簡潔直觀,對新手非常友好,短時間內就能快速入門,能夠讓用戶把更多的精力集中在實際的項目開發上。

這是 xmake 在今年的首個版本,也是完全適配支持 Apple Silicon (macOS ARM) 設備的首個版本。

這個版本,我們主要改進了對 C/C++ 依賴包的集成支持,更加的穩定,並且能夠更加靈活的實現定製化配置編譯。

另外,我們還重點改進 vs/vsxmake 兩個vs工程生成器插件,修復了很多細節問題,並且對子工程分組也做了支持,現在可以生成類似下圖的工程結構。

關於 Zig 方面,0.7.1 版本修復了很多我之前反饋的問題,現在 xmake 也已經可以很好的支持對 zig 項目的編譯。

同時,我們還新開發了一個 luarocks=build-xmake 插件去用 xmake 替換 luarocks 內置的構建系統。

最後,在這個版本中,我們繼續改進了 xmake f --menu 圖形化配置菜單,完全支持鼠標操作和滾動支持,也對 utf8 做了支持。

  • 項目源碼

  • 官方文檔

  • 入門課程

新特性介紹

新增 add_requireconfs 改進包配置

儘管之前的版本,我們可以通過 add_requires("libpng", {configs = {shared = true}}) 的方式來定義和配置依賴包。

但是,如果用戶項目的工程龐大,依賴包非常多,且每個包都需要不同的編譯配置參數,那麼配置起來還是會非常繁瑣,並且具有侷限性,比如無法改寫內部的子依賴包配置。

因此,我們新增了 add_requireconfs 去更靈活方便的配置每個包的配置以及它的子依賴,下面我們重點介紹幾種用法:

擴充指定包的配置

這是基本用法,比如我們已經通過 add_requires("zlib") 聲明瞭一個包,想要在後面對這個 zlib 的配置進行擴展,改成動態庫編譯,可以通過下面的方式配置。

add_requires("zlib")
add_requireconfs("zlib", {configs = {shared = true}})

它等價於

add_requires("zlib", {configs = {shared = true}})
設置通用的默認配置

上面的用法,我們還看不出有什麼實際用處,但如果依賴多了就能看出效果了,比如下面這樣:

add_requires("zlib", {configs = {shared = true}})
add_requires("pcre", {configs = {shared = true}})
add_requires("libpng", {configs = {shared = true}})
add_requires("libwebp", {configs = {shared = true}})
add_requires("libcurl", {configs = {shared = false}})

是不是非常繁瑣,如果我們用上 add_requireconfs 來設置默認配置,就可以極大的簡化成下面的配置:

add_requireconfs("*", {configs = {shared = true}})
add_requires("zlib")
add_requires("pcre")
add_requires("libpng")
add_requires("libwebp")
add_requires("libcurl", {configs = {shared = false}})

上面的配置,我們通過 add_requireconfs("*", {configs = {shared = true}}) 使用模式匹配的方式,設置所有的依賴包默認走動態庫編譯安裝。

但是,我們又通過 add_requires("libcurl", {configs = {shared = false}}) 將 libcurl 進行了特殊配置,強制走靜態庫編譯安裝。

最終的配置結果爲:zlib/pcre/libpng/libwebp 是 shared 庫,libcurl 是靜態庫。

我們通過模式匹配的方式,可以將一些每個包的常用配置都放置到統一的 add_requireconfs 中去預先配置好,極大簡化每個 add_requires 的定義。

!> 默認情況下,對於相同的配置,xmake 會優先使用 add_requires 中的配置,而不是 add_requireconfs。

如果 add_requires("zlib 1.2.11") 中設置了版本,就會優先使用 add_requires 的配置,完全忽略 add_requireconfs 裏面的版本配置,當然我們也可以通過 override 來完全重寫 add_requires 中指定的版本。

add_requires("zlib 1.2.11")
add_requireconfs("zlib", {override = true, version = "1.2.10"})
改寫包依賴配置

其實 add_requireconfs 最大的用處是可以讓用戶改寫安裝包的特定依賴包的配置。

什麼意思呢,比如我們項目中集成使用 libpng 這個包,並且使用了動態庫版本,但是 libpng 內部依賴的 zlib 庫其實還是靜態庫版本。

add_requires("libpng", {configs = {shared = true}})

那如果我們想讓 libpng 依賴的 zlib 包也改成動態庫編譯,應該怎麼配置呢?這就需要 add_requireconfs 了。

add_requires("libpng", {configs = {shared = true}})
add_requireconfs("libpng.zlib", {configs = {shared = true}})

通過 libpng.zlib 依賴路徑的寫法,指定內部某個依賴,改寫內部依賴配置。

如果依賴路徑很深,比如 foo -> bar -> xyz 的依賴鏈,我們可以寫成:foo.bar.xyz

我們也可以改寫 libpng 依賴的內部 zlib 庫版本:

add_requires("libpng")
add_requireconfs("libpng.zlib", {version = "1.2.10"})
級聯依賴的模式匹配

如果一個包的依賴非常多,且依賴層次也很深,怎麼辦呢,比如 libwebp 這個包,它的依賴有:

libwebp
  - libpng
    - zlib
    - cmake
  - libjpeg
  - libtiff
    - zlib
  - giflib
  - cmake

如果我想改寫 libwebp 裏面的所有的依賴庫都加上特定配置,那麼挨個配置,就會非常繁瑣,這個時候就需要 add_requireconfs() 的遞歸依賴模式匹配來支持了。

add_requires("libwebp")
add_requireconfs("libwebp.**|cmake", {configs = {cxflags = "-DTEST"}})

上面的配置,我們將 libwebp 中所以的庫依賴就額外加上了 -DTEST 來編譯,但是 cmake 依賴屬於構建工具依賴,我們可以通過 |xxx 的方式排除它。

這裏的模式匹配寫法,與 add_files() 非常類似。

我們在給幾個例子,比如這回我們只改寫 libwebp 下單級的依賴配置,啓用調試庫:

add_requires("libwebp")
add_requireconfs("libwebp.*|cmake", {debug = true})

圖形化配置支持鼠標和滾動操作

我們升級了 xmake 所使用的 tui 組件庫:LTUI,增加了對鼠標的支持,以及部分組件的滾動支持,我們可以再圖形化配置中,更加靈活方便的配置編譯選項。

stdin 重定向輸入支持

之前的版本中,xmake 提供的 os.execv/os.runv 等進程執行接口,僅僅只支持 stdout/stderr 輸出重定向,但是並不支持 stdin 輸入重定向,因此在這個版本中,我們對其也做了支持。

使用方式如下:

os.execv("foo", {"arg1""arg2"}, {stdin = "/tmp/a"})

我們可以執行進程的時候,將 /tmp/a 文件作爲重定向輸入,當然我們還可以傳遞 {stdout = "/tmp/out"} 等作爲重定向輸出。

vs 工程分組支持

我們新增了一個接口 set_group,來對每個 target 進行分組支持,此接口目前僅用於 vs/vsxmake 工程生成,對 vs 工程內部子工程目錄樹按指定結構分組展示,不過後續也可能對其他模塊增加分組支持。

比如對於下面的分組配置:

add_rules("mode.debug""mode.release")

target("test1")
    set_kind("binary")
    add_files("src/*.cpp")
    set_group("group1")

target("test2")
    set_kind("binary")
    add_files("src/*.cpp")
    set_group("group1")

target("test3")
    set_kind("binary")
    add_files("src/*.cpp")
    set_group("group1/group2")

target("test4")
    set_kind("binary")
    add_files("src/*.cpp")
    set_group("group3/group4")

target("test5")
    set_kind("binary")
    add_files("src/*.cpp")

target("test6")
    set_kind("binary")
    add_files("src/*.cpp")

生成的 vs 工程目錄結構效果如下:

其中 set_group("group1/group2") 可以將 target 設置到二級分組中去。

vs 工程自動更新規則

如果覺得每次通過 xmake project -k vsxmake 命令來生成和更新 vs 工程很繁瑣,我們現在可以通過在 xmake.lua 中配置 plugin.vsxmake.autoupdate 規則來實現自動更新。

用戶可以在 vs 工程中每次執行構建後,如果文件列表或者 xmake.lua 有改動,vs 工程都會自動更新。

add_rules("plugin.vsxmake.autoupdate")

target("test")
    set_kind("binary")
    add_files("src/*.c")

vs/vsxmake 工程插件改進

除了上面提到的分組支持和自動更新,這個版本中,我們還修復了不少 vs 工程相關的問題,比如:intellisense 提示改進,路徑被截斷的問題修復,全面支持遠程依賴包

改進 windows 註冊表支持

xmake 改進了內部的 winos 模塊,新增了一些接口來更加方便的訪問註冊表,獲取 windows 上的註冊表配置。

winos.registry_keys

  • 獲取註冊表建列表

支持通過模式匹配的方式,遍歷獲取註冊表鍵路徑列表,* 爲單級路徑匹配,** 爲遞歸路徑匹配。

local keypaths = winos.registry_keys("HKEY_LOCAL_MACHINE\\SOFTWARE\\*\\Windows NT\\*\\CurrentVersion\\AeDebug")
for _, keypath in ipairs(keypaths) do
    print(winos.registry_query(keypath .. ";Debugger"))
end

winos.registry_values

  • 獲取註冊表值名列表

支持通過模式匹配的方式,獲取指定鍵路徑的值名列表,; 之後的就是指定的鍵名模式匹配字符串。

local valuepaths = winos.registry_values("HKEY_LOCAL_MACHINE\\SOFTWARE\\xx\\AeDebug;Debug*")
for _, valuepath in ipairs(valuepaths) do
    print(winos.registry_query(valuepath))
end

winos.registry_query

  • 獲取註冊表建值

獲取指定註冊表建路徑下的值,如果沒有指定值名,那麼獲取鍵路徑默認值

local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug")
local value, errors = winos.registry_query("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debugger")

Zig 項目構建支持

在上個版本中,xmake 已經對 zig 進行了實驗性支持,但是期間也躺了不少坑,尤其是 windows/macos 上構建中遇到了不少問題。

然後在最新的 zig 0.7.1 中,已經將我遇到的大部分問題都修復了,現在 xmake 已經可以很好的支持 zig 項目編譯。

我們可以通過下面的命令,快速創建一個 Zig 空工程:

$ xmake create -l zig console

xmake.lua 內容如下:

add_rules("mode.debug""mode.release")

target("console")
    set_kind("binary")
    add_files("src/*.zig")

可以看到,其實配置方式跟 C/C++ 並沒有什麼不同,由於 Zig 和 C 有很好的二進制兼容,因此我們也可以使用 add_requires 來給 zig 項目添加 C/C++ 包的遠程依賴支持。

然後執行 xmake 就可以完成編譯了。

$ xmake

然後繼續運行 run 命令,就可以直接執行 zig 程序,輸出運行結果。

$ xmake run
Hello world!

我們還可以很方便的實現 C 和 Zig 的混合編譯支持,只需要添加上對應的 C 代碼文件就可以了。

add_rules("mode.debug""mode.release")

target("console")
    set_kind("binary")
    add_files("src/*.zig""src/*.c")

完整代碼例子見:Zig with C

Luarocks 插件

luarocks 是 lua 的一個包管理工具,提供了各種 lua 模塊的安裝集成,不過它本身在對 lua c 模塊進行構建是採用的內建的構建機制。

比如在它的 rockspec 文件中通過 builtin 構建類型來描述常用 lua c 模塊的構建:

build = {
    type = "builtin",
    modules = {
        ["module.hello"] = {
            sources = "src/test.c"
        }
    },
    copy_directories = {}
}

這對於小模塊而言,並沒有什麼問題,但如果模塊的 c 代碼結構比較複雜,它內置的構建規則還是有很多的侷限性,並不靈活,另外切換 msvc / mingw 工具鏈以及參數配置什麼的都不夠靈活。

因此,xmake 提供了 luarocks=build-xmake 插件去替換 luarocks 內置的構建系統,替換方式也很簡單,只需要將 builtin 構建類型改成 xmake,並加上 luarocks-build-xmake 依賴就行了。

dependencies = {
    "lua >= 5.1",
    "luarocks-build-xmake"
}
build = {
    type = "xmake",
    modules = {
        ["module.hello"] = {
            sources = "src/test.c"
        }
    },
    copy_directories = {}
}

但是這樣還是很繁瑣,還是要基於 rockspec 文件中 modules 中的源文件列表來描述規則,然後 luarocks-build-xmake 會自動根據配置生成 xmake.lua 來完成構建。

不過既然用了 xmake,那麼自己的 lua 模塊,完全可以用 xmake.lua 來維護,這樣構建配置就更加靈活了,因此我們只需要下面這樣就行了。

dependencies = {
    "lua >= 5.1",
    "luarocks-build-xmake"
}
build = {
    type = "xmake",
    copy_directories = {}
}

只需要設置當前切換到 xmake 編譯,完全使用 lua 模塊項目內置的 xmake.lua 規則文件。

支持在 windows 安裝部署 Qt 程序

非常感謝 @SirLynix 的貢獻,xmake 已經可以支持在 windows 上部署安裝 Qt 應用程序。

我們只需要正常維護一個 Qt 程序,例如:

add_rules("mode.debug""mode.release")

target("demo")
    add_rules("qt.quickapp")
    add_headerfiles("src/*.h")
    add_files("src/*.cpp")
    add_files("src/qml.qrc")

然後,我們只需要執行下面的編譯安裝命令,xmake 就會自動調用 windeployqt.exe 程序去安裝部署我們的 Qt 應用。

$ xmake
$ xmake install -o d:\installdir

相關補丁:#1145

另外,在之前的版本中,xmake 也已經支持對 macOS 和 android 版本的 Qt 程序進行部署打包,每次只需要正常的編譯命令,就可以生成 QT .app/.apk 安裝包。

$ xmake f -p android --ndk=/xxx/android-ndk-r20b --sdk=/xxx
$ xmake

一些問題修復

我們還修復了不少用戶反饋的問題,這裏我們介紹一些比較重要的 bug 修復,例如:

我們修復了 add_defines("TEST=\"hello world\"") 中內部帶有空的雙引號問題,之前編譯會出錯。

另外我們改進了 vstudio 環境的查找和支持,解決了用戶 home 目錄和環境變量中帶有中文導致的編譯失敗問題。

我們也改進了 llvm 工具鏈,解決了 macOS 下如果沒有安裝 xcode 的情況下,使用 llvm 工具鏈缺少 isysroot 配置問題,以及 msvc 下頭文件依賴編譯偶爾失效問題。

更新內容

新特性

  • #1035: 圖形配置菜單完整支持鼠標事件,並且新增滾動欄

  • #1098: 支持傳遞 stdin 到 os.execv 進行輸入重定向

  • #1079: 爲 vsxmake 插件添加工程自動更新插件,add_rules("plugin.vsxmake.autoupdate")

  • 添加 xmake f --vs_runtime=MTset_runtimes("MT") 去更方便的對 target 和 package 進行設置

  • #1032: 支持枚舉註冊表 keys 和 values

  • #1026: 支持對 vs/vsmake 工程增加分組設置

  • #1178: 添加 add_requireconfs() 接口去重寫依賴包的配置

  • #1043: 爲 luarocks 模塊添加 luarocks.module 構建規則

  • #1190: 添加對 Apple Silicon (macOS ARM) 設備的支持

  • #1145: 支持在 windows 上安裝部署 Qt 程序, 感謝 @SirLynix

改進

  • #1072: 修復並改進 cl 編譯器頭文件依賴信息

  • 針對 ui 模塊和 xmake f --menu 增加 utf8 支持

  • 改進 zig 語言在 macOS 上的支持

  • #1135: 針對特定 target 改進多平臺多工具鏈同時配置支持

  • #1153: 改進 llvm 工具鏈,針對 macos 上編譯增加 isysroot 支持

  • #1071: 改進 vs/vsxmake 生成插件去支持遠程依賴包

  • 改進 vs/vsxmake 工程生成插件去支持全局的 set_arch() 設置

  • #1164: 改進 vsxmake 插件調試加載 console 程序

  • #1179: 改進 llvm 工具鏈,添加 isysroot

Bugs 修復

  • #1091: 修復不正確的繼承鏈接依賴

  • #1105: 修復 vsxmake 插件 c++ 語言標準智能提示錯誤

  • #1132: 修復 vsxmake 插件中配置路徑被截斷問題

  • #1142: 修復安裝包的時候,出現git找不到問題

  • 修復在 macOS Big Sur 上 macos.version 問題

  • #1084: 修復 add_defines() 中帶有雙引號和空格導致無法正確處理宏定義的問題

  • #1195: 修復 unicode 編碼問題,改進 vs 環境查找和進程執行

關注公衆號

TBOOX開源工程

專注C跨平臺開發解決方案

長按二維碼關注



本文分享自微信公衆號 - TBOOX開源工程(tboox-os)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章