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

相關文章
相關標籤/搜索