XMake 接口手冊

2018-10-12 19:52 更新

接口規(guī)范

命名規(guī)范

接口的命名,是有按照預(yù)定義的一些規(guī)范來命名的,這樣更加方便理解和易于使用,目前命名按照如下一些規(guī)則:

接口規(guī)則 描述
is_前綴的接口 表示為條件判斷
set_前綴的接口 表示為覆蓋設(shè)置
add_前綴的接口 表示為追加設(shè)置
s后綴的接口 表示支持多值傳入,例如:add_files("*.c", "test.cpp")
on_前綴的接口 表示為覆蓋內(nèi)置腳本
before_前綴的接口 表示為在內(nèi)置腳本運(yùn)行前,執(zhí)行此腳本
after_前綴的接口 表示為在內(nèi)置腳本運(yùn)行后,執(zhí)行此腳本
scope("name")的接口 表示為定義一個(gè)描述域,例如:target("xxx")option("xxx")
描述域/描述設(shè)置 建議縮進(jìn)表示

接口文檔

條件判斷

條件判斷的api,一般用于必須要處理特定平臺的編譯邏輯的場合。。通常跟lua的if語句配合使用。

接口 描述 支持版本
is_os 判斷當(dāng)前構(gòu)建目標(biāo)的操作系統(tǒng) >= 2.0.1
is_arch 判斷當(dāng)前編譯架構(gòu) >= 2.0.1
is_plat 判斷當(dāng)前編譯平臺 >= 2.0.1
is_host 判斷當(dāng)前主機(jī)環(huán)境操作系統(tǒng) >= 2.1.4
is_mode 判斷當(dāng)前編譯模式 >= 2.0.1
is_kind 判斷當(dāng)前編譯類型 >= 2.0.1
is_option 判斷選項(xiàng)是否啟用 >= 2.0.1

is_os

判斷當(dāng)前構(gòu)建目標(biāo)的操作系統(tǒng)

-- 如果當(dāng)前操作系統(tǒng)是ios
if is_os("ios") then
    add_files("src/xxx/*.m")
end

目前支持的操作系統(tǒng)有:

  • windows
  • linux
  • android
  • macosx
  • ios

is_arch

判斷當(dāng)前編譯架構(gòu)

用于檢測編譯配置:xmake f -a armv7

-- 如果當(dāng)前架構(gòu)是x86_64或者i386
if is_arch("x86_64", "i386") then
    add_files("src/xxx/*.c")
end


-- 如果當(dāng)前平臺是armv7, arm64, armv7s, armv7-a
if is_arch("armv7", "arm64", "armv7s", "armv7-a") then
    -- ...
end

如果像上面那樣一個(gè)個(gè)去判斷所有arm架構(gòu),也許會很繁瑣,畢竟每個(gè)平臺的架構(gòu)類型很多,xmake提供了類似add_files中的通配符匹配模式,來更加簡潔的進(jìn)行判斷:

--如果當(dāng)前平臺是arm平臺
if is_arch("arm*") then
    -- ...
end

*就可以匹配所有了。。

is_plat

判斷當(dāng)前編譯平臺

用于檢測編譯配置:xmake f -p iphoneos

-- 如果當(dāng)前平臺是android
if is_plat("android") then
    add_files("src/xxx/*.c")
end


-- 如果當(dāng)前平臺是macosx或者iphoneos
if is_plat("macosx", "iphoneos") then
    add_mxflags("-framework Foundation")
    add_ldflags("-framework Foundation")
end

目前支持的平臺有:

  • windows
  • cross
  • linux
  • macosx
  • android
  • iphoneos
  • watchos

當(dāng)然你也可以自己擴(kuò)展添加自己的平臺,甚至直接指定自己的平臺名:

$ xmake f -p other --sdk=...

如果指定的平臺名不存在,就會自動切到cross平臺進(jìn)行交叉編譯,但是缺可以通過is_plat("other")來判斷自己的平臺邏輯。

is_host

判斷當(dāng)前主機(jī)環(huán)境的操作系統(tǒng)

有些編譯平臺是可以在多個(gè)不同的操作系統(tǒng)進(jìn)行構(gòu)建的,例如:android的ndk就支持linux,macOS還有windows環(huán)境。

這個(gè)時(shí)候就可以通過這個(gè)接口,區(qū)分當(dāng)前是在哪個(gè)系統(tǒng)環(huán)境下進(jìn)行的構(gòu)建。

-- 如果當(dāng)前主機(jī)環(huán)境是windows
if is_host("windows") then
    add_includes("C:\\includes")
else
    add_includes("/usr/includess")
end

目前支持的主機(jī)環(huán)境有:

  • windows
  • linux
  • macosx

你也可以通過$(host)內(nèi)置變量或者os.host接口,來進(jìn)行獲取

is_mode

判斷當(dāng)前編譯模式

用于檢測編譯配置:xmake f -m debug

編譯模式的類型并不是內(nèi)置的,可以自由指定,一般指定:debug, release, profile 這些就夠用了,當(dāng)然你也可以在xmake.lua使用其他模式名來判斷。

-- 如果當(dāng)前編譯模式是debug
if is_mode("debug") then


    -- 添加DEBUG編譯宏
    add_defines("DEBUG")


    -- 啟用調(diào)試符號
    set_symbols("debug")


    -- 禁用優(yōu)化
    set_optimize("none")


end


-- 如果是release或者profile模式
if is_mode("release", "profile") then


    -- 如果是release模式
    if is_mode("release") then


        -- 隱藏符號
        set_symbols("hidden")


        -- strip所有符號
        set_strip("all")


        -- 忽略幀指針
        add_cxflags("-fomit-frame-pointer")
        add_mxflags("-fomit-frame-pointer")


    -- 如果是profile模式
    else


        -- 啟用調(diào)試符號
        set_symbols("debug")


    end


    -- 添加擴(kuò)展指令集
    add_vectorexts("sse2", "sse3", "ssse3", "mmx")
end

is_kind

判斷當(dāng)前編譯類型

判斷當(dāng)前是否編譯的是動態(tài)庫還是靜態(tài)庫,用于檢測編譯配置:xmake f -k [static|shared]

一般用于如下場景:

target("test")


    -- 通過配置設(shè)置目標(biāo)的kind
    set_kind("$(kind)")
    add_files("src/*c")


    -- 如果當(dāng)前編譯的是靜態(tài)庫,那么添加指定文件
    if is_kind("static") then
        add_files("src/xxx.c")
    end

編譯配置的時(shí)候,可手動切換,編譯類型:

## 編譯靜態(tài)庫
$ xmake f -k static
$ xmake

## 編譯動態(tài)庫
$ xmake f -k shared
$ xmake

is_option

判斷選項(xiàng)是否啟用

用于檢測自定義的編譯配置選型:xmake f --xxxx=y

如果某個(gè)自動檢測選項(xiàng)、手動設(shè)置選項(xiàng)被啟用,那么可以通過is_option接口來判斷,例如:

-- 如果手動啟用了xmake f --demo=y 選項(xiàng)
if is_option("demo") then


    -- 編譯demo目錄下的代碼
    add_subdirs("src/demo")
end

全局接口

全局接口影響整個(gè)工程描述,被調(diào)用后,后面被包含進(jìn)來的所有子xmake.lua都會受影響。

接口 描述 支持版本
includes 添加子工程文件和目錄 >= 2.1.5
set_modes 設(shè)置支持的編譯模式 >= 2.1.2
set_project 設(shè)置工程名 >= 2.0.1
set_version 設(shè)置工程版本 >= 2.0.1
set_xmakever 設(shè)置最小xmake版本 >= 2.1.1
add_subdirs 添加子工程目錄 >= 1.0.1
add_subfiles 添加子工程文件 >= 1.0.1
add_moduledirs 添加模塊目錄 >= 2.1.5
add_plugindirs 添加插件目錄 >= 2.0.1
add_packagedirs 添加包目錄 >= 2.0.1

includes

添加子工程文件和目錄

同時(shí)支持子工程文件和目錄的添加,用于替代add_subdirsadd_subfiles接口。

set_modes

設(shè)置支持的編譯模式

這個(gè)是可選接口,一般情況下不需要設(shè)置,目前僅用于對工程增加更加細(xì)致的描述信息,方便vs工程的多模式生成,以及其他xmake插件中獲取模式信息。

例如:

set_modes("debug", "release")

如果設(shè)置了這個(gè),xmake就知道當(dāng)前工程支持哪些編譯模式,這樣生成vs工程文件的時(shí)候,只需要:

$ xmake project -k vs2017

不再需要額外手動指定需要的編譯模式了,此外其他一些想要獲取工程信息的插件,也許也會需要這些設(shè)置信息。

<p class="tip"> 當(dāng)然,對于is_mode接口,set_modes不是必須的,就算不設(shè)置,也是可以通過is_mode正常判斷當(dāng)前的編譯模式。 </p>

set_project

設(shè)置工程名

設(shè)置工程名,在doxygen自動文檔生成插件、工程文件生成插件中會用到,一般設(shè)置在xmake.lua的最開頭,當(dāng)然放在其他地方也是可以的

-- 設(shè)置工程名
set_project("tbox")


-- 設(shè)置工程版本
set_version("1.5.1")

set_version

設(shè)置工程版本

設(shè)置項(xiàng)目版本,可以放在xmake.lua任何地方,一般放在最開頭,例如:

set_version("1.5.1")

以tbox為例,如果調(diào)用set_config_header設(shè)置了config.h,那么會自動生成如下宏:

// version
#define TB_CONFIG_VERSION "1.5.1"
#define TB_CONFIG_VERSION_MAJOR 1
#define TB_CONFIG_VERSION_MINOR 5
#define TB_CONFIG_VERSION_ALTER 1
#define TB_CONFIG_VERSION_BUILD 201510220917

2.1.7版本支持buildversion的配置:

set_version("1.5.1", {build = "%Y%m%d%H%M"})

set_xmakever

設(shè)置最小xmake版本

用于處理xmake版本兼容性問題,如果項(xiàng)目的xmake.lua,通過這個(gè)接口設(shè)置了最小xmake版本支持,那么用戶環(huán)境裝的xmake低于要求的版本,就會提示錯(cuò)誤。

一般情況下,建議默認(rèn)對其進(jìn)行設(shè)置,這樣對用戶比較友好,如果xmake.lua中用到了高版本的api接口,用戶那邊至少可以知道是否因?yàn)榘姹静粚?dǎo)致的構(gòu)建失敗。

設(shè)置如下:

-- 設(shè)置最小版本為:2.1.0,低于此版本的xmake編譯此工程將會提示版本錯(cuò)誤信息
set_xmakever("2.1.0")

add_subdirs

添加子工程目錄

每個(gè)子工程對應(yīng)一個(gè)xmake.lua的工程描述文件。

雖然一個(gè)xmake.lua也可以描述多個(gè)子工程模塊,但是如果工程越來越大,越來越復(fù)雜,適當(dāng)?shù)哪K化是很有必要的。。

這就需要add_subdirs了,將每個(gè)子模塊放到不同目錄中,并為其建立一個(gè)新的xmake.lua獨(dú)立去維護(hù)它,例如:

./tbox
├── src
│   ├── demo
│   │   └── xmake.lua (用來描述測試模塊)
│   └── tbox
│       └── xmake.lua(用來描述libtbox庫模塊)
└── xmake.lua(用該描述通用配置信息,以及對子模塊的維護(hù))

tbox/xmake.lua中通過add_subdirs將擁有xmale.lua的子模塊的目錄,添加進(jìn)來,就可以了,例如:

-- 添加libtbox庫模塊目錄
add_subdirs("src/tbox") 


-- 如果xmake f --demo=y,啟用了demo模塊,那么包含demo目錄
if is_option("demo") then 
    add_subdirs("src/demo") 
end

默認(rèn)情況下,xmake會去編譯在所有xmake.lua中描述的所有target目標(biāo),如果只想編譯指定目標(biāo),可以執(zhí)行:

## 僅僅編譯tbox庫模塊
$ xmake build tbox

需要注意的是,每個(gè)子xmake.lua中所有的路徑設(shè)置都是相對于當(dāng)前這個(gè)子xmake.lua所在的目錄的,都是相對路徑,這樣方便維護(hù)

add_subfiles

添加子工程文件

add_subfiles的作用與add_subdirs類似,唯一的區(qū)別就是:這個(gè)接口直接指定xmake.lua文件所在的路徑,而不是目錄,例如:

add_subfiles("src/tbox/xmake.lua")

add_moduledirs

添加模塊目錄

xmake內(nèi)置的擴(kuò)展模塊都在xmake/modules目錄下,可通過import來導(dǎo)入他們,如果自己在工程里面實(shí)現(xiàn)了一些擴(kuò)展模塊, 可以放置在這個(gè)接口指定的目錄下,import也就會能找到,并且優(yōu)先進(jìn)行導(dǎo)入。

例如定義一個(gè)find_openssl.lua的擴(kuò)展模塊,用于擴(kuò)展內(nèi)置的lib.detect.find_package接口,則只需要將它放置在:

projectdir/xmake/modules/detect/packages/find_openssl.lua

然后在工程xmake.lua下指定這個(gè)模塊目錄,find_package就可以自動找到了:

add_moduledirs("projectdir/xmake/modules")

add_plugindirs

添加插件目錄

xmake內(nèi)置的插件都是放在xmake/plugins目錄下,但是對于用戶自定義的一些特定工程的插件,如果不想放置在xmake安裝目錄下,那么可以在xmake.lua中進(jìn)行配置指定的其他插件路徑。

-- 將當(dāng)前工程下的plugins目錄設(shè)置為自定義插件目錄
add_plugindirs("$(projectdir)/plugins")

這樣,xmake在編譯此工程的時(shí)候,也就加載這些插件。

add_packagedirs

添加包目錄

通過設(shè)置依賴包目錄,可以方便的集成一些第三方的依賴庫,以tbox工程為例,其包目錄如下:

tbox.pkg
- base.pkg
- zlib.pkg
- polarssl.pkg
- openssl.pkg
- mysql.pkg
- pcre.pkg
- ...

如果要讓當(dāng)前工程識別加載這些包,首先要指定包目錄路徑,例如:

add_packagedirs("pkg")

指定好后,就可以在target作用域中,通過add_packages接口,來添加集成包依賴了,例如:

target("tbox")
    add_packages("zlib", "polarssl", "pcre", "mysql")

工程目標(biāo)

定義和設(shè)置子工程模塊,每個(gè)target對應(yīng)一個(gè)子工程,最后會生成一個(gè)目標(biāo)程序,有可能是可執(zhí)行程序,也有可能是庫模塊。

<p class="tip"> target的接口,都是可以放置在target外面的全局作用域中的,如果在全局中設(shè)置,那么會影響所有子工程target。 </p>

例如:

-- 會同時(shí)影響test和test2目標(biāo)
add_defines("DEBUG")


target("test")
    add_files("*.c")


target("test2")
    add_files("*.c")

<p class="tip"> target域是可以重復(fù)進(jìn)入來實(shí)現(xiàn)分離設(shè)置的。 </p>

接口 描述 支持版本
target 定義工程目標(biāo) >= 1.0.1
target_end 結(jié)束定義工程目標(biāo) >= 2.1.1
set_kind 設(shè)置目標(biāo)編譯類型 >= 1.0.1
set_strip 設(shè)置是否strip信息 >= 1.0.1
set_default 設(shè)置是否為默認(rèn)構(gòu)建安裝目標(biāo) >= 2.1.3
set_options 設(shè)置關(guān)聯(lián)選項(xiàng) >= 1.0.1
set_symbols 設(shè)置符號信息 >= 1.0.1
set_basename 設(shè)置目標(biāo)文件名 >= 2.1.2
set_warnings 設(shè)置警告級別 >= 1.0.1
set_optimize 設(shè)置優(yōu)化級別 >= 1.0.1
set_languages 設(shè)置代碼語言標(biāo)準(zhǔn) >= 1.0.1
set_headerdir 設(shè)置頭文件安裝目錄 >= 1.0.1
set_targetdir 設(shè)置生成目標(biāo)文件目錄 >= 1.0.1
set_objectdir 設(shè)置對象文件生成目錄 >= 1.0.1
on_load 自定義目標(biāo)加載腳本 >= 2.1.5
on_build 自定義編譯腳本 >= 2.0.1
on_clean 自定義清理腳本 >= 2.0.1
on_package 自定義打包腳本 >= 2.0.1
on_install 自定義安裝腳本 >= 2.0.1
on_uninstall 自定義卸載腳本 >= 2.0.1
on_run 自定義運(yùn)行腳本 >= 2.0.1
before_build 在構(gòu)建之前執(zhí)行一些自定義腳本 >= 2.0.1
before_clean 在清除之前執(zhí)行一些自定義腳本 >= 2.0.1
before_package 在打包之前執(zhí)行一些自定義腳本 >= 2.0.1
before_install 在安裝之前執(zhí)行一些自定義腳本 >= 2.0.1
before_uninstall 在卸載之前執(zhí)行一些自定義腳本 >= 2.0.1
before_run 在運(yùn)行之前執(zhí)行一些自定義腳本 >= 2.0.1
after_build 在構(gòu)建之后執(zhí)行一些自定義腳本 >= 2.0.1
after_clean 在清除之后執(zhí)行一些自定義腳本 >= 2.0.1
after_package 在打包之后執(zhí)行一些自定義腳本 >= 2.0.1
after_install 在安裝之后執(zhí)行一些自定義腳本 >= 2.0.1
after_uninstall 在卸載之后執(zhí)行一些自定義腳本 >= 2.0.1
after_run 在運(yùn)行之后執(zhí)行一些自定義腳本 >= 2.0.1
set_config_h 設(shè)置自動生成的配置頭文件路徑 >= 1.0.1 < 2.1.5 已廢棄
set_config_h_prefix 設(shè)置自動生成的頭文件中宏定義命名前綴 >= 1.0.1 < 2.1.5 已廢棄
set_config_header 設(shè)置自動生成的配置頭文件路徑和前綴 >= 2.1.5
set_pcheader 設(shè)置c預(yù)編譯頭文件 >= 2.1.5
set_pcxxheader 設(shè)置c++預(yù)編譯頭文件 >= 2.1.5
add_deps 添加子工程目標(biāo)依賴 >= 1.0.1
add_links 添加鏈接庫名 >= 1.0.1
add_files 添加源代碼文件 >= 1.0.1
add_headers 添加安裝的頭文件 >= 1.0.1
add_linkdirs 添加鏈接庫搜索目錄 >= 1.0.1
add_rpathdirs 添加運(yùn)行時(shí)候動態(tài)鏈接庫搜索目錄 >= 2.1.3
add_includedirs 添加頭文件搜索目錄 >= 1.0.1
add_defines 添加宏定義 >= 1.0.1
add_undefines 取消宏定義 >= 1.0.1
add_defines_h 添加宏定義到頭文件 >= 1.0.1
add_undefines_h 取消宏定義到頭文件 >= 1.0.1
add_cflags 添加c編譯選項(xiàng) >= 1.0.1
add_cxflags 添加c/c++編譯選項(xiàng) >= 1.0.1
add_cxxflags 添加c++編譯選項(xiàng) >= 1.0.1
add_mflags 添加objc編譯選項(xiàng) >= 1.0.1
add_mxflags 添加objc/objc++編譯選項(xiàng) >= 1.0.1
add_mxxflags 添加objc++編譯選項(xiàng) >= 1.0.1
add_scflags 添加swift編譯選項(xiàng) >= 2.0.1
add_asflags 添加匯編編譯選項(xiàng) >= 2.0.1
add_gcflags 添加go編譯選項(xiàng) >= 2.1.1
add_ldflags 添加鏈接選項(xiàng) >= 1.0.1
add_arflags 添加靜態(tài)庫歸檔選項(xiàng) >= 1.0.1
add_shflags 添加動態(tài)庫鏈接選項(xiàng) >= 1.0.1
add_cfunc 添加單個(gè)c庫函數(shù)檢測 >= 2.0.1
add_cxxfunc 添加單個(gè)c++庫函數(shù)檢測 >= 2.0.1
add_cfuncs 添加c庫函數(shù)檢測 >= 2.0.1
add_cxxfuncs 添加c++庫函數(shù)接口 >= 2.0.1
add_packages 添加包依賴 >= 2.0.1
add_options 添加關(guān)聯(lián)選項(xiàng) >= 2.0.1
add_languages 添加語言標(biāo)準(zhǔn) >= 1.0.1
add_vectorexts 添加向量擴(kuò)展指令 >= 1.0.1
add_frameworks 添加鏈接框架 >= 2.1.1
add_frameworkdirs 添加鏈接框架的搜索目錄 >= 2.1.5

target

定義工程目標(biāo)

定義一個(gè)新的控制臺工程目標(biāo),工程名為test,最后生成的目標(biāo)名也是test

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

可以重復(fù)調(diào)用這個(gè)api,進(jìn)入target域修改設(shè)置

-- 定義目標(biāo)demo,并進(jìn)入demo設(shè)置模式
target("demo")
    set_kind("binary")
    add_files("src/demo.c")


-- 定義和設(shè)置其他目標(biāo)
target("other")
    ...


-- 重新進(jìn)入demo目標(biāo)域,添加test.c文件
target("demo")
    add_files("src/test.c")

<p class="tip"> 所有根域的設(shè)置,會全局影響所有target目標(biāo),但是不會影響option的定義。 </p>

-- 在根域?qū)λ衪arget添加-DDEBUG的宏定義,影響所有target(demo和test都會加上此宏定義)
add_defines("DEBUG")


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


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

target_end

結(jié)束定義工程目標(biāo)

這是一個(gè)可選的api,如果不調(diào)用,那么target("xxx")之后的所有設(shè)置都是針對這個(gè)target進(jìn)行的,除非進(jìn)入其他target, option, task域。

如果想設(shè)置完當(dāng)前target后,顯示離開target域,進(jìn)入根域設(shè)置,那么可以通過這個(gè)api才操作,例如:

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


-- 此處已在根域
-- ...

如果不調(diào)用這個(gè)api的話:

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


-- 此處還在上面target域中,之后的設(shè)置還是針對test進(jìn)行的設(shè)置
-- ...


-- 這個(gè)時(shí)候才離開test,進(jìn)入另外一個(gè)target域中
target("test2")
    ...

target:set_kind

設(shè)置目標(biāo)編譯類型

設(shè)置目標(biāo)類型,目前支持的類型有:

描述
binary 二進(jìn)制程序
static 靜態(tài)庫程序
shared 動態(tài)庫程序

target("demo")
    set_kind("binary")

target:set_strip

設(shè)置是否strip信息

設(shè)置當(dāng)前目標(biāo)的strip模式,目前支持一下模式:

描述
debug 鏈接的時(shí)候,strip掉調(diào)試符號
all 鏈接的時(shí)候,strip掉所有符號,包括調(diào)試符號

這個(gè)api一般在release模式下使用,可以生成更小的二進(jìn)制程序。。

target("xxxx")
    set_strip("all")

<p class="tip"> 這個(gè)api不一定非得在target之后使用,如果沒有target指定,那么將會設(shè)置到全局模式。。 </p>

target:set_default

設(shè)置是否為默認(rèn)構(gòu)建安裝目標(biāo)

這個(gè)接口用于設(shè)置給定工程目標(biāo)是否作為默認(rèn)構(gòu)建,如果沒有調(diào)用此接口進(jìn)行設(shè)置,那么這個(gè)目標(biāo)就是默認(rèn)被構(gòu)建的,例如:

target("test1")
    set_default(false)


target("test2")
    set_default(true)


target("test3")
    ...

上述代碼的三個(gè)目標(biāo),在執(zhí)行xmake, xmake install, xmake package, xmake run等命令的時(shí)候,如果不指定目標(biāo)名,那么:

目標(biāo)名 行為
test1 不會被默認(rèn)構(gòu)建、安裝、打包和運(yùn)行
test2 默認(rèn)構(gòu)建、安裝、打包和運(yùn)行
test3 默認(rèn)構(gòu)建、安裝、打包和運(yùn)行

通過上面的例子,可以看到默認(rèn)目標(biāo)可以設(shè)置多個(gè),運(yùn)行的時(shí)候也會依次運(yùn)行。

<p class="tip"> 需要注意的是,xmake uninstallxmake clean命令不受此接口設(shè)置影響,因?yàn)橛脩舸蟛糠智闆r下都是喜歡清除和卸載所有。 </p>

如果不想使用默認(rèn)的目標(biāo),那么可以手動指定需要構(gòu)建安裝的目標(biāo):

$ xmake build targetname
$ xmake install targetname

如果要強(qiáng)制構(gòu)建安裝所有目標(biāo),可以傳入[-a|--all]參數(shù):

$ xmake build [-a|--all]
$ xmake install [-a|--all]

target:set_options

設(shè)置關(guān)聯(lián)選項(xiàng)

添加選項(xiàng)依賴,如果通過option接口自定義了一些選項(xiàng),那么只有在指定target目標(biāo)域下,添加此選項(xiàng),才能進(jìn)行關(guān)聯(lián)生效。

-- 定義一個(gè)hello選項(xiàng)
option("hello")
    set_default(false)
    set_showmenu(true)
    add_defines("HELLO_ENABLE")


target("test")
    -- 如果hello選項(xiàng)被啟用了,這個(gè)時(shí)候就會將-DHELLO_ENABLE宏應(yīng)用到test目標(biāo)上去
    set_options("hello")

<p class="warning"> 只有調(diào)用set_options進(jìn)行關(guān)聯(lián)生效后,option 中定義的一些設(shè)置才會影響到此target目標(biāo),例如:宏定義、鏈接庫、編譯選項(xiàng)等等 </p>

target:set_symbols

設(shè)置符號信息

設(shè)置目標(biāo)的符號模式,如果當(dāng)前沒有定義target,那么將會設(shè)置到全局狀態(tài)中,影響所有后續(xù)的目標(biāo)。

目前主要支持一下幾個(gè)級別:

描述
debug 添加調(diào)試符號
hidden 設(shè)置符號不可見

這兩個(gè)值也可以同時(shí)被設(shè)置,例如:

-- 添加調(diào)試符號, 設(shè)置符號不可見
set_symbols("debug", "hidden")

如果沒有調(diào)用這個(gè)api,默認(rèn)是禁用調(diào)試符號的。。

target:set_basename

設(shè)置目標(biāo)文件名

默認(rèn)情況下,生成的目標(biāo)文件名基于target("name")中配置的值,例如:

-- 目標(biāo)文件名為:libxxx.a
target("xxx")
    set_kind("static")


-- 目標(biāo)文件名為:libxxx2.so
target("xxx2")
    set_kind("shared")

默認(rèn)的命名方式,基本上可以滿足大部分情況下的需求,但是如果有時(shí)候想要更加定制化目標(biāo)文件名

例如,按編譯模式和架構(gòu)區(qū)分目標(biāo)名,這個(gè)時(shí)候可以使用這個(gè)接口,來設(shè)置:

target("xxx")
    set_kind("static")
    set_basename("xxx_$(mode)_$(arch)")

