xmake集成了内置的远程包依赖管理

  xmake集成了内置的远程包依赖管理,用户只须要简单地在项目中添加本身所须要的包和版本,便可自动下载和集成对应的包到项目中,而且实现编译和连接。
  
  例如:
  
  add_requires("libuv master", "ffmpeg", "zlib 1.20.*")
  
  add_requires("tbox >1.6.1", {optional = true, debug = true})
  
  add_requires("boost", {alias = "boost_context", configs = {context = true}})
  
  target("test")
  
  set_kind("binary")
  
  add_files("src/*.c")
  
  add_packages("libuv", "ffmpeg", "tbox", "boost_context", "zlib")
  
  xmake的包仓库设计之初,就考虑到了语义版本支持,以及依赖包的跨平台支持,只要包自身能支持的平台,均可以集成进来,好比zlib包,在xmake中使用,iphoneos, android以及mingw平台下都是彻底可用的。
  
  用户只须要简单的切下构建平台:
  
  xmake f -p iphoneos -a arm64
  
  xmake
  
  note: try installing these packages (pass -y to skip confirm)?
  
  in xmake-repo:
  
  -> zlib 1.2.11
  
  please input: y (y/n)
  
  => download https://www.xcdeyiju.com  downloads.sourceforge.net/project/libpng/zlib/1.2.11/zlib-1.2.11.tar.gz .. ok
  
  => install zlib 1.2.11 .. ok
  
  就能够对iphoneos平台下载集成add_requires中对应的包,xmake的最终目标,是打造一个跨平台的包仓库,用户再也不须要满地找c/c++库,而后研究各类平台的移植,只须要简单的添加上包依赖,便可在各个平台都能方便使用。
  
  固然了,目前xmake的官方仓库还在发展初期,里面的包还不多,支持的平台也不是很完善,所以,这里我简单介绍下用户如何去本身制做和上传本身须要的c/c++包,并如何提交到咱们的仓库中(也能够自建私有仓库), 但愿有兴趣的小伙伴能够帮忙贡献一份微薄之力,一块儿共同打造和创建c/c++依赖包生态。
  
  项目源码
  
  官方文档
  
  添加包到仓库
  
  仓库包结构
  
  在制做本身的包以前,咱们须要先了解下一个包仓库的结构,不论是官方包仓库,仍是自建私有包仓库,结构都是相同的:
  
  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.chengmingdl.com ")
  
  set_description("A Massively Spiffy Yet Delicately Unobtrusive Compression Library")
  
  set_urls(http://www.senta7.net/content/?729.html,
  
  "https://www.yuechaoyule.com  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"www.seocelve.com, 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"www.csyldl.com).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",www.baiyiyulgw.com {includes = "zlib.h"}))
  
  end)
  
  这个包规则对windows, linux, macosx, iphoneos,mingw等平台都添加了安装规则,基本上已经作到了全平台覆盖,甚至一些交叉编译平台,算是一个比较典型的例子了。
  
  固然,有些包依赖源码实现力度,并不能彻底跨平台,那么只需对它支持的平台设置安装规则便可。
  
  set_homepage
  
  设置包所在项目的官方页面地址。
  
  set_description
  
  设置包的相关描述信息,通常经过xmake require --info zlib查看相关包信息时候,会看到。
  
  set_kind
  
  设置包类型,对于依赖库,则不用设置,若是是可执行包,须要设置为binary。
  
  package("cmake")
  
  set_kind("binary")
  
  set_homepage("https://cmake.org")
  
  set_description("A cross-platform family of tool designed to build, test and package software")
  
  set_urls
  
  设置包的源码包或者git仓库地址,跟add_urls不一样的是,此接口是覆盖性设置,而add_urls是追加设置,其余使用方式相似,这个根据不一样须要来选择。
  
  add_urls
  
  添加包的源码包或者git仓库地址,此接口通常跟add_version配对使用,用于设置每一个源码包的版本和对应的sha256值。
  
  !> 能够经过添加多个urls做为镜像源,xmake会自动检测优先选用最快的url进行下载,若是下载失败则会尝试其余urls。
  
  add_urls("https://github.com/protobuf-c/protobuf-c/releases/download/v$(version)/protobuf-c-$(version).tar.gz")
  
  add_versions("1.3.1", "51472d3a191d6d7b425e32b612e477c06f73fe23e07f6a6a839b11808e9d2267")
  
  urls里面的$(version)内置变量,会根据实际安装时候选择的版本适配进去,而版本号都是从add_versions中指定的版本列表中选择的。
  
  若是对于urls里面带有比较复杂的版本串,没有跟add_versions有直接对应关系,则须要经过下面的方式定制化转换下:
  
  add_urls("https://sqlite.org/2018/sqlite-autoconf-$(version)000.tar.gz",
  
  {version = function (version) return version:gsub("%.", "") end})
  
  add_versions("3.24.0", "d9d14e88c6fb6d68de9ca0d1f9797477d82fc3aed613558f87ffbdbbc5ceb74a")
  
  add_versions("3.23.0", "b7711a1800a071674c2bf76898ae8584fc6c9643cfe933cfc1bc54361e3a6e49")
  
  固然,咱们也只能够添加git源码地址:
  
  add_urls("https://gitlab.gnome.org/GNOME/libxml2.git")
  
  若是设置的多个镜像地址对应的源码包sha256是不一样的,咱们能够经过alias的方式来分别设置
  
  add_urls("https://ffmpeg.org/releases/ffmpeg-$(version).tar.bz2", {alias = "home"})
  
  add_urls("https://github.com/FFmpeg/FFmpeg/archive/n$(version).zip", {alias = "github"})
  
  add_versions("home:4.0.2", "346c51735f42c37e0712e0b3d2f6476c86ac15863e4445d9e823fe396420d056")
  
  add_versions("github:4.0.2", "4df1ef0bf73b7148caea1270539ef7bd06607e0ea8aa2fbf1bb34062a097f026")
  
  add_versions
  
  用于设置每一个源码包的版本和对应的sha256值,具体描述见:add_urls
  
  add_patches
  
  此接口用于针对源码包,在编译安装前,先打对应设置的补丁包,再对其进行编译,而且可支持同时打多个补丁。
  
  if is_plat("macosx") then
  
  add_patches("1.15", "https://www.yacuangyl.com raw.githubusercontent.com/Homebrew/patches/9be2793af/libiconv/patch-utf8mac.diff",
  
  "e8128732f22f63b5c656659786d2cf76f1450008f36bcf541285268c66cabeab")
  
  end
  
  例如,上面的代码,就是针对macosx下编译的时候,打上对应的patch-utf8mac.diff补丁,而且每一个补丁后面也是要设置sha256值的,确保完整性。
  
  add_links
  
  默认状况下,xmake会去自动检测安装后的库,设置连接关系,可是有时候并非很准,若是要本身手动调整连接顺序,以及连接名,则能够经过这个接口来设置。
  
  add_links("mbedtls", "mbedx509", "mbedcrypto")
  
  add_syslinks
  
  添加一些系统库连接,有些包集成连接的时候,还须要依赖一些系统库,才能连接经过,这个时候能够在包描述里面都附加上去。
  
  if is_plat("macosx") then
  
  add_frameworks("CoreGraphics", "CoreFoundation", "Foundation")
  
  elseif is_plat("windows") then
  
  add_defines("CAIRO_WIN32_STATIC_BUILD=1")
  
  add_syslinks("gdi32", "msimg32", "user32")
  
  else
  
  add_syslinks("pthread")
  
  end
  
  add_frameworks
  
  添加依赖的系统frameworks连接。
  
  示例见:add_syslinks
  
  add_linkdirs
  
  包的连接库搜索目录也是能够调整的,不过一般都不须要,除非一些库安装完不在prefix/lib下面,而在lib的子目录下,默认搜索不到的话。
  
  add_includedirs
  
  添加其余头文件搜索目录。
  
  add_defines
  
  能够对集成的包对外输出一些特定的定义选项。
  
  add_configs
  
  咱们能够经过此接口添加每一个包的对外输出配置参数:
  
  package("pcre2")
  
  set_homepage("https://www.pcre.org/")
  
  set_description("A Perl Compatible Regular Expressions Library")
  
  add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}})
  
  on_load(function (package)
  
  local bitwidth = package:config("bitwidth") or "8"
  
  package:add("links", "pcre2-" .. bitwidth)
  
  package:add("defines", "PCRE2_CODE_UNIT_WIDTH=" .. bitwidth)
  
  end)
  
  在工程项目里面,咱们也能够查看特定包的可配置参数和值列表:
  
  $ xmake require --info pcre2
  
  The package info of project:
  
  require(pcre2):
  
  -> description: A Perl Compatible Regular Expressions Library
  
  -> version: 10.31
  
  ...
  
  -> configs:
  
  -> bitwidth:
  
  -> description: Set the code unit width.
  
  -> values: {"8","16","32"}
  
  -> default: 8
  
  而后在项目里面,启用这些配置,编译集成带有特定配置的包:
  
  add_requires("pcre2", {configs = {bitwidth = 16}})
  
  on_load
  
  这是个可选的接口,若是要更加灵活的动态判断各类平台架构,针对性作设置,能够在这个里面完成,例如:
  
  on_load(function (package)
  
  local bitwidth = package:config("bitwidth") or "8"
  
  package:add("links", "pcre" .. (bitwidth ~= "8" and bitwidth or ""))
  
  if not package:config("shared") then
  
  package:add("defines", "PCRE_STATIC")
  
  end
  
  end)
  
  pcre包须要作一些针对bitwidth的判断,才能肯定对外输出的连接库名字,还须要针对动态库增长一些defines导出,这个时候在on_load里面设置,就更加灵活了。
  
  on_install
  
  这个接口主要用于添加安装脚本,前面的字符串参数用于设置支持的平台,像on_load, on_test等其余脚本域也是一样支持的。
  
  平台过滤
  
  完整的过滤语法以下:plat|arch1,arch2@host|arch1,arch2
  
  看上去很是的复杂,其实很简单,其中每一个阶段都是可选的,可部分省略,对应:编译平台|编译架构@主机平台|主机架构
  
  若是不设置任何平台过滤条件,那么默认全平台支持,里面的脚本对全部平台生效,例如:
  
  on_install(function (package)
  
  -- TODO
  
  end)
  
  若是安装脚本对特定平台生效,那么直接指定对应的编译平台,能够同时指定多个:
  
  on_install("linux", "macosx", function (package)
  
  -- TODO
  
  end)
  
  若是还要细分到指定架构才能生效,能够这么写:
  
  on_install("linux|x86_64", "iphoneos|arm64", function (package)
  
  -- TODO
  
  end)
  
  若是还要限制执行的主机环境平台和架构,能够在后面追加@host|arch,例如:
  
  on_install("mingw@windows", function (package)
  
  -- TODO
  
  end)
  
  意思就是仅对windows下编译mingw平台生效。
  
  咱们也能够不指定比那一平台和架构,仅设置主机平台和架构,这一般用于描述一些跟编译工具相关的依赖包,只能在主机环境运行。
  
  例如,咱们编译的包,依赖了cmake,须要添加cmake的包描述,那么里面编译安装环境,只能是主机平台:
  
  on_install("@windows", "@linux", "@macosx", function (package)
  
  -- TODO
  
  end)
  
  其余一些例子:
  
  -- `@linux`
  
  -- `@linux|x86_64`
  
  -- `@macosx,linux`
  
  -- `android@macosx,linux`
  
  -- `android|armv7-a@macosx,linux`
  
  -- `android|armv7-a@macosx,linux|x86_64`
  
  -- `android|armv7-a@linux|x86_64`
  
  编译工具
  
  咱们内置了一些安装经常使用编译工具脚本,用于针对不一样源码依赖的构建工具链,进行方便的构架支持,例如:autoconf, cmake, meson等,
  
  xmake
  
  若是是基于xmake的依赖包,那么集成起来就很是简单了,xmake对其作了很是好的内置集成支持,能够直接对其进行跨平台编译支持,通常状况下只须要:
  
  on_install(function (package)
  
  import("package.tools.xmake").install(package)
  
  end)
  
  若是要传递一些特有的编译配置参数:
  
  on_install(function (package)
  
  import("package.tools.xmake").install(package, {"--xxx=y"})
  
  end)
  
  cmake
  
  若是是基于cmake的包,集成起来也很简答,一般也只须要设置一些配置参数便可,不过还须要先添加上cmake的依赖才行:
  
  add_deps("cmake")
  
  on_install(function (package)
  
  import("package.tools.cmake").install(package, {"-Dxxx=ON"})
  
  end)
  
  autoconf
  
  若是是基于autoconf的包,集成方式跟cmake相似,只是传递的配置参数不一样而已,不过一般状况下,unix系统都内置了autoconf系列工具,因此不加相关依赖也没事。
  
  on_install(function (package)
  
  import("package.tools.autoconf").install(package, {"--enable-shared=no"})
  
  end)
  
  不过,有些源码包用系统内置的autoconf可能不能彻底知足,那么能够加上autoconf系列依赖,对其进行构建:
  
  add_deps("autoconf", "automake", "libtool", "pkg-config")
  
  on_install(function (package)
  
  import("package.tools.autoconf").install(package, {"--enable-shared=no"})
  
  end)
  
  meson
  
  若是是meson,还须要加上ninja的依赖来执行构建才行。
  
  add_deps("meson", "ninja")
  
  on_install(function (package)
  
  import("package.tools.meson").install(package, {"-Dxxx=ON"})
  
  end)
  
  on_test
  
  安装后,须要设置对应的测试脚本,执行一些测试,确保安装包的可靠性,若是测试不经过,则会撤销整个安装包。
  
  on_test(function (package)
  
  assert(package:has_cfuncs("inflate", {includes = "zlib.h"}))
  
  end)
  
  上面的脚本调用包内置的has_cfuncs接口,检测安装后的包是否存在zlib.h头文件,以及库和头文件里面是否存在inflate这个接口函数。
  
  xmake会去尝试编译连接来作测试,has_cfuncs用于检测c函数,而has_cxxfuncs则能够检测c++库函数。
  
  而includes里面能够设置多个头文件,例如:includes = {"xxx.h", "yyy.h"}
  
  咱们还能够传递一些本身的编译参数进去检测,例如:
  
  on_test(function (package)
  
  assert(package:has_cxxfuncs("func1", {includes = "xxx.h", configs = {defines = "c++14", cxflags = "-Dxxx"}}))
  
  end)
  
  咱们也能够经过check_csnippets和check_cxxsnippets检测一个代码片断:
  
  on_test(function (package)
  
  assert(package:check_cxxsnippets({test = [[
  
  #include <boost/algorithm/string.hpp>
  
  #include <string>
  
  #include <vector>
  
  #include <assert.h>
  
  using namespace boost::algorithm;
  
  using namespace std;
  
  static void test() {
  
  string str("a,b");
  
  vector<string> strVec;
  
  split(strVec, str, is_any_of(","));
  
  assert(strVec.size()==2);
  
  assert(strVec[0]=="a");
  
  assert(strVec[1]=="b");
  
  }
  
  ]]}, {configs = {languages = "c++14"}}))
  
  end)
  
  若是是可执行包,也能够经过尝试运行来检测:
  
  on_test(function (package)
  
  os.run("xxx --help")
  
  end)
  
  若是运行失败,那么测试不会经过。
  
  扩展配置参数
  
  详情见:add_configs
  
  内置配置参数
  
  除了能够经过add_configs设置一些扩展的配置参数之外,xmake还提供了一些内置的配置参数,可使用
  
  启用调试包
  
  add_requires("xxx", {debug = true})
  
  包描述里面必须有相关处理才能支持:
  
  on_install(function (package)
  
  local configs = {}
  
  if package:debug() then
  
  table.insert(configs, "--enable-debug")
  
  end
  
  import("package.tools.autoconf").install(package)
  
  end)
  
  设置msvc运行时库
  
  add_requires("xxx", {configs = {vs_runtime = "MT"}})
  
  一般状况下,经过import("package.tools.autoconf").install等内置工具脚本安装的包,内部都对vs_runtime自动处理过了。
  
  可是若是是一些特殊的源码包,构建规则比较特殊,那么须要本身处理了:
  
  on_install(function (package)
  
  io.gsub("build/Makefile.win32.common", "%-MD", "-" .. package:config("vs_runtime"))
  
  end)
  
  添加环境变量
  
  对于一些库,里面也带了可执行的工具,若是须要在集成包的时候,使用上这些工具,那么也能够设置上对应PATH环境变量:
  
  package("luajit")
  
  on_load(function (package)
  
  if is_plat("windows") then
  
  package:addenv("PATH", "lib")
  
  end
  
  package:addenv("PATH", "bin")
  
  end)
  
  而在项目工程中,只有经过add_packages集成对应的包后,对应的环境变量才会生效。
  
  add_requires("luajit")
  
  target("test")
  
  set_kind("binary")
  
  add_packages("luajit")
  
  after_run(function (package)
  
  os.exec("luajit --version")
  
  end)
  
  安装二进制包
  
  xmake也是支持直接引用二进制版本包,直接安装使用,例如:
  
  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。
  
  咱们能够执行下面的脚本进行测试指定包:
  
  cd xmake-repo
  
  xmake l scripts/test.lua -v -D zlib
  
  上面的命令,会强制从新下载和安装zlib包,测试整个安装流程是否ok,加上-v -D是为了能够看到完整详细的日志信息和出错信息,方便调试分析。
  
  若是网络环境很差,不想每次测试都去从新下载全部依赖,能够加上--shallow参数来执行,这个参数告诉脚本,仅仅从新解压本地缓存的zlib源码包,从新执行安装命令,但不会下载各类依赖。
  
  cd xmake-repo
  
  xmake l scripts/test.lua -v -D --shallow zlib
  
  若是咱们想测试其余平台的包规则是否正常,好比: android, iphoneos等平台,能够经过-p/--plat或者-a/--arch来指定。
  
  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
  
  提交包到官方仓库
  
  目前这个特性刚完成不久,目前官方仓库的包还不是不少,有些包也许还不支持部分平台,不过这并非太大问题,后期迭代几个版本后,我会不断扩充完善包仓库。
  
  若是你须要的包,当前的官方仓库尚未收录,能够提交issues或者本身能够在本地调通后,贡献提交到官方仓库:xmake-repo
  
  详细的贡献说明,见:CONTRIBUTING.md
  
  关于如何制做本身的包,能够看下上文:添加包到仓库。html

相关文章
相关标签/搜索