xmake v2.5.8 釋出,新增 Pascal/Swig 程式和 Lua53 執行時支援

waruqi發表於2021-10-09

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

這個版本,我們主要增加了對 Pascal 語言專案和 Swig 模組的構建支援,而對於上個版本新增的 Vala 語言支援,我們也做了進一步改進,增加了對動態庫和靜態庫的構建支援。

除此之外,xmake 現在也已經支援了可選的 Lua5.3 執行時,提供更好的跨平臺支援能力,目前 xmake 已經能夠在 LoongArch 架構上正常執行。

新特性介紹

Pascal 語言支援

目前,我們可以使用跨平臺的 Free pascal 工具鏈 fpc 去編譯構建 Pascal 程式,例如:

控制檯程式

add_rules("mode.debug", "mode.release")
target("test")
    set_kind("binary")
    add_files("src/*.pas")

動態庫程式

add_rules("mode.debug", "mode.release")
target("foo")
    set_kind("shared")
    add_files("src/foo.pas")

target("test")
    set_kind("binary")
    add_deps("foo")
    add_files("src/main.pas")

我們也可以通過 add_fcflags() 介面新增 Pascal 程式碼相關的編譯選項。

更多例子見:Pascal examples

Vala 庫編譯支援

上個版本,我們新增了對 Vala 語言的支援,但是之前只能支援控制檯程式的編譯,無法生成庫檔案。而這個版本中,我們額外增加了對靜態庫和動態庫的編譯支援。

靜態庫程式

我們能夠通過 add_values("vala.header", "mymath.h") 設定匯出的介面標頭檔案名,通過 add_values("vala.vapi", "mymath-1.0.vapi") 設定匯出的 vapi 檔名。

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

add_requires("glib")

target("mymath")
    set_kind("static")
    add_rules("vala")
    add_files("src/mymath.vala")
    add_values("vala.header", "mymath.h")
    add_values("vala.vapi", "mymath-1.0.vapi")
    add_packages("glib")

target("test")
    set_kind("binary")
    add_deps("mymath")
    add_rules("vala")
    add_files("src/main.vala")
    add_packages("glib")

動態庫程式

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

add_requires("glib")

target("mymath")
    set_kind("shared")
    add_rules("vala")
    add_files("src/mymath.vala")
    add_values("vala.header", "mymath.h")
    add_values("vala.vapi", "mymath-1.0.vapi")
    add_packages("glib")

target("test")
    set_kind("binary")
    add_deps("mymath")
    add_rules("vala")
    add_files("src/main.vala")
    add_packages("glib")

更多例子見:Vala examples

Swig 模組支援

我們提供了 swig.cswig.cpp 規則,可以對指定的指令碼語言,呼叫 swig 程式生成 c/c++ 模組介面程式碼,然後配合 xmake 的包管理系統實現完全自動化的模組和依賴包整合。

相關 issues: #1622

Lua/C 模組

add_rules("mode.release", "mode.debug")
add_requires("lua")

target("example")
    add_rules("swig.c", {moduletype = "lua"})
    add_files("src/example.i", {swigflags = "-no-old-metatable-bindings"})
    add_files("src/example.c")
    add_packages("lua")

其中,swigflags 可以設定傳遞一些 swig 特有的 flags 選項。

Python/C 模組

add_rules("mode.release", "mode.debug")
add_requires("python 3.x")

target("example")
    add_rules("swig.c", {moduletype = "python"})
    add_files("src/example.i", {scriptdir = "share"})
    add_files("src/example.c")
    add_packages("python")

如果設定了 scriptdir,那麼我們執行安裝的時候,會將對應模組的 python wrap 指令碼安裝到指定目錄。

Python/C++ 模組

add_rules("mode.release", "mode.debug")
add_requires("python 3.x")

target("example")
    add_rules("swig.cpp", {moduletype = "python"})
    add_files("src/example.i", {scriptdir = "share"})
    add_files("src/example.cpp")
    add_packages("python")

Lua5.3 執行時支援

xmake 之前一直使用的 Luajit 作為預設的執行時,因為當初考慮到 Luajit 相對更加快速,並且固定的 lua 5.1 語法更加適合 xmake 內部實現的需要。

但是考慮到 Luajit 的更新不給力,作者維護不是很積極,並且它的跨平臺性比較差,對於一些新出的架構,比如:Loongarch,riscv 等支援不及時,這多少限制了 xmake 的平臺支援力度。

為此,新版本中,我們也將 Lua5.3 作為可選的執行時內建了進來,我們只需要通過下面的命令編譯安裝 xmake,就可以從 Luajit 切換到 Lua5.3 執行時:

Linux/macOS

$ make RUNTIME=lua

Windows

$ cd core
$ xmake f --runtime=lua
$ xmake

目前,當前版本還是預設採用的 luajit 執行時,使用者可以根據自己的需求切換到 Lua5.3 執行時,但這對於使用者的專案 xmake.lua 配置指令碼幾乎沒有任何相容性影響。