如果這個(gè)時(shí)候,編譯配置為:xmake f -m debug -a armv7,那么生成的文件名為:libxxx_debug_armv7.a

如果還想進(jìn)一步定制目標(biāo)文件的目錄名,可參考:set_targetdir。

或者通過編寫自定義腳本,實(shí)現(xiàn)更高級的邏輯,具體見:after_buildos.mv。

target:set_warnings

設(shè)置警告級別

設(shè)置當(dāng)前目標(biāo)的編譯的警告級別,一般支持一下幾個(gè)級別:

描述
none 禁用所有警告
less 啟用較少的警告
more 啟用較多的警告
all 啟用所有警告
error 將所有警告作為編譯錯(cuò)誤

這個(gè)api的參數(shù)是可以混合添加的,例如:

-- 啟用所有警告,并且作為編譯錯(cuò)誤處理
set_warnings("all", "error")

如果當(dāng)前沒有目標(biāo),調(diào)用這個(gè)api將會設(shè)置到全局模式。。

target:set_optimize

設(shè)置優(yōu)化級別

設(shè)置目標(biāo)的編譯優(yōu)化等級,如果當(dāng)前沒有設(shè)置目標(biāo),那么將會設(shè)置到全局狀態(tài)中,影響所有后續(xù)的目標(biāo)。

目前主要支持一下幾個(gè)級別:

描述
none 禁用優(yōu)化
fast 快速優(yōu)化
faster 更快的優(yōu)化
fastest 最快運(yùn)行速度的優(yōu)化
smallest 最小化代碼優(yōu)化
aggressive 過度優(yōu)化

例如:

-- 最快運(yùn)行速度的優(yōu)化
set_optimize("fastest")

target:set_languages

設(shè)置代碼語言標(biāo)準(zhǔn)

設(shè)置目標(biāo)代碼編譯的語言標(biāo)準(zhǔn),如果當(dāng)前沒有目標(biāo)存在,將會設(shè)置到全局模式中。。。

支持的語言標(biāo)準(zhǔn)目前主要有以下幾個(gè):

描述
ansi c語言標(biāo)準(zhǔn): ansi
c89 c語言標(biāo)準(zhǔn): c89
gnu89 c語言標(biāo)準(zhǔn): gnu89
c99 c語言標(biāo)準(zhǔn): c99
gnu99 c語言標(biāo)準(zhǔn): gnu99
cxx98 c++語言標(biāo)準(zhǔn): c++98
gnuxx98 c++語言標(biāo)準(zhǔn): gnu++98
cxx11 c++語言標(biāo)準(zhǔn): c++11
gnuxx11 c++語言標(biāo)準(zhǔn): gnu++11
cxx14 c++語言標(biāo)準(zhǔn): c++14
gnuxx14 c++語言標(biāo)準(zhǔn): gnu++14
cxx1z c++語言標(biāo)準(zhǔn): c++1z
gnuxx1z c++語言標(biāo)準(zhǔn): gnu++1z
cxx17 c++語言標(biāo)準(zhǔn): c++17
gnuxx17 c++語言標(biāo)準(zhǔn): gnu++17

c標(biāo)準(zhǔn)和c++標(biāo)準(zhǔn)可同時(shí)進(jìn)行設(shè)置,例如:

-- 設(shè)置c代碼標(biāo)準(zhǔn):c99, c++代碼標(biāo)準(zhǔn):c++11
set_languages("c99", "cxx11")

<p class="warning"> 并不是設(shè)置了指定的標(biāo)準(zhǔn),編譯器就一定會按這個(gè)標(biāo)準(zhǔn)來編譯,畢竟每個(gè)編譯器支持的力度不一樣,但是xmake會盡最大可能的去適配當(dāng)前編譯工具的支持標(biāo)準(zhǔn)。。。 <br><br> 例如: <br> windows下vs的編譯器并不支持按c99的標(biāo)準(zhǔn)來編譯c代碼,只能支持到c89,但是xmake為了盡可能的支持它,所以在設(shè)置c99的標(biāo)準(zhǔn)后,xmake會強(qiáng)制按c++代碼模式去編譯c代碼,從一定程度上解決了windows下編譯c99的c代碼問題。。 用戶不需要去額外做任何修改。。 </p>

target:set_headerdir

設(shè)置頭文件安裝目錄

設(shè)置頭文件的輸出目錄,默認(rèn)輸出到build目錄中。

target("test")
    set_headerdir("$(buildir)/include")

對于需要安裝哪些頭文件,可參考add_headers接口。

target:set_targetdir

設(shè)置生成目標(biāo)文件目錄

設(shè)置目標(biāo)程序文件的輸出目錄,一般情況下,不需要設(shè)置,默認(rèn)會輸出在build目錄下

而build的目錄可以在工程配置的時(shí)候,手動修改:

xmake f -o /tmp/build

修改成/tmp/build后,目標(biāo)文件默認(rèn)輸出到/tmp/build下面。

而如果用這個(gè)接口去設(shè)置,就不需要每次敲命令修改了,例如:

target("test")
    set_targetdir("/tmp/build")

<p class="tip"> 如果顯示設(shè)置了set_targetdir, 那么優(yōu)先選擇set_targetdir指定的目錄為目標(biāo)文件的輸出目錄。 </p>

target:set_objectdir

設(shè)置對象文件生成目錄

設(shè)置目標(biāo)target的對象文件(*.o/obj)的輸出目錄,例如:

target("test")
    set_objectdir("$(buildir)/.objs")

target:on_load

自定義目標(biāo)加載腳本

在target初始化加載的時(shí)候,將會執(zhí)行此腳本,在里面可以做一些動態(tài)的目標(biāo)配置,實(shí)現(xiàn)更靈活的目標(biāo)描述定義,例如:

target("test")
    on_load(function (target)
        target:add("defines", "DEBUG", "TEST=\"hello\"")
        target:add("linkdirs", "/usr/lib", "/usr/local/lib")
        target:add({includedirs = "/usr/include", "links" = "pthread"})
    end)

可以在on_load里面,通過target:set, target:add 來動態(tài)添加各種target屬性。

target:on_build

自定義編譯腳本

覆蓋target目標(biāo)默認(rèn)的構(gòu)建行為,實(shí)現(xiàn)自定義的編譯過程,一般情況下,并不需要這么做,除非確實(shí)需要做一些xmake默認(rèn)沒有提供的編譯操作。

你可以通過下面的方式覆蓋它,來自定義編譯操作:

target("test")


    -- 設(shè)置自定義編譯腳本
    on_build(function (target) 
        print("build it")
    end)

注:2.1.5版本之后,所有target的自定義腳本都可以針對不同平臺和架構(gòu),分別處理,例如:

target("test")
    on_build("iphoneos|arm*", function (target)
        print("build for iphoneos and arm")
    end)

其中如果第一個(gè)參數(shù)為字符串,那么就是指定這個(gè)腳本需要在哪個(gè)平臺|架構(gòu)下,才會被執(zhí)行,并且支持模式匹配,例如arm*匹配所有arm架構(gòu)。

當(dāng)然也可以只設(shè)置平臺,不設(shè)置架構(gòu),這樣就是匹配指定平臺下,執(zhí)行腳本:

target("test")
    on_build("windows", function (target)
        print("build for windows")
    end)

<p class="tip"> 一旦對這個(gè)target目標(biāo)設(shè)置了自己的build過程,那么xmake默認(rèn)的構(gòu)建過程將不再被執(zhí)行。 </p>

target:on_clean

自定義清理腳本

覆蓋target目標(biāo)的xmake [c|clean}的清理操作,實(shí)現(xiàn)自定義清理過程。

target("test")


    -- 設(shè)置自定義清理腳本
    on_clean(function (target) 


        -- 僅刪掉目標(biāo)文件
        os.rm(target:targetfile())
    end)

一些target接口描述如下:

target接口 描述
target:name() 獲取目標(biāo)名
target:targetfile() 獲取目標(biāo)文件路徑
target:get("kind") 獲取目標(biāo)的構(gòu)建類型
target:get("defines") 獲取目標(biāo)的宏定義
target:get("xxx") 其他通過 set_/add_接口設(shè)置的target信息,都可以通過此接口來獲取
target:add("links", "pthread") 添加目標(biāo)設(shè)置
target:set("links", "pthread", "z") 覆寫目標(biāo)設(shè)置
target:deps() 獲取目標(biāo)的所有依賴目標(biāo)
target:dep("depname") 獲取指定的依賴目標(biāo)
target:sourcebatches() 獲取目標(biāo)的所有源文件列表

target:on_package

自定義打包腳本

覆蓋target目標(biāo)的xmake [p|package}的打包操作,實(shí)現(xiàn)自定義打包過程,如果你想對指定target打包成自己想要的格式,可以通過這個(gè)接口自定義它。

這個(gè)接口還是挺實(shí)用的,例如,編譯玩jni后,將生成的so,打包進(jìn)apk包中。

-- 定義一個(gè)android app的測試demo
target("demo")


    -- 生成動態(tài)庫:libdemo.so
    set_kind("shared")


    -- 設(shè)置對象的輸出目錄,可選
    set_objectdir("$(buildir)/.objs")


    -- 每次編譯完的libdemo.so的生成目錄,設(shè)置為app/libs/armeabi
    set_targetdir("libs/armeabi")


    -- 添加jni的代碼文件
    add_files("jni/*.c")


    -- 設(shè)置自定義打包腳本,在使用xmake編譯完libdemo.so后,執(zhí)行xmake p進(jìn)行打包
    -- 會自動使用ant將app編譯成apk文件
    --
    on_package(function (target) 


        -- 使用ant編譯app成apk文件,輸出信息重定向到日志文件
        os.run("ant debug") 
    end)

target:on_install

自定義安裝腳本

覆蓋target目標(biāo)的xmake [i|install}的安裝操作,實(shí)現(xiàn)自定義安裝過程。

例如,將生成的apk包,進(jìn)行安裝。

target("test")


    -- 設(shè)置自定義安裝腳本,自動安裝apk文件
    on_install(function (target) 


        -- 使用adb安裝打包生成的apk文件
        os.run("adb install -r ./bin/Demo-debug.apk")
    end)

target:on_uninstall

自定義卸載腳本

覆蓋target目標(biāo)的xmake [u|uninstall}的卸載操作,實(shí)現(xiàn)自定義卸載過程。

target("test")
    on_uninstall(function (target) 
        ...
    end)

target:on_run

自定義運(yùn)行腳本

覆蓋target目標(biāo)的xmake [r|run}的運(yùn)行操作,實(shí)現(xiàn)自定義運(yùn)行過程。

例如,運(yùn)行安裝好的apk程序:

target("test")


    -- 設(shè)置自定義運(yùn)行腳本,自動運(yùn)行安裝好的app程序,并且自動獲取設(shè)備輸出信息
    on_run(function (target) 


        os.run("adb shell am start -n com.demo/com.demo.DemoTest")
        os.run("adb logcat")
    end)

target:before_build

在構(gòu)建之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的構(gòu)建操作,只是在構(gòu)建之前增加一些自定義的操作。

target("test")
    before_build(function (target)
        print("")
    end)

target:before_clean

在清理之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的清理操作,只是在清理之前增加一些自定義的操作。

target("test")
    before_clean(function (target)
        print("")
    end)

target:before_package

在打包之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的打包操作,只是在打包之前增加一些自定義的操作。

target("test")
    before_package(function (target)
        print("")
    end)

target:before_install

在安裝之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的安裝操作,只是在安裝之前增加一些自定義的操作。

target("test")
    before_install(function (target)
        print("")
    end)

target:before_uninstall

在卸載之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的卸載操作,只是在卸載之前增加一些自定義的操作。

target("test")
    before_uninstall(function (target)
        print("")
    end)

target:before_run

在運(yùn)行之前執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的運(yùn)行操作,只是在運(yùn)行之前增加一些自定義的操作。

target("test")
    before_run(function (target)
        print("")
    end)

target:after_build

在構(gòu)建之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的構(gòu)建操作,只是在構(gòu)建之后增加一些自定義的操作。

例如,對于ios的越獄開發(fā),構(gòu)建完程序后,需要用ldid進(jìn)行簽名操作

target("test")
    after_build(function (target)
        os.run("ldid -S %s", target:targetfile())
    end)

target:after_clean

在清理之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的清理操作,只是在清理之后增加一些自定義的操作。

一般可用于清理編譯某target自動生成的一些額外的臨時(shí)文件,這些文件xmake默認(rèn)的清理規(guī)則可能沒有清理到,例如:

target("test")
    after_clean(function (target)
        os.rm("$(buildir)/otherfiles")
    end)

target:after_package

在打包之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的打包操作,只是在打包之后增加一些自定義的操作。

target("test")
    after_package(function (target)
        print("")
    end)

target:after_install

在安裝之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的安裝操作,只是在安裝之后增加一些自定義的操作。

target("test")
    after_install(function (target)
        print("")
    end)
target:after_uninstall

在卸載之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的卸載操作,只是在卸載之后增加一些自定義的操作。

target("test")
    after_uninstall(function (target)
        print("")
    end)

target:after_run

在運(yùn)行之后執(zhí)行一些自定義腳本

并不會覆蓋默認(rèn)的運(yùn)行操作,只是在運(yùn)行之后增加一些自定義的操作。

target("test")
    after_run(function (target)
        print("")
    end)

target:set_config_h

設(shè)置自動生成的配置頭文件路徑

<p class="warning"> 2.1.5版本之后,此接口已廢棄,請使用set_config_header。 </p>

如果你想在xmake配置項(xiàng)目成功后,或者自動檢測某個(gè)選項(xiàng)通過后,把檢測的結(jié)果寫入配置頭文件,那么需要調(diào)用這個(gè)接口來啟用自動生成config.h文件。

使用方式例如:

target("test")


    -- 啟用并設(shè)置需要自動生成的config.h文件路徑
    set_config_h("$(buildir)/config.h")


    -- 設(shè)置自動檢測生成的宏開關(guān)的名字前綴
    set_config_h_prefix("TB_CONFIG")

當(dāng)這個(gè)target中通過下面的這些接口,對這個(gè)target添加了相關(guān)的選項(xiàng)依賴、包依賴、接口依賴后,如果某依賴被啟用,那么對應(yīng)的一些宏定義配置,會自動寫入被設(shè)置的config.h文件中去。

這些接口,其實(shí)底層都用到了option選項(xiàng)中的一些檢測設(shè)置,例如:

option("wchar")


    -- 添加對wchar_t類型的檢測
    add_ctypes("wchar_t")


    -- 如果檢測通過,自動生成 TB_CONFIG_TYPE_HAVE_WCHAR的宏開關(guān)到config.h
    add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")


target("test")


    -- 啟用頭文件自動生成
    set_config_h("$(buildir)/config.h")
    set_config_h_prefix("TB_CONFIG")


    -- 添加對wchar選項(xiàng)的依賴關(guān)聯(lián),只有加上這個(gè)關(guān)聯(lián),wchar選項(xiàng)的檢測結(jié)果才會寫入指定的config.h中去
    add_options("wchar")

target:set_config_h_prefix

設(shè)置自動生成的頭文件中宏定義命名前綴

<p class="warning"> 2.1.5版本之后,此接口已廢棄,請使用set_config_header。 </p>

具體使用見:set_config_h

如果設(shè)置了:

target("test")
    set_config_h_prefix("TB_CONFIG")

那么,選項(xiàng)中add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")的$(prefix)會自動被替換成新的前綴值。

target:set_config_header

設(shè)置自動生成的配置頭文件路徑和前綴

此接口是set_config_hset_config_h_prefix的升級版本,2.1.5之后支持。

如果你想在xmake配置項(xiàng)目成功后,或者自動檢測某個(gè)選項(xiàng)通過后,把檢測的結(jié)果寫入配置頭文件,那么需要調(diào)用這個(gè)接口來啟用自動生成config.h文件。

使用方式例如:

target("test")
    set_config_header("$(buildir)/config.h", {prefix = "TB_CONFIG"})

上面的代碼,啟用并設(shè)置需要自動生成的config.h文件路徑,并且設(shè)置自動檢測生成的宏開關(guān)的名字前綴:TB_CONFIG, 當(dāng)然這個(gè)前綴的設(shè)置是可選的。

target("test")
    set_config_header("$(buildir)/config.h")

如果不設(shè)置前綴,將會自動根據(jù)target名生成一個(gè)唯一字串。

當(dāng)這個(gè)target中通過下面的這些接口,對這個(gè)target添加了相關(guān)的選項(xiàng)依賴、包依賴、接口依賴后,如果某依賴被啟用,那么對應(yīng)的一些宏定義配置,會自動寫入被設(shè)置的config.h文件中去。

這些接口,其實(shí)底層都用到了option選項(xiàng)中的一些檢測設(shè)置,例如:

option("wchar")


    -- 添加對wchar_t類型的檢測
    add_ctypes("wchar_t")


    -- 如果檢測通過,自動生成 TB_CONFIG_TYPE_HAVE_WCHAR的宏開關(guān)到config.h
    add_defines_h("$(prefix)_TYPE_HAVE_WCHAR")


target("test")


    -- 啟用頭文件自動生成
    set_config_header("$(buildir)/config.h", {prefix = "TB_CONFIG"})


    -- 添加對wchar選項(xiàng)的依賴關(guān)聯(lián),只有加上這個(gè)關(guān)聯(lián),wchar選項(xiàng)的檢測結(jié)果才會寫入指定的config.h中去
    add_options("wchar")

target:set_pcheader

設(shè)置c預(yù)編譯頭文件

xmake支持通過預(yù)編譯頭文件去加速c程序編譯,目前支持的編譯器有:gcc, clang和msvc。

使用方式如下:

target("test")
    set_pcheader("header.h")

target:set_pcxxheader

設(shè)置c++預(yù)編譯頭文件

xmake支持通過預(yù)編譯頭文件去加速c++程序編譯,目前支持的編譯器有:gcc, clang和msvc。

使用方式如下:

target("test")
    set_pcxxheader("header.h")

target:add_deps

添加子工程目標(biāo)依賴

添加當(dāng)前目標(biāo)的依賴目標(biāo),編譯的時(shí)候,會去優(yōu)先編譯依賴的目標(biāo),然后再編譯當(dāng)前目標(biāo)。。。

target("test1")
    set_kind("static")
    set_files("*.c")


target("test2")
    set_kind("static")
    set_files("*.c")


target("demo")


    -- 添加依賴目標(biāo):test1, test2
    add_deps("test1", "test2")


    -- 鏈接libtest1.a,libtest2.a
    add_links("test1", "test2")

上面的例子,在編譯目標(biāo)demo的時(shí)候,需要先編譯test1, test2目標(biāo),因?yàn)閐emo會去用到他們

<p class="tip"> 2.1.5版本后,target會自動繼承依賴目標(biāo)中的配置和屬性,不再需要額外調(diào)用add_links, add_includedirsadd_linkdirs等接口去關(guān)聯(lián)依賴目標(biāo)了。 </p>

2.1.5版本之后,上述代碼可簡化為:

target("test1")
    set_kind("static")
    set_files("*.c")


target("test2")
    set_kind("static")
    set_files("*.c")


target("demo")
    add_deps("test1", "test2") -- 會自動鏈接依賴目標(biāo)

并且繼承關(guān)系是支持級聯(lián)的,例如:

target("library1")
    set_kind("static")
    add_files("*.c")
    add_headers("inc1/*.h")


target("library2")
    set_kind("static")
    add_deps("library1")
    add_files("*.c")
    add_headers("inc2/*.h")


target("test")
    set_kind("binary")
    add_deps("library2")

如果我們還是想以前那樣,并不想繼承依賴target的任何配置,如何操作呢?這個(gè)在2.1.6版本中也對其進(jìn)行了支持,通過:

add_deps("dep1", "dep2", {inherit = false})

通過顯示設(shè)置inherit配置,來告訴xmake,這兩個(gè)依賴的配置是否需要被繼承,如果不設(shè)置,默認(rèn)就是啟用繼承的。

target:add_links

添加鏈接庫名

為當(dāng)前目標(biāo)添加鏈接庫,一般這個(gè)要與add_linkdirs配對使用。

target("demo")


    -- 添加對libtest.a的鏈接,相當(dāng)于 -ltest 
    add_links("test")


    -- 添加鏈接搜索目錄
    add_linkdirs("$(buildir)/lib")

target:add_files

添加源代碼文件

用于添加目標(biāo)工程的源文件,甚至庫文件,目前支持的一些文件類型:

支持的源文件類型 描述
.c/.cpp/.cc/.cxx c++文件
.s/.S/.asm 匯編文件
.m/.mm objc文件
.swift swift文件
.go golang文件
.o/.obj 對象文件
.a/.lib 靜態(tài)庫文件,會自動合并庫到目標(biāo)程序
.rc msvc的資源文件

其中通配符*表示匹配當(dāng)前目錄下文件,而**則匹配多級目錄下的文件。

例如:

add_files("src/test_*.c")
add_files("src/xxx/**.cpp")
add_files("src/asm/*.S", "src/objc/**/hello.m")

add_files的使用其實(shí)是相當(dāng)靈活方便的,其匹配模式借鑒了premake的風(fēng)格,但是又對其進(jìn)行了改善和增強(qiáng)。

使得不僅可以匹配文件,還有可以在添加文件同時(shí),過濾排除指定模式的一批文件。

例如:

-- 遞歸添加src下的所有c文件,但是不包括src/impl/下的所有c文件
add_files("src/**.c|impl/*.c")


-- 添加src下的所有cpp文件,但是不包括src/test.cpp、src/hello.cpp以及src下所有帶xx_前綴的cpp文件
add_files("src/*.cpp|test.cpp|hello.cpp|xx_*.cpp")

其中分隔符|之后的都是需要排除的文件,這些文件也同樣支持匹配模式,并且可以同時(shí)添加多個(gè)過濾模式,只要中間用|分割就行了。。

添加文件的時(shí)候支持過濾一些文件的一個(gè)好處就是,可以為后續(xù)根據(jù)不同開關(guān)邏輯添加文件提供基礎(chǔ)。

<p class="tip"> 為了使得描述上更加的精簡,|之后的過濾描述都是基于起一個(gè)模式:src/*.cpp*之前的目錄為基礎(chǔ)的。 所以上面的例子后面過濾的都是在src下的文件,這個(gè)是要注意的。 </p>

2.1.6版本之后,對add_files進(jìn)行了改進(jìn),支持基于files更細(xì)粒度的編譯選項(xiàng)控制,例如:

target("test")
    add_defines("TEST1")
    add_files("src/*.c")
    add_files("test/*.c", "test2/test2.c", {defines = "TEST2", languages = "c99", includedirs = ".", cflags = "-O0"})

可以在add_files的最后一個(gè)參數(shù),傳入一個(gè)配置table,去控制指定files的編譯選項(xiàng),里面的配置參數(shù)跟target的一致,并且這些文件還會繼承target的通用配置-DTEST1。

target:add_headers

添加安裝的頭文件

安裝指定的頭文件到build目錄,如果設(shè)置了set_headerdir, 則輸出到指定目錄。

安裝規(guī)則的語法跟add_files類似,例如:

    -- 安裝tbox目錄下所有的頭文件(忽略impl目錄下的文件),并且按()指定部分作為相對路徑,進(jìn)行安裝
    add_headers("../(tbox/**.h)|**/impl/**.h")

target:add_linkdirs

添加鏈接庫搜索目錄

設(shè)置鏈接庫的搜索目錄,這個(gè)接口的使用方式如下:

target("test")
    add_linkdirs("$(buildir)/lib")

此接口相當(dāng)于gcc的-Lxxx鏈接選項(xiàng)。

一般他是與add_links配合使用的,當(dāng)然也可以直接通過add_ldflags或者add_shflags接口來添加,也是可以的。

<p class="tip"> 如果不想在工程中寫死,可以通過:xmake f --linkdirs=xxx或者xmake f --ldflags="-L/xxx"的方式來設(shè)置,當(dāng)然這種手動設(shè)置的目錄搜索優(yōu)先級更高。 </p>

target:add_rpathdirs

添加程序運(yùn)行時(shí)動態(tài)庫的加載搜索目錄

通過add_linkdirs設(shè)置動態(tài)庫的鏈接搜索目錄后,程序被正常鏈接,但是在linux平臺想要正常運(yùn)行編譯后的程序,會報(bào)加載動態(tài)庫失敗。

因?yàn)闆]找到動態(tài)庫的加載目錄,想要正常運(yùn)行依賴動態(tài)庫的程序,需要設(shè)置LD_LIBRARY_PATH環(huán)境變量,指定需要加載的動態(tài)庫目錄。

但是這種方式是全局的,影響太廣,更好的方式是通過-rpath=xxx的鏈接器選項(xiàng),在鏈接程序的時(shí)候設(shè)置好需要加載的動態(tài)庫搜索路徑,而xmake對其進(jìn)行了封裝,通過add_rpathdirs更好的處理跨平臺問題。

具體使用如下:

target("test")
    set_kind("binary")
    add_linkdirs("$(buildir)/lib")
    add_rpathdirs("$(buildir)/lib")

只需要在鏈接的時(shí)候,在設(shè)置下rpath目錄就好了,雖然也可以通過add_ldflags("-Wl,-rpath=xxx")達(dá)到相同的目的,但是這個(gè)接口更加通用。

內(nèi)部會對不同平臺進(jìn)行處理,像在macOS下,是不需要-rpath設(shè)置的,也是可以正常加載運(yùn)行程序,因此針對這個(gè)平臺,xmake內(nèi)部會直接忽略器設(shè)置,避免鏈接報(bào)錯(cuò)。

而在為dlang程序進(jìn)行動態(tài)庫鏈接時(shí),xmake會自動處理成-L-rpath=xxx來傳入dlang的鏈接器,這樣就避免了直接使用add_ldflags需要自己判斷和處理不同平臺和編譯器問題。

2.1.7版本對這個(gè)接口進(jìn)行了改進(jìn),支持:@loader_path, @executable_path$ORIGIN的內(nèi)置變量,來指定程序的加載目錄,它們的效果基本上是一樣的,主要是為了同時(shí)兼容macho, elf。

例如:

target("test")
    set_kind("binary")
    add_linkdirs("$(buildir)/lib")
    add_rpathdirs("@loader_path/lib")

指定test程序加載當(dāng)前執(zhí)行目錄下lib/*.[so|dylib]的動態(tài)庫文件,這將有助于提升程序的可移植性,不用寫死絕對路徑和相對路徑,導(dǎo)致程序和目錄切換引起程序加載動態(tài)庫失敗。

target:add_includedirs

添加頭文件搜索目錄

設(shè)置頭文件的搜索目錄,這個(gè)接口的使用方式如下:

target("test")
    add_includedirs("$(buildir)/include")

當(dāng)然也可以直接通過add_cxflags或者add_mxflags等接口來設(shè)置,也是可以的。

<p class="tip"> 如果不想在工程中寫死,可以通過:xmake f --includedirs=xxx或者xmake f --cxflags="-I/xxx"的方式來設(shè)置,當(dāng)然這種手動設(shè)置的目錄搜索優(yōu)先級更高。 </p>

target:add_defines

添加宏定義

add_defines("DEBUG", "TEST=0", "TEST2=\"hello\"")

相當(dāng)于設(shè)置了編譯選項(xiàng):

-DDEBUG -DTEST=0 -DTEST2=\"hello\"

target:add_undefines

取消宏定義

add_undefines("DEBUG")

相當(dāng)于設(shè)置了編譯選項(xiàng):-UDEBUG

在代碼中相當(dāng)于:#undef DEBUG

target:add_defines_h

添加宏定義到頭文件

添加宏定義到config.h配置文件,config.h的設(shè)置,可參考set_config_h接口。

target:add_undefines_h

取消宏定義到頭文件

config.h配置文件中通過undef禁用宏定義,config.h的設(shè)置,可參考set_config_h接口。

target:add_cflags

添加c編譯選項(xiàng)

僅對c代碼添加編譯選項(xiàng)

add_cflags("-g", "-O2", "-DDEBUG")

<p class="warning"> 所有選項(xiàng)值都基于gcc的定義為標(biāo)準(zhǔn),如果其他編譯器不兼容(例如:vc),xmake會自動內(nèi)部將其轉(zhuǎn)換成對應(yīng)編譯器支持的選項(xiàng)值。 用戶無需操心其兼容性,如果其他編譯器沒有對應(yīng)的匹配值,那么xmake會自動忽略器設(shè)置。 </p>

target:add_cxflags

添加c/c++編譯選項(xiàng)

同時(shí)對c/c++代碼添加編譯選項(xiàng)

target:add_cxxflags

添加c++編譯選項(xiàng)

僅對c++代碼添加編譯選項(xiàng)

target:add_mflags

添加objcc編譯選項(xiàng)

僅對objc代碼添加編譯選項(xiàng)

add_mflags("-g", "-O2", "-DDEBUG")

target:add_mxflags

添加objc/objc++編譯選項(xiàng)

同時(shí)對objc/objc++代碼添加編譯選項(xiàng)

add_mxflags("-framework CoreFoundation")

target:add_mxxflags

添加objc++編譯選項(xiàng)

僅對objc++代碼添加編譯選項(xiàng)

add_mxxflags("-framework CoreFoundation")

target:add_scflags

添加swift編譯選項(xiàng)

對swift代碼添加編譯選項(xiàng)

add_scflags("xxx")

target:add_asflags

添加匯編編譯選項(xiàng)

對匯編代碼添加編譯選項(xiàng)

add_asflags("xxx")

target:add_gcflags

添加go編譯選項(xiàng)

對golang代碼添加編譯選項(xiàng)

add_gcflags("xxx")

target:add_dcflags

添加dlang編譯選項(xiàng)

對dlang代碼添加編譯選項(xiàng)

add_dcflags("xxx")

target:add_rcflags

添加rust編譯選項(xiàng)

對rust代碼添加編譯選項(xiàng)

add_rcflags("xxx")

target:add_ldflags

添加鏈接選項(xiàng)

添加靜態(tài)鏈接庫選項(xiàng)

add_ldflags("-L/xxx", "-lxxx")

target:add_arflags

添加靜態(tài)庫歸檔選項(xiàng)

影響對靜態(tài)庫的生成

add_arflags("xxx")
target:add_shflags

添加動態(tài)庫鏈接選項(xiàng)

影響對動態(tài)庫的生成

add_shflags("xxx")

target:add_cfunc

添加單個(gè)c庫函數(shù)檢測

add_cfuncs類似,只是僅對單個(gè)函數(shù)接口進(jìn)行設(shè)置,并且僅對target域生效,option中不存在此接口。

此接口的目的主要是為了在config.h中更加高度定制化的生成宏開關(guān),例如:

target("demo")

    
    -- 設(shè)置和啟用config.h
    set_config_h("$(buildir)/config.h")
    set_config_h_prefix("TEST")


    -- 僅通過參數(shù)一設(shè)置模塊名前綴
    add_cfunc("libc",       nil,        nil,        {"sys/select.h"},   "select")


    -- 通過參數(shù)三,設(shè)置同時(shí)檢測鏈接庫:libpthread.a
    add_cfunc("pthread",    nil,        "pthread",  "pthread.h",        "pthread_create")


    -- 通過參數(shù)二設(shè)置接口別名
    add_cfunc(nil,          "PTHREAD",  nil,        "pthread.h",        "pthread_create")

生成的結(jié)果如下:

#ifndef TEST_H
#define TEST_H


// 宏命名規(guī)則:$(prefix)前綴 _ 模塊名(如果非nil)_ HAVE _ 接口名或者別名 (大寫)
#define TEST_LIBC_HAVE_SELECT 1
#define TEST_PTHREAD_HAVE_PTHREAD_CREATE 1
#define TEST_HAVE_PTHREAD 1


#endif

如果要更加靈活的函數(shù)檢測,可以通過lib.detect.has_cfuncs在自定義腳本中實(shí)現(xiàn)。

target:add_cxxfunc

添加單個(gè)c++庫函數(shù)檢測

add_cfunc類似,只是檢測的函數(shù)接口是c++函數(shù)。

target:add_cfuncs

添加c庫函數(shù)檢測

<p class="warning"> 此接口是targetoption共用的接口,但是接口行為稍有不同。 </p>

接口域 描述 例子
target 頭文件、鏈接庫和函數(shù)接口同時(shí)指定 add_cfuncs("libc", nil, {"signal.h", "setjmp.h"}, "signal", "setjmp", "sigsetjmp{sigjmp_buf buf; sigsetjmp(buf, 0);}", "kill")
option 僅指定函數(shù)接口,頭文件依賴add_cincludes等獨(dú)立接口 add_cincludes("setjmp.h") add_cfuncs("sigsetjmp")

對于option,這個(gè)接口的使用很簡單,跟add_cincludes類似,例如:

option("setjmp")
    set_default(false)
    add_cincludes("setjmp.h")
    add_cfuncs("sigsetjmp", "setjmp")
    add_defines("HAVE_SETJMP")


target("test")
    add_options("setjmp")

此選項(xiàng)檢測是否存在setjmp的一些接口,如果檢測通過那么test目標(biāo)程序?qū)由?code>HAVE_SETJMP的宏定義。

<p class="warning"> 需要注意的是,在option中使用此接口檢測依賴函數(shù),需要同時(shí)使用獨(dú)立的add_cincludes增加頭文件搜索路徑,指定add_links鏈接庫(可選),否則檢測不到指定函數(shù)。 <br><br> 并且某些頭文件接口是通過宏開關(guān)分別定義的,那么檢測的時(shí)候最好通過add_defines帶上依賴的宏開關(guān)。 </p>

對于target,此接口可以同時(shí)設(shè)置:依賴的頭文件、依賴的鏈接模塊、依賴的函數(shù)接口,保證檢測環(huán)境的完整性,例如:

target("test")


    -- 添加libc庫接口相關(guān)檢測
    -- 第一個(gè)參數(shù):模塊名,用于最后的宏定義前綴生成
    -- 第二個(gè)參數(shù):鏈接庫
    -- 第三個(gè)參數(shù):頭文件
    -- 之后的都是函數(shù)接口列表
    add_cfuncs("libc", nil,         {"signal.h", "setjmp.h"},           "signal", "setjmp", "sigsetjmp{sigjmp_buf buf; sigsetjmp(buf, 0);}", "kill")


    -- 添加pthread庫接口相關(guān)檢測,同時(shí)指定需要檢測`libpthread.a`鏈接庫是否存在
    add_cfuncs("posix", "pthread",  "pthread.h",                        "pthread_mutex_init",
                                                                        "pthread_create", 
                                                                        "pthread_setspecific", 
                                                                        "pthread_getspecific",
                                                                        "pthread_key_create",
                                                                        "pthread_key_delete")

設(shè)置test目標(biāo),依賴這些接口,構(gòu)建時(shí)會預(yù)先檢測他們,并且如果通過set_config_h接口設(shè)置的自動生成頭文件:config.h

那么,檢測結(jié)果會自動加到對應(yīng)的config.h上去,這也是option沒有的功能,例如:

#define TB_CONFIG_LIBC_HAVE_SIGNAL 1
#define TB_CONFIG_LIBC_HAVE_SETJMP 1
#define TB_CONFIG_LIBC_HAVE_SIGSETJMP 1
#define TB_CONFIG_LIBC_HAVE_KILL 1


#define TB_CONFIG_POSIX_HAVE_PTHREAD_MUTEX_INIT 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_SETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_GETSPECIFIC 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_CREATE 1
#define TB_CONFIG_POSIX_HAVE_PTHREAD_KEY_DELETE 1

由于,不同頭文件中,函數(shù)的定義方式不完全相同,例如:宏函數(shù)、靜態(tài)內(nèi)聯(lián)函數(shù)、extern函數(shù)等。

要想完全檢測成功,檢測語法上需要一定程度的靈活性,下面是一些語法規(guī)則:

檢測語法 例子
純函數(shù)名 sigsetjmp
單行調(diào)用 sigsetjmp((void*)0, 0)
函數(shù)塊調(diào)用 sigsetjmp{sigsetjmp((void*)0, 0);}
函數(shù)塊 + 變量 sigsetjmp{int a = 0; sigsetjmp((void*)a, a);}

target:add_cxxfuncs

添加c++庫函數(shù)檢測

add_cfuncs類似,只是檢測的函數(shù)接口是c++函數(shù)。

target:add_options

添加關(guān)聯(lián)選項(xiàng)

這個(gè)接口跟set_options類似,唯一的區(qū)別就是,此處是追加選項(xiàng),而set_options每次設(shè)置會覆蓋先前的設(shè)置。

target:add_packages

添加包依賴

在target作用域中,添加集成包依賴,例如:

target("test")
    add_packages("zlib", "polarssl", "pcre", "mysql")

這樣,在編譯test目標(biāo)時(shí),如果這個(gè)包存在的,將會自動追加包里面的宏定義、頭文件搜索路徑、鏈接庫目錄,也會自動鏈接包中所有庫。

用戶不再需要自己單獨(dú)調(diào)用add_links,add_includedirs, add_ldflags等接口,來配置依賴庫鏈接了。

對于如何設(shè)置包搜索目錄,可參考:add_packagedirs 接口

target:add_languages

添加語言標(biāo)準(zhǔn)

set_languages類似,唯一區(qū)別是這個(gè)接口不會覆蓋掉之前的設(shè)置,而是追加設(shè)置。

target:add_vectorexts

添加向量擴(kuò)展指令

添加擴(kuò)展指令優(yōu)化選項(xiàng),目前支持以下幾種擴(kuò)展指令集:

add_vectorexts("mmx")
add_vectorexts("neon")
add_vectorexts("avx", "avx2")
add_vectorexts("sse", "sse2", "sse3", "ssse3")

<p class="tip"> 如果當(dāng)前設(shè)置的指令集編譯器不支持,xmake會自動忽略掉,所以不需要用戶手動去判斷維護(hù),只需要將你需要的指令集全部設(shè)置上就行了。 </p>

target:add_frameworks

添加鏈接框架

目前主要用于iosmacosx平臺的objcswift程序,例如:

target("test")
    add_frameworks("Foundation", "CoreFoundation")

當(dāng)然也可以使用add_mxflagsadd_ldflags來設(shè)置,不過比較繁瑣,不建議這樣設(shè)置。

target("test")
    add_mxflags("-framework Foundation", "-framework CoreFoundation")
    add_ldflags("-framework Foundation", "-framework CoreFoundation")

如果不是這兩個(gè)平臺,這些設(shè)置將會被忽略。

target:add_frameworkdirs

添加鏈接框架搜索目錄

對于一些第三方framework,那么僅僅通過add_frameworks是沒法找到的,還需要通過這個(gè)接口來添加搜索目錄。

target("test")
    add_frameworks("MyFramework")
    add_frameworkdirs("/tmp/frameworkdir", "/tmp/frameworkdir2")

選項(xiàng)定義

定義和設(shè)置選項(xiàng)開關(guān),每個(gè)option對應(yīng)一個(gè)選項(xiàng),可用于自定義編譯配置選項(xiàng)、開關(guān)設(shè)置。

<p class="tip"> 除了target以外的所有域接口,例如option,task等的接口,默認(rèn)不能放置在外面的全局作用域中的(除非部分跟target共用的接口除外)。 如果要設(shè)置值影響所有optiontask等選項(xiàng),可以通過匿名全局域來設(shè)置。 </p>

例如:

-- 進(jìn)入option的匿名全局域,里面的設(shè)置會同時(shí)影響test和test2選項(xiàng)
option()
    add_defines("DEBUG")


option("test")
    -- ... 
    -- 盡量保持縮進(jìn),因?yàn)檫@個(gè)之后的所有設(shè)置,都是針對test選項(xiàng)的


option("test2")
    -- ... 

<p class="tip"> option域是可以重復(fù)進(jìn)入來實(shí)現(xiàn)分離設(shè)置的,如果要顯示離開當(dāng)前選項(xiàng)的作用域設(shè)置,可以手動調(diào)用option_end接口。 </p>

接口 描述 支持版本
option 定義選項(xiàng) >= 2.0.1
option_end 結(jié)束定義選項(xiàng) >= 2.1.1
add_deps 添加選項(xiàng)依賴 >= 2.1.5
before_check 選項(xiàng)檢測之前執(zhí)行此腳本 >= 2.1.5
on_check 自定義選項(xiàng)檢測腳本 >= 2.1.5
after_check 選項(xiàng)檢測之后執(zhí)行此腳本 >= 2.1.5
set_default 設(shè)置默認(rèn)值 >= 2.0.1
set_showmenu 設(shè)置是否啟用菜單顯示 >= 1.0.1
set_category 設(shè)置選項(xiàng)分類,僅用于菜單顯示 >= 1.0.1
set_description 設(shè)置菜單顯示描述 >= 1.0.1
add_links 添加鏈接庫檢測 >= 1.0.1
add_linkdirs 添加鏈接庫檢測需要的搜索目錄 >= 1.0.1
add_rpathdirs 添加運(yùn)行時(shí)候動態(tài)鏈接庫搜索目錄 >= 2.1.3
add_cincludes 添加c頭文件檢測 >= 1.0.1
add_cxxincludes 添加c++頭文件檢測 >= 1.0.1
add_ctypes 添加c類型檢測 >= 1.0.1
add_cxxtypes 添加c++類型檢測 >= 1.0.1
add_csnippet 添加c代碼片段檢測 >= 2.1.5
add_cxxsnippet 添加c++代碼片段檢測 >= 2.1.5
set_warnings 設(shè)置警告級別 >= 1.0.1
set_optimize 設(shè)置優(yōu)化級別 >= 1.0.1
set_languages 設(shè)置代碼語言標(biāo)準(zhǔn) >= 1.0.1
add_includedirs 添加頭文件搜索目錄 >= 1.0.1
add_defines 添加宏定義 >= 1.0.1
add_undefines 取消宏定義 >= 1.0.1
add_defines_h 添加宏定義到頭文件 >= 1.0.1
add_undefines_h 取消宏定義到頭文件 >= 1.0.1
add_cflags 添加c編譯選項(xiàng) >= 1.0.1
add_cxflags 添加c/c++編譯選項(xiàng) >= 1.0.1
add_cxxflags 添加c++編譯選項(xiàng) >= 1.0.1
add_mflags 添加objc編譯選項(xiàng) >= 2.0.1
add_mxflags 添加objc/objc++編譯選項(xiàng) >= 2.0.1
add_mxxflags 添加objc++編譯選項(xiàng) >= 2.0.1
add_scflags 添加swift編譯選項(xiàng) >= 2.1.1
add_asflags 添加匯編編譯選項(xiàng) >= 2.1.1
add_gcflags 添加go編譯選項(xiàng) >= 2.1.1
add_dcflags 添加dlang編譯選項(xiàng) >= 2.1.1
add_rcflags 添加rust編譯選項(xiàng) >= 2.1.1
add_ldflags 添加鏈接選項(xiàng) >= 2.1.1
add_arflags 添加靜態(tài)庫歸檔選項(xiàng) >= 2.1.1
add_shflags 添加動態(tài)庫鏈接選項(xiàng) >= 2.0.1
add_cfuncs 添加c庫函數(shù)檢測 >= 1.0.1
add_cxxfuncs 添加c++庫函數(shù)接口 >= 1.0.1
add_languages 添加語言標(biāo)準(zhǔn) >= 2.0.1
add_vectorexts 添加向量擴(kuò)展指令 >= 2.0.1
add_frameworks 添加鏈接框架 >= 2.1.1
add_frameworkdirs 添加鏈接框架 >= 2.1.5
廢棄接口 描述 支持版本
add_bindings 添加正向關(guān)聯(lián)選項(xiàng),同步啟用和禁用 >= 2.0.1 < 2.1.5
add_rbindings 添加逆向關(guān)聯(lián)選項(xiàng),同步啟用和禁用 >= 2.0.1 < 2.1.5
add_defines_if_ok 如果檢測選項(xiàng)通過,則添加宏定義 >= 1.0.1 < 2.1.5
add_defines_h_if_ok 如果檢測選項(xiàng)通過,則添加宏定義到配置頭文件 >= 1.0.1 < 2.1.5
add_undefines_if_ok 如果檢測選項(xiàng)通過,則取消宏定義 >= 1.0.1 < 2.1.5
add_undefines_h_if_ok 如果檢測選項(xiàng)通過,則在配置頭文件中取消宏定義 >= 1.0.1 < 2.1.5

option

定義選項(xiàng)

定義和設(shè)置選項(xiàng)開關(guān),可用于自定義編譯配置選項(xiàng)、開關(guān)設(shè)置。

例如,定義一個(gè)是否啟用test的選項(xiàng):

option("test")
    set_default(false)
    set_showmenu(true)
    add_defines("-DTEST")

然后關(guān)聯(lián)到指定的target中去:

target("demo")
    add_options("test")

這樣,一個(gè)選項(xiàng)就算定義好了,如果這個(gè)選項(xiàng)被啟用,那么編譯這個(gè)target的時(shí)候,就會自動加上-DTEST的宏定義。

## 手動啟用這個(gè)選項(xiàng)
$ xmake f --test=y
$ xmake

option_end

結(jié)束定義選項(xiàng)

這是一個(gè)可選api,顯示離開選項(xiàng)作用域,用法和target_end類似。

option:add_deps

添加選項(xiàng)依賴

通過設(shè)置依賴,可以調(diào)整選項(xiàng)的檢測順序,一般用于on_check等檢測腳本的調(diào)用時(shí)機(jī)。

option("small")
    set_default(true)
    on_check(function (option)
        -- ...
    end)


option("test")
    add_deps("small")
    set_default(true)
    on_check(function (option)
        if option:dep("small"):enabled() then
            option:enable(false)
        end
    end)

當(dāng)依賴的small選項(xiàng)檢測完成后,通過判斷small選項(xiàng)的狀態(tài),來控制test的選項(xiàng)狀態(tài)。

option:before_check

選項(xiàng)檢測之前執(zhí)行此腳本

例如:在檢測之前,通過find_package來查找包,將links, includedirslinkdirs等信息添加到option中去, 然后開始選項(xiàng)檢測,通過后就會自動鏈接到target上。

option("zlib")
    before_check(function (option)
        import("lib.detect.find_package")
        option:add(find_package("zlib"))
    end)

option:on_check

自定義選項(xiàng)檢測腳本

此腳本會覆蓋內(nèi)置的選項(xiàng)檢測邏輯。

option("test")
    add_deps("small")
    set_default(true)
    on_check(function (option)
        if option:dep("small"):enabled() then
            option:enable(false)
        end
    end)

如果test依賴的選項(xiàng)通過,則禁用test選項(xiàng)。

option:after_check

選項(xiàng)檢測之后執(zhí)行此腳本

在選項(xiàng)檢測完成后,執(zhí)行此腳本做一些后期處理,也可以在此時(shí)重新禁用選項(xiàng):

option("test")
    add_deps("small")
    add_links("pthread")
    after_check(function (option)
        option:enable(false)
    end)

option:set_default

設(shè)置選項(xiàng)默認(rèn)值

在沒有通過xmake f --option=[y|n}等命令修改選項(xiàng)值的時(shí)候,這個(gè)選項(xiàng)本身也是有個(gè)默認(rèn)值的,可以通過這個(gè)接口來設(shè)置:

option("test")
    -- 默認(rèn)禁用這個(gè)選項(xiàng)
    set_default(false)

選項(xiàng)的值不僅支持boolean類型,也可以是字符串類型,例如:

option("test")
    set_default("value")
值類型 描述 配置
boolean 一般用作參數(shù)開關(guān),值范圍:true/false xmake f --optionname=[y/n/yes/no/true/false]
string 可以是任意字符串,一般用于模式判斷 xmake f --optionname=value

如果是boolean值的選項(xiàng),可以通過is_option來進(jìn)行判斷,選項(xiàng)是否被啟用。

如果是string類型的選項(xiàng),可以在內(nèi)建變量中直接使用,例如:

-- 定義一個(gè)路徑配置選項(xiàng),默認(rèn)使用臨時(shí)目錄
option("rootdir")
    set_default("$(tmpdir)")
    set_showmenu(true)


target("test")
    -- 添加指定選項(xiàng)目錄中的源文件
    add_files("$(rootdir)/*.c")

其中,$(rootdir) 就是自定義的選項(xiàng)內(nèi)建變量,通過手動配置,可以動態(tài)修改它的值:

$ xmake f --rootdir=~/projectdir/src
$ xmake

給這個(gè)rootdir選項(xiàng)指定一個(gè)其他的源碼目錄路徑,然后編譯。

選項(xiàng)的檢測行為:

default值 檢測行為
沒有設(shè)置 優(yōu)先手動配置修改,默認(rèn)禁用,否則自動檢測,可根據(jù)手動傳入的值類型,自動切換boolean和string類型
false 開關(guān)選項(xiàng),不自動檢測,默認(rèn)禁用,可手動配置修改
true 開關(guān)選項(xiàng),不自動檢測,默認(rèn)啟用,可手動配置修改
string類型 無開關(guān)狀態(tài),不自動檢測,可手動配置修改,一般用于配置變量傳遞

option:set_showmenu

設(shè)置是否啟用菜單顯示

如果設(shè)置為true,那么在xmake f --help里面就會出現(xiàn)這個(gè)選項(xiàng),也就能通過xmake f --optionname=xxx進(jìn)行配置,否則只能在xmake.lua內(nèi)部使用,無法手動配置修改。

option("test")
    set_showmenu(true)

設(shè)置為啟用菜單后,執(zhí)行xmake f --help可以看到,幫助菜單里面多了一項(xiàng):

Options:
    ...


    --test=TEST

option:set_category

設(shè)置選項(xiàng)分類,僅用于菜單顯示

這個(gè)是個(gè)可選配置,僅用于在幫助菜單中,進(jìn)行分類顯示選項(xiàng),同一類別的選項(xiàng),會在同一個(gè)分組里面顯示,這樣菜單看起來更加的美觀。

例如:

option("test1")
    set_showmenu(true)
    set_category("test")


option("test2")
    set_showmenu(true)
    set_category("test")


option("demo1")
    set_showmenu(true)
    set_category("demo")


option("demo2")
    set_showmenu(true)
    set_category("demo")

這里四個(gè)選項(xiàng)分別歸類于兩個(gè)分組:testdemo,那么顯示的布局類似這樣:

Options:
    ...


    --test1=TEST1
    --test2=TEST2

 
    --demo1=DEMO1
    --demo2=DEMO2

這個(gè)接口,僅僅是為了調(diào)整顯示布局,更加美觀而已,沒其他用途。

option:set_description

設(shè)置菜單顯示描述

設(shè)置選項(xiàng)菜單顯示時(shí),右邊的描述信息,用于幫助用戶更加清楚的知道這個(gè)選項(xiàng)的用途,例如:

option("test")
    set_default(false)
    set_showmenu(true)
    set_description("Enable or disable test")

生成的菜單內(nèi)容如下:

Options:
    ...


    --test=TEST                       Enable or disable test (default: false)

這個(gè)接口也支持多行顯示,輸出更加詳細(xì)的描述信息,例如:

option("mode")
    set_default("debug")
    set_showmenu(true)
    set_description("Set build mode"
                    "    - debug"
                    "    - release"
                    "    - profile")

生成的菜單內(nèi)容如下:

Options:
    ...


    --mode=MODE                       Set build mode (default: debug)
                                          - debug
                                          - release
                                          - profile

看到這個(gè)菜單,用戶就能清楚地知道,定義的這個(gè)mode選項(xiàng)的具體用處,以及如何使用了:

$ xmake f --mode=release

option:add_bindings

添加正向關(guān)聯(lián)選項(xiàng),同步啟用和禁用

<p class="tip"> 2.1.5版本之后已廢棄,請用add_deps, on_check, after_check等接口代替。 </p>

綁定關(guān)聯(lián)選項(xiàng),例如我想在命令行中配置一個(gè)smallest的參數(shù):xmake f --smallest=y

這個(gè)時(shí)候,需要同時(shí)禁用多個(gè)其他的選項(xiàng)開關(guān),來禁止編譯多個(gè)模塊,就是這個(gè)需求,相當(dāng)于一個(gè)選項(xiàng) 與其他 多個(gè)選項(xiàng)之間 是有聯(lián)動效應(yīng)的。

而這個(gè)接口就是用來設(shè)置需要正向綁定的一些關(guān)聯(lián)選項(xiàng),例如:

-- 定義選項(xiàng)開關(guān): --smallest=y|n
option("smallest")


    -- 添加正向綁定,如果smallest被啟用,下面的所有選項(xiàng)開關(guān)也會同步被啟用
    add_bindings("nozip", "noxml", "nojson")

option:add_rbindings

添加逆向關(guān)聯(lián)選項(xiàng),同步啟用和禁用

<p class="tip"> 2.1.5版本之后已廢棄,請用add_deps, on_check, after_check等接口代替。 </p>

逆向綁定關(guān)聯(lián)選項(xiàng),被關(guān)聯(lián)選項(xiàng)的開關(guān)狀態(tài)是相反的。

-- 定義選項(xiàng)開關(guān): --smallest=y|n
option("smallest")


    -- 添加反向綁定,如果smallest被啟用,下面的所有模塊全部禁用
    add_rbindings("xml", "zip", "asio", "regex", "object", "thread", "network", "charset", "database")
    add_rbindings("zlib", "mysql", "sqlite3", "openssl", "polarssl", "pcre2", "pcre", "base")

<p class="warning"> 需要注意的是,命令行配置是有順序的,你可以先通過啟用smallest禁用所有模塊,然后添加其他選項(xiàng),逐一啟用。 </p>

例如:

-- 禁用所有模塊,然后僅僅啟用xml和zip模塊
$ xmake f --smallest=y --xml=y --zip=y

option:add_links

添加鏈接庫檢測

如果指定的鏈接庫檢測通過,此選項(xiàng)將被啟用,并且對應(yīng)關(guān)聯(lián)的target會自動加上此鏈接,例如:

option("pthread")
    set_default(false)
    add_links("pthread")
    add_linkdirs("/usr/local/lib")


target("test")
    add_options("pthread")

如果檢測通過,test目標(biāo)編譯的時(shí)候就會自動加上:-L/usr/local/lib -lpthread 編譯選項(xiàng)

option:add_linkdirs

添加鏈接庫檢測時(shí)候需要的搜索目錄

這個(gè)是可選的,一般系統(tǒng)庫不需要加這個(gè),也能檢測通過,如果確實(shí)沒找到,可以自己追加搜索目錄,提高檢測通過率。具體使用見:add_links

option:add_rpathdirs

添加程序運(yùn)行時(shí)動態(tài)庫的加載搜索目錄

在選項(xiàng)通過檢測后,會自動添加到對應(yīng)的target上去,具體使用見:target.add_rpathdirs

option:add_cincludes

添加c頭文件檢測

如果c頭文件檢測通過,此選項(xiàng)將被啟用,例如:

option("pthread")
    set_default(false)
    add_cincludes("pthread.h")
    add_defines("ENABLE_PTHREAD")


target("test")
    add_options("pthread")

此選項(xiàng)檢測是否存在pthread.h的頭文件,如果檢測通過那么test目標(biāo)程序?qū)由?code>ENABLE_PTHREAD的宏定義。

如果想要更加靈活的檢測,可以通過lib.detect.has_cincludesoption.on_check中去實(shí)現(xiàn)。

option:add_cxxincludes

添加c++頭文件檢測

add_cincludes類似,只是檢測的頭文件類型是c++頭文件。

option:add_ctypes

添加c類型檢測

如果c類型檢測通過,此選項(xiàng)將被啟用,例如:

option("wchar")
    set_default(false)
    add_cincludes("wchar_t")
    add_defines("HAVE_WCHAR")


target("test")
    add_options("wchar")

此選項(xiàng)檢測是否存在wchar_t的類型,如果檢測通過那么test目標(biāo)程序?qū)由?code>HAVE_WCHAR的宏定義。

如果想要更加靈活的檢測,可以通過lib.detect.has_ctypesoption.on_check中去實(shí)現(xiàn)。

option:add_cxxtypes

添加c++類型檢測

add_ctypes類似,只是檢測的類型是c++類型。

option:add_csnippet

添加c代碼片段檢測

如果現(xiàn)有的add_ctypes, add_cfuncs等不能滿足當(dāng)前的檢測需求, 可以用這個(gè)接口實(shí)現(xiàn)更加定制化檢測一些編譯器特性檢測,具體見: add_cxxsnippet。

option:add_cxxsnippet

添加c++代碼片段檢測

可以用這個(gè)接口實(shí)現(xiàn)更加定制化檢測一些編譯器特性檢測,尤其是c++的各種特性的檢測支持,例如:

option("constexpr")
    add_cxxsnippet("constexpr int f(int x) { int sum=0; for (int i=0; i<=x; ++i) sum += i; return sum; } constexpr int x = f(5);  static_assert(x == 15);")

上述代碼,實(shí)現(xiàn)對c++的constexpr特性的檢測,如果檢測通過,則啟用constexpr選項(xiàng),當(dāng)然這里只是個(gè)例子。

對于編譯器特性的檢測,有更加方便高效的檢測模塊,提供更強(qiáng)大的檢測支持,具體見:compiler.has_featuresdetect.check_cxsnippets

如果想要更加靈活的檢測,可以通過lib.detect.check_cxsnippetsoption.on_check中去實(shí)現(xiàn)。

option:add_defines_if_ok

如果檢測選項(xiàng)通過,則添加宏定義

<p class="tip"> 2.1.5版本之后已廢棄,請用add_defines接口代替。 </p>

檢測選項(xiàng)通過后才會被設(shè)置,具體使用見add_cincludes中的例子。

option:add_defines_h_if_ok

如果檢測選項(xiàng)通過,則添加宏定義到配置頭文件

<p class="tip"> 2.1.5版本之后已廢棄,請用add_defines_h接口代替。 </p>

add_defines_if_ok類似,只是檢測通過后,會在config.h頭文件中自動加上被設(shè)置的宏定義。

例如:

option("pthread")
    set_default(false)
    add_cincludes("pthread.h")
    add_defines_h_if_ok("ENABLE_PTHREAD")


target("test")
    add_options("pthread")

通過后,會在config.h中加上:

#define ENABLE_PTHREAD 1

具體config.h如何設(shè)置,見:set_config_h

option:add_undefines_if_ok

如果檢測選項(xiàng)通過,則取消宏定義

<p class="tip"> 2.1.5版本之后已廢棄,請用add_undefines接口代替。 </p>

add_defines_if_ok類似,只是檢測通過后,取消被設(shè)置的宏定義。

option:add_undefines_h_if_ok

如果檢測選項(xiàng)通過,則在配置頭文件中取消宏定義

<p class="tip"> 2.1.5版本之后已廢棄,請用add_undefines_h接口代替。 </p>

add_defines_h_if_ok類似,只是檢測通過后,會在config.h中取消被設(shè)置的宏定義。

#undef DEFINED_MACRO

具體config.h如何設(shè)置,見:set_config_h

插件任務(wù)

xmake可以實(shí)現(xiàn)自定義任務(wù)或者插件,其兩者的核心就是task任務(wù),其兩者實(shí)際上是一樣的,xmake的插件都是用task實(shí)現(xiàn)的。

本質(zhì)上都是任務(wù),只是set_category分類不同而已。

接口 描述 支持版本
task 定義插件或者任務(wù) >= 2.0.1
task_end 結(jié)束定義插件或任務(wù) >= 2.1.1
set_menu 設(shè)置任務(wù)菜單 >= 2.0.1
set_category 設(shè)置任務(wù)類別 >= 2.0.1
on_run 設(shè)置任務(wù)運(yùn)行腳本 >= 2.0.1

task

定義插件或者任務(wù)

task域用于描述一個(gè)自定義的任務(wù)實(shí)現(xiàn),與targetoption同級。

例如,這里定義一個(gè)最簡單的任務(wù):

task("hello")


    -- 設(shè)置運(yùn)行腳本
    on_run(function ()
        print("hello xmake!")
    end)

這個(gè)任務(wù)只需要打印hello xmake!,那如何來運(yùn)行呢?

由于這里沒有使用set_menu設(shè)置菜單,因此這個(gè)任務(wù)只能再xmake.lua的自定義腳本或者其他任務(wù)內(nèi)部調(diào)用,例如:

target("test")


    after_build(function (target)

 
        -- 導(dǎo)入task模塊
        import("core.project.task")


        -- 運(yùn)行hello任務(wù)
        task.run("hello")
    end)

在構(gòu)建完test目標(biāo)后運(yùn)行hello任務(wù)。

task_end

結(jié)束定義插件或任務(wù)

這是一個(gè)可選api,顯示離開選項(xiàng)作用域,用法和target_end類似。

task:set_menu

設(shè)置任務(wù)菜單

通過設(shè)置一個(gè)菜單,這個(gè)任務(wù)就可以開放給用戶自己通過命令行手動調(diào)用,菜單的設(shè)置如下:

task("echo")


    -- 設(shè)置運(yùn)行腳本
    on_run(function ()


        -- 導(dǎo)入?yún)?shù)選項(xiàng)模塊
        import("core.base.option")


        -- 初始化顏色模式
        local modes = ""
        for _, mode in ipairs({"bright", "dim", "blink", "reverse"}) do
            if option.get(mode) then
                modes = modes .. " " .. mode 
            end
        end


        -- 獲取參數(shù)內(nèi)容并且顯示信息
        cprint("${%s%s}%s", option.get("color"), modes, table.concat(option.get("contents") or {}, " "))
    end)


    -- 設(shè)置插件的命令行選項(xiàng),這里沒有任何參數(shù)選項(xiàng),僅僅顯示插件描述
    set_menu {
                -- 設(shè)置菜單用法
                usage = "xmake echo [options]"


                -- 設(shè)置菜單描述
            ,   description = "Echo the given info!"


                -- 設(shè)置菜單選項(xiàng),如果沒有選項(xiàng),可以設(shè)置為{}
            ,   options = 
                {
                    -- 設(shè)置k模式作為key-only型bool參數(shù)
                    {'b', "bright",     "k",  nil,       "Enable bright."               }      
                ,   {'d', "dim",        "k",  nil,       "Enable dim."                  }      
                ,   {'-', "blink",      "k",  nil,       "Enable blink."                }      
                ,   {'r', "reverse",    "k",  nil,       "Reverse color."               }      


                    -- 菜單顯示時(shí),空白一行
                ,   {}


                    -- 設(shè)置kv作為key-value型參數(shù),并且設(shè)置默認(rèn)值:black
                ,   {'c', "color",      "kv", "black",   "Set the output color."
                                                     ,   "    - red"   
                                                     ,   "    - blue"
                                                     ,   "    - yellow"
                                                     ,   "    - green"
                                                     ,   "    - magenta"
                                                     ,   "    - cyan" 
                                                     ,   "    - white"                  }


                    -- 設(shè)置`vs`作為values多值型參數(shù),還有`v`單值類型
                    -- 一般放置在最后,用于獲取可變參數(shù)列表
                ,   {}
                ,   {nil, "contents",   "vs", nil,       "The info contents."           }
                }
            } 

定義完這個(gè)任務(wù)后,執(zhí)行xmake --help,就會多出一個(gè)任務(wù)項(xiàng)來:

Tasks:


    ...


    echo                    Echo the given info!

如果通過set_category設(shè)置分類為plugin,那么這個(gè)任務(wù)就是一個(gè)插件了:

Plugins:


    ...


    echo                    Echo the given info!

想要手動運(yùn)行這個(gè)任務(wù),可以執(zhí)行:

$ xmake echo hello xmake!

就行了,如果要看這個(gè)任務(wù)定義的菜單,只需要執(zhí)行:xmake echo [-h|--help],顯示結(jié)果如下:

Usage: $xmake echo [options]


Echo the given info!


Options: 
    -v, --verbose                          Print lots of verbose information.
        --backtrace                        Print backtrace information for debugging.
        --profile                          Print performance data for debugging.
        --version                          Print the version number and exit.
    -h, --help                             Print this help message and exit.

                                           
    -F FILE, --file=FILE                   Read a given xmake.lua file.
    -P PROJECT, --project=PROJECT          Change to the given project directory.
                                           Search priority:
                                               1. The Given Command Argument
                                               2. The Envirnoment Variable: XMAKE_PROJECT_DIR
                                               3. The Current Directory

                                           
    -b, --bright                           Enable bright.
    -d, --dim                              Enable dim.
    --, --blink                            Enable blink.
    -r, --reverse                          Reverse color.

                                           
    -c COLOR, --color=COLOR                Set the output color. (default: black)
                                               - red
                                               - blue
                                               - yellow
                                               - green
                                               - magenta
                                               - cyan
                                               - white

                                           
    contents ...                           The info contents.

<p class="tip"> 其中菜單最開頭的部分選項(xiàng),是xmake內(nèi)置的常用選項(xiàng),基本上每個(gè)任務(wù)都會用到,不需要自己額外定義,簡化菜單定義。 </p>

下面,我們來實(shí)際運(yùn)行下這個(gè)任務(wù),例如我要顯示紅色的hello xmake!,只需要:

$ xmake echo -c red hello xmake!

也可以使用選項(xiàng)全名,并且加上高亮:

$ xmake echo --color=red --bright hello xmake!

最后面的可變參數(shù)列表,在run腳本中通過option.get("contents")獲取,返回的是一個(gè)table類型的數(shù)組。

task:set_category

設(shè)置任務(wù)類別

僅僅用于菜單的分組顯示,當(dāng)然插件默認(rèn)會用plugin,內(nèi)置任務(wù)默認(rèn)會用:action,但也僅僅只是個(gè)約定。

<p class="tips"> 你可以使用任何自己定義的名字,相同名字會分組歸類到一起顯示,如果設(shè)置為plugin,就會顯示到xmake的Plugins分組中去。 </p>

例如:

Plugins: 
    l, lua               Run the lua script.
    m, macro             Run the given macro.
       doxygen           Generate the doxygen document.
       project           Generate the project file.
       hello             Hello xmake!
       app2ipa           Generate .ipa file from the given .app
       echo              Echo the given info!

如果沒有調(diào)用這個(gè)接口設(shè)置分類,默認(rèn)使用Tasks分組顯示,代表普通任務(wù)。

task:on_run

設(shè)置任務(wù)運(yùn)行腳本

可以有兩種設(shè)置方式,最簡單的就是設(shè)置內(nèi)嵌函數(shù):

task("hello")


    on_run(function ()
        print("hello xmake!")
    end)

這種對于小任務(wù)很方便,也很簡潔,但是對于大型任務(wù)就不太適用了,例如插件等,需要復(fù)雜的腳本支持。

這個(gè)時(shí)候就需要獨(dú)立的模塊文件來設(shè)置運(yùn)行腳本,例如:

task("hello")
    on_run("main")

這里的main設(shè)置為腳本運(yùn)行主入口模塊,文件名為main.lua,放在定義taskxmake.lua的同目錄下,當(dāng)然你可以起其他文件名。

目錄結(jié)構(gòu)如下:

projectdir
    - xmake.lua
    - main.lua

main.lua里面內(nèi)容如下:

function main(...)
    print("hello xmake!")
end

就是一個(gè)簡單的帶main主函數(shù)的腳本文件,你可以通過import導(dǎo)入各種擴(kuò)展模塊,實(shí)現(xiàn)復(fù)雜功能,例如:

-- 導(dǎo)入?yún)?shù)選項(xiàng)模塊
import("core.base.option")


-- 入口函數(shù)
function main(...)


    -- 獲取參數(shù)內(nèi)容
    print("color: %s", option.get("color"))
end

你也可以在當(dāng)前目錄下,創(chuàng)建多個(gè)自定義的模塊文件,通過import導(dǎo)入后使用,例如:

projectdir
    - xmake.lua
    - main.lua
    - module.lua

module.lua的內(nèi)容如下:

-- 定義一個(gè)導(dǎo)出接口
function hello()
    print("hello xmake!")
end

<p class="tip"> 私有接口,通過_hello帶下滑線前綴命名,這樣導(dǎo)入的模塊就不會包含此接口,只在模塊自身內(nèi)部使用。 </p>

然后在main.lua進(jìn)行調(diào)用:

import("module")


function main(...)
    module.hello()
end

更多模塊介紹見:內(nèi)置模塊擴(kuò)展模塊

其中,main(...)中參數(shù),是通過task.run指定的,例如:

task.run("hello", {color="red"}, arg1, arg2, arg3)

里面的arg1, arg2這些就是傳入hello任務(wù)main(...)入口的參數(shù)列表,而{color="red"}用來指定任務(wù)菜單中的參數(shù)選項(xiàng)。

更加詳細(xì)的task.run描述,見:task.run

平臺擴(kuò)展

xmake除了內(nèi)置的一些構(gòu)建平臺,還可以自己擴(kuò)展自定義構(gòu)建平臺,可以將自己實(shí)現(xiàn)的平臺放置在以下目錄即可, xmake會自動檢測并且加載他們:

平臺目錄 描述
projectdir/.xmake/platforms 當(dāng)前工程的平臺目錄, 只對當(dāng)前工程有效
globaldir/.xmake/platforms 全局配置的平臺目錄,當(dāng)前主機(jī)全局有效
installdir/xmake/platforms xmake安裝后內(nèi)置的平臺目錄

用戶可根據(jù)不同需求,將自定義的平臺放置在對應(yīng)的目錄中。

<p class="warning"> 平臺的擴(kuò)展定義,盡量不要放到工程xmake.lua中去,新建一個(gè)單獨(dú)的平臺目錄放置相關(guān)描述實(shí)現(xiàn)。 </p>

平臺描述的目錄結(jié)構(gòu):

platforms


    - myplat1
        - xmake.lua


    - myplat2
        - xmake.lua

其中xmake.lua為每個(gè)平臺的主描述文件,相當(dāng)于入口描述。

接口 描述 支持版本
platform 定義平臺 >= 2.0.1
platform_end 結(jié)束定義平臺 >= 2.1.1
set_os 設(shè)置平臺系統(tǒng) >= 2.0.1
set_menu 設(shè)置平臺菜單 >= 2.0.1
set_hosts 設(shè)置平臺支持的主機(jī)環(huán)境 >= 2.0.1
set_archs 設(shè)置平臺支持的架構(gòu)環(huán)境 >= 2.0.1
set_tooldirs 設(shè)置平臺工具的搜索目錄 >= 2.0.1
on_load 設(shè)置加載平臺環(huán)境配置腳本 >= 2.0.1
on_check 設(shè)置平臺工具的檢測腳本 >= 2.0.1
on_install 設(shè)置平臺相關(guān)的工程目標(biāo)安裝腳本 >= 2.0.5
on_uninstall 設(shè)置平臺相關(guān)的工程目標(biāo)卸載腳本 >= 2.0.5

platform

定義平臺

自定義一個(gè)平臺域,例如:

platform("iphoneos")

    
    -- 設(shè)置操作系統(tǒng)
    set_os("ios")


    -- 設(shè)置主機(jī)環(huán)境
    set_hosts("macosx")


    -- 設(shè)置支持的架構(gòu)
    set_archs("armv7", "armv7s", "arm64", "i386", "x86_64")


    -- 設(shè)置gcc, clang等平臺相關(guān)工具的搜索目錄
    set_tooldirs("/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin")


    -- 設(shè)置gcc,clang等工具的檢測腳本文件
    on_check("check")


    -- 設(shè)置平臺初始化加載腳本文件,如果實(shí)現(xiàn)不復(fù)雜的話,可以使用內(nèi)嵌函數(shù)
    on_load("load")


    -- 設(shè)置平臺的幫助菜單
    set_menu {
                config = 
                {   
                    {}   
                ,   {nil, "xcode_dir",      "kv", "auto",       "the xcode application directory"   }
                ,   {nil, "xcode_sdkver",   "kv", "auto",       "the sdk version for xcode"         }
                ,   {nil, "target_minver",  "kv", "auto",       "the target minimal version"        }
                ,   {}
                ,   {nil, "mobileprovision","kv", "auto",       "The Provisioning Profile File"     }
                ,   {nil, "codesign",       "kv", "auto",       "The Code Signing Indentity"        }
                ,   {nil, "entitlements",   "kv", "auto",       "The Code Signing Entitlements"     }
                }


            ,   global = 
                {   
                    {}
                ,   {nil, "xcode_dir",      "kv", "auto",       "the xcode application directory"   }
                ,   {}
                ,   {nil, "mobileprovision","kv", "auto",       "The Provisioning Profile File"     }
                ,   {nil, "codesign",       "kv", "auto",       "The Code Signing Indentity"        }
                ,   {nil, "entitlements",   "kv", "auto",       "The Code Signing Entitlements"     }
                }
            }

<p class="warning"> 是在platforms目錄相關(guān)平臺的xmake.lua中編寫,而不是在工程目錄的xmake.lua中。 </p>

platform_end

結(jié)束定義平臺

這是一個(gè)可選api,顯示離開選項(xiàng)作用域,用法和target_end類似。

set_os

設(shè)置平臺系統(tǒng)

設(shè)置目標(biāo)平臺的操作系統(tǒng),例如:ios, android, linux, windows

platform("iphoneos")
    set_os("ios")

這個(gè)一般用于在自定義腳本和插件開發(fā)中,core.platform.platform模塊中進(jìn)行訪問,獲取當(dāng)前平臺的操作系統(tǒng)。

set_menu

設(shè)置平臺菜單

先給個(gè)設(shè)置的例子:

platform("iphoneos")
    ...


    -- 設(shè)置平臺的幫助菜單
    set_menu {
                config = 
                {   
                    {}   
                ,   {nil, "xcode_dir",      "kv", "auto",       "the xcode application directory"   }
                ,   {nil, "xcode_sdkver",   "kv", "auto",       "the sdk version for xcode"         }
                ,   {nil, "target_minver",  "kv", "auto",       "the target minimal version"        }
                ,   {}
                ,   {nil, "mobileprovision","kv", "auto",       "The Provisioning Profile File"     }
                ,   {nil, "codesign",       "kv", "auto",       "The Code Signing Indentity"        }
                ,   {nil, "entitlements",   "kv", "auto",       "The Code Signing Entitlements"     }
                }


            ,   global = 
                {   
                    {}
                ,   {nil, "xcode_dir",      "kv", "auto",       "the xcode application directory"   }
                ,   {}
                ,   {nil, "mobileprovision","kv", "auto",       "The Provisioning Profile File"     }
                ,   {nil, "codesign",       "kv", "auto",       "The Code Signing Indentity"        }
                ,   {nil, "entitlements",   "kv", "auto",       "The Code Signing Entitlements"     }
                }
            }

其中config組用來設(shè)置:xmake f --help中的本地工程菜單,global用來設(shè)置:xmake g --help全局平臺配置中的菜單。

具體設(shè)置格式可參考:task:set_menu

set_hosts

設(shè)置平臺支持的主機(jī)環(huán)境

用來設(shè)置當(dāng)前目標(biāo)平臺支持主機(jī)構(gòu)建環(huán)境,例如iphoneos平臺可以在macosx主機(jī)系統(tǒng)上構(gòu)建,那么可以設(shè)置為:

platform("iphoneos")
    set_hosts("macosx")

android平臺可以同時(shí)在linux, "macosx", windows主機(jī)環(huán)境中構(gòu)建,那么可以設(shè)置為:

platform("android")
    set_hosts("linux", "macosx", "windows")

set_archs

設(shè)置平臺支持的架構(gòu)環(huán)境

用來設(shè)置當(dāng)前目標(biāo)平臺支持的編譯架構(gòu)環(huán)境,例如iphoneos平臺可以構(gòu)建armv7, armv7s, arm64, i386, x86_64等架構(gòu),那么可以設(shè)置為:

platform("iphoneos")
    set_archs("armv7", "armv7s", "arm64", "i386", "x86_64")

配置好架構(gòu)后,執(zhí)行:xmake f -h,就會在對應(yīng)arch參數(shù)描述,自動顯示設(shè)置的架構(gòu)列表:

    -a ARCH, --arch=ARCH                   Compile for the given architecture. (default: auto)
                                               - android: armv5te armv6 armv7-a armv8-a arm64-v8a
                                               - iphoneos: armv7 armv7s arm64 i386 x86_64
                                               - linux: i386 x86_64
                                               - macosx: i386 x86_64
                                               - mingw: i386 x86_64
                                               - watchos: armv7k i386
                                               - windows: x86 x64 amd64 x86_amd64

set_tooldirs

設(shè)置平臺工具的搜索目錄

xmake會自動檢測當(dāng)前平臺支持的一些構(gòu)建工具是否存在,例如編譯器、鏈接器等,如果要提高檢測通過率,可以在平臺配置的時(shí)候,設(shè)置一些工具環(huán)境搜索目錄,例如:

platform("linux")


    -- 在linux下檢測這些目錄環(huán)境
    set_tooldirs("/usr/bin", "/usr/local/bin", "/opt/bin", "/opt/local/bin")

on_load

設(shè)置加載平臺環(huán)境配置腳本

一般用于在平臺剛加載時(shí),設(shè)置一些基本配置:生成目標(biāo)文件命名格式、平臺相關(guān)編譯選項(xiàng)等

platform("windows")


    -- on load
    on_load(function ()


        -- init the file formats
        _g.formats          = {}
        _g.formats.static   = {"", ".lib"}
        _g.formats.object   = {"", ".obj"}
        _g.formats.shared   = {"", ".dll"}
        _g.formats.binary   = {"", ".exe"}
        _g.formats.symbol   = {"", ".pdb"}


        -- init flags for dlang
        local dc_archs = { x86 = "-m32", x64 = "-m64", amd64 = "-m64", x86_amd64 = "-m64" }
        _g.dcflags       = { dc_archs[arch] or "" }
        _g["dc-shflags"] = { dc_archs[arch] or "" }
        _g["dc-ldflags"] = { dc_archs[arch] or "" }


        -- ok
        return _g
    end)

如果加載邏輯比較復(fù)雜,可以獨(dú)立成單獨(dú)init.lua文件,然后設(shè)置為:

platform("xxxx")
    on_load("init")

通過這種方式,會自動加載平臺腳本目錄下對應(yīng)的init.lua文件,調(diào)用function main() end函數(shù)入口,完成復(fù)雜加載邏輯。

on_check

設(shè)置平臺工具的檢測腳本

由于每個(gè)平臺檢測的工具非常多,腳本比較復(fù)雜,一般直接獨(dú)立成check.lua文件來實(shí)現(xiàn)檢測邏輯,例如:

platform("xxx")
    on_check("check")

具體的檢測代碼入口如下:

-- check it
function main(kind)


    -- init the check list of config
    _g.config = 
    {
        __check_arch
    ,   checker.check_ccache
    ,   _check_toolchains
    }


    -- init the check list of global
    _g.global = 
    {
        checker.check_ccache
    ,   _check_ndk_sdkver
    }


    -- check it
    checker.check(kind, _g)
end

具體實(shí)現(xiàn)這里就不介紹了,可以參考xmake源碼目錄下的platforms平臺配置代碼: check.lua

on_install

設(shè)置目標(biāo)工程在指定平臺的安裝腳本

具體實(shí)現(xiàn)邏輯見xmake源碼:install.lua

on_uninstall

設(shè)置目標(biāo)工程在指定平臺的卸載腳本

具體實(shí)現(xiàn)邏輯見xmake源碼:uninstall.lua

語言擴(kuò)展

有待后續(xù)完善。。

工程模板

template
set_description
set_projectdir
add_macros
add_macrofiles

內(nèi)置變量

xmake提供了 $(varname) 的語法,來支持內(nèi)置變量的獲取,例如:

add_cxflags("-I$(buildir)")

它將會在在實(shí)際編譯的時(shí)候,將內(nèi)置的 buildir 變量轉(zhuǎn)換為實(shí)際的構(gòu)建輸出目錄:-I./build

一般內(nèi)置變量可用于在傳參時(shí)快速獲取和拼接變量字符串,例如:

target("test")


    -- 添加工程源碼目錄下的源文件
    add_files("$(projectdir)/src/*.c")


    -- 添加構(gòu)建目錄下的頭文件搜索路徑
    add_includedirs("$(buildir)/inc")

也可以在自定義腳本的模塊接口中使用,例如:

target("test")
    on_run(function (target)
        -- 復(fù)制當(dāng)前腳本目錄下的頭文件到輸出目錄
        os.cp("$(scriptdir)/xxx.h", "$(buildir)/inc")
    end)

所有的內(nèi)置變量,也可以通過val接口,來獲取他們的值。

這種使用內(nèi)置變量的方式,使得描述編寫更加的簡潔易讀,下面是一些xmake內(nèi)置的變量,可以直接獲?。?/p>

接口 描述 支持版本
$(os) 獲取當(dāng)前編譯平臺的操作系統(tǒng) >= 2.0.1
$(host) 獲取本機(jī)操作系統(tǒng) >= 2.0.1
$(tmpdir) 獲取臨時(shí)目錄 >= 2.0.1
$(curdir) 獲取當(dāng)前目錄 >= 2.0.1
$(buildir) 獲取構(gòu)建輸出目錄 >= 2.0.1
$(scriptdir) 獲取工程描述腳本目錄 >= 2.1.1
$(globaldir) 獲取全局配置目錄 >= 2.0.1
$(configdir) 獲取本地工程配置目錄 >= 2.0.1
$(programdir) xmake安裝腳本目錄 >= 2.1.5
$(projectdir) 獲取工程根目錄 >= 2.0.1
$(shell) 執(zhí)行外部shell命令 >= 2.0.1
$(env) 獲取外部環(huán)境變量 >= 2.1.5
$(reg) 獲取windows注冊表配置項(xiàng)的值 >= 2.1.5

當(dāng)然這種變量模式,也是可以擴(kuò)展的,默認(rèn)通過xmake f --var=val命令,配置的參數(shù)都是可以直接獲取,例如:

target("test")
    add_defines("-DTEST=$(var)")

<p class="tip"> 所有xmake f --xxx=...配置的參數(shù)值,都是可以通過內(nèi)置變量獲取到,例如:xmake f --arch=x86對應(yīng)$(arch),其他的還有$(plat), $(mode)等等。 具體有哪些參數(shù),可以通過:xmake f -h才查看。 </p>

既然支持直接從配置選項(xiàng)中獲取,那么當(dāng)然也就能很方便的擴(kuò)展自定義的選項(xiàng),來獲取自定義的變量了,具體如何自定義選項(xiàng)見:option

var.$(os)

獲取當(dāng)前編譯平臺的操作系統(tǒng)

如果當(dāng)前編譯的是iphoneos,那么這個(gè)值就是:ios,以此類推。

var.$(host)

獲取本機(jī)操作系統(tǒng)

指的是當(dāng)前本機(jī)環(huán)境的主機(jī)系統(tǒng),如果你是在macOS上編譯,那么系統(tǒng)就是:macosx

var.$(tmpdir)

獲取臨時(shí)目錄

一般用于臨時(shí)存放一些非永久性文件。

var.$(curdir)

獲取當(dāng)前目錄

一般默認(rèn)是執(zhí)行xmake命令時(shí)的工程根目錄,當(dāng)然如果通過os.cd改變了目錄的話,這個(gè)值也會一起改變。

var.$(buildir)

獲取當(dāng)前的構(gòu)建輸出目錄

默認(rèn)一般為當(dāng)前工程根目錄下的:./build目錄,也可以通過執(zhí)行:xmake f -o /tmp/build命令來修改默認(rèn)的輸出目錄。

var.$(scriptdir)

獲取當(dāng)前工程描述腳本的目錄

也就是對應(yīng)xmake.lua所在的目錄路徑。

var.$(globaldir)

全局配置目錄

xmake的xmake g|global全局配置命令,數(shù)據(jù)存儲的目錄路徑,在里面可以放置一些自己的插件、平臺腳本。

默認(rèn)為:~/.config

var.$(configdir)

當(dāng)前工程配置目錄

當(dāng)前工程的配置存儲目錄,也就是xmake f|config配置命令的存儲目錄,默認(rèn)為:projectdir/.config

var.$(programdir)

xmake安裝腳本目錄

也就是XMAKE_PROGRAM_DIR環(huán)境變量所在目錄,我們也可以通過設(shè)置這個(gè)環(huán)境量,來修改xmake的加載腳本,實(shí)現(xiàn)版本切換。

var.$(projectdir)

工程根目錄

也就是xmake -P xxx命令中指定的目錄路徑,默認(rèn)不指定就是xmake命令執(zhí)行時(shí)的當(dāng)前目錄,一般用于定位工程文件。

var.$(shell)

執(zhí)行外部shell命令

除了內(nèi)置的變量處理,xmake還支持原生shell的運(yùn)行,來處理一些xmake內(nèi)置不支持的功能

例如,現(xiàn)在有個(gè)需求,我想用在編譯linux程序時(shí),調(diào)用pkg-config獲取到實(shí)際的第三方鏈接庫名,可以這么做:

target("test")
    set_kind("binary")
    if is_plat("linux") then
        add_ldflags("$(shell pkg-config --libs sqlite3)")
    end

當(dāng)然,xmake有自己的自動化第三庫檢測機(jī)制,一般情況下不需要這么麻煩,而且lua自身的腳本化已經(jīng)很不錯(cuò)了。。

但是這個(gè)例子可以說明,xmake是完全可以通過原生shell,來與一些第三方的工具進(jìn)行配合使用。。

var.$(env)

獲取外部環(huán)境變量

例如,可以通過獲取環(huán)境變量中的路徑:

target("test")
    add_includedirs("$(env PROGRAMFILES)/OpenSSL/inc")

var.$(reg)

獲取windows注冊表配置項(xiàng)的值

通過 regpath; name 的方式獲取注冊表中某個(gè)項(xiàng)的值:

print("$(reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\XXXX;Name)")

內(nèi)置模塊

在自定義腳本、插件腳本、任務(wù)腳本、平臺擴(kuò)展、模板擴(kuò)展等腳本代碼中使用,也就是在類似下面的代碼塊中,可以使用這些模塊接口:

on_run(function (target)
    print("hello xmake!")
end)

<p class="warning"> 為了保證外層的描述域盡可能簡潔、安全,一般不建議在這個(gè)域使用接口和模塊操作api,因此大部分模塊接口只能再腳本域使用,來實(shí)現(xiàn)復(fù)雜功能。</br> 當(dāng)然少部分只讀的內(nèi)置接口還是可以在描述域使用的,具體見下表: </p>

接口 描述 可使用域 支持版本
val 獲取內(nèi)置變量的值 腳本域 >= 2.1.5
import 導(dǎo)入擴(kuò)展摸塊 腳本域 >= 2.0.1
inherit 導(dǎo)入并繼承基類模塊 腳本域 >= 2.0.1
ifelse 類似三元條件判斷 描述域、腳本域 >= 2.0.1
try-catch-finally 異常捕獲 腳本域 >= 2.0.1
pairs 用于遍歷字典 描述域、腳本域 >= 2.0.1
ipairs 用于遍歷數(shù)組 描述域、腳本域 >= 2.0.1
print 換行打印終端日志 描述域、腳本域 >= 2.0.1
printf 無換行打印終端日志 腳本域 >= 2.0.1
cprint 換行彩色打印終端日志 腳本域 >= 2.0.1
cprintf 無換行彩色打印終端日志 腳本域 >= 2.0.1
format 格式化字符串 描述域、腳本域 >= 2.0.1
vformat 格式化字符串,支持內(nèi)置變量轉(zhuǎn)義 腳本域 >= 2.0.1
raise 拋出異常中斷程序 腳本域 >= 2.0.1
os 系統(tǒng)操作模塊 部分只讀操作描述域、腳本域 >= 2.0.1
io 文件操作模塊 腳本域 >= 2.0.1
path 路徑操作模塊 描述域、腳本域 >= 2.0.1
table 數(shù)組和字典操作模塊 描述域、腳本域 >= 2.0.1
string 字符串操作模塊 描述域、腳本域 >= 2.0.1
process 進(jìn)程操作模塊 腳本域 >= 2.0.1
coroutine 協(xié)程操作模塊 腳本域 >= 2.0.1

在描述域使用接口調(diào)用的實(shí)例如下,一般僅用于條件控制:

-- 掃描當(dāng)前xmake.lua目錄下的所有子目錄,以每個(gè)目錄的名字定義一個(gè)task任務(wù)
for _, taskname in ipairs(os.dirs("*"), path.basename) do
    task(taskname)
        on_run(function ()
        end)
end

上面所說的腳本域、描述域主要是指:

-- 描述域
target("test")

    
    -- 描述域
    set_kind("static")
    add_files("src/*.c")


    on_run(function (target)
        -- 腳本域
    end)


-- 描述域

val

獲取內(nèi)置變量的值

內(nèi)置變量可以通過此接口直接獲取,而不需要再加$()的包裹,使用更加簡單,例如:

print(val("host"))
print(val("env PATH"))
local s = val("shell echo hello")

而用vformat就比較繁瑣了:

local s = vformat("$(shell echo hello)")

不過vformat支持字符串參數(shù)格式化,更加強(qiáng)大, 所以應(yīng)用場景不同。

import

導(dǎo)入擴(kuò)展摸塊

import的主要用于導(dǎo)入xmake的擴(kuò)展類庫以及一些自定義的類庫模塊,一般用于:

  • 自定義腳本(on_build, on_run ..)
  • 插件開發(fā)
  • 模板開發(fā)
  • 平臺擴(kuò)展
  • 自定義任務(wù)task

導(dǎo)入機(jī)制如下:

  1. 優(yōu)先從當(dāng)前腳本目錄下導(dǎo)入
  2. 再從擴(kuò)展類庫中導(dǎo)入

導(dǎo)入的語法規(guī)則:

基于.的類庫路徑規(guī)則,例如:

導(dǎo)入core核心擴(kuò)展模塊

import("core.base.option")
import("core.project")
import("core.base.task") -- 2.1.5 以前是 core.project.task
import("core")


function main()

    
    -- 獲取參數(shù)選項(xiàng)
    print(option.get("version"))


    -- 運(yùn)行任務(wù)和插件
    task.run("hello")
    project.task.run("hello")
    core.base.task.run("hello")
end

導(dǎo)入當(dāng)前目錄下的自定義模塊:

目錄結(jié)構(gòu):

plugin
  - xmake.lua
  - main.lua
  - modules
    - hello1.lua
    - hello2.lua

在main.lua中導(dǎo)入modules

import("modules.hello1")
import("modules.hello2")

導(dǎo)入后就可以直接使用里面的所有公有接口,私有接口用_前綴標(biāo)示,表明不會被導(dǎo)出,不會被外部調(diào)用到。。

除了當(dāng)前目錄,我們還可以導(dǎo)入其他指定目錄里面的類庫,例如:

import("hello3", {rootdir = "/home/xxx/modules"})

為了防止命名沖突,導(dǎo)入后還可以指定的別名:

import("core.platform.platform", {alias = "p"})


function main()

 
    -- 這樣我們就可以使用p來調(diào)用platform模塊的plats接口,獲取所有xmake支持的平臺列表了
    table.dump(p.plats())
end

import不僅可以導(dǎo)入類庫,還支持導(dǎo)入的同時(shí)作為繼承導(dǎo)入,實(shí)現(xiàn)模塊間的繼承關(guān)系

import("xxx.xxx", {inherit = true})

這樣導(dǎo)入的不是這個(gè)模塊的引用,而是導(dǎo)入的這個(gè)模塊的所有公有接口本身,這樣就會跟當(dāng)前模塊的接口進(jìn)行合并,實(shí)現(xiàn)模塊間的繼承。

2.1.5版本新增兩個(gè)新屬性:import("xxx.xxx", {try = true, anonymous = true})

try為true,則導(dǎo)入的模塊不存在的話,僅僅返回nil,并不會拋異常后中斷xmake. anonymous為true,則導(dǎo)入的模塊不會引入當(dāng)前作用域,僅僅在import接口返回導(dǎo)入的對象引用。

inherit

導(dǎo)入并繼承基類模塊

這個(gè)等價(jià)于import接口的inherit模式,也就是:

import("xxx.xxx", {inherit = true})

inherit接口的話,會更簡潔些:

inherit("xxx.xxx")

使用實(shí)例,可以參看xmake的tools目錄下的腳本:clang.lua

這個(gè)就是clang工具模塊繼承了gcc的部分實(shí)現(xiàn)。

ifelse

類似三元條件判斷

由于lua沒有內(nèi)置的三元運(yùn)算符,通過封裝ifelse接口,實(shí)現(xiàn)更加簡潔的條件選擇:

local ok = ifelse(a == 0, "ok", "no")

try-catch-finally

異常捕獲

lua原生并沒有提供try-catch的語法來捕獲異常處理,但是提供了pcall/xpcall等接口,可在保護(hù)模式下執(zhí)行l(wèi)ua函數(shù)。

因此,可以通過封裝這兩個(gè)接口,來實(shí)現(xiàn)try-catch塊的捕獲機(jī)制。

我們可以先來看下,封裝后的try-catch使用方式:

try
{
    -- try 代碼塊
    function ()
        error("error message")
    end,


    -- catch 代碼塊
    catch 
    {
        -- 發(fā)生異常后,被執(zhí)行
        function (errors)
            print(errors)
        end
    }
}

上面的代碼中,在try塊內(nèi)部認(rèn)為引發(fā)了一個(gè)異常,并且拋出錯(cuò)誤消息,在catch中進(jìn)行了捕獲,并且將錯(cuò)誤消息進(jìn)行輸出顯示。

而finally的處理,這個(gè)的作用是對于try{}代碼塊,不管是否執(zhí)行成功,都會執(zhí)行到finally塊中

也就說,其實(shí)上面的實(shí)現(xiàn),完整的支持語法是:try-catch-finally模式,其中catch和finally都是可選的,根據(jù)自己的實(shí)際需求提供

例如:

try
{
    -- try 代碼塊
    function ()
        error("error message")
    end,


    -- catch 代碼塊
    catch 
    {
        -- 發(fā)生異常后,被執(zhí)行
        function (errors)
            print(errors)
        end
    },


    -- finally 代碼塊
    finally 
    {
        -- 最后都會執(zhí)行到這里
        function (ok, errors)
            -- 如果try{}中存在異常,ok為true,errors為錯(cuò)誤信息,否則為false,errors為try中的返回值
        end
    }
}

或者只有finally塊:

try
{
    -- try 代碼塊
    function ()
        return "info"
    end,


    -- finally 代碼塊
    finally 
    {
        -- 由于此try代碼沒發(fā)生異常,因此ok為true,errors為返回值: "info"
        function (ok, errors)
        end
    }
}

處理可以在finally中獲取try里面的正常返回值,其實(shí)在僅有try的情況下,也是可以獲取返回值的:

-- 如果沒發(fā)生異常,result 為返回值:"xxxx",否則為nil
local result = try
{
    function ()
        return "xxxx"
    end
}

在xmake的自定義腳本、插件開發(fā)中,也是完全基于此異常捕獲機(jī)制

這樣使得擴(kuò)展腳本的開發(fā)非常的精簡可讀,省去了繁瑣的if err ~= nil then返回值判斷,在發(fā)生錯(cuò)誤時(shí),xmake會直接拋出異常進(jìn)行中斷,然后高亮提示詳細(xì)的錯(cuò)誤信息。

例如:

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


    -- 在編譯完ios程序后,對目標(biāo)程序進(jìn)行l(wèi)did簽名
    after_build(function (target))
        os.run("ldid -S %s", target:targetfile())
    end

只需要一行os.run就行了,也不需要返回值判斷是否運(yùn)行成功,因?yàn)檫\(yùn)行失敗后,xmake會自動拋異常,中斷程序并且提示錯(cuò)誤

如果你想在運(yùn)行失敗后,不直接中斷xmake,繼續(xù)往下運(yùn)行,可以自己加個(gè)try快就行了:

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


    after_build(function (target))
        try
        {
            function ()
                os.run("ldid -S %s", target:targetfile())
            end
        }
    end

如果還想捕獲出錯(cuò)信息,可以再加個(gè)catch:

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


    after_build(function (target))
        try
        {
            function ()
                os.run("ldid -S %s", target:targetfile())
            end,
            catch 
            {
                function (errors)
                    print(errors)
                end
            }
        }
    end

不過一般情況下,在xmake中寫自定義腳本,是不需要手動加try-catch的,直接調(diào)用各種api,出錯(cuò)后讓xmake默認(rèn)的處理程序接管,直接中斷就行了。。

pairs

用于遍歷字典

這個(gè)是lua原生的內(nèi)置api,在xmake中,在原有的行為上對其進(jìn)行了一些擴(kuò)展,來簡化一些日常的lua遍歷代碼。

先看下默認(rèn)的原生寫法:

local t = {a = "a", b = "b", c = "c", d = "d", e = "e", f = "f"}


for key, val in pairs(t) do
    print("%s: %s", key, val)
end

這對于通常的遍歷操作就足夠了,但是如果我們相對其中每個(gè)遍歷出來的元素,獲取其大寫,我們可以這么寫:

for key, val in pairs(t, function (v) return v:upper() end) do
     print("%s: %s", key, val)
end

甚至傳入一些參數(shù)到第二個(gè)function中,例如:

for key, val in pairs(t, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
     print("%s: %s", key, val)
end

ipairs

用于遍歷數(shù)組

這個(gè)是lua原生的內(nèi)置api,在xmake中,在原有的行為上對其進(jìn)行了一些擴(kuò)展,來簡化一些日常的lua遍歷代碼。

先看下默認(rèn)的原生寫法:

for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}) do
     print("%d %s", idx, val)
end

擴(kuò)展寫法類似pairs接口,例如:

for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v) return v:upper() end) do
     print("%d %s", idx, val)
end


for idx, val in ipairs({"a", "b", "c", "d", "e", "f"}, function (v, a, b) return v:upper() .. a .. b end, "a", "b") do
     print("%d %s", idx, val)
end

這樣可以簡化for塊代碼的邏輯,例如我要遍歷指定目錄,獲取其中的文件名,但不包括路徑,就可以通過這種擴(kuò)展方式,簡化寫法:

for _, filename in ipairs(os.dirs("*"), path.filename) do
    -- ...
end

print

換行打印終端日志

此接口也是lua的原生接口,xmake在原有行為不變的基礎(chǔ)上也進(jìn)行了擴(kuò)展,同時(shí)支持:格式化輸出、多變量輸出。

先看下原生支持的方式:

print("hello xmake!")
print("hello", "xmake!", 123)

并且同時(shí)還支持?jǐn)U展的格式化寫法:

print("hello %s!", "xmake")
print("hello xmake! %d", 123)

xmake會同時(shí)支持這兩種寫法,內(nèi)部會去自動智能檢測,選擇輸出行為。

printf

無換行打印終端日志

類似print接口,唯一的區(qū)別就是不換行。

cprint

換行彩色打印終端日志

行為類似print,區(qū)別就是此接口還支持彩色終端輸出,并且支持emoji字符輸出。

例如:

    cprint('${bright}hello xmake')
    cprint('${red}hello xmake')
    cprint('${bright green}hello ${clear}xmake')
    cprint('${blue onyellow underline}hello xmake${clear}')
    cprint('${red}hello ${magenta}xmake')
    cprint('${cyan}hello ${dim yellow}xmake')

顯示結(jié)果如下:

cprint_colors

跟顏色相關(guān)的描述,都放置在 ${ } 里面,可以同時(shí)設(shè)置多個(gè)不同的屬性,例如:

    ${bright red underline onyellow}

表示:高亮紅色,背景黃色,并且?guī)禄€

所有這些描述,都會影響后面一整行字符,如果只想顯示部分顏色的文字,可以在結(jié)束位置,插入${clear}清楚前面顏色描述

例如:

    ${red}hello ${clear}xmake

這樣的話,僅僅hello是顯示紅色,其他還是正常默認(rèn)黑色顯示。

其他顏色屬于,我這里就不一一介紹,直接貼上xmake代碼里面的屬性列表吧:

    colors.keys = 
    {
        -- 屬性
        reset       = 0 -- 重置屬性
    ,   clear       = 0 -- 清楚屬性
    ,   default     = 0 -- 默認(rèn)屬性
    ,   bright      = 1 -- 高亮
    ,   dim         = 2 -- 暗色
    ,   underline   = 4 -- 下劃線
    ,   blink       = 5 -- 閃爍
    ,   reverse     = 7 -- 反轉(zhuǎn)顏色
    ,   hidden      = 8 -- 隱藏文字


        -- 前景色 
    ,   black       = 30
    ,   red         = 31
    ,   green       = 32
    ,   yellow      = 33
    ,   blue        = 34
    ,   magenta     = 35 
    ,   cyan        = 36
    ,   white       = 37


        -- 背景色 
    ,   onblack     = 40
    ,   onred       = 41
    ,   ongreen     = 42
    ,   onyellow    = 43
    ,   onblue      = 44
    ,   onmagenta   = 45
    ,   oncyan      = 46
    ,   onwhite     = 47

除了可以色彩高亮顯示外,如果你的終端是在macosx下,lion以上的系統(tǒng),xmake還可以支持emoji表情的顯示哦,對于不支持系統(tǒng),會 忽略顯示,例如:

    cprint("hello xmake${beer}")
    cprint("hello${ok_hand} xmake")

上面兩行代碼,我打印了一個(gè)homebrew里面經(jīng)典的啤酒符號,下面那行打印了一個(gè)ok的手勢符號,是不是很炫哈。。

cprint_emoji

所有的emoji表情,以及xmake里面對應(yīng)的key,都可以通過emoji符號里面找到。。

2.1.7版本支持24位真彩色輸出,如果終端支持的話:

import("core.base.colors")
if colors.truecolor() then
    cprint("${255;0;0}hello")
    cprint("${on;255;0;0}hello${clear} xmake")
    cprint("${bright 255;0;0 underline}hello")
    cprint("${bright on;255;0;0 0;255;0}hello${clear} xmake")
end

xmake對于truecolor的檢測支持,是通過$COLORTERM環(huán)境變量來實(shí)現(xiàn)的,如果你的終端支持truecolor,可以手動設(shè)置此環(huán)境變量,來告訴xmake啟用truecolor支持。

可以通過下面的命令來啟用和測試:

$ export COLORTERM=truecolor
$ xmake --version

cprintf

無換行彩色打印終端日志

此接口類似cprint,區(qū)別就是不換行輸出。

format

格式化字符串

如果只是想格式化字符串,不進(jìn)行輸出,可以使用這個(gè)接口,此接口跟string.format接口等價(jià),只是個(gè)接口名簡化版。

local s = format("hello %s", xmake)

vformat

格式化字符串,支持內(nèi)置變量轉(zhuǎn)義

此接口跟format接口類似,只是增加對內(nèi)置變量的獲取和轉(zhuǎn)義支持。

local s = vformat("hello %s $(mode) $(arch) $(env PATH)", xmake)

raise

拋出異常中斷程序

如果想在自定義腳本、插件任務(wù)中中斷xmake運(yùn)行,可以使用這個(gè)接口拋出異常,如果上層沒有顯示調(diào)用try-catch捕獲的話,xmake就會中斷執(zhí)行,并且顯示出錯(cuò)信息。

if (errors) raise(errors)

如果在try塊中拋出異常,就會在catch和finally中進(jìn)行errors信息捕獲,具體見:try-catch

os

系統(tǒng)操作模塊,屬于內(nèi)置模塊,無需使用import導(dǎo)入,可直接腳本域調(diào)用其接口。

此模塊也是lua的原生模塊,xmake在其基礎(chǔ)上進(jìn)行了擴(kuò)展,提供更多實(shí)用的接口。

接口 描述 支持版本
os.cp 復(fù)制文件或目錄 >= 2.0.1
os.mv 移動重命名文件或目錄 >= 2.0.1
os.rm 刪除文件或目錄樹 >= 2.0.1
os.trycp 嘗試復(fù)制文件或目錄 >= 2.1.6
os.trymv 嘗試移動重命名文件或目錄 >= 2.1.6
os.tryrm 嘗試刪除文件或目錄樹 >= 2.1.6
os.cd 進(jìn)入指定目錄 >= 2.0.1
os.rmdir 刪除目錄樹 >= 2.0.1
os.mkdir 創(chuàng)建指定目錄 >= 2.0.1
os.isdir 判斷目錄是否存在 >= 2.0.1
os.isfile 判斷文件是否存在 >= 2.0.1
os.exists 判斷文件或目錄是否存在 >= 2.0.1
os.dirs 遍歷獲取指定目錄下的所有目錄 >= 2.0.1
os.files 遍歷獲取指定目錄下的所有文件 >= 2.0.1
os.filedirs 遍歷獲取指定目錄下的所有文件或目錄 >= 2.0.1
os.run 安靜運(yùn)行程序 >= 2.0.1
os.runv 安靜運(yùn)行程序,帶參數(shù)列表 >= 2.1.5
os.exec 回顯運(yùn)行程序 >= 2.0.1
os.execv 回顯運(yùn)行程序,帶參數(shù)列表 >= 2.1.5
os.iorun 運(yùn)行并獲取程序輸出內(nèi)容 >= 2.0.1
os.iorunv 運(yùn)行并獲取程序輸出內(nèi)容,帶參數(shù)列表 >= 2.1.5
os.getenv 獲取環(huán)境變量 >= 2.0.1
os.setenv 設(shè)置環(huán)境變量 >= 2.0.1
os.tmpdir 獲取臨時(shí)目錄路徑 >= 2.0.1
os.tmpfile 獲取臨時(shí)文件路徑 >= 2.0.1
os.curdir 獲取當(dāng)前目錄路徑 >= 2.0.1
os.scriptdir 獲取腳本目錄路徑 >= 2.0.1
os.programdir 獲取xmake安裝主程序腳本目錄 >= 2.1.5
os.projectdir 獲取工程主目錄 >= 2.1.5
os.arch 獲取當(dāng)前系統(tǒng)架構(gòu) >= 2.0.1
os.host 獲取當(dāng)前主機(jī)系統(tǒng) >= 2.0.1

os.cp

  • 復(fù)制文件或目錄

行為和shell中的cp命令類似,支持路徑通配符匹配(使用的是lua模式匹配),支持多文件復(fù)制,以及內(nèi)置變量支持。

例如:

os.cp("$(scriptdir)/*.h", "$(projectdir)/src/test/**.h", "$(buildir)/inc")

上面的代碼將:當(dāng)前xmake.lua目錄下的所有頭文件、工程源碼test目錄下的頭文件全部復(fù)制到$(buildir)輸出目錄中。

其中$(scriptdir), $(projectdir) 這些變量是xmake的內(nèi)置變量,具體詳情見:內(nèi)置變量的相關(guān)文檔。

*.h**.h中的匹配模式,跟add_files中的類似,前者是單級目錄匹配,后者是遞歸多級目錄匹配。

此接口同時(shí)支持目錄的遞歸復(fù)制,例如:

-- 遞歸復(fù)制當(dāng)前目錄到臨時(shí)目錄
os.cp("$(curdir)/test/", "$(tmpdir)/test")

<p class="tip"> 盡量使用os.cp接口,而不是os.run("cp .."),這樣更能保證平臺一致性,實(shí)現(xiàn)跨平臺構(gòu)建描述。 </p>

os.mv

  • 移動重命名文件或目錄

os.cp的使用類似,同樣支持多文件移動操作和模式匹配,例如:

-- 移動多個(gè)文件到臨時(shí)目錄
os.mv("$(buildir)/test1", "$(buildir)/test2", "$(tmpdir)")


-- 文件移動不支持批量操作,也就是文件重命名
os.mv("$(buildir)/libtest.a", "$(buildir)/libdemo.a")

os.rm

  • 刪除文件或目錄樹

支持遞歸刪除目錄,批量刪除操作,以及模式匹配和內(nèi)置變量,例如:

os.rm("$(buildir)/inc/**.h", "$(buildir)/lib/")

os.trycp

  • 嘗試復(fù)制文件或目錄

os.cp類似,唯一的區(qū)別就是,此接口操作失敗不會拋出異常中斷xmake,而是通過返回值標(biāo)示是否執(zhí)行成功。

if os.trycp("file", "dest/file") then
end

os.trymv

  • 嘗試移動文件或目錄

os.mv類似,唯一的區(qū)別就是,此接口操作失敗不會拋出異常中斷xmake,而是通過返回值標(biāo)示是否執(zhí)行成功。

if os.trymv("file", "dest/file") then
end

os.tryrm

  • 嘗試刪除文件或目錄

os.rm類似,唯一的區(qū)別就是,此接口操作失敗不會拋出異常中斷xmake,而是通過返回值標(biāo)示是否執(zhí)行成功。

if os.tryrm("file") then
end

os.cd

  • 進(jìn)入指定目錄

這個(gè)操作用于目錄切換,同樣也支持內(nèi)置變量,但是不支持模式匹配和多目錄處理,例如:

-- 進(jìn)入臨時(shí)目錄
os.cd("$(tmpdir)")

如果要離開進(jìn)入之前的目錄,有多種方式:

-- 進(jìn)入上級目錄
os.cd("..")


-- 進(jìn)入先前的目錄,相當(dāng)于:cd -
os.cd("-")


-- 進(jìn)入目錄前保存之前的目錄,用于之后跨級直接切回
local oldir = os.cd("./src")
...
os.cd(oldir)

os.rmdir

  • 僅刪除目錄

如果不是目錄就無法刪除。

os.mkdir

  • 創(chuàng)建目錄

支持批量創(chuàng)建和內(nèi)置變量,例如:

os.mkdir("$(tmpdir)/test", "$(buildir)/inc")

os.isdir

  • 判斷是否為目錄

如果目錄不存在,則返回false

if os.isdir("src") then
    -- ...
end

os.isfile

  • 判斷是否為文件

如果文件不存在,則返回false

if os.isfile("$(buildir)/libxxx.a") then
    -- ...
end

os.exists

  • 判斷文件或目錄是否存在

如果文件或目錄不存在,則返回false

-- 判斷目錄存在
if os.exists("$(buildir)") then
    -- ...
end


-- 判斷文件存在
if os.exists("$(buildir)/libxxx.a") then
    -- ...
end

os.dirs

  • 遍歷獲取指定目錄下的所有目錄

支持add_files中的模式匹配,支持遞歸和非遞歸模式遍歷,返回的結(jié)果是一個(gè)table數(shù)組,如果獲取不到,返回空數(shù)組,例如:

-- 遞歸遍歷獲取所有子目錄
for _, dir in ipairs(os.dirs("$(buildir)/inc/**")) do
    print(dir)
end

os.files

  • 遍歷獲取指定目錄下的所有文件

支持add_files中的模式匹配,支持遞歸和非遞歸模式遍歷,返回的結(jié)果是一個(gè)table數(shù)組,如果獲取不到,返回空數(shù)組,例如:

-- 非遞歸遍歷獲取所有子文件
for _, filepath in ipairs(os.files("$(buildir)/inc/*.h")) do
    print(filepath)
end

os.filedirs

  • 遍歷獲取指定目錄下的所有文件和目錄

支持add_files中的模式匹配,支持遞歸和非遞歸模式遍歷,返回的結(jié)果是一個(gè)table數(shù)組,如果獲取不到,返回空數(shù)組,例如:

-- 遞歸遍歷獲取所有子文件和目錄
for _, filedir in ipairs(os.filedirs("$(buildir)/**")) do
    print(filedir)
end

os.run

  • 安靜運(yùn)行原生shell命令

用于執(zhí)行第三方的shell命令,但不會回顯輸出,僅僅在出錯(cuò)后,高亮輸出錯(cuò)誤信息。

此接口支持參數(shù)格式化、內(nèi)置變量,例如:

-- 格式化參數(shù)傳入
os.run("echo hello %s!", "xmake")


-- 列舉構(gòu)建目錄文件
os.run("ls -l $(buildir)")

<p class="warning"> 使用此接口執(zhí)行shell命令,容易使構(gòu)建跨平臺性降低,對于os.run("cp ..")這種盡量使用os.cp代替。<br> 如果必須使用此接口運(yùn)行shell程序,請自行使用config.plat接口判斷平臺支持。 </p>

更加高級的進(jìn)程運(yùn)行和控制,見process模塊接口。

os.runv

  • 安靜運(yùn)行原生shell命令,帶參數(shù)列表

os.run類似,只是傳遞參數(shù)的方式是通過參數(shù)列表傳遞,而不是字符串命令,例如:

os.runv("echo", {"hello", "xmake!"})

os.exec

  • 回顯運(yùn)行原生shell命令

os.run接口類似,唯一的不同是,此接口執(zhí)行shell程序時(shí),是帶回顯輸出的,一般調(diào)試的時(shí)候用的比較多

os.execv

  • 回顯運(yùn)行原生shell命令,帶參數(shù)列表

os.execv類似,只是傳遞參數(shù)的方式是通過參數(shù)列表傳遞,而不是字符串命令,例如:

os.execv("echo", {"hello", "xmake!"})

os.iorun

  • 安靜運(yùn)行原生shell命令并獲取輸出內(nèi)容

os.run接口類似,唯一的不同是,此接口執(zhí)行shell程序后,會獲取shell程序的執(zhí)行結(jié)果,相當(dāng)于重定向輸出。

可同時(shí)獲取stdout, stderr中的內(nèi)容,例如:

local outdata, errdata = os.iorun("echo hello xmake!")

os.iorunv

  • 安靜運(yùn)行原生shell命令并獲取輸出內(nèi)容,帶參數(shù)列表

os.iorunv類似,只是傳遞參數(shù)的方式是通過參數(shù)列表傳遞,而不是字符串命令,例如:

local result, errors = os.iorunv("echo", {"hello", "xmake!"})

os.getenv

  • 獲取系統(tǒng)環(huán)境變量

print(os.getenv("PATH"))

os.setenv

  • 設(shè)置系統(tǒng)環(huán)境變量

os.setenv("HOME", "/tmp/")

os.tmpdir

  • 獲取臨時(shí)目錄

$(tmpdir)結(jié)果一致,只不過是直接獲取返回一個(gè)變量,可以用后續(xù)字符串維護(hù)。

print(path.join(os.tmpdir(), "file.txt"))

等價(jià)于:

print("$(tmpdir)/file.txt"))

os.tmpfile

  • 獲取臨時(shí)文件路徑

用于獲取生成一個(gè)臨時(shí)文件路徑,僅僅是個(gè)路徑,文件需要自己創(chuàng)建。

os.curdir

  • 獲取當(dāng)前目錄路徑

$(curdir)結(jié)果一致,只不過是直接獲取返回一個(gè)變量,可以用后續(xù)字符串維護(hù)。

用法參考:os.tmpdir。

os.scriptdir

  • 獲取當(dāng)前描述腳本的路徑

$(scriptdir)結(jié)果一致,只不過是直接獲取返回一個(gè)變量,可以用后續(xù)字符串維護(hù)。

用法參考:os.tmpdir。

os.programdir

  • 獲取xmake安裝主程序腳本目錄

$(programdir)結(jié)果一致,只不過是直接獲取返回一個(gè)變量,可以用后續(xù)字符串維護(hù)。

os.projectdir

  • 獲取工程主目錄

$(projectdir)結(jié)果一致,只不過是直接獲取返回一個(gè)變量,可以用后續(xù)字符串維護(hù)。

os.arch

  • 獲取當(dāng)前系統(tǒng)架構(gòu)

也就是當(dāng)前主機(jī)系統(tǒng)的默認(rèn)架構(gòu),例如我在linux x86_64上執(zhí)行xmake進(jìn)行構(gòu)建,那么返回值是:x86_64

os.host

  • 獲取當(dāng)前主機(jī)的操作系統(tǒng)

$(host)結(jié)果一致,例如我在linux x86_64上執(zhí)行xmake進(jìn)行構(gòu)建,那么返回值是:linux

io

io操作模塊,擴(kuò)展了lua內(nèi)置的io模塊,提供更多易用的接口。

接口 描述 支持版本
io.open 打開文件用于讀寫 >= 2.0.1
io.load 從指定路徑文件反序列化加載所有table內(nèi)容 >= 2.0.1
io.save 序列化保存所有table內(nèi)容到指定路徑文件 >= 2.0.1
io.readfile 從指定路徑文件讀取所有內(nèi)容 >= 2.1.3
io.writefile 寫入所有內(nèi)容到指定路徑文件 >= 2.1.3
io.gsub 全文替換指定路徑文件的內(nèi)容 >= 2.0.1
io.tail 讀取和顯示文件的尾部內(nèi)容 >= 2.0.1
io.cat 讀取和顯示文件的所有內(nèi)容 >= 2.0.1
io.print 帶換行格式化輸出內(nèi)容到文件 >= 2.0.1
io.printf 無換行格式化輸出內(nèi)容到文件 >= 2.0.1

io.open

  • 打開文件用于讀寫

這個(gè)是屬于lua的原生接口,詳細(xì)使用可以參看lua的官方文檔:The Complete I/O Model

如果要讀取文件所有內(nèi)容,可以這么寫:

local file = io.open("$(tmpdir)/file.txt", "r")
if file then
    local data = file:read("*all")
    file:close()
end

或者可以使用io.readfile更加快速地讀取。

如果要寫文件,可以這么操作:

-- 打開文件:w 為寫模式, a 為追加寫模式
local file = io.open("xxx.txt", "w")
if file then


    -- 用原生的lua接口寫入數(shù)據(jù)到文件,不支持格式化,無換行,不支持內(nèi)置變量
    file:write("hello xmake\n")


    -- 用xmake擴(kuò)展的接口寫入數(shù)據(jù)到文件,支持格式化,無換行,不支持內(nèi)置變量
    file:writef("hello %s\n", "xmake")


    -- 使用xmake擴(kuò)展的格式化傳參寫入一行,帶換行符,并且支持內(nèi)置變量
    file:print("hello %s and $(buildir)", "xmake")


    -- 使用xmake擴(kuò)展的格式化傳參寫入一行,無換行符,并且支持內(nèi)置變量
    file:printf("hello %s and $(buildir) \n", "xmake")


    -- 關(guān)閉文件
    file:close()
end

io.load

  • 從指定路徑文件反序列化加載所有table內(nèi)容

可以從文件中加載序列化好的table內(nèi)容,一般與io.save配合使用,例如:

-- 加載序列化文件的內(nèi)容到table
local data = io.load("xxx.txt")
if data then


    -- 在終端中dump打印整個(gè)table中內(nèi)容,格式化輸出
    table.dump(data)
end

io.save

  • 序列化保存所有table內(nèi)容到指定路徑文件

可以序列化存儲table內(nèi)容到指定文件,一般與io.load配合使用,例如:

io.save("xxx.txt", {a = "a", b = "b", c = "c"})

存儲結(jié)果為:

{
    ["b"] = "b"
,   ["a"] = "a"
,   ["c"] = "c"
}

io.readfile

  • 從指定路徑文件讀取所有內(nèi)容

可在不打開文件的情況下,直接讀取整個(gè)文件的內(nèi)容,更加的方便,例如:

local data = io.readfile("xxx.txt")

io.writefile

  • 寫入所有內(nèi)容到指定路徑文件

可在不打開文件的情況下,直接寫入整個(gè)文件的內(nèi)容,更加的方便,例如:

io.writefile("xxx.txt", "all data")

io.gsub

  • 全文替換指定路徑文件的內(nèi)容

類似string.gsub接口,全文模式匹配替換內(nèi)容,不過這里是直接操作文件,例如:

-- 移除文件所有的空白字符
io.gsub("xxx.txt", "%s+", "")

io.tail

  • 讀取和顯示文件的尾部內(nèi)容

讀取文件尾部指定行數(shù)的數(shù)據(jù),并顯示,類似cat xxx.txt | tail -n 10命令,例如:

-- 顯示文件最后10行內(nèi)容
io.tail("xxx.txt", 10)

io.cat

  • 讀取和顯示文件的所有內(nèi)容

讀取文件的所有內(nèi)容并顯示,類似cat xxx.txt命令,例如:

io.cat("xxx.txt")

io.print

  • 帶換行格式化輸出內(nèi)容到文件

直接格式化傳參輸出一行字符串到文件,并且?guī)Q行,例如:

io.print("xxx.txt", "hello %s!", "xmake")

io.printf

  • 無換行格式化輸出內(nèi)容到文件

直接格式化傳參輸出一行字符串到文件,不帶換行,例如:

io.printf("xxx.txt", "hello %s!\n", "xmake")

path

路徑操作模塊,實(shí)現(xiàn)跨平臺的路徑操作,這是xmake的一個(gè)自定義的模塊。

接口 描述 支持版本
path.join 拼接路徑 >= 2.0.1
path.translate 轉(zhuǎn)換路徑到當(dāng)前平臺的路徑風(fēng)格 >= 2.0.1
path.basename 獲取路徑最后不帶后綴的文件名 >= 2.0.1
path.filename 獲取路徑最后帶后綴的文件名 >= 2.0.1
path.extension 獲取路徑的后綴名 >= 2.0.1
path.directory 獲取路徑最后的目錄名 >= 2.0.1
path.relative 轉(zhuǎn)換成相對路徑 >= 2.0.1
path.absolute 轉(zhuǎn)換成絕對路徑 >= 2.0.1
path.is_absolute 判斷是否為絕對路徑 >= 2.0.1

path.join

  • 拼接路徑

將多個(gè)路徑項(xiàng)進(jìn)行追加拼接,由于windows/unix風(fēng)格的路徑差異,使用api來追加路徑更加跨平臺,例如:

print(path.join("$(tmpdir)", "dir1", "dir2", "file.txt"))

上述拼接在unix上相當(dāng)于:$(tmpdir)/dir1/dir2/file.txt,而在windows上相當(dāng)于:$(tmpdir)\\dir1\\dir2\\file.txt

如果覺得這樣很繁瑣,不夠清晰簡潔,可以使用:path.translate方式,格式化轉(zhuǎn)換路徑字符串到當(dāng)前平臺支持的格式。

path.translate

  • 轉(zhuǎn)換路徑到當(dāng)前平臺的路徑風(fēng)格

格式化轉(zhuǎn)化指定路徑字符串到當(dāng)前平臺支持的路徑風(fēng)格,同時(shí)支持windows/unix格式的路徑字符串參數(shù)傳入,甚至混合傳入,例如:

print(path.translate("$(tmpdir)/dir/file.txt"))
print(path.translate("$(tmpdir)\\dir\\file.txt"))
print(path.translate("$(tmpdir)\\dir/dir2//file.txt"))

上面這三種不同格式的路徑字符串,經(jīng)過translate規(guī)范化后,就會變成當(dāng)前平臺支持的格式,并且會去掉冗余的路徑分隔符。

path.basename

  • 獲取路徑最后不帶后綴的文件名

print(path.basename("$(tmpdir)/dir/file.txt"))

顯示結(jié)果為:file

path.filename

  • 獲取路徑最后帶后綴的文件名

print(path.filename("$(tmpdir)/dir/file.txt"))

顯示結(jié)果為:file.txt

path.extension

  • 獲取路徑的后綴名

print(path.extensione("$(tmpdir)/dir/file.txt"))

顯示結(jié)果為:.txt

path.directory

  • 獲取路徑最后的目錄名

print(path.directory("$(tmpdir)/dir/file.txt"))

顯示結(jié)果為:dir

path.relative

  • 轉(zhuǎn)換成相對路徑

print(path.relative("$(tmpdir)/dir/file.txt", "$(tmpdir)"))

顯示結(jié)果為:dir/file.txt

第二個(gè)參數(shù)是指定相對的根目錄,如果不指定,則默認(rèn)相對當(dāng)前目錄:

os.cd("$(tmpdir)")
print(path.relative("$(tmpdir)/dir/file.txt"))

這樣結(jié)果是一樣的。

path.absolute

  • 轉(zhuǎn)換成絕對路徑

print(path.absolute("dir/file.txt", "$(tmpdir)"))

顯示結(jié)果為:$(tmpdir)/dir/file.txt

第二個(gè)參數(shù)是指定相對的根目錄,如果不指定,則默認(rèn)相對當(dāng)前目錄:

os.cd("$(tmpdir)")
print(path.absolute("dir/file.txt"))

這樣結(jié)果是一樣的。

path.is_absolute

  • 判斷是否為絕對路徑

if path.is_absolute("/tmp/file.txt") then
    -- 如果是絕對路徑
end

table

table屬于lua原生提供的模塊,對于原生接口使用可以參考:lua官方文檔

xmake中對其進(jìn)行了擴(kuò)展,增加了一些擴(kuò)展接口:

接口 描述 支持版本
table.join 合并多個(gè)table并返回 >= 2.0.1
table.join2 合并多個(gè)table到第一個(gè)table >= 2.0.1
table.dump 輸出table的所有內(nèi)容 >= 2.0.1
table.unique 對table中的內(nèi)容進(jìn)行去重 >= 2.0.1
table.slice 獲取table的切片 >= 2.0.1

table.join

  • 合并多個(gè)table并返回

可以將多個(gè)table里面的元素進(jìn)行合并后,返回到一個(gè)新的table中,例如:

local newtable = table.join({1, 2, 3}, {4, 5, 6}, {7, 8, 9})

結(jié)果為:{1, 2, 3, 4, 5, 6, 7, 8, 9}

并且它也支持字典的合并:

local newtable = table.join({a = "a", b = "b"}, {c = "c"}, {d = "d"})

結(jié)果為:{a = "a", b = "b", c = "c", d = "d"}

table.join2

  • 合并多個(gè)table到第一個(gè)table

類似table.join,唯一的區(qū)別是,合并的結(jié)果放置在第一個(gè)參數(shù)中,例如:

local t = {0, 9}
table.join2(t, {1, 2, 3})

結(jié)果為:t = {0, 9, 1, 2, 3}

table.dump

  • 輸出table的所有內(nèi)容

遞歸格式化打印table中的所有內(nèi)容,一般用于調(diào)試, 例如:

table.dump({1, 2, 3})

結(jié)果為:{1, 2, 3}

table.unique

  • 對table中的內(nèi)容進(jìn)行去重

去重table的元素,一般用于數(shù)組table,例如:

local newtable = table.unique({1, 1, 2, 3, 4, 4, 5})

結(jié)果為:{1, 2, 3, 4, 5}

table.slice

  • 獲取table的切片

用于提取數(shù)組table的部分元素,例如:

-- 提取第4個(gè)元素后面的所有元素,結(jié)果:{4, 5, 6, 7, 8, 9}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4)


-- 提取第4-8個(gè)元素,結(jié)果:{4, 5, 6, 7, 8}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8)


-- 提取第4-8個(gè)元素,間隔步長為2,結(jié)果:{4, 6, 8}
table.slice({1, 2, 3, 4, 5, 6, 7, 8, 9}, 4, 8, 2)

string

字符串模塊為lua原生自帶的模塊,具體使用見:lua官方手冊

xmake中對其進(jìn)行了擴(kuò)展,增加了一些擴(kuò)展接口:

接口 描述 支持版本
string.startswith 判斷字符串開頭是否匹配 >= 1.0.1
string.endswith 判斷字符串結(jié)尾是否匹配 >= 1.0.1
string.split 分割字符串 >= 1.0.1
string.trim 去掉字符串左右空白字符 >= 1.0.1
string.ltrim 去掉字符串左邊空白字符 >= 1.0.1
string.rtrim 去掉字符串右邊空白字符 >= 1.0.1

string.startswith

  • 判斷字符串開頭是否匹配

local s = "hello xmake"
if s:startswith("hello") then
    print("match")
end

string.endswith

  • 判斷字符串結(jié)尾是否匹配

local s = "hello xmake"
if s:endswith("xmake") then
    print("match")
end

string.split

  • 分割字符串

通過指定的分隔符進(jìn)行字符串分割,分隔符可以是:字符,字符串、模式匹配字符串,例如:

local s = "hello     xmake!"
s:split("%s+")

根據(jù)連續(xù)空白字符進(jìn)行分割,結(jié)果為:hello, xmake!

local s = "hello,xmake:123"
s:split("[,:]")

上面的代碼根據(jù),或者:字符進(jìn)行分割,結(jié)果為:hello, xmake, 123

string.trim

  • 去掉字符串左右空白字符

string.trim("    hello xmake!    ")

結(jié)果為:"hello xmake!"

string.ltrim

  • 去掉字符串左邊空白字符

string.ltrim("    hello xmake!    ")

結(jié)果為:"hello xmake! "

string.rtrim

  • 去掉字符串右邊空白字符

string.rtrim("    hello xmake!    ")

結(jié)果為:" hello xmake!"

process

這個(gè)是xmake擴(kuò)展的進(jìn)程控制模塊,用于更加靈活的控制進(jìn)程,比起:os.run系列靈活性更高,也更底層。

接口 描述 支持版本
process.open 打開進(jìn)程 >= 2.0.1
process.wait 等待進(jìn)程結(jié)束 >= 2.0.1
process.close 關(guān)閉進(jìn)程對象 >= 2.0.1
process.waitlist 同時(shí)等待多個(gè)進(jìn)程 >= 2.0.1

process.open

  • 打開進(jìn)程

通過路徑創(chuàng)建運(yùn)行一個(gè)指定程序,并且返回對應(yīng)的進(jìn)程對象:

-- 打開進(jìn)程,后面兩個(gè)參數(shù)指定需要捕獲的stdout, stderr文件路徑
local proc = process.open("echo hello xmake!", outfile, errfile)
if proc then


    -- 等待進(jìn)程執(zhí)行完成
    --
    -- 參數(shù)二為等待超時(shí),-1為永久等待,0為嘗試獲取進(jìn)程狀態(tài)
    -- 返回值waitok為等待狀態(tài):1為等待進(jìn)程正常結(jié)束,0為進(jìn)程還在運(yùn)行中,-1位等待失敗
    -- 返回值status為,等待進(jìn)程結(jié)束后,進(jìn)程返回的狀態(tài)碼
    local waitok, status = process.wait(proc, -1)


    -- 釋放進(jìn)程對象
    process.close(proc)
end

process.wait

  • 等待進(jìn)程結(jié)束

具體使用見:process.open

process.close

  • 關(guān)閉進(jìn)程對象

具體使用見:process.open

process.waitlist

  • 同時(shí)等待多個(gè)進(jìn)程

-- 第二個(gè)參數(shù)是等待超時(shí),返回進(jìn)程狀態(tài)列表
for _, procinfo in ipairs(process.waitlist(procs, -1)) do

    
    -- 每個(gè)進(jìn)程的:進(jìn)程對象、進(jìn)程pid、進(jìn)程結(jié)束狀態(tài)碼
    local proc      = procinfo[1]
    local procid    = procinfo[2]
    local status    = procinfo[3]


end

coroutine

協(xié)程模塊是lua原生自帶的模塊,具使用見:lua官方手冊

擴(kuò)展模塊

所有擴(kuò)展模塊的使用,都需要通過import接口,進(jìn)行導(dǎo)入后才能使用。

core.base.option

一般用于獲取xmake命令參數(shù)選項(xiàng)的值,常用于插件開發(fā)。

接口 描述 支持版本
option.get 獲取參數(shù)選項(xiàng)值 >= 2.0.1

option.get

  • 獲取參數(shù)選項(xiàng)值

在插件開發(fā)中用于獲取參數(shù)選項(xiàng)值,例如:

-- 導(dǎo)入選項(xiàng)模塊
import("core.base.option")


-- 插件入口函數(shù)
function main(...)
    print(option.get("info"))
end

上面的代碼獲取hello插件,執(zhí)行:xmake hello --info=xxxx 命令時(shí)候傳入的--info=選項(xiàng)的值,并顯示:xxxx

對于非main入口的task任務(wù)或插件,可以這么使用:

task("hello")
    on_run(function ())
        import("core.base.option")
        print(option.get("info"))
    end)

core.base.global

用于獲取xmake全局的配置信息,也就是xmake g|global --xxx=val 傳入的參數(shù)選項(xiàng)值。

接口 描述 支持版本
global.get 獲取指定配置值 >= 2.0.1
global.load 加載配置 >= 2.0.1
global.directory 獲取全局配置信息目錄 >= 2.0.1
global.dump 打印輸出所有全局配置信息 >= 2.0.1

<p class="tip"> 2.1.5版本之前為core.project.global。 </p>

global.get

  • 獲取指定配置值

類似config.get,唯一的區(qū)別就是這個(gè)是從全局配置中獲取。

global.load

  • 加載配置

類似global.get,唯一的區(qū)別就是這個(gè)是從全局配置中加載。

global.directory

  • 獲取全局配置信息目錄

默認(rèn)為~/.config目錄。

global.dump

  • 打印輸出所有全局配置信息

輸出結(jié)果如下:

{
    clean = true
,   ccache = "ccache"
,   xcode_dir = "/Applications/Xcode.app"
}

core.base.task

用于任務(wù)操作,一般用于在自定義腳本中、插件任務(wù)中,調(diào)用運(yùn)行其他task任務(wù)。

接口 描述 支持版本
task.run 運(yùn)行指定任務(wù) >= 2.0.1

<p class="tip"> 2.1.5版本之前為core.project.task。 </p>

task.run

  • 運(yùn)行指定任務(wù)

用于在自定義腳本、插件任務(wù)中運(yùn)行task定義的任務(wù)或插件,例如:

task("hello")
    on_run(function ()
        print("hello xmake!")
    end)


target("demo")
    on_clean(function(target)


        -- 導(dǎo)入task模塊
        import("core.base.task")


        -- 運(yùn)行這個(gè)hello task
        task.run("hello")
    end)

我們還可以在運(yùn)行任務(wù)時(shí),增加參數(shù)傳遞,例如:

task("hello")
    on_run(function (arg1, arg2)
        print("hello xmake: %s %s!", arg1, arg2)
    end)


target("demo")
    on_clean(function(target)


        -- 導(dǎo)入task
        import("core.base.task")


        -- {} 這個(gè)是給第一種選項(xiàng)傳參使用,這里置空,這里在最后面?zhèn)魅肓藘蓚€(gè)參數(shù):arg1, arg2
        task.run("hello", {}, "arg1", "arg2")
    end)

對于task.run的第二個(gè)參數(shù),用于傳遞命令行菜單中的選項(xiàng),而不是直接傳入function (arg, ...)函數(shù)入口中,例如:

-- 導(dǎo)入task
import("core.base.task")


-- 插件入口
function main(...)


    -- 運(yùn)行內(nèi)置的xmake配置任務(wù),相當(dāng)于:xmake f|config --plat=iphoneos --arch=armv7
    task.run("config", {plat="iphoneos", arch="armv7"})
emd

core.tool.linker

鏈接器相關(guān)操作,常用于插件開發(fā)。

接口 描述 支持版本
linker.link 執(zhí)行鏈接 >= 2.0.1
linker.linkcmd 獲取鏈接命令行 >= 2.0.1
linker.linkargv 獲取鏈接命令行列表 >= 2.1.5
linker.linkflags 獲取鏈接選項(xiàng) >= 2.0.1
linker.has_flags 判斷指定鏈接選項(xiàng)是否支持 >= 2.1.5

linker.link

  • 執(zhí)行鏈接

針對target,鏈接指定對象文件列表,生成對應(yīng)的目標(biāo)文件,例如:

linker.link({"a.o", "b.o", "c.o"}, target:targetfile(), {target = target})

其中target,為工程目標(biāo),這里傳入,主要用于獲取target特定的鏈接選項(xiàng),具體如果獲取工程目標(biāo)對象,見:core.project.project

當(dāng)然也可以不指定target,例如:

linker.link("binary", "cc", {"a.o", "b.o", "c.o"}, "/tmp/targetfile")

linker.linkcmd

  • 獲取鏈接命令行字符串

直接獲取linker.link中執(zhí)行的命令行字符串,相當(dāng)于:

local cmdstr = linker.linkcmd("static", "cxx", {"a.o", "b.o", "c.o"}, target:targetfile(), {target = target})

注:后面{target = target}擴(kuò)展參數(shù)部分是可選的,如果傳遞了target對象,那么生成的鏈接命令,會加上這個(gè)target配置對應(yīng)的鏈接選項(xiàng)。

并且還可以自己傳遞各種配置,例如:

local cmdstr = linker.linkcmd("static", "cxx", {"a.o", "b.o", "c.o"}, target:targetfile(), {config = {linkdirs = "/usr/lib"}})

linker.linkargv

  • 獲取鏈接命令行參數(shù)列表

linker.linkcmd稍微有點(diǎn)區(qū)別的是,此接口返回的是參數(shù)列表,table表示,更加方便操作:

local program, argv = linker.linkargv("static", "cxx", {"a.o", "b.o", "c.o"}, target:targetfile(), {target = target})

其中返回的第一個(gè)值是主程序名,后面是參數(shù)列表,而os.args(table.join(program, argv))等價(jià)于linker.linkcmd。

我們也可以通過傳入返回值給os.runv來直接運(yùn)行它:os.runv(linker.linkargv(..))

linker.linkflags

  • 獲取鏈接選項(xiàng)

獲取linker.linkcmd中的鏈接選項(xiàng)字符串部分,不帶shellname和對象文件列表,并且是按數(shù)組返回,例如:

local flags = linker.linkflags("shared", "cc", {target = target})
for _, flag in ipairs(flags) do
    print(flag)
end

返回的是flags的列表數(shù)組。

linker.has_flags

  • 判斷指定鏈接選項(xiàng)是否支持

雖然通過lib.detect.has_flags也能判斷,但是那個(gè)接口更加底層,需要指定鏈接器名稱 而此接口只需要指定target的目標(biāo)類型,源文件類型,它會自動切換選擇當(dāng)前支持的鏈接器。

if linker.has_flags(target:targetkind(), target:sourcekinds(), "-L/usr/lib -lpthread") then
    -- ok
end

core.tool.compiler

編譯器相關(guān)操作,常用于插件開發(fā)。

接口 描述 支持版本
compiler.compile 執(zhí)行編譯 >= 2.0.1
compiler.compcmd 獲取編譯命令行 >= 2.0.1
compiler.compargv 獲取編譯命令行列表 >= 2.1.5
compiler.compflags 獲取編譯選項(xiàng) >= 2.0.1
compiler.has_flags 判斷指定編譯選項(xiàng)是否支持 >= 2.1.5
compiler.features 獲取所有編譯器特性 >= 2.1.5
compiler.has_features 判斷指定編譯特性是否支持 >= 2.1.5

compiler.compile

  • 執(zhí)行編譯

針對target,鏈接指定對象文件列表,生成對應(yīng)的目標(biāo)文件,例如:

compiler.compile("xxx.c", "xxx.o", "xxx.h.d", {target = target})

其中target,為工程目標(biāo),這里傳入主要用于獲取taeget的特定編譯選項(xiàng),具體如果獲取工程目標(biāo)對象,見:core.project.project

xxx.h.d文件用于存儲為此源文件的頭文件依賴文件列表,最后這兩個(gè)參數(shù)都是可選的,編譯的時(shí)候可以不傳他們:

compiler.compile("xxx.c", "xxx.o")

來單純編譯一個(gè)源文件。

compiler.compcmd

  • 獲取編譯命令行

直接獲取compiler.compile中執(zhí)行的命令行字符串,相當(dāng)于:

local cmdstr = compiler.compcmd("xxx.c", "xxx.o", {target = target})

注:后面{target = target}擴(kuò)展參數(shù)部分是可選的,如果傳遞了target對象,那么生成的編譯命令,會加上這個(gè)target配置對應(yīng)的鏈接選項(xiàng)。

并且還可以自己傳遞各種配置,例如:

local cmdstr = compiler.compcmd("xxx.c", "xxx.o", {config = {includedirs = "/usr/include", defines = "DEBUG"}})

通過target,我們可以導(dǎo)出指定目標(biāo)的所有源文件編譯命令:

import("core.project.project")


for _, target in pairs(project.targets()) do
    for sourcekind, sourcebatch in pairs(target:sourcebatches()) do
        for index, objectfile in ipairs(sourcebatch.objectfiles) do
            local cmdstr = compiler.compcmd(sourcebatch.sourcefiles[index], objectfile, {target = target})
        end
    end
end

compiler.compargv

  • 獲取編譯命令行列表

compiler.compargv稍微有點(diǎn)區(qū)別的是,此接口返回的是參數(shù)列表,table表示,更加方便操作:

local program, argv = compiler.compargv("xxx.c", "xxx.o")

compiler.compflags

  • 獲取編譯選項(xiàng)

獲取compiler.compcmd中的編譯選項(xiàng)字符串部分,不帶shellname和文件列表,例如:

local flags = compiler.compflags(sourcefile, {target = target})
for _, flag in ipairs(flags) do
    print(flag)
end

返回的是flags的列表數(shù)組。

compiler.has_flags

  • 判斷指定編譯選項(xiàng)是否支持

雖然通過lib.detect.has_flags也能判斷,但是那個(gè)接口更加底層,需要指定編譯器名稱。 而此接口只需要指定語言類型,它會自動切換選擇當(dāng)前支持的編譯器。

-- 判斷c語言編譯器是否支持選項(xiàng): -g
if compiler.has_flags("c", "-g") then
    -- ok
end


-- 判斷c++語言編譯器是否支持選項(xiàng): -g
if compiler.has_flags("cxx", "-g") then
    -- ok
end

compiler.features

  • 獲取所有編譯器特性

雖然通過lib.detect.features也能獲取,但是那個(gè)接口更加底層,需要指定編譯器名稱。 而此接口只需要指定語言類型,它會自動切換選擇當(dāng)前支持的編譯器,然后獲取當(dāng)前的編譯器特性列表。

-- 獲取當(dāng)前c語言編譯器的所有特性
local features = compiler.features("c")


-- 獲取當(dāng)前c++語言編譯器的所有特性,啟用c++11標(biāo)準(zhǔn),否則獲取不到新標(biāo)準(zhǔn)的特性
local features = compiler.features("cxx", {config = {cxxflags = "-std=c++11"}})


-- 獲取當(dāng)前c++語言編譯器的所有特性,傳遞工程target的所有配置信息
local features = compiler.features("cxx", {target = target, config = {defines = "..", includedirs = ".."}})

所有c編譯器特性列表:

特性名
c_static_assert
c_restrict
c_variadic_macros
c_function_prototypes

所有c++編譯器特性列表:

特性名
cxx_variable_templates
cxx_relaxed_constexpr
cxx_aggregate_default_initializers
cxx_contextual_conversions
cxx_attribute_deprecated
cxx_decltype_auto
cxx_digit_separators
cxx_generic_lambdas
cxx_lambda_init_captures
cxx_binary_literals
cxx_return_type_deduction
cxx_decltype_incomplete_return_types
cxx_reference_qualified_functions
cxx_alignof
cxx_attributes
cxx_inheriting_constructors
cxx_thread_local
cxx_alias_templates
cxx_delegating_constructors
cxx_extended_friend_declarations
cxx_final
cxx_nonstatic_member_init
cxx_override
cxx_user_literals
cxx_constexpr
cxx_defaulted_move_initializers
cxx_enum_forward_declarations
cxx_noexcept
cxx_nullptr
cxx_range_for
cxx_unrestricted_unions
cxx_explicit_conversions
cxx_lambdas
cxx_local_type_template_args
cxx_raw_string_literals
cxx_auto_type
cxx_defaulted_functions
cxx_deleted_functions
cxx_generalized_initializers
cxx_inline_namespaces
cxx_sizeof_member
cxx_strong_enums
cxx_trailing_return_types
cxx_unicode_literals
cxx_uniform_initialization
cxx_variadic_templates
cxx_decltype
cxx_default_function_template_args
cxx_long_long_type
cxx_right_angle_brackets
cxx_rvalue_references
cxx_static_assert
cxx_extern_templates
cxx_func_identifier
cxx_variadic_macros
cxx_template_template_parameters

compiler.has_features

  • 判斷指定的編譯器特性是否支持

雖然通過lib.detect.has_features也能獲取,但是那個(gè)接口更加底層,需要指定編譯器名稱。 而此接口只需要指定需要檢測的特姓名稱列表,就能自動切換選擇當(dāng)前支持的編譯器,然后判斷指定特性在當(dāng)前的編譯器中是否支持。

if compiler.has_features("c_static_assert") then
    -- ok
end


if compiler.has_features({"c_static_assert", "cxx_constexpr"}, {languages = "cxx11"}) then
    -- ok
end


if compiler.has_features("cxx_constexpr", {target = target, defines = "..", includedirs = ".."}) then
    -- ok
end

具體特性名有哪些,可以參考:compiler.features。

core.project.config

用于獲取工程編譯時(shí)候的配置信息,也就是xmake f|config --xxx=val 傳入的參數(shù)選項(xiàng)值。

接口 描述 支持版本
config.get 獲取指定配置值 >= 2.0.1
config.load 加載配置 >= 2.0.1
config.arch 獲取當(dāng)前工程的架構(gòu)配置 >= 2.0.1
config.plat 獲取當(dāng)前工程的平臺配置 >= 2.0.1
config.mode 獲取當(dāng)前工程的編譯模式配置 >= 2.0.1
config.buildir 獲取當(dāng)前工程的輸出目錄配置 >= 2.0.1
config.directory 獲取當(dāng)前工程的配置信息目錄 >= 2.0.1
config.dump 打印輸出當(dāng)前工程的所有配置信息 >= 2.0.1

config.get

  • 獲取指定配置值

用于獲取xmake f|config --xxx=val的配置值,例如:

target("test")
    on_run(function (target)


        -- 導(dǎo)入配置模塊
        import("core.project.config")


        -- 獲取配置值
        print(config.get("xxx"))
    end)

config.load

  • 加載配置

一般用于插件開發(fā)中,插件任務(wù)中不像工程的自定義腳本,環(huán)境需要自己初始化加載,默認(rèn)工程配置是沒有被加載的,如果要用config.get接口獲取工程配置,那么需要先:



-- 導(dǎo)入配置模塊
import("core.project.config")


function main(...)


    -- 先加載工程配置
    config.load()

    
    -- 獲取配置值
    print(config.get("xxx"))
end

config.arch

  • 獲取當(dāng)前工程的架構(gòu)配置

也就是獲取xmake f|config --arch=armv7的平臺配置,相當(dāng)于config.get("arch")。

config.plat

  • 獲取當(dāng)前工程的平臺配置

也就是獲取xmake f|config --plat=iphoneos的平臺配置,相當(dāng)于config.get("plat")。

config.mode

  • 獲取當(dāng)前工程的編譯模式配置

也就是獲取xmake f|config --mode=debug的平臺配置,相當(dāng)于config.get("mode")。

config.buildir

  • 獲取當(dāng)前工程的輸出目錄配置

也就是獲取xmake f|config -o /tmp/output的平臺配置,相當(dāng)于config.get("buildir")。

config.directory

  • 獲取當(dāng)前工程的配置信息目錄

獲取工程配置的存儲目錄,默認(rèn)為:projectdir/.config

config.dump

  • 打印輸出當(dāng)前工程的所有配置信息

輸出結(jié)果例如:

{
    sh = "xcrun -sdk macosx clang++"
,   xcode_dir = "/Applications/Xcode.app"
,   ar = "xcrun -sdk macosx ar"
,   small = true
,   object = false
,   arch = "x86_64"
,   xcode_sdkver = "10.12"
,   ex = "xcrun -sdk macosx ar"
,   cc = "xcrun -sdk macosx clang"
,   rc = "rustc"
,   plat = "macosx"
,   micro = false
,   host = "macosx"
,   as = "xcrun -sdk macosx clang"
,   dc = "dmd"
,   gc = "go"
,   openssl = false
,   ccache = "ccache"
,   cxx = "xcrun -sdk macosx clang"
,   sc = "xcrun -sdk macosx swiftc"
,   mm = "xcrun -sdk macosx clang"
,   buildir = "build"
,   mxx = "xcrun -sdk macosx clang++"
,   ld = "xcrun -sdk macosx clang++"
,   mode = "release"
,   kind = "static"
}

core.project.global

<p class="tip"> 此模塊自2.1.5版本后遷移至core.base.global。 </p>

core.project.task

<p class="tip"> 此模塊自2.1.5版本后遷移至core.base.task。 </p>

core.project.project

用于獲取當(dāng)前工程的一些描述信息,也就是在xmake.lua工程描述文件中定義的配置信息,例如:target、option等。

接口 描述 支持版本
project.load 加載工程配置 >= 2.0.1 (2.1.5廢棄)
project.directory 獲取工程目錄 >= 2.0.1
project.target 獲取指定工程目標(biāo)對象 >= 2.0.1
project.targets 獲取工程目標(biāo)對象列表 >= 2.0.1
project.option 獲取指定的選項(xiàng)對象 >= 2.1.5
project.options 獲取工程所有的選項(xiàng)對象 >= 2.1.5
project.name 獲取當(dāng)前工程名 >= 2.0.1
project.version 獲取當(dāng)前工程版本號 >= 2.0.1

project.load

  • 加載工程描述配置

僅在插件中使用,因?yàn)檫@個(gè)時(shí)候還沒有加載工程配置信息,在工程目標(biāo)的自定義腳本中,不需要執(zhí)行此操作,就可以直接訪問工程配置。

-- 導(dǎo)入工程模塊
import("core.project.project")


-- 插件入口
function main(...)


    -- 加載工程描述配置
    project.load()


    -- 訪問工程描述,例如獲取指定工程目標(biāo)
    local target = project.target("test")
end

<p class="tip"> 2.1.5版本后,不在需要,工程加載會自動在合適時(shí)機(jī)延遲加載。 </p>

project.directory

  • 獲取工程目錄

獲取當(dāng)前工程目錄,也就是xmake -P xxx中指定的目錄,否則為默認(rèn)當(dāng)前xmake命令執(zhí)行目錄。

<p class="tip"> 2.1.5版本后,建議使用os.projectdir來獲取。 </p>

project.target

  • 獲取指定工程目標(biāo)對象

獲取和訪問指定工程目標(biāo)配置,例如:

local target = project.target("test")
if target then


    -- 獲取目標(biāo)文件名
    print(target:targetfile())


    -- 獲取目標(biāo)類型,也就是:binary, static, shared
    print(target:targetkind())


    -- 獲取目標(biāo)名
    print(target:name())


    -- 獲取目標(biāo)源文件
    local sourcefiles = target:sourcefiles()


    -- 獲取目標(biāo)安裝頭文件列表
    local srcheaders, dstheaders = target:headerfiles()


    -- 獲取目標(biāo)依賴
    print(target:get("deps"))
end

project.targets

  • 獲取工程目標(biāo)對象列表

返回當(dāng)前工程的所有編譯目標(biāo),例如:

for targetname, target in pairs(project.targets())
    print(target:targetfile())
end

project.option

  • 獲取指定選項(xiàng)對象

獲取和訪問工程中指定的選項(xiàng)對象,例如:

local option = project.option("test")
if option:enabled() then
    option:enable(false)
end

project.options

  • 獲取工程所有選項(xiàng)對象

返回當(dāng)前工程的所有編譯目標(biāo),例如:

for optionname, option in pairs(project.options())
    print(option:enabled())
end

project.name

  • 獲取當(dāng)前工程名

也就是獲取set_project的工程名配置。

print(project.name())

project.version

  • 獲取當(dāng)前工程版本號

也就是獲取set_version的工程版本配置。

print(project.version())

core.language.language

用于獲取編譯語言相關(guān)信息,一般用于代碼文件的操作。

接口 描述 支持版本
language.extensions 獲取所有語言的代碼后綴名列表 >= 2.1.1
language.targetkinds 獲取所有語言的目標(biāo)類型列表 >= 2.1.1
language.sourcekinds 獲取所有語言的源文件類型列表 >= 2.1.1
language.sourceflags 加載所有語言的源文件編譯選項(xiàng)名列表 >= 2.1.1
language.load 加載指定語言 >= 2.1.1
language.load_sk 從源文件類型加載指定語言 >= 2.1.1
language.load_ex 從源文件后綴名加載指定語言 >= 2.1.1
language.sourcekind_of 獲取指定源文件的源文件類型 >= 2.1.1

language.extensions

  • 獲取所有語言的代碼后綴名列表

獲取結(jié)果如下:

{
     [".c"]      = cc
,    [".cc"]     = cxx
,    [".cpp"]    = cxx
,    [".m"]      = mm
,    [".mm"]     = mxx
,    [".swift"]  = sc
,    [".go"]     = gc
}

language.targetkinds

  • 獲取所有語言的目標(biāo)類型列表

獲取結(jié)果如下:

{
     binary = {"ld", "gc-ld", "dc-ld"}
,    static = {"ar", "gc-ar", "dc-ar"}
,    shared = {"sh", "dc-sh"}
}

language.sourcekinds

  • 獲取所有語言的源文件類型列表

獲取結(jié)果如下:

{
     cc  = ".c"
,    cxx = {".cc", ".cpp", ".cxx"}
,    mm  = ".m"
,    mxx = ".mm"
,    sc  = ".swift"
,    gc  = ".go"
,    rc  = ".rs"
,    dc  = ".d"
,    as  = {".s", ".S", ".asm"}
}

language.sourceflags

  • 加載所有語言的源文件編譯選項(xiàng)名列表

獲取結(jié)果如下:

{
     cc  = {"cflags", "cxflags"}
,    cxx = {"cxxflags", "cxflags"}
,    ...
}

language.load

  • 加載指定語言

從語言名稱加載具體語言對象,例如:

local lang = language.load("c++")
if lang then
    print(lang:name())
end

language.load_sk

  • 從源文件類型加載指定語言

從源文件類型:cc, cxx, mm, mxx, sc, gc, as ..加載具體語言對象,例如:

local lang = language.load_sk("cxx")
if lang then
    print(lang:name())
end

language.load_ex

  • 從源文件后綴名加載指定語言

從源文件后綴名:.cc, .c, .cpp, .mm, .swift, .go ..加載具體語言對象,例如:

local lang = language.load_sk(".cpp")
if lang then
    print(lang:name())
end

language.sourcekind_of

  • 獲取指定源文件的源文件類型

也就是從給定的一個(gè)源文件路徑,獲取它是屬于那種源文件類型,例如:

print(language.sourcekind_of("/xxxx/test.cpp"))

顯示結(jié)果為:cxx,也就是c++類型,具體對應(yīng)列表見:language.sourcekinds

core.platform.platform

平臺信息相關(guān)操作

接口 描述 支持版本
platform.get 獲取指定平臺相關(guān)配置信息 >= 2.0.1

platform.get

  • 獲取指定平臺相關(guān)配置信息

獲取平臺配置xmake.lua中設(shè)置的信息,一般只有在寫插件的時(shí)候會用到,例如:

-- 獲取當(dāng)前平臺的所有支持架構(gòu)
print(platform.get("archs"))


-- 獲取指定iphoneos平臺的目標(biāo)文件格式信息
local formats = platform.get("formats", "iphoneos")
table.dump(formats)

具體有哪些可讀的平臺配置信息,可參考:platform

core.platform.environment

環(huán)境相關(guān)操作,用于進(jìn)入和離開指定環(huán)境變量對應(yīng)的終端環(huán)境,一般用于path環(huán)境的進(jìn)入和離開,尤其是一些需要特定環(huán)境的構(gòu)建工具,例如:msvc的工具鏈。

接口 描述 支持版本
environment.enter 進(jìn)入指定環(huán)境 >= 2.0.1
environment.leave 離開指定環(huán)境 >= 2.0.1

目前支持的環(huán)境有:

接口 描述 支持版本
toolchains 工具鏈執(zhí)行環(huán)境 >= 2.0.1

environment.enter

  • 進(jìn)入指定環(huán)境

進(jìn)入指定環(huán)境,例如msvc有自己的環(huán)境變量環(huán)境用于運(yùn)行構(gòu)建工具,例如:cl.exe, link.exe這些,這個(gè)時(shí)候想要在xmake里面運(yùn)行他們,需要:

-- 進(jìn)入工具鏈環(huán)境
environment.enter("toolchains")


-- 這個(gè)時(shí)候運(yùn)行cl.exe才能正常運(yùn)行,這個(gè)時(shí)候的path等環(huán)境變量都會進(jìn)入msvc的環(huán)境模式
os.run("cl.exe ..")


-- 離開工具鏈環(huán)境
environment.leave("toolchains")

因此為了通用性,默認(rèn)xmake編譯事都會設(shè)置這個(gè)環(huán)境,在linux下基本上內(nèi)部環(huán)境不需要特殊切換,目前僅對windows下msvc進(jìn)行了處理。

environment.leave

  • 離開指定環(huán)境

具體使用見:environment.enter

lib.detect

此模塊提供了非常強(qiáng)大的探測功能,用于探測程序、編譯器、語言特性、依賴包等。

<p class="tip"> 此模塊的接口分散在多個(gè)模塊目錄中,盡量通過導(dǎo)入單個(gè)接口來使用,這樣效率更高,例如:import("lib.detect.find_package"),而不是通過import("lib.detect")導(dǎo)入所有來調(diào)用。 </p>

接口 描述 支持版本
detect.find_file 查找文件 >= 2.1.5
detect.find_path 查找文件路徑 >= 2.1.5
detect.find_library 查找?guī)煳募?/td> >= 2.1.5
detect.find_program 查找可執(zhí)行程序 >= 2.1.5
detect.find_programver 查找可執(zhí)行程序版本號 >= 2.1.5
detect.find_package 查找包文件,包含庫文件和搜索路徑 >= 2.1.5
detect.find_tool 查找工具 >= 2.1.5
detect.find_toolname 查找工具名 >= 2.1.5
detect.features 獲取指定工具的所有特性 >= 2.1.5
detect.has_features 判斷指定特性是否支持 >= 2.1.5
detect.has_flags 判斷指定參數(shù)選項(xiàng)是否支持 >= 2.1.5
detect.has_cfuncs 判斷指定c函數(shù)是否存在 >= 2.1.5
detect.has_cxxfuncs 判斷指定c++函數(shù)是否存在 >= 2.1.5
detect.has_cincludes 判斷指定c頭文件是否存在 >= 2.1.5
detect.has_cxxincludess 判斷指定c++頭文件是否存在 >= 2.1.5
detect.has_ctypes 判斷指定c類型是否存在 >= 2.1.5
detect.has_cxxtypes 判斷指定c++類型是否存在 >= 2.1.5
detect.check_cxsnippets 檢測c/c++代碼片段是否能夠編譯通過 >= 2.1.5

detect.find_file

  • 查找文件

這個(gè)接口提供了比os.files更加強(qiáng)大的工程, 可以同時(shí)指定多個(gè)搜索目錄,并且還能對每個(gè)目錄指定附加的子目錄,來模式匹配查找,相當(dāng)于是os.files的增強(qiáng)版。

例如:

import("lib.detect.find_file")


local file = find_file("ccache", { "/usr/bin", "/usr/local/bin"})

如果找到,返回的結(jié)果是:/usr/bin/ccache

它同時(shí)也支持模式匹配路徑,進(jìn)行遞歸查找,類似os.files

local file = find_file("test.h", { "/usr/include", "/usr/local/include/**"})

不僅如此,里面的路徑也支持內(nèi)建變量,來從環(huán)境變量和注冊表中獲取路徑進(jìn)行查找:

local file = find_file("xxx.h", { "$(env PATH)", "$(reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\XXXX;Name)"})

如果路徑規(guī)則比較復(fù)雜多變,還可以通過自定義腳本來動態(tài)生成路徑傳入:

local file = find_file("xxx.h", { "$(env PATH)", function () return val("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\XXXX;Name"):match("\"(.-)\"") end})

大部分場合下,上面的使用已經(jīng)滿足各種需求了,如果還需要一些擴(kuò)展功能,可以通過傳入第三個(gè)參數(shù),自定義一些可選配置,例如:

local file = find_file("test.h", { "/usr", "/usr/local"}, {suffixes = {"/include", "/lib"}})

通過指定suffixes子目錄列表,可以擴(kuò)展路徑列表(第二個(gè)參數(shù)),使得實(shí)際的搜索目錄擴(kuò)展為:

/usr/include
/usr/lib
/usr/local/include
/usr/local/lib

并且不用改變路徑列表,就能動態(tài)切換子目錄來搜索文件。

<p class="tip"> 我們也可以通過xmake lua插件來快速調(diào)用和測試此接口:xmake lua lib.detect.find_file test.h /usr/local </p>

detect.find_path

  • 查找路徑

這個(gè)接口的用法跟lib.detect.find_file類似,唯一的區(qū)別是返回的結(jié)果不同。 此接口查找到傳入的文件路徑后,返回的是對應(yīng)的搜索路徑,而不是文件路徑本身,一般用于查找文件對應(yīng)的父目錄位置。

import("lib.detect.find_path")


local p = find_path("include/test.h", { "/usr", "/usr/local"})

上述代碼如果查找成功,則返回:/usr/local,如果test.h/usr/local/include/test.h的話。

還有一個(gè)區(qū)別就是,這個(gè)接口傳入不只是文件路徑,還可以傳入目錄路徑來查找:

local p = find_path("lib/xxx", { "$(env PATH)", "$(reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\XXXX;Name)"})

同樣,此接口也支持模式匹配和后綴子目錄:

local p = find_path("include/*.h", { "/usr", "/usr/local/**"}, {suffixes = "/subdir"})

detect.find_library

  • 查找?guī)煳募?/li>

此接口用于指定的搜索目錄中查找?guī)煳募o態(tài)庫,動態(tài)庫),例如:

import("lib.detect.find_library")


local library = find_library("crypto", {"/usr/lib", "/usr/local/lib"})

在macosx上運(yùn)行,返回的結(jié)果如下:

{
    filename = libcrypto.dylib
,   linkdir = /usr/lib
,   link = crypto
,   kind = shared
}

如果不指定是否需要靜態(tài)庫還是動態(tài)庫,那么此接口會自動選擇一個(gè)存在的庫(有可能是靜態(tài)庫、也有可能是動態(tài)庫)進(jìn)行返回。

如果需要強(qiáng)制指定需要查找的庫類型,可以指定kind參數(shù)為(static/shared):

local library = find_library("crypto", {"/usr/lib", "/usr/local/lib"}, {kind = "static"})

此接口也支持suffixes后綴子目錄搜索和模式匹配操作:

local library = find_library("cryp*", {"/usr", "/usr/local"}, {suffixes = "/lib"})

detect.find_program

  • 查找可執(zhí)行程序

這個(gè)接口比lib.detect.find_tool較為原始底層,通過指定的參數(shù)目錄來查找可執(zhí)行程序。

import("lib.detect.find_program")


local program = find_program("ccache")

上述代碼猶如沒有傳遞搜索目錄,所以它會嘗試直接執(zhí)行指定程序,如果運(yùn)行ok,那么直接返回:ccache,表示查找成功。

指定搜索目錄,修改嘗試運(yùn)行的檢測命令參數(shù)(默認(rèn)是:ccache --version):

local program = find_program("ccache", {"/usr/bin", "/usr/local/bin"}, "--help") 

上述代碼會嘗試運(yùn)行:/usr/bin/ccache --help,如果運(yùn)行成功,則返回:/usr/bin/ccache

如果--help也沒法滿足需求,有些程序沒有--version/--help參數(shù),那么可以自定義運(yùn)行腳本,來運(yùn)行檢測:

local program = find_program("ccache", {"/usr/bin", "/usr/local/bin"}, function (program) os.run("%s -h", program) end)

同樣,搜索路徑列表支持內(nèi)建變量和自定義腳本:

local program = find_program("ccache", {"$(env PATH)", "$(reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug;Debugger)"})
local program = find_program("ccache", {"$(env PATH)", function () return "/usr/local/bin" end})

<p class="tip"> 為了加速頻發(fā)查找的效率,此接口是默認(rèn)自帶cache的,所以就算頻繁查找相同的程序,也不會花太多時(shí)間。 如果要禁用cache,可以在工程目錄執(zhí)行xmake f -c清除本地cache。 </p>

我們也可以通過xmake lua lib.detect.find_program ccache 來快速測試。

detect.find_programver

  • 查找可執(zhí)行程序版本號

import("lib.detect.find_programver")


local programver = find_programver("ccache")

返回結(jié)果為:3.2.2

默認(rèn)它會通過ccache --version嘗試獲取版本,如果不存在此參數(shù),可以自己指定其他參數(shù):

local version = find_programver("ccache", "-v")

甚至自定義版本獲取腳本:

local version = find_programver("ccache", function () return os.iorun("ccache --version") end)

對于版本號的提取規(guī)則,如果內(nèi)置的匹配模式不滿足要求,也可以自定義:

local version = find_programver("ccache", "--version", "(%d+%.?%d*%.?%d*.-)%s")
local version = find_programver("ccache", "--version", function (output) return output:match("(%d+%.?%d*%.?%d*.-)%s") end)

<p class="tip"> 為了加速頻發(fā)查找的效率,此接口是默認(rèn)自帶cache的,如果要禁用cache,可以在工程目錄執(zhí)行xmake f -c清除本地cache。 </p>

我們也可以通過xmake lua lib.detect.find_programver ccache 來快速測試。

detect.find_package

  • 查找包文件

此接口也是用于查找?guī)煳募?,但是?a href="#detect-find_library">lib.detect.find_library更加上層,也更為強(qiáng)大和簡單易用,因?yàn)樗且园鼮榱Χ冗M(jìn)行查找。

那怎樣算是一個(gè)完整的包,它包含:

  1. 多個(gè)靜態(tài)庫或者動態(tài)庫文件
  2. 庫的搜索目錄
  3. 頭文件的搜索目錄
  4. 可選的編譯鏈接選項(xiàng),例如:defines
  5. 可選的版本號

例如我們查找一個(gè)openssl包:

import("lib.detect.find_package")


local package = find_package("openssl")

返回的結(jié)果如下:

{links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}}

如果查找成功,則返回一個(gè)包含所有包信息的table,如果失敗返回nil

這里的返回結(jié)果可以直接作為target:add, option:add的參數(shù)傳入,用于動態(tài)增加target/option的配置:

option("zlib")
    set_showmenu(true)
    before_check(function (option)
        import("lib.detect.find_package")
        option:add(find_package("zlib"))
    end)

target("test")
    on_load(function (target)
        import("lib.detect.find_package")
        target:add(find_package("zlib"))
    end)

如果系統(tǒng)上裝有homebrew, pkg-config等第三方工具,那么此接口會嘗試使用它們?nèi)ジ倪M(jìn)查找結(jié)果。

我們也可以通過指定版本號,來選擇查找指定版本的包(如果這個(gè)包獲取不到版本信息或者沒有匹配版本的包,則返回nil):

local package = find_package("openssl", {version = "1.0.1"})

默認(rèn)情況下查找的包是根據(jù)如下規(guī)則匹配平臺,架構(gòu)和模式的:

  1. 如果參數(shù)傳入指定了{plat = "iphoneos", arch = "arm64", mode = "release"},則優(yōu)先匹配,例如:find_package("openssl", {plat = "iphoneos"})。
  2. 如果是在當(dāng)前工程環(huán)境,存在配置文件,則優(yōu)先嘗試從config.get("plat"), config.get("arch")config.get("mode")獲取平臺架構(gòu)進(jìn)行匹配。
  3. 最后從os.host()os.arch()中進(jìn)行匹配,也就是當(dāng)前主機(jī)的平臺架構(gòu)環(huán)境。

如果系統(tǒng)的庫目錄以及pkg-config都不能滿足需求,找不到包,那么可以自己手動設(shè)置搜索路徑:

local package = find_package("openssl", {linkdirs = {"/usr/lib", "/usr/local/lib"}, includedirs = "/usr/local/include"})

也可以同時(shí)指定需要搜索的鏈接名,頭文件名:

local package = find_package("openssl", {links = {"ssl", "crypto"}, includes = "ssl.h"}})

甚至可以指定xmake的packagedir/*.pkg包目錄,用于查找對應(yīng)的openssl.pkg包,一般用于查找內(nèi)置在工程目錄中的本地包。

例如,tbox工程內(nèi)置了pkg/openssl.pkg本地包載項(xiàng)目中,我們可以通過下面的腳本,傳入{packagedirs = ""}參數(shù)優(yōu)先查找本地包,如果找不到再去找系統(tǒng)包。

target("test")
    on_load(function (target)
        import("lib.detect.find_package")
        target:add(find_package("openssl", {packagedirs = path.join(os.projectdir(), "pkg")}))
    end)

總結(jié)下,現(xiàn)在的查找順序:

  1. 如果指定{packagedirs = ""}參數(shù),優(yōu)先從這個(gè)參數(shù)指定的路徑中查找本地包*.pkg
  2. 如果在xmake/modules下面存在detect.packages.find_xxx腳本,那么嘗試調(diào)用此腳本來改進(jìn)查找結(jié)果
  3. 如果系統(tǒng)存在pkg-config,并且查找的是系統(tǒng)環(huán)境的庫,則嘗試使用pkg-config提供的路徑和鏈接信息進(jìn)行查找
  4. 如果系統(tǒng)存在homebrew,并且查找的是系統(tǒng)環(huán)境的庫,則嘗試使用brew --prefix xxx提供的信息進(jìn)行查找
  5. 從參數(shù)中指定的pathes路徑和一些已知的系統(tǒng)路徑/usr/lib, /usr/include中進(jìn)行查找

這里需要著重說下第二點(diǎn),通過在detect.packages.find_xxx腳本來改進(jìn)查找結(jié)果,很多時(shí)候自動的包探測是沒法完全探測到包路徑的, 尤其是針對windows平臺,沒有默認(rèn)的庫目錄,也沒有包管理app,很多庫裝的時(shí)候,都是自己所處放置在系統(tǒng)目錄,或者添加注冊表項(xiàng)。

因此查找起來沒有同意的規(guī)則,這個(gè)時(shí)候,就可以自定義一個(gè)查找腳本,去改進(jìn)find_package的查找機(jī)制,對指定包進(jìn)行更精準(zhǔn)的查找。

在xmake自帶的xmake/modules/detect/packages目錄下,已經(jīng)有許多的內(nèi)置包腳本,來對常用的包進(jìn)行更好的查找支持。 當(dāng)然這不可能滿足所有用戶的需求,如果用戶需要的包還是找不到,那么可以自己定義一個(gè)查找腳本,例如:

查找一個(gè)名為openssl的包,可以編寫一個(gè)find_openssl.lua的腳本放置在工程目錄:

projectdir
 - xmake
   - modules
     - detect/package/find_openssl.lua

然后在工程的xmake.lua文件的開頭指定下這個(gè)modules的目錄:

add_moduledirs("$(projectdir)/xmake/modules")

這樣xmake就能找到自定義的擴(kuò)展模塊了。

接下來我們看下find_openssl.lua的實(shí)現(xiàn):

-- imports
import("lib.detect.find_path")
import("lib.detect.find_library")


-- find openssl 
--
-- @param opt   the package options. e.g. see the options of find_package()
--
-- @return      see the return value of find_package()
--
function main(opt)


    -- for windows platform
    --
    -- http://www.slproweb.com/products/Win32OpenSSL.html
    --
    if opt.plat == "windows" then


        -- init bits
        local bits = ifelse(opt.arch == "x64", "64", "32")


        -- init search pathes
        local pathes = {"$(reg HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL %(" .. bits .. "-bit%)_is1;Inno Setup: App Path)",
                        "$(env PROGRAMFILES)/OpenSSL",
                        "$(env PROGRAMFILES)/OpenSSL-Win" .. bits,
                        "C:/OpenSSL",
                        "C:/OpenSSL-Win" .. bits}


        -- find library
        local result = {links = {}, linkdirs = {}, includedirs = {}}
        for _, name in ipairs({"libssl", "libcrypto"}) do
            local linkinfo = find_library(name, pathes, {suffixes = "lib"})
            if linkinfo then
                table.insert(result.links, linkinfo.link)
                table.insert(result.linkdirs, linkinfo.linkdir)
            end
        end


        -- not found?
        if #result.links ~= 2 then
            return 
        end


        -- find include
        table.insert(result.includedirs, find_path("openssl/ssl.h", pathes, {suffixes = "include"}))


        -- ok
        return result
    end
end

里面對windows平臺進(jìn)行注冊表讀取,去查找指定的庫文件,其底層其實(shí)也是調(diào)用的find_library等接口。

<p class="tip"> 為了加速頻發(fā)查找的效率,此接口是默認(rèn)自帶cache的,如果要禁用cache,可以在工程目錄執(zhí)行xmake f -c清除本地cache。 也可以通過指定force參數(shù),來禁用cache,強(qiáng)制重新查找:find_package("openssl", {force = true}) </p>

我們也可以通過xmake lua lib.detect.find_package openssl 來快速測試。

detect.find_tool

  • 查找工具

此接口也是用于查找可執(zhí)行程序,不過比lib.detect.find_program更加的高級,功能也更加強(qiáng)大,它對可執(zhí)行程序進(jìn)行了封裝,提供了工具這個(gè)概念:

  • toolname: 工具名,可執(zhí)行程序的簡稱,用于標(biāo)示某個(gè)工具,例如:gcc, clang
  • program: 可執(zhí)行程序命令,例如:xcrun -sdk macosx clang

其對應(yīng)關(guān)系如下:

toolname program
clang xcrun -sdk macosx clang
gcc /usr/toolchains/bin/arm-linux-gcc
link link.exe -lib

lib.detect.find_program只能通過傳入的原始program命令或路徑,去判斷該程序是否存在。 而find_tool則可以通過更加一致的toolname去查找工具,并且返回對應(yīng)的program完整命令路徑,例如:

import("lib.detect.find_tool")


local tool = find_tool("clang")

返回的結(jié)果為:{name = "clang", program = "clang"},這個(gè)時(shí)候還看不出區(qū)別,我們可以手動指定可執(zhí)行的命令:

local tool = find_tool("clang", {program = "xcrun -sdk macosx clang"})

返回的結(jié)果為:{name = "clang", program = "xcrun -sdk macosx clang"}

而在macosx下,gcc就是clang,如果我們執(zhí)行gcc --version可以看到就是clang的一個(gè)馬甲,我們可以通過find_tool接口進(jìn)行智能識別:

local tool = find_tool("gcc")

返回的結(jié)果為:{name = "clang", program = "gcc"}

通過這個(gè)結(jié)果就可以看的區(qū)別來了,工具名實(shí)際會被標(biāo)示為clang,但是可執(zhí)行的命令用的是gcc。

我們也可以指定{version = true}參數(shù)去獲取工具的版本,并且指定一個(gè)自定義的搜索路徑,也支持內(nèi)建變量和自定義腳本哦:

local tool = find_tool("clang", {version = true, {pathes = {"/usr/bin", "/usr/local/bin", "$(env PATH)", function () return "/usr/xxx/bin" end}})

返回的結(jié)果為:{name = "clang", program = "/usr/bin/clang", version = "4.0"}

這個(gè)接口是對find_program的上層封裝,因此也支持自定義腳本檢測:

local tool = find_tool("clang", {check = "--help"}) 
local tool = find_tool("clang", {check = function (tool) os.run("%s -h", tool) end})

最后總結(jié)下,find_tool的查找流程:

  1. 優(yōu)先通過{program = "xxx"}的參數(shù)來嘗試運(yùn)行和檢測。
  2. 如果在xmake/modules/detect/tools下存在detect.tools.find_xxx腳本,則調(diào)用此腳本進(jìn)行更加精準(zhǔn)的檢測。
  3. 嘗試從/usr/bin,/usr/local/bin等系統(tǒng)目錄進(jìn)行檢測。

我們也可以在工程xmake.luaadd_moduledirs指定的模塊目錄中,添加自定義查找腳本,來改進(jìn)檢測機(jī)制:

projectdir
  - xmake/modules
    - detect/tools/find_xxx.lua

例如我們自定義一個(gè)find_7z.lua的查找腳本:

import("lib.detect.find_program")
import("lib.detect.find_programver")


function main(opt)


    -- init options
    opt = opt or {}


    -- find program
    local program = find_program(opt.program or "7z", opt.pathes, opt.check or "--help")


    -- find program version
    local version = nil
    if program and opt and opt.version then
        version = find_programver(program, "--help", "(%d+%.?%d*)%s")
    end


    -- ok?
    return program, version
end

將它放置到工程的模塊目錄下后,執(zhí)行:xmake l lib.detect.find_tool 7z就可以查找到了。

<p class="tip"> 為了加速頻發(fā)查找的效率,此接口是默認(rèn)自帶cache的,如果要禁用cache,可以在工程目錄執(zhí)行xmake f -c清除本地cache。 </p>

我們也可以通過xmake lua lib.detect.find_tool clang 來快速測試。

detect.find_toolname

  • 查找工具名

通過program命令匹配對應(yīng)的工具名,例如:

program toolname
xcrun -sdk macosx clang clang
/usr/bin/arm-linux-gcc gcc
link.exe -lib link
gcc-5 gcc
arm-android-clang++ clangxx
pkg-config pkg_config

toolname相比program,更能唯一標(biāo)示某個(gè)工具,也方便查找和加載對應(yīng)的腳本find_xxx.lua。

detect.features

  • 獲取指定工具的所有特性

此接口跟compiler.features類似,區(qū)別就是此接口更加的原始,傳入的參數(shù)是實(shí)際的工具名toolname。

并且此接口不僅能夠獲取編譯器的特性,任何工具的特性都可以獲取,因此更加通用。

import("lib.detect.features")


local features = features("clang")
local features = features("clang", {flags = "-O0", program = "xcrun -sdk macosx clang"})
local features = features("clang", {flags = {"-g", "-O0", "-std=c++11"}})

通過傳入flags,可以改變特性的獲取結(jié)果,例如一些c++11的特性,默認(rèn)情況下獲取不到,通過啟用-std=c++11后,就可以獲取到了。

所有編譯器的特性列表,可以見:compiler.features。

detect.has_features

  • 判斷指定特性是否支持

此接口跟compiler.has_features類似,但是更加原始,傳入的參數(shù)是實(shí)際的工具名toolname。

并且此接口不僅能夠判斷編譯器的特性,任何工具的特性都可以判斷,因此更加通用。

import("lib.detect.has_features")


local features = has_features("clang", "cxx_constexpr")
local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = {"-g", "-O0"}, program = "xcrun -sdk macosx clang"})
local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = "-g"})

如果指定的特性列表存在,則返回實(shí)際支持的特性子列表,如果都不支持,則返回nil,我們也可以通過指定flags去改變特性的獲取規(guī)則。

所有編譯器的特性列表,可以見:compiler.features。

detect.has_flags

  • 判斷指定參數(shù)選項(xiàng)是否支持

此接口跟compiler.has_flags類似,但是更加原始,傳入的參數(shù)是實(shí)際的工具名toolname。

import("lib.detect.has_flags")


local ok = has_flags("clang", "-g")
local ok = has_flags("clang", {"-g", "-O0"}, {program = "xcrun -sdk macosx clang"})
local ok = has_flags("clang", "-g -O0", {toolkind = "cxx"})

如果檢測通過,則返回true。

此接口的檢測做了一些優(yōu)化,除了cache機(jī)制外,大部分場合下,會去拉取工具的選項(xiàng)列表(--help)直接判斷,如果選項(xiàng)列表里獲取不到的話,才會通過嘗試運(yùn)行的方式來檢測。

detect.has_cfuncs

  • 判斷指定c函數(shù)是否存在

此接口是lib.detect.check_cxsnippets的簡化版本,僅用于檢測函數(shù)。

import("lib.detect.has_cfuncs")


local ok = has_cfuncs("setjmp")
local ok = has_cfuncs({"sigsetjmp((void*)0, 0)", "setjmp"}, {includes = "setjmp.h"})

對于函數(shù)的描述規(guī)則如下:

函數(shù)描述 說明
sigsetjmp 純函數(shù)名
sigsetjmp((void*)0, 0) 函數(shù)調(diào)用
sigsetjmp{int a = 0; sigsetjmp((void*)a, a);} 函數(shù)名 + {}塊

在最后的可選參數(shù)中,除了可以指定includes外,還可以指定其他的一些參數(shù)用于控制編譯檢測的選項(xiàng)條件:

{ verbose = false, target = [target|option], includes = .., config = {linkdirs = .., links = .., defines = ..}}

其中verbose用于回顯檢測信息,target用于在檢測前追加target中的配置信息, 而config用于自定義配置跟target相關(guān)的編譯選項(xiàng)。

detect.has_cxxfuncs

  • 判斷指定c++函數(shù)是否存在

此接口跟lib.detect.has_cfuncs類似,請直接參考它的使用說明,唯一區(qū)別是這個(gè)接口用于檢測c++函數(shù)。

detect.has_cincludes

  • 判斷指定c頭文件是否存在

此接口是lib.detect.check_cxsnippets的簡化版本,僅用于檢測頭文件。

import("lib.detect.has_cincludes")


local ok = has_cincludes("stdio.h")
local ok = has_cincludes({"stdio.h", "stdlib.h"}, {target = target})
local ok = has_cincludes({"stdio.h", "stdlib.h"}, {config = {defines = "_GNU_SOURCE=1", languages = "cxx11"}})

detect.has_cxxincludes

  • 判斷指定c++頭文件是否存在

此接口跟lib.detect.has_cincludess類似,請直接參考它的使用說明,唯一區(qū)別是這個(gè)接口用于檢測c++頭文件。

detect.has_ctypes

  • 判斷指定c類型是否存在

此接口是lib.detect.check_cxsnippets的簡化版本,僅用于檢測函數(shù)。

import("lib.detect.has_ctypes")


local ok = has_ctypes("wchar_t")
local ok = has_ctypes({"char", "wchar_t"}, {includes = "stdio.h"})
local ok = has_ctypes("wchar_t", {includes = {"stdio.h", "stdlib.h"}, config = {"defines = "_GNU_SOURCE=1", languages = "cxx11"}})

detect.has_cxxtypes

  • 判斷指定c++類型是否存在

此接口跟lib.detect.has_ctypess類似,請直接參考它的使用說明,唯一區(qū)別是這個(gè)接口用于檢測c++類型。

detect.check_cxsnippets

  • 檢測c/c++代碼片段是否能夠編譯通過

通用的c/c++代碼片段檢測接口,通過傳入多個(gè)代碼片段列表,它會自動生成一個(gè)編譯文件,然后常識對它進(jìn)行編譯,如果編譯通過返回true。

對于一些復(fù)雜的編譯器特性,連compiler.has_features都無法檢測到的時(shí)候,可以通過此接口通過嘗試編譯來檢測它。

import("lib.detect.check_cxsnippets")


local ok = check_cxsnippets("void test() {}")
local ok = check_cxsnippets({"void test(){}", "#define TEST 1"}, {types = "wchar_t", includes = "stdio.h"})

此接口是detect.has_cfuncs, detect.has_cincludesdetect.has_ctypes等接口的通用版本,也更加底層。

因此我們可以用它來檢測:types, functions, includes 還有 links,或者是組合起來一起檢測。

第一個(gè)參數(shù)為代碼片段列表,一般用于一些自定義特性的檢測,如果為空,則可以僅僅檢測可選參數(shù)中條件,例如:

local ok = check_cxsnippets({}, {types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}})

上面那個(gè)調(diào)用,會去同時(shí)檢測types, includes和funcs是否都滿足,如果通過返回true。

還有其他一些可選參數(shù):

{ verbose = false, target = [target|option], sourcekind = "[cc|cxx]"}

其中verbose用于回顯檢測信息,target用于在檢測前追加target中的配置信息, sourcekind 用于指定編譯器等工具類型,例如傳入cxx強(qiáng)制作為c++代碼來檢測。

net.http

此模塊提供http的各種操作支持,目前提供的接口如下:

接口 描述 支持版本
http.download 下載http文件 >= 2.1.5

http.download

  • 下載http文件

這個(gè)接口比較簡單,就是單純的下載文件。

import("net.http")


http.download("http://xmake.io", "/tmp/index.html")

privilege.sudo

此接口用于通過sudo來運(yùn)行命令,并且提供了平臺一致性處理,對于一些需要root權(quán)限運(yùn)行的腳本,可以使用此接口。

<p class="warning"> 為了保證安全性,除非必須使用的場合,其他情況下盡量不要使用此接口。 </p>

接口 描述 支持版本
sudo.has 判斷sudo是否支持 >= 2.1.5
sudo.run 安靜運(yùn)行程序 >= 2.1.5
sudo.runv 安靜運(yùn)行程序,帶參數(shù)列表 >= 2.1.5
sudo.exec 回顯運(yùn)行程序 >= 2.1.5
sudo.execv 回顯運(yùn)行程序,帶參數(shù)列表 >= 2.1.5
sudo.iorun 運(yùn)行并獲取程序輸出內(nèi)容 >= 2.1.5
sudo.iorunv 運(yùn)行并獲取程序輸出內(nèi)容,帶參數(shù)列表 >= 2.1.5

sudo.has

  • 判斷sudo是否支持

目前僅在macosx/linux下支持sudo,windows上的管理員權(quán)限運(yùn)行暫時(shí)還不支持,因此建議使用前可以通過此接口判斷支持情況后,針對性處理。

import("privilege.sudo")


if sudo.has() then
    sudo.run("rm /system/file")
end

sudo.run

  • 安靜運(yùn)行原生shell命令

具體用法可參考:os.run。

import("privilege.sudo")


sudo.run("rm /system/file")

sudo.runv

  • 安靜運(yùn)行原生shell命令,帶參數(shù)列表

具體用法可參考:os.runv。

sudo.exec

  • 回顯運(yùn)行原生shell命令

具體用法可參考:os.exec

sudo.execv

  • 回顯運(yùn)行原生shell命令,帶參數(shù)列表

具體用法可參考:os.execv

sudo.iorun

  • 安靜運(yùn)行原生shell命令并獲取輸出內(nèi)容

具體用法可參考:os.iorun。

sudo.iorunv

  • 安靜運(yùn)行原生shell命令并獲取輸出內(nèi)容,帶參數(shù)列表

具體用法可參考:os.iorunv

devel.git

此接口提供了git各種命令的訪問接口,相對于直接調(diào)用git命令,此模塊提供了更加上層易用的封裝接口,并且提供對git的自動檢測和跨平臺處理。

<p class="tip"> 目前windows上,需要手動安裝git包后,才能檢測到,后續(xù)版本會提供自動集成git功能,用戶將不用關(guān)心如何安裝git,就可以直接使用。 </p>

接口 描述 支持版本
git.clone clone代碼庫 >= 2.1.5
git.pull 拉取代碼庫最新提交 >= 2.1.5
git.clean 清理代碼庫文件 >= 2.1.5
git.checkout 簽出指定分支版本 >= 2.1.5
git.refs 獲取所有引用列表 >= 2.1.5
git.tags 獲取所有標(biāo)記列表 >= 2.1.5
git.branches 獲取所有分支列表 >= 2.1.5

git.clone

  • clone代碼庫

此接口對應(yīng)git clone命令

import("devel.git")

 
git.clone("git@github.com:tboox/xmake.git")
git.clone("git@github.com:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})

git.pull

  • 拉取代碼庫最新提交

此接口對應(yīng)git pull命令

import("devel.git")

 
git.pull()
git.pull({remote = "origin", tags = true, branch = "master", repodir = "/tmp/xmake"})

git.clean

  • 清理代碼庫文件

此接口對應(yīng)git clean命令

import("devel.git")

 
git.clean()
git.clean({repodir = "/tmp/xmake", force = true})

git.checkout

  • 簽出指定分支版本

此接口對應(yīng)git checkout命令

import("devel.git")

 
git.checkout("master", {repodir = "/tmp/xmake"})
git.checkout("v1.0.1", {repodir = "/tmp/xmake"})

git.refs

  • 獲取所有引用列表

此接口對應(yīng)git ls-remote --refs命令

import("devel.git")

 
local refs = git.refs(url)

git.tags

  • 獲取所有標(biāo)記列表

此接口對應(yīng)git ls-remote --tags命令

import("devel.git")

 
local tags = git.tags(url)

git.branches

  • 獲取所有分支列表

此接口對應(yīng)git ls-remote --heads命令

import("devel.git")

 
local branches = git.branches(url)

utils.archive

此模塊用于壓縮和解壓縮文件。

接口 描述 支持版本
archive.extract 解壓文件 >= 2.1.5

archive.extract

  • 解壓文件

支持大部分常用壓縮文件的解壓,它會自動檢測系統(tǒng)提供了哪些解壓工具,然后適配到最合適的解壓器對指定壓縮文件進(jìn)行解壓操作。

import("utils.archive")


archive.extract("/tmp/a.zip", "/tmp/outputdir")
archive.extract("/tmp/a.7z", "/tmp/outputdir")
archive.extract("/tmp/a.gzip", "/tmp/outputdir")
archive.extract("/tmp/a.tar.bz2", "/tmp/outputdir")
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號