XMake 插件開發(fā)

2018-10-12 19:52 更新

插件開發(fā)

簡介

XMake完全支持插件模式,我們可以很方便的擴展實現(xiàn)自己的插件,并且xmake也提供了一些內建的使用插件。

我們可以執(zhí)行下 xmake -h 看下當前支持的插件:

Plugins: 
    l, lua                                 Run the lua script.
    m, macro                               Run the given macro.
       doxygen                             Generate the doxygen document.
       hello                               Hello xmake!
       project                             Create the project file.

  • lua: 運行l(wèi)ua腳本的插件
  • macro: 這個很實用,宏腳本插件,可以手動錄制多條xmake命令并且回放,也可以通過腳本實現(xiàn)一些復雜的宏腳本,這個我們后續(xù)會更加詳細的介紹
  • doxygen:一鍵生成doxygen文檔的插件
  • hello: 插件demo,僅僅顯示一句話:'hello xmake!'
  • project: 生成工程文件的插件,目前僅支持(makefile),后續(xù)還會支持(vs,xcode等工程)的生成

快速開始

接下來我們介紹下本文的重點,一個簡單的hello xmake插件的開發(fā),代碼如下:

-- 定義一個名叫hello的插件任務
task("hello")


    -- 設置類型為插件
    set_category("plugin")


    -- 插件運行的入口
    on_run(function ()


        -- 顯示hello xmake!
        print("hello xmake!")


    end)


    -- 設置插件的命令行選項,這里沒有任何參數(shù)選項,僅僅顯示插件描述
    set_menu {
                -- usage
                usage = "xmake hello [options]"


                -- description
            ,   description = "Hello xmake!"


                -- options
            ,   options = {}
            } 

這個插件的文件結構如下:

hello
 - xmake.lua

現(xiàn)在一個最簡單的插件寫完了,那怎么讓它被xmake檢測到呢,有三種方式:

  1. 把 hello 這個文件夾放置在 xmake的插件安裝目錄 xmake/plugins,這個里面都是些內建的插件
  2. 把 hello 文件夾放置在 ~/.xmake/plugins 用戶全局目錄,這樣對當前xmake 全局生效
  3. 把 hello 文件夾放置在任意地方,通過在工程描述文件xmake.lua中調用add_plugindirs("./hello") 添加當前的工程的插件搜索目錄,這樣只對當前工程生效

運行插件

接下來,我們嘗試運行下這個插件:

xmake hello

顯示結果:

hello xmake!

最后我們還可以在target自定義的腳本中運行這個插件:

target("demo")

    
    -- 構建之后運行插件
    after_build(function (target)

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


        -- 運行插件任務
        task.run("hello")
    end)

內置插件

宏記錄和回放

簡介

我們可以通過這個插件,快速記錄和回放我們平常頻繁使用到的一些xmake操作,來簡化我們日常的開發(fā)工作。

它提供了一些功能:

  • 手動記錄和回放多條執(zhí)行過的xmake命令
  • 支持快速的匿名宏創(chuàng)建和回放
  • 支持命名宏的長久記錄和重用
  • 支持宏腳本的批量導入和導出
  • 支持宏腳本的刪除、顯示等管理功能
  • 支持自定義高級宏腳本,以及參數(shù)配置

記錄操作

## 開始記錄宏
$ xmake macro --begin


## 執(zhí)行一些xmake命令
$ xmake f -p android --ndk=/xxx/ndk -a armv7-a
$ xmake p
$ xmake f -p mingw --sdk=/mingwsdk
$ xmake p
$ xmake f -p linux --sdk=/toolsdk --toolchains=/xxxx/bin
$ xmake p
$ xmake f -p iphoneos -a armv7
$ xmake p
$ xmake f -p iphoneos -a arm64
$ xmake p
$ xmake f -p iphoneos -a armv7s
$ xmake p
$ xmake f -p iphoneos -a i386
$ xmake p
$ xmake f -p iphoneos -a x86_64
$ xmake p


## 結束宏記錄,這里不設置宏名字,所以記錄的是一個匿名宏
xmake macro --end 

回放

## 回放一個匿名宏
$ xmake macro .

命名宏

匿名宏的好處就是快速記錄,快速回放,如果需要長久保存,就需要給宏取個名字。

$ xmake macro --begin
$ ...
$ xmake macro --end macroname
$ xmake macro macroname

導入導出宏

導入指定的宏腳本或者宏目錄:

$ xmake macro --import=/xxx/macro.lua macroname
$ xmake macro --import=/xxx/macrodir

導出指定的宏到腳本或者目錄:

$ xmake macro --export=/xxx/macro.lua macroname
$ xmake macro --export=/xxx/macrodir

列舉顯示宏

列舉所有xmake內置的宏腳本:

$ xmake macro --list

顯示指定的宏腳本內容:

$ xmake macro --show macroname

自定義宏腳本

我們也可以自己編寫個宏腳本 macro.lua 然后導入到xmake中去。

function main()
    os.exec("xmake f -p android --ndk=/xxx/ndk -a armv7-a")
    os.exec("xmake p")
    os.exec("xmake f -p mingw --sdk=/mingwsdk")
    os.exec("xmake p")
    os.exec("xmake f -p linux --sdk=/toolsdk --toolchains=/xxxx/bin")
    os.exec("xmake p")
    os.exec("xmake f -p iphoneos -a armv7")
    os.exec("xmake p")
    os.exec("xmake f -p iphoneos -a arm64")
    os.exec("xmake p")
    os.exec("xmake f -p iphoneos -a armv7s")
    os.exec("xmake p")
    os.exec("xmake f -p iphoneos -a i386")
    os.exec("xmake p")
    os.exec("xmake f -p iphoneos -a x86_64")
    os.exec("xmake p")  
end

導入到xmake,并且定義宏名字:

$ xmake macro --import=/xxx/macro.lua [macroname]

回放這個宏腳本:

$ xmake macro [.|macroname]

內置的宏腳本

XMake 提供了一些內置的宏腳本,來簡化我們的日常開發(fā)工作。

例如,我們可以使用 package 宏來對iphoneos平臺的所有架構,一次性批量構建和打包:

$ xmake macro package -p iphoneos 

高級的宏腳本編寫

以上面提到的package宏為例,我們看下其具體代碼,里面通過import導入一些擴展模塊,實現(xiàn)了復雜的腳本操作。

-- imports
import("core.base.option")
import("core.project.config")
import("core.project.project")
import("core.platform.platform")


-- the options
local options =
{
    {'p', "plat",       "kv",  os.host(),   "Set the platform."                                    }
,   {'f', "config",     "kv",  nil,         "Pass the config arguments to \"xmake config\" .."     }
,   {'o', "outputdir",  "kv",  nil,         "Set the output directory of the package."             }
}


-- package all
--
-- .e.g
-- xmake m package 
-- xmake m package -f "-m debug"
-- xmake m package -p linux
-- xmake m package -p iphoneos -f "-m debug --xxx ..." -o /tmp/xxx
-- xmake m package -f \"--mode=debug\"
--
function main(argv)


    -- parse arguments
    local args = option.parse(argv, options, "Package all architectures for the given the platform."
                                           , ""
                                           , "Usage: xmake macro package [options]")


    -- package all archs
    local plat = args.plat
    for _, arch in ipairs(platform.archs(plat)) do


        -- config it
        os.exec("xmake f -p %s -a %s %s -c %s", plat, arch, args.config or "", ifelse(option.get("verbose"), "-v", ""))


        -- package it
        if args.outputdir then
            os.exec("xmake p -o %s %s", args.outputdir, ifelse(option.get("verbose"), "-v", ""))
        else
            os.exec("xmake p %s", ifelse(option.get("verbose"), "-v", ""))
        end
    end


    -- package universal for iphoneos, watchos ...
    if plat == "iphoneos" or plat == "watchos" then


        -- load configure
        config.load()


        -- load project
        project.load()


        -- enter the project directory
        os.cd(project.directory())


        -- the outputdir directory
        local outputdir = args.outputdir or config.get("buildir")


        -- package all targets
        for _, target in pairs(project.targets()) do


            -- get all modes
            local modedirs = os.match(format("%s/%s.pkg/lib/*", outputdir, target:name()), true)
            for _, modedir in ipairs(modedirs) do

                
                -- get mode
                local mode = path.basename(modedir)


                -- make lipo arguments
                local lipoargs = nil
                for _, arch in ipairs(platform.archs(plat)) do
                    local archfile = format("%s/%s.pkg/lib/%s/%s/%s/%s", outputdir, target:name(), mode, plat, arch, path.filename(target:targetfile())) 
                    if os.isfile(archfile) then
                        lipoargs = format("%s -arch %s %s", lipoargs or "", arch, archfile) 
                    end
                end
                if lipoargs then


                    -- make full lipo arguments
                    lipoargs = format("-create %s -output %s/%s.pkg/lib/%s/%s/universal/%s", lipoargs, outputdir, target:name(), mode, plat, path.filename(target:targetfile()))


                    -- make universal directory
                    os.mkdir(format("%s/%s.pkg/lib/%s/%s/universal", outputdir, target:name(), mode, plat))


                    -- package all archs
                    os.execv("xmake", {"l", "lipo", lipoargs})
                end
            end
        end
    end
end

<p class="tip"> 如果你想要獲取更多宏參數(shù)選項信息,請運行: xmake macro --help </p>

運行自定義lua腳本

這個跟宏腳本類似,只是省去了導入導出操作,直接指定lua腳本來加載運行,這對于想要快速測試一些接口模塊,驗證自己的某些思路,都是一個不錯的方式。

運行指定的腳本文件

我們先寫個簡單的lua腳本:

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

然后直接運行它就行了:

$ xmake lua /tmp/test.lua

<p class="tip"> 當然,你也可以像宏腳本那樣,使用import接口導入擴展模塊,實現(xiàn)復雜的功能。 </p>

運行內置的腳本命令

你可以運行 xmake lua -l 來列舉所有內置的腳本名,例如:

$ xmake lua -l
scripts:
    cat
    cp
    echo
    versioninfo
    ...

并且運行它們:

$ xmake lua cat ~/file.txt
$ xmake lua echo "hello xmake"
$ xmake lua cp /tmp/file /tmp/file2
$ xmake lua versioninfo

運行交互命令 (REPL)

有時候在交互模式下,運行命令更加的方便測試和驗證一些模塊和api,也更加的靈活,不需要再去額外寫一個腳本文件來加載。

我們先看下,如何進入交互模式:

## 不帶任何參數(shù)執(zhí)行,就可以進入
$ xmake lua
>


## 進行表達式計算
> 1 + 2
3


## 賦值和打印變量值
> a = 1
> a
1


## 多行輸入和執(zhí)行
> for _, v in pairs({1, 2, 3}) do
>> print(v)
>> end
1
2
3

我們也能夠通過 import 來導入擴展模塊:

> task = import("core.project.task")
> task.run("hello")
hello xmake!

如果要中途取消多行輸入,只需要輸入字符:q 就行了

> for _, v in ipairs({1, 2}) do
>> print(v)
>> q             <--  取消多行輸入,清空先前的輸入數(shù)據(jù)
> 1 + 2
3

生成IDE工程文件

簡介

XMake跟cmake, premake等其他一些構建工具的區(qū)別在于:

<p class="warning"> xmake默認是直接構建運行的,生成第三方的IDE的工程文件僅僅作為插件來提供。 </p>

這樣做的一個好處是:插件更加容易擴展,維護也更加獨立和方便。

生成Makefile

$ xmake project -k makefile

生成compiler_commands

導出每個源文件的編譯信息,生成基于clang的編譯數(shù)據(jù)庫文件,json格式,可用于跟ide,編輯器,靜態(tài)分析工具進行交互。

$ xmake project -k compile_commands

輸出的內容格式如下:

[
  { "directory": "/home/user/llvm/build",
    "command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc",
    "file": "file.cc" },
  ...
]

對于compile_commands的詳細說明見:JSONCompilationDatabase

生成VisualStudio工程

$ xmake project -k [vs2008|vs2013|vs2015|..]

v2.1.2以上版本,增強了vs201x版本工程的生成,支持多模式+多架構生成,生成的時候只需要指定:

$ xmake project -k vs2017 -m "debug,release"

生成后的工程文件,同時支持debug|x86, debug|x64, release|x86, release|x64四種配置模式。

如果不想每次生成的時候,指定模式,可以把模式配置加到xmake.lua的中,例如:

-- 配置當前的工程,支持哪些編譯模式
set_modes("debug", "release")

具體set_modes的使用,可以參考對應的接口手冊文檔。

生成doxygen文檔

請先確保本機已安裝doxygen工具,然后在工程目錄下運行:

$ xmake doxygen

更多插件

請到插件倉庫進行下載安裝: xmake-plugins.

從app生成ipa包

這僅僅是一個小插件,ios開發(fā)的同學,可能會用的到。

$ xmake app2ipa --icon=/xxx.png /xxx/ios.app -o /xxx.ios.ipa
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號