跳转到内容

分发包

定义包配置

仓库包结构

在制作自己的包之前,我们需要先了解下一个包仓库的结构,不管是官方包仓库,还是自建私有包仓库,结构都是相同的:

xmake-repo
  - packages
    - t/tbox/xmake.lua
    - z/zlib/xmake.lua

通过上面的结构,可以看到每个包都会有个xmake.lua用于描述它的安装规则,并且根据z/zlib两级子目录分类存储,方便快速检索。

包描述说明

关于包的描述规则,基本上都是在它的xmake.lua里面完成的,这跟项目工程里面的xmake.lua描述很类似,不同的是描述域仅支持package()

不过,在项目xmake.lua里面,也是可以直接添加package()来内置包描述的,连包仓库都省了,有时候这样会更加方便。

首先,我们先拿zlib的描述规则,来直观感受下,这个规则可以在xmake-repo/z/zlib/xmake.lua下找到。

package("zlib")

    set_homepage("http://www.zlib.net")
    set_description("A Massively Spiffy Yet Delicately Unobtrusive Compression Library")

    set_urls("http://zlib.net/zlib-$(version).tar.gz",
             "https://downloads.sourceforge.net/project/libpng/zlib/$(version)/zlib-$(version).tar.gz")

    add_versions("1.2.10", "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017")
    add_versions("1.2.11", "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1")

    on_install("windows", function (package)
        io.gsub("win32/Makefile.msc", "%-MD", "-" .. package:config("vs_runtime"))
        os.vrun("nmake -f win32\\Makefile.msc zlib.lib")
        os.cp("zlib.lib", package:installdir("lib"))
        os.cp("*.h", package:installdir("include"))
    end)

    on_install("linux", "macosx", function (package)
        import("package.tools.autoconf").install(package, {"--static"})
    end)

    on_install("iphoneos", "android@linux,macosx", "mingw@linux,macosx", function (package)
        import("package.tools.autoconf").configure(package, {host = "", "--static"})
        io.gsub("Makefile", "\nAR=.-\n",      "\nAR=" .. (package:build_getenv("ar") or "") .. "\n")
        io.gsub("Makefile", "\nARFLAGS=.-\n", "\nARFLAGS=cr\n")
        io.gsub("Makefile", "\nRANLIB=.-\n",  "\nRANLIB=\n")
        os.vrun("make install -j4")
    end)

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

这个包规则对windows, linux, macosx, iphoneos,mingw等平台都添加了安装规则,基本上已经做到了全平台覆盖,甚至一些交叉编译平台,算是一个比较典型的例子了。

当然,有些包依赖源码实现力度,并不能完全跨平台,那么只需对它支持的平台设置安装规则即可。

更多详细的包配置 API 说明见:包接口文档

扩展配置参数

详情见:add_configs

内置配置参数

除了可以通过add_configs设置一些扩展的配置参数以外,xmake还提供了一些内置的配置参数,可以使用

启用调试包

lua
add_requires("xxx", {debug = true})

包描述里面必须有相关处理才能支持:

lua
on_install(function (package)
    local configs = {}
    if package:debug() then
        table.insert(configs, "--enable-debug")
    end
    import("package.tools.autoconf").install(package)
end)

设置msvc运行时库

lua
add_requires("xxx", {configs = {vs_runtime = "MT"}})

通常情况下,通过import("package.tools.autoconf").install等内置工具脚本安装的包,内部都对vs_runtime自动处理过了。

但是如果是一些特殊的源码包,构建规则比较特殊,那么需要自己处理了:

lua
on_install(function (package)
    io.gsub("build/Makefile.win32.common", "%-MD", "-" .. package:config("vs_runtime"))
end)

添加环境变量

对于一些库,里面也带了可执行的工具,如果需要在集成包的时候,使用上这些工具,那么也可以设置上对应PATH环境变量:

lua
package("luajit")
    on_load(function (package)
        if is_plat("windows") then
            package:addenv("PATH", "lib")
        end
        package:addenv("PATH", "bin")
    end)

而在项目工程中,只有通过add_packages集成对应的包后,对应的环境变量才会生效。

lua
add_requires("luajit")
target("test")
    set_kind("binary")
    add_packages("luajit")
    after_run(function (package)
        os.exec("luajit --version")
    end)

安装二进制包

xmake也是支持直接引用二进制版本包,直接安装使用,例如:

lua
if is_plat("windows") then
    set_urls("https://www.libsdl.org/release/SDL2-devel-$(version)-VC.zip")
    add_versions("2.0.8", "68505e1f7c16d8538e116405411205355a029dcf2df738dbbc768b2fe95d20fd")
end

on_install("windows", function (package)
    os.cp("include", package:installdir())
    os.cp("lib/$(arch)/*.lib", package:installdir("lib"))
    os.cp("lib/$(arch)/*.dll", package:installdir("lib"))
end)