因為 xmake 的配置介面都已經做了一層的抽象封裝,一些 Luajit/Lua5.3 存在相容性差異的原生介面是不會開放給使用者使用的,所以對專案構建來說,是完全無感知的。

唯一的區別就是,帶有 Lua5.3 的 xmake 支援更多的平臺和架構。

效能對比

我做過一些基礎構建測試,不管是啟動時間,構建效能還是記憶體佔用,Lua5.3 和 Luajit 的 xmake 都幾乎沒有任何差別。因為對於構建系統,主要的效能瓶頸是在編譯器上,自身指令碼的損耗佔比是非常小的。

而且 xmake 內部的一些底層 Lua 模組,比如 io,字元編碼,字串操作等,都自己用 c 程式碼全部重寫過的,完全不依賴特定的 Lua 執行時引擎。

是否會考慮預設切換到 Lua?

由於我們剛剛支援 Lua5.3,儘管目前測試下來已經比較穩定,但是為了確保使用者環境不受到任何影響,我們還需要再觀察一段時間,短期還是預設使用 Luajit。

等到 2.6.1 版本開始,我們會全面開始切換到 Lua5.3 作為預設的執行時環境,大家有興趣的話,也可以線幫忙測試下,如果遇到問題,歡迎到 issues 上反饋。

LoongArch 架構支援

由於我們增加了 Lua5.3 執行時支援,所以現在我們已經可以支援再 LoongArch 架構上執行 xmake,並且所有測試例子都已經測試通過。

Lua 5.4

目前,我們對 Lua 5.4 還保持觀望狀態,如果後面等 lua5.4 穩定了,我們也會嘗試考慮繼續升級到 Lua5.4。

第三方原始碼混合編譯支援

整合 CMake 程式碼庫

新版本中,我們已經能夠通過 xmake 的包模式直接整合自己專案中帶有 CMakeLists.txt 的程式碼庫,而不是通過遠端下載安裝。

相關 issues: #1714

例如,我們有如下專案結構:

├── foo
│   ├── CMakeLists.txt
│   └── src
│       ├── foo.c
│       └── foo.h
├── src
│   └── main.c
├── test.lua
└── xmake.lua

foo 目錄下是一個使用 cmake 維護的靜態庫,而根目錄下使用了 xmake 來維護,我們可以在 xmake.lua 中通過定義 package("foo") 包來描述如何構建 foo 程式碼庫。

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

package("foo")
    add_deps("cmake")
    set_sourcedir(path.join(os.scriptdir(), "foo"))
    on_install(function (package)
        local configs = {}
        table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))
        table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"))
        import("package.tools.cmake").install(package, configs)
    end)
    on_test(function (package)
        assert(package:has_cfuncs("add", {includes = "foo.h"}))
    end)
package_end()

add_requires("foo")

target("demo")
    set_kind("binary")
    add_files("src/main.c")
    add_packages("foo")

其中,我們通過 set_sourcedir() 來設定 foo 包的程式碼目錄位置,然後通過 import 匯入 package.tools.cmake 輔助模組來呼叫 cmake 構建程式碼,xmake 會自動獲取生成的 libfoo.a 和對應的標頭檔案。

!> 如果僅僅本地原始碼整合,我們不需要額外設定 add_urlsadd_versions

關於包的配置描述,詳情見:包描述說明

定義完包後,我們就可以通過 add_requires("foo")add_packages("foo") 來整合使用它了,就跟整合遠端包一樣的使用方式。

另外,on_test 是可選的,如果想要嚴格檢測包的編譯安裝是否成功,可以在裡面做一些測試。

完整例子見:Library with CMakeLists

整合 autoconf 程式碼庫

我們也可以使用 package.tools.autoconf 來本地整合帶有 autoconf 維護的第三方程式碼庫。

package("pcre2")

    set_sourcedir(path.join(os.scriptdir(), "3rd/pcre2"))

    add_configs("jit", {description = "Enable jit.", default = true, type = "boolean"})
    add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}})

    on_load(function (package)
        local bitwidth = package:config("bitwidth") or "8"
        package:add("links", "pcre2-" .. bitwidth)
        package:add("defines", "PCRE2_CODE_UNIT_WIDTH=" .. bitwidth)
        if not package:config("shared") then
            package:add("defines", "PCRE2_STATIC")
        end
    end)

    on_install("macosx", "linux", "mingw", function (package)
        local configs = {}
        table.insert(configs, "--enable-shared=" .. (package:config("shared") and "yes" or "no"))
        table.insert(configs, "--enable-static=" .. (package:config("shared") and "no" or "yes"))
        if package:debug() then
            table.insert(configs, "--enable-debug")
        end
        if package:config("pic") ~= false then
            table.insert(configs, "--with-pic")
        end
        if package:config("jit") then
            table.insert(configs, "--enable-jit")
        end
        local bitwidth = package:config("bitwidth") or "8"
        if bitwidth ~= "8" then
            table.insert(configs, "--disable-pcre2-8")
            table.insert(configs, "--enable-pcre2-" .. bitwidth)
        end
        import("package.tools.autoconf").install(package, configs)
    end)

    on_test(function (package)
        assert(package:has_cfuncs("pcre2_compile", {includes = "pcre2.h"}))
    end)

