xmake v2.3.4 釋出, 更加完善的工具鏈支援

waruqi發表於2020-06-08

為了讓xmake更好得支援交叉編譯,這個版本我重構了整個工具鏈,使得工具鏈的切換更加的方便快捷,並且現在使用者可以很方便地在xmake.lua中擴充套件自己的工具鏈。

關於平臺的支援上,我們新增了對*BSD系統的支援,另外,此版本還新增了一個ninja主題風格,實現類似ninja的編譯進度顯示,例如:

xmake v2.3.4 釋出, 更加完善的工具鏈支援

新特性介紹

工具鏈改進

工具鏈和平臺完全分離

之前的版本,平臺和工具鏈繫結的過於緊密,例如xmake f -p windows 平臺,預設只能使用msvc的編譯,想要切到clang或者其他編譯器,就只能走交叉編譯平臺:xmake f -p cross

但是這樣的話,一些windows平臺特有的設定就丟失了,而且使用者也沒法使用if is_plat("windows") then來判斷windows平臺做特定的設定。

其實平臺和工具鏈是完全可以獨立開來的,新版本經過重構後,即使是windows平臺以及其他任何平臺,也可以方便快速的切換到clang, llvm等其他工具鏈。

$ xmake f -p windows --toolchain=clang

內建工具鏈

雖然xmake的交叉編譯配置支援所有工具鏈,也提供一定程度的智慧分析和工具鏈探測,但通用方案多少對特定工具鏈支援需要追加各種額外的配置,例如額外傳遞一些--ldflags=, --cxflags=引數什麼的。

而新版本xmake內建了一些常用工具鏈,可以省去交叉編譯工具鏈複雜的配置過程,只需要傳遞工具鏈名到--toolchain=xxx即可。

切換到llvm工具鏈:

$ xmake f -p cross --toolchain=llvm --sdk="C:\Program Files\LLVM"
$ xmake

切換到GNU-RM工具鏈:

$ xmake f -p cross --toolchain=gnu-rm --sdk=/xxx/cc-arm-none-eabi-9-2019-q4-major
$ xmake

就可以快速切換的指定的交叉編譯工具鏈,對於內建的工具鏈,可以省去大部分配置,通常只需要--toolchain=--sdk=即可,其他的配置都會自動設定好,確保編譯正常。

那xmake還支援哪些內建工具鏈呢?我們可以通過下面的命令檢視:

$ xmake show -l toolchains
xcode         Xcode IDE
vs            VisualStudio IDE
yasm          The Yasm Modular Assembler
clang         A C language family frontend for LLVM
go            Go Programming Language Compiler
dlang         D Programming Language Compiler
sdcc          Small Device C Compiler
cuda          CUDA Toolkit
ndk           Android NDK
rust          Rust Programming Language Compiler
llvm          A collection of modular and reusable compiler and toolchain technologies
cross         Common cross compilation toolchain
nasm          NASM Assembler
gcc           GNU Compiler Collection
mingw         Minimalist GNU for Windows
gnu-rm        GNU Arm Embedded Toolchain
envs          Environment variables toolchain
fasm          Flat Assembler

工具鏈的同步切換

新版本xmake還支援工具鏈的完整同步切換,這個是什麼意思呢?

比如,我們要從預設的gcc切換到clang編譯,可能需要切一些工具集,xmake f --cc=clang --cxx=clang --ld=clang++ --sh=clang++,因為編譯器切了,對應的連結器,靜態庫歸檔器什麼的都得同時切才行。

這麼挨個切一邊,確實很蛋疼,作者本人也是受不了了,所以重構工具鏈的時候,這塊也重點改進了下,現在只需要:

$ xmake f --toolchain=clang
$ xmake

就可以完全把所有clang工具集整體切過去,那如何重新切回gcc呢,也很方便:

或者

$ xmake f --toolchain=gcc
$ xmake

自定義工具鏈

另外,我們現在也可以在xmake.lua中自定義toolchain,然後通過xmake f --toolchain=myclang指定切換,例如:

toolchain("myclang")
    set_kind("standalone")
    set_toolset("cc", "clang")
    set_toolset("cxx", "clang", "clang++")
    set_toolset("ld", "clang++", "clang")
    set_toolset("sh", "clang++", "clang")
    set_toolset("ar", "ar")
    set_toolset("ex", "ar")
    set_toolset("strip", "strip")
    set_toolset("mm", "clang")
    set_toolset("mxx", "clang", "clang++")
    set_toolset("as", "clang")

    -- ...