本地测试

如果在本地xmake-repo仓库中,已经添加和制作好了新的包,可以在本地运行测试下,是否通过,如果测试通过,即可提交pr到官方仓库,请求merge。

我们可以执行下面的脚本进行测试指定包:

sh
cd xmake-repo
xmake l scripts/test.lua -v -D zlib

上面的命令,会强制重新下载和安装zlib包,测试整个安装流程是否ok,加上-v -D是为了可以看到完整详细的日志信息和出错信息,方便调试分析。

如果网络环境不好,不想每次测试都去重新下载所有依赖,可以加上--shallow参数来执行,这个参数告诉脚本,仅仅重新解压本地缓存的zlib源码包,重新执行安装命令,但不会下载各种依赖。

sh
cd xmake-repo
xmake l scripts/test.lua -v -D --shallow zlib

如果我们想测试其他平台的包规则是否正常,比如: android, iphoneos等平台,可以通过-p/--plat或者-a/--arch来指定。

sh
cd xmake-repo
xmake l scripts/test.lua -v -D --shallow -p iphoneos -a arm64 zlib
xmake l scripts/test.lua -v -D --shallow -p android --ndk=/xxxx zlib

生成远程包

除了本地包格式,xmake package 现在也支持生成远程包,便于用户将他们快速提交到远程仓库。

我们只需要在打包时候,修改包格式。

sh
$ xmake package -f remote
packages/f/foo/xmake.lua
lua
package("foo")
    set_description("The foo package")
    set_license("Apache-2.0")
    add_deps("add", "sub")

    add_urls("https://github.com/myrepo/foo.git")
    add_versions("1.0", "<shasum256 or gitcommit>")

    on_install(function (package)
        local configs = {}
        if package:config("shared") then
            configs.kind = "shared"
        end
        import("package.tools.xmake").install(package, configs)
    end)

    on_test(function (package)
        -- TODO check includes and interfaces
        -- assert(package:has_cfuncs("foo", {includes = "foo.h"})
    end)

包定义配置相比本地包,多了实际的安装逻辑,以及 urls 和 versions 的设置,

我们也能够通过附加参数,去修改 urls,versions 等配置值,例如:

sh
$ xmake package -f remote --url=https://xxxx/xxx.tar.gz --shasum=xxxxx --homepage=xxxxx`

xmake 也会从 target 的 set_licenseset_version 等配置中读取相关配置信息。

提交包到官方仓库

目前这个特性刚完成不久,目前官方仓库的包还不是很多,有些包也许还不支持部分平台,不过这并不是太大问题,后期迭代几个版本后,我会不断扩充完善包仓库。

如果你需要的包,当前的官方仓库还没有收录,可以提交issues或者自己可以在本地调通后,贡献提交到官方仓库:xmake-repo

详细的贡献说明,见:CONTRIBUTING.md

关于如何制作自己的包,可以看下上文:添加包到仓库

分发和使用自定义包规则

2.7.2 版本之后,我们可以在包管理仓库中,添加自定义构架规则脚本,实现跟随包进行动态下发和安装。

我们需要将自定义规则放到仓库的 packages/x/xxx/rules 目录中,它会跟随包一起被安装。

但是,它也存在一些限制:

  • 在包中规则,我们不能添加 on_load, after_load 脚本,但是通常我们可以使用 on_config 来代替。

添加包规则

我们需要将规则脚本添加到 rules 固定目录下,例如:packages/z/zlib/rules/foo.lua

lua
rule("foo")
    on_config(function (target)
        print("foo: on_config %s", target:name())
    end)

应用包规则

使用规则的方式跟之前类似,唯一的区别就是,我们需要通过 @packagename/ 前缀去指定访问哪个包里面的规则。

具体格式:add_rules("@packagename/rulename"),例如:add_rules("@zlib/foo")

lua
add_requires("zlib", {system = false})
target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("zlib")
    add_rules("@zlib/foo")

通过包别名引用规则

如果存在一个包的别名,xmake 将优先考虑包的别名来获得规则。

lua
add_requires("zlib", {alias = "zlib2", system = false})
target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("zlib2")
    add_rules("@zlib2/foo")

添加包规则依赖

我们可以使用add_deps("@bar")来添加相对于当前包目录的其他规则。

然而,我们不能添加来自其他包的规则依赖,它们是完全隔离的,我们只能参考用户项目中由add_requires导入的其他包的规则。

packages/z/zlib/rules/foo.lua

lua
rule("foo")
    add_deps("@bar")
    on_config(function (target)
        print("foo: on_config %s", target:name())
    end)

packages/z/zlib/rules/bar.lua

lua
rule("bar")
    on_config(function (target)
        print("bar: on_config %s", target:name())
    end)