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://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.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等平台都添加了安裝規則,基本上已經做到了全平台覆寫,甚至一些交叉編譯平台,算是一個比較典型的例子了。
當然,有些包依賴源碼實作力度,并不能完全跨平台,那麼隻需對它支援的平台設定安裝規則即可。
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://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
關于如何制作自己的包,可以看下上文:添加包到倉庫。