高级特性之自定义脚本使用
原文链接 https://waruqi.github.io/2016/06/09/custom-action.cn/
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
xmake提供了自定义打包、安装、运行脚本,可以更加灵活的针对个人实际需求来操作xmake
这里用一个例子详细说明下,比如有个需求,我需要自动编译、安装、运行android app工程,并且能够支持jni 可以进行如下操作
首先创建个基于ant的android app工程,目录结构如下:
app
└── android
├── AndroidManifest.xml
├── ant.properties
├── bin
│ └── Demo-debug.apk
├── build.xml
├── jni
│ └── demo.c
├── libs
│ └── armeabi
│ └── libdemo.so
├── local.properties
├── proguard-project.txt
├── project.properties
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ └── main.xml
│ └── values
│ └── strings.xml
├── src
│ └── com
│ └── demo
│ └── DemoTest.java
└── xmake.lua
新版本中对自定义脚本进行了重大升级,支持了task机制,以及类库import机制,写法上也更加的精简可读
我们可以对比下新老版本的自定义脚本写法,当然新版的xmake对这些老的api也是向下兼容的,如果还在使用老版本api,也是不影响使用的。。
我们重点讲解下新版的写法:
-- 定义一个android app的测试demo
target("demo")
-- 生成动态库:libdemo.so
set_kind("shared")
-- 设置对象的输出目录,可选
set_objectdir("$(buildir)/.objs")
-- 每次编译完的libdemo.so的生成目录,设置为app/libs/armeabi
set_targetdir("libs/armeabi")
-- 添加jni的代码文件
add_files("jni/*.c")
-- 设置自定义打包脚本,在使用xmake编译完libdemo.so后,执行xmake p进行打包
-- 会自动使用ant将app编译成apk文件
--
on_package(function (target)
-- trace
print("buiding app")
-- 使用ant编译app成apk文件,输出信息重定向到日志文件
os.run("ant debug")
end)
-- 设置自定义安装脚本,自动安装apk文件
on_install(function (target)
-- trace
print("installing app")
-- 使用adb安装打包生成的apk文件
os.run("adb install -r ./bin/Demo-debug.apk")
end)
-- 设置自定义运行脚本,自动运行安装好的app程序,并且自动获取设备输出信息
on_run(function (target)
-- run it
os.run("adb shell am start -n com.demo/com.demo.DemoTest")
os.run("adb logcat")
end)
修改完xmake.lua后,就可以很方便的使用了:
# 重新编译工程,生成libdemo.so到app/libs/armeabi
xmake -r
# 打包app为apk
xmake p
# 安装apk到设备上
xmake i
# 运行app,并获取日志信息
xmake r demo
如果觉得上面的步骤有点繁琐,可以简化成:
# 安装的时候,会先去自动打包,所以可以省略xmake p
xmake -r; xmake i; xmake r demo
如果是增量编译,不需要重建,可以继续简化:
xmake i; xmake r demo
当然,由于是根据自己的实际需求自定义的脚本,可能跨平台性有点弱,像这里只能支持android的编译平台,
我们继续重点说下新版本中这些的api的使用,xmake针对 构建、打包、清除、安装、卸载、运行都提供了对应的自定义脚本入口
下面的on_xxx接口会直接替换内置的实现
- on_build: 自定义构建脚本
- on_clean: 自定义清除脚本
- on_package: 自定义打包脚本
- on_install: 自定义安装脚本
- on_uninstall: 自定义卸载脚本
- on_run: 自定义运行脚本
下面的 before_xxx接口,会在on_xxx之前执行
- before_build: 在构建之前执行一些自定义脚本
- before_clean: 在清除之前执行一些自定义脚本
- before_package: 在打包之前执行一些自定义脚本
- before_install: 在安装之前执行一些自定义脚本
- before_uninstall: 在卸载之前执行一些自定义脚本
- before_run: 在运行之前执行一些自定义脚本
下面的 after_xxx接口,会在on_xxx之后执行
- after_build: 在构建之后执行一些自定义脚本
- after_clean: 在清除之后执行一些自定义脚本
- after_package: 在打包之后执行一些自定义脚本
- after_install: 在安装之后执行一些自定义脚本
- after_uninstall: 在卸载之后执行一些自定义脚本
- after_run: 在运行之后执行一些自定义脚本
这些api的原型都是:
function (target)
end
其中的参数就是当前的target,你可以从中获取一些基本信息,例如:
on_run(function (target)
-- 显示目标名
print(target:name())
-- 显示目标文件路径
print(target:targetfile())
-- 显示目标的构建类型
print(target:get("kind"))
-- 显示目标的宏定义
print(target:get("defines"))
-- 其他通过 set_/add_接口设置的target信息,都可以通过 target:get("xxx") 来获取
end)
自定义脚本中,其作用域和xmake.lua上层的描述域是不同的,xmake里面有严格的沙盒管理,不会导致互相冲突
而且自定义脚本内部提供了大量内建类库和扩展类库,以供使用,扩展类库可以通过 import 进行导入, 例如
on_run(function (target)
-- 导入工程类
import("core.project.project")
-- 获取当前工程目录
print(project.directory())
end)
详细的扩展类库使用,见 import
一些内建类库有:
- os: 系统类库
- string: 字符串类库
- path: 路径类库
- table: table和array处理
- io: 文件io处理
- coroutine: 协程类库
一些内建的api有:
- raise:引发异常
- try/catch/finally: 异常捕获处理
- print/printf:打印
- format: 格式化字符串
更多详细类库和内建api介绍,见后续介绍。。。