其中set_toolset用於挨個設定不同的工具集,比如編譯器、連結器、彙編器等。

xmake預設會從xmake f --sdk=xx的sdk引數中去探測工具,當然我們也可以在xmake.lua中對每個自定義工具鏈呼叫set_sdk("/xxx/llvm")來寫死工具鏈sdk地址。

關於這塊的詳情介紹,可以到自定義工具鏈章節檢視

更多詳情見:#780

針對特定target設定工具鏈

除了自定義工具鏈,我們也可以對某個特定的target單獨切換設定不同的工具鏈,和set_toolset不同的是,此介面是對完整工具鏈的整體切換,比如cc/ld/sh等一系列工具集。

這也是推薦做法,因為像gcc/clang等大部分編譯工具鏈,編譯器和連結器都是配套使用的,要切就得整體切,單獨零散的切換設定會很繁瑣。

比如我們切換test目標到clang+yasm兩個工具鏈:

target("test")
    set_kind("binary")
    add_files("src/*.c")
    set_toolchains("clang", "yasm")

或者可以通過set_toolset來對每個target的工具鏈中的特定工具單獨設定。

target("test")
    set_kind("binary")
    set_toolset("cxx", "clang")
    set_toolset("ld", "clang++")

ninja構建主題

構建進度風格類似ninja,採用單行進度條,不再回滾進度,使用者可以根據自己的喜好設定。

除了進度展示不同外,其他都跟預設主題的配置相同。

$ xmake g --theme=ninja
xmake v2.3.4 釋出, 更加完善的工具鏈支援

設定構建行為策略

xmake有很多的預設行為,比如:自動檢測和對映flags、跨target並行構建等,雖然提供了一定的智慧化處理,但重口難調,不一定滿足所有的使用者的使用習慣和需求。

因此,從v2.3.4開始,xmake提供預設構建策略的修改設定,開放給使用者一定程度上的可配置性。

使用方式如下:

set_policy("check.auto_ignore_flags", false)

只需要在專案根域設定這個配置,就可以禁用flags的自動檢測和忽略機制,另外set_policy也可以針對某個特定的target區域性生效。

target("test")
    set_policy("check.auto_ignore_flags", false)

!> 另外,如果設定的策略名是無效的,xmake也會有警告提示。

如果要獲取當前xmake支援的所有策略配置列表和描述,可以執行下面的命令:

$ xmake l core.project.policy.policies
{ 
  "check.auto_map_flags" = { 
    type = "boolean",
    description = "Enable map gcc flags to the current compiler and linker automatically.",
    default = true 
  },
  "build.across_targets_in_parallel" = { 
    type = "boolean",
    description = "Enable compile the source files for each target in parallel.",
    default = true 
  },
  "check.auto_ignore_flags" = { 
    type = "boolean",
    description = "Enable check and ignore unsupported flags automatically.",
    default = true 
  } 
}

check.auto_ignore_flags

xmake預設會對所有add_cxflags, add_ldflags介面設定的原始flags進行自動檢測,如果檢測當前編譯器和連結器不支援它們,就會自動忽略。

這通常是很有用的,像一些可選的編譯flags,即使不支援也能正常編譯,但是強行設定上去,其他使用者在編譯的時候,有可能會因為編譯器的支援力度不同,出現一定程度的編譯失敗。

但,由於自動檢測並不保證100%可靠,有時候會有一定程度的誤判,所以某些使用者並不喜歡這個設定(尤其是針對交叉編譯工具鏈,更容易出現失敗)。

目前,v2.3.4版本如果檢測失敗,會有警告提示避免使用者莫名躺坑,例如:

warning: add_ldflags("-static") is ignored, please pass `{force = true}` or call `set_policy("check.auto_ignore_flags", false)` if you want to set it.

根據提示,我們可以自己分析判斷,是否需要強制設定這個flags,一種就是通過:

add_ldflags("-static", {force = true})

來顯示的強制設定上它,跳過自動檢測,這對於偶爾的flags失敗,是很有效快捷的處理方式,但是對於交叉編譯時候,一堆的flags設定檢測不過的情況下,每個都設定force太過於繁瑣。

這個時候,我們就可以通過set_policy來對某個target或者整個project直接禁用預設的自動檢測行為:

set_policy("check.auto_ignore_flags", false)
target("test")
    add_ldflags("-static")

然後我們就可以隨意設定各種原始flags,xmake不會去自動檢測和忽略他們了。

check.auto_map_flags

這是xmake的另外一個對flags的智慧分析處理,通常像add_links, add_defines這種xmake內建的api去設定的配置,是具有跨平臺特性的,不同編譯器平臺會自動處理成對應的原始flags。

但是,有些情況,使用者還是需要自己通過add_cxflags, add_ldflags設定原始的編譯連結flags,這些flags並不能很好的跨編譯器

就拿-O0的編譯優化flags來說,雖然有set_optimize來實現跨編譯器配置,但如果使用者直接設定add_cxflags("-O0")呢?gcc/clang下可以正常處理,但是msvc下就不支援了

也許我們能通過if is_plat() then來分平臺處理,但很繁瑣,因此xmake內建了flags的自動對映功能。

基於gcc flags的普及性,xmake採用gcc的flags命名規範,對其根據不同的編譯實現自動對映,例如:

add_cxflags("-O0")

這一行設定,在gcc/clang下還是-O0,但如果當前是msvc編譯器,那邊會自動對映為msvc對應-Od編譯選項來禁用優化。

整個過程,使用者是完全無感知的,直接執行xmake就可以跨編譯器完成編譯。

!> 當然,目前的自動對映實現還不是很成熟,沒有100%覆蓋所有gcc的flags,所以還是有不少flags是沒去對映的。

也有部分使用者並不喜歡這種自動對映行為,那麼我們可以通過下面的設定完全禁用這個預設的行為:

set_policy("check.auto_map_flags", false)

build.across_targets_in_parallel

這個策略也是預設開啟的,主要用於跨target間執行並行構建,v2.3.3之前的版本,並行構建只能針對單個target內部的所有原始檔,
跨target的編譯,必須要要等先前的target完全link成功,才能執行下一個target的編譯,這在一定程度上會影響編譯速度。

然而每個target的原始檔是可以完全並行化處理的,最終在一起執行link過程,v2.3.3之後的版本通過這個優化,構建速度提升了30%。

當然,如果有些特殊的target裡面的構建原始檔要依賴先前的target(尤其是一些自定義rules的情況,雖然很少遇到),我們也可以通過下面的設定禁用這個優化行為:

set_policy("build.across_targets_in_parallel", false)

新增編譯模式

mode.releasedbg

為當前工程xmake.lua新增releasedbg編譯模式的配置規則,例如:

add_rules("mode.releasedbg")

!> 與release模式相比,此模式還會額外開啟除錯符號,這通常是非常有用的。

相當於:

if is_mode("releasedbg") then
    set_symbols("debug")
    set_optimize("fastest")
    set_strip("all")
end

我們可以通過:xmake f -m releasedbg來切換到此編譯模式。

mode.minsizerel

為當前工程xmake.lua新增minsizerel編譯模式的配置規則,例如:

add_rules("mode.minsizerel")

!> 與release模式相比,此模式更加傾向於最小程式碼編譯優化,而不是速度優先。

相當於:

if is_mode("minsizerel") then
    set_symbols("hidden")
    set_optimize("smallest")
    set_strip("all")
end

我們可以通過:xmake f -m minsizerel來切換到此編譯模式。

顯示指定資訊和列表

顯示xmake自身和當前專案的基礎資訊

$ xmake show
The information of xmake:
    version: 2.3.3+202006011009
    host: macosx/x86_64
    programdir: /Users/ruki/.local/share/xmake
    programfile: /Users/ruki/.local/bin/xmake
    globaldir: /Users/ruki/.xmake
    tmpdir: /var/folders/32/w9cz0y_14hs19lkbs6v6_fm80000gn/T/.xmake501/200603
    workingdir: /Users/ruki/projects/personal/tbox
    packagedir: /Users/ruki/.xmake/packages
    packagedir(cache): /Users/ruki/.xmake/cache/packages/2006