package.tools.autoconfpackage.tools.cmake 模組都是可以支援 mingw/cross/iphoneos/android 等交叉編譯平臺和工具鏈的,xmake 會自動傳遞對應的工具鏈進去,使用者不需要做任何其他事情。

整合其他構建系統

我們還支援整合 Meson/Scons/Make 等其他構建系統維護的程式碼庫,僅僅只需要匯入對應的構建輔助模組,這裡就不一一細講了,我們可以進一步查閱文件:整合本地第三方原始碼庫

改進編譯器特性檢測

在之前的版本中,我們可以通過 check_features 輔助介面來檢測指定的編譯器特性,比如:

includes("check_features.lua")

target("test")
    set_kind("binary")
    add_files("*.c")
    add_configfiles("config.h.in")
    configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr")
    configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})

config.h.in

${define HAS_CONSTEXPR}
${define HAS_CONSEXPR_AND_STATIC_ASSERT}

config.h

/* #undef HAS_CONSTEXPR */
#define HAS_CONSEXPR_AND_STATIC_ASSERT 1

如果當前 cxx_constexpr 特性支援,就會在 config.h 中啟用 HAS_CONSTEXPR 巨集。

新增 C/C++ 標準支援檢測

2.5.8 之後,我們繼續新增了對 cstd 和 c++ std 版本檢測支援,相關 issues: #1715

例如:

configvar_check_features("HAS_CXX_STD_98", "cxx_std_98")
configvar_check_features("HAS_CXX_STD_11", "cxx_std_11", {languages = "c++11"})
configvar_check_features("HAS_CXX_STD_14", "cxx_std_14", {languages = "c++14"})
configvar_check_features("HAS_CXX_STD_17", "cxx_std_17", {languages = "c++17"})
configvar_check_features("HAS_CXX_STD_20", "cxx_std_20", {languages = "c++20"})
configvar_check_features("HAS_C_STD_89", "c_std_89")
configvar_check_features("HAS_C_STD_99", "c_std_99")
configvar_check_features("HAS_C_STD_11", "c_std_11", {languages = "c11"})
configvar_check_features("HAS_C_STD_17", "c_std_17", {languages = "c17"})

新增編譯器內建巨集檢測

我們還能檢測編譯器存在一些內建的巨集定義,比如:__GNUC__ 等,我們可以通過 check_macrosconfigvar_check_macros 輔助指令碼來檢測它們是否存在。

相關 issues: #1715

-- 檢測巨集是否定義
configvar_check_macros("HAS_GCC", "__GNUC__")
-- 檢測巨集沒有被定義
configvar_check_macros("NO_GCC", "__GNUC__", {defined = false})
-- 檢測巨集條件
configvar_check_macros("HAS_CXX20", "__cplusplus >= 202002L", {languages = "c++20"})

增加對 Qt 4.x 的支援

除了 Qt 5.x 和 6.x,我們對於一些基於 Qt 4.x 的老專案,xmake 也增加了支援。

增加對 Android NDK r23 的支援

由於 google 對 Android NDK 的一些結構改動,導致 r23 影響了 xmake 對 android 專案部分編譯特性的支援,在這個版本中,我們也做了修復。

修復 vsxmake 外掛 Unicode 編碼問題

另外,如果基於 Unicode 作為專案目錄,那麼生成的 vsxmake 專案會收到影響,導致 vs 專案編譯和訪問上存在很多問題,我們也在新版本中做了修復。

更新內容

新特性

  • #388: Pascal 語言支援,可以使用 fpc 來編譯 free pascal
  • #1682: 新增可選的額lua5.3 執行時替代 luajit,提供更好的平臺相容性。
  • #1622: 支援 Swig
  • #1714: 支援內建 cmake 等第三方專案的混合編譯
  • #1715: 支援探測編譯器語言標準特性,並且新增 check_macros 檢測介面
  • xmake 支援在 Loongarch 架構上執行

改進

  • #1618: 改進 vala 支援構建動態庫和靜態庫程式
  • 改進 Qt 規則去支援 Qt 4.x
  • 改進 set_symbols("debug") 支援 clang/windows 生成 pdb 檔案
  • #1638: 改進合併靜態庫
  • 改進 on_load/after_load 去支援動態的新增 target deps
  • #1675: 針對 mingw 平臺,重新命名動態庫和匯入庫檔名字尾
  • #1694: 支援在 set_configvar 中定義一個不帶引號的字串變數
  • 改進對 Android NDK r23 的支援
  • set_languages 新增 c++latestclatest 配置值
  • #1720: 新增 save_scoperestore_scope 去修復 check_xxx 相關介面
  • #1726: 改進 compile_commands 生成器去支援 nvcc

Bugs 修復

  • #1671: 修復安裝預編譯包後,*.cmake 裡面的一些不正確的絕對路徑
  • #1689: 修復 vsxmake 外掛的 unicode 字元顯示和載入問題

相關文章