The information of project: tbox
    version: 1.6.5
    plat: macosx
    arch: x86_64
    mode: release
    buildir: build
    configdir: /Users/ruki/projects/personal/tbox/.xmake/macosx/x86_64
    projectdir: /Users/ruki/projects/personal/tbox
    projectfile: /Users/ruki/projects/personal/tbox/xmake.lua

顯示工具鏈列表

$ xmake show -l toolchains
xcode         Xcode IDE
vs            VisualStudio IDE
yasm          The Yasm Modular Assembler
clang         A C language family frontend for LLVM
...

顯示指定target配置資訊

$ xmake show --target=tbox
The information of target(tbox):
    kind: static
    targetfile: build/macosx/x86_64/release/libtbox.a
    rules: mode.release, mode.debug, mode.profile, mode.coverage
    options: info, float, wchar, exception, force-utf8, deprecated, xml, zip, hash, regex, coroutine, object, charset, database
    packages: mbedtls, polarssl, openssl, pcre2, pcre, zlib, mysql, sqlite3
    links: pthread
    syslinks: pthread, dl, m, c
    cxflags: -Wno-error=deprecated-declarations, -fno-strict-aliasing, -Wno-error=expansion-to-defined, -fno-stack-protector
    defines: __tb_small__, __tb_prefix__="tbox"
    mxflags: -Wno-error=deprecated-declarations, -fno-strict-aliasing, -Wno-error=expansion-to-defined
    headerfiles: src/(tbox/**.h)|**/impl/**.h, src/(tbox/prefix/**/prefix.S), src/(tbox/math/impl/*.h), src/(tbox/utils/impl/*.h), build/macosx/x86_64/release/tbox.config.h
    includedirs: src, build/macosx/x86_64/release
    at: /Users/ruki/projects/personal/tbox/src/tbox/xmake.lua
    sourcebatch(cc): with rule(c.build)
      -> src/tbox/string/static_string.c
         -> build/.objs/tbox/macosx/x86_64/release/src/tbox/string/static_string.c.o
         -> build/.deps/tbox/macosx/x86_64/release/src/tbox/string/static_string.c.o.d
      -> src/tbox/platform/sched.c
         -> build/.objs/tbox/macosx/x86_64/release/src/tbox/platform/sched.c.o
         -> build/.deps/tbox/macosx/x86_64/release/src/tbox/platform/sched.c.o.d
      -> src/tbox/stream/stream.c
         -> build/.objs/tbox/macosx/x86_64/release/src/tbox/stream/stream.c.o
         -> build/.deps/tbox/macosx/x86_64/release/src/tbox/stream/stream.c.o.d
      -> src/tbox/utils/base32.c
         -> build/.objs/tbox/macosx/x86_64/release/src/tbox/utils/base32.c.o
         -> build/.deps/tbox/macosx/x86_64/release/src/tbox/utils/base32.c.o.d

顯示內建編譯模式列表

$ xmake show -l modes

顯示內建編譯規則列表

$ xmake show -l rules

顯示其他資訊

還在完善中,詳情見:https://github.com/xmake-io/xmake/issues/798

或者執行:

$ xmake show --help

更新內容

新特性

  • #630: 支援*BSD系統,例如:FreeBSD, ..
  • 新增wprint介面去顯示警告資訊
  • #784: 新增set_policy()去設定修改一些內建的策略,比如:禁用自動flags檢測和對映
  • #780: 針對target新增set_toolchains/set_toolsets實現更完善的工具鏈設定,並且實現platform和toolchains分離
  • #798: 新增xmake show外掛去顯示xmake內建的各種資訊
  • #797: 新增ninja主題風格,顯示ninja風格的構建進度條,xmake g --theme=ninja
  • #816: 新增mode.releasedbg和mode.minsizerel編譯模式規則
  • #819: 支援ansi/vt100終端字元控制

改進

  • #771: 檢測includedirs,linkdirs和frameworkdirs的輸入有效性
  • #774: xmake f --menu視覺化配置選單支援視窗大小Resize調整
  • #782: 新增add_cxflags等配置flags自動檢測失敗提示
  • #808: 生成cmakelists外掛增加對add_frameworks的支援
  • #820: 支援獨立的工作目錄和構建目錄,保持專案目錄完全乾淨

Bugs修復

  • #786: 修復標頭檔案依賴檢測
  • #810: 修復linux下gcc strip debug符號問題

相關文章