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等平台都添加了安装规则,基本上已经做到了全平台覆盖,甚至一些交叉编译平台,算是一个比较典型的例子了。
当然,有些包依赖源码实现力度,并不能完全跨平台,那么只需对它支持的平台设置安装规则即可。
这个版本主要对Cuda项目的构建做了很多的改进,并且新增了对lex/yacc编译支持,同时也对target新增了on_link
, before_link
和after_link
等链接阶段的定制化支持。
这里,我还要感谢下@OpportunityLiu对xmake的支持,这个版本中OpportunityLiu贡献了大量的代码去改进Cuda的支持。 此外,他还帮忙改进了xmake的整个单元测试框架,自更新程序,命令行tab补全以及ci脚本,使得xmake的更新迭代更加高效和稳定。
2.2.6之前的版本,对cuda的编译支持并不是很完善,至少连头文件依赖检测也是没有提供的,因此如果cuda代码一多,每次改动都会编译所有,并不能像c/c++代码那样做到检测改动,进行增量编译。
而在新版本中,xmake对其进行了支持,现在已经可以很好的在不同平台下,处理依赖关系了,这对日常编译和开发效率也会有不少的提升。
之前的版本,添加gencodes配置非常的繁琐,并不简洁,可以看下之前的配置:
target("cuda_console")
set_kind("binary")
add_files("src/*.cu")
add_cuflags("-gencode arch=compute_30,code=sm_30", "-gencode arch=compute_35,code=sm_35")
add_cuflags("-gencode arch=compute_37,code=sm_37", "-gencode arch=compute_50,code=sm_50")
add_cuflags("-gencode arch=compute_52,code=sm_52", "-gencode arch=compute_60,code=sm_60")
add_cuflags("-gencode arch=compute_61,code=sm_61", "-gencode arch=compute_70,code=sm_70")
add_cuflags("-gencode arch=compute_70,code=compute_70")
add_ldflags("-gencode arch=compute_30,code=sm_30", "-gencode arch=compute_35,code=sm_35")
add_ldflags("-gencode arch=compute_37,code=sm_37", "-gencode arch=compute_50,code=sm_50")
add_ldflags("-gencode arch=compute_52,code=sm_52", "-gencode arch=compute_60,code=sm_60")
add_ldflags("-gencode arch=compute_61,code=sm_61", "-gencode arch=compute_70,code=sm_70")
add_ldflags("-gencode arch=compute_70,code=compute_70")
因此为了精简xmake.lua的配置,针对cuda项目增加的add_cugencodes
api来简化配置,改进后如下:
target("cuda_console")
set_kind("binary")
add_files("src/*.cu")
-- generate SASS code for each SM architecture
add_cugencodes("sm_30", "sm_35", "sm_37", "sm_50", "sm_52", "sm_60", "sm_61", "sm_70")
-- generate PTX code from the highest SM architecture to guarantee forward-compatibility
add_cugencodes("compute_70")
另外当配置成add_cugencodes("native")
的时候,xmake会自动探测当前设备支持的gencodes,自动添加进来,会更加的方便高效。
这个,也要感谢下OpportunityLiu提供的探测代码以及对add_cugencodes
的实现。
首先,不得不承认,cmake很强大,发展了这么多年,整个生态已经相当完善,功能也相当丰富,这点xmake目前是比不了的。
当初我做xmake的目的,也并不是为了完全替代cmake,这没啥意义,只是觉得cmake的语法和易用性满足不了我,我还是更喜欢更简单直观的方式去描述和维护项目,在不同平台下提供近乎一致的使用体验。
因此,xmake的语法描述和使用体验还是非常好的,这也是xmake最大的亮点之一,我在这块设计上做了很多改进,为了降低学习和项目维护门槛,也更容易快速上手。
在这里,我只拿xmake中一些比较占优的特性去跟cmake作对比,仅仅只是为了突出说明xmake在某些方面的优势和易用性,并没有任何贬低cmake的意思。
如果大家看完此篇文章的对比分析,觉得xmake确实好用,能够满足部分项目维护上的需求,解决一些痛点,提高项目维护效率的话,不妨试试体验下。
我先罗列下构建工具的一些主要基础特性对比,大部分特性两者都是支持的,而xmake的优势主要还是在:语法、包仓库管理、构建体验上
feature | xmake | cmake |
---|---|---|
语法 | Lua语法,简洁直观,快速上手 | DSL,复杂,学习成本高 |
自建包仓库管理 | 多仓库支持,可自建私有包仓库 | 不支持 |
第三方包管理集成 | vcpkg/conan/brew | vcpkg/conan/其他 |
构建行为 | 直接构建,无依赖 | 生成工程文件,调用第三方构建工具 |
依赖 | 仅依赖编译工具链 | 依赖编译工具链+第三方构建工具 |
查找依赖包 | 支持 | 支持 |
编译器特性检测 | 支持 | 支持 |
工程文件生成 | 支持 | 支持 |
跨平台 | 支持 | 支持 |
IDE/编辑器插件 | 支持 | 支持 |
模块和插件扩展 | 支持 | 支持 |
target("test")
set_kind("binary")
add_files("src/main.c")
add_executable(test "")
target_sources(test PRIVATE src/main.c)
xmake支持通配符匹配的方式,添加一批源文件进来,*.c
匹配当前目录下所有文件,**.c
匹配递归目录下所有文件。
这种方式,对于平常项目中新增一些文件编译,就不需要每次修改xmake.lua了,自动同步,可以节省不少时间。
target("test")
set_kind("binary")
add_files("src/*.c")
add_files("test/*.c", "example/**.cpp")
xmake的add_files()
是非常灵活强大的,不仅可以支持各种不同类型源文件添加,还可以在添加的同时排除一些指定文件。
比如:递归添加src下的所有c文件,但是不包括src/impl/下的所有c文件。
add_files("src/**.c|impl/*.c")
更多关于这个接口的使用说明,见相关文档:add_files接口文档
这个版本主要对远程依赖包的支持进一步完善,并且新增了对clib包依赖的支持,另外现在xmake已经能够直接编译Qt/Android项目,并且可以直接生成apk包,以及安装到设备支持。
此版本还对xmake的启动性能做了优化,解决了windows启动慢的问题,提速98%,整体编译速度也加快了不少。
最近正好写了篇与cmake的对比分析文章,有兴趣的同学可以看下:xmake vs cmake对比分析
我们可以先创建一个Qt空项目,并且尝试编译生成apk,例如:
xmake create -t quickapp_qt -l c++ appdemo
cd appdemo
xmake f -p android --ndk=~/Downloads/android-ndk-r19c/ --android_sdk=~/Library/Android/sdk/ -c
xmake
[ 0%]: compiling.qt.qrc src/qml.qrc
[ 50%]: ccache compiling.release src/main.cpp
[100%]: linking.release libappdemo.so
[100%]: generating.qt.app appdemo.apk
然后安装到设备:
xmake install
installing appdemo ...
installing build/android/armv7-a/release/appdemo.apk ..
Success
install ok!👌
非常简单,我们可以看下其xmake.lua描述,其实跟在pc上编译维护Qt项目并没有区别,完全一样的描述文件,仅仅只是编译的时候切换到了android平台而已。
add_rules("mode.debug", "mode.release")
target("appdemo")
add_rules("qt.application")
add_headerfiles("src/*.h")
add_files("src/*.cpp")
add_files("src/qml.qrc")
add_frameworks("QtQuick")
新版本对内置的包管理进行了重构,已经支持的非常完善了,我们可以通过
add_requires("libuv master", "ffmpeg", "zlib 1.20.*")`
方便的安装使用依赖包,但是官方的包仓库xmake-repo目前收录的包还非常少,因此为了扩充xmake的包仓库,
xmake新增了对第三方包管理器的内置支持,通过包命名空间显式指定其他包管理器中的包,目前支持对conan::
,brew::
和vcpkg::
包管理中的包进行安装。
add_requires("brew::zlib", {alias = "zlib"}})
add_requires("brew::pcre2/libpcre2-8", {alias = "pcre2"}})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("pcre2", "zlib")
add_requires("vcpkg::zlib", "vcpkg::pcre2")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("vcpkg::zlib", "vcpkg::pcre2")
不过需要注意的是,使用vcpkg,需要先对vcpkg与xmake进行集成才行,详细操作如下:
windows上用户装完vcpkg后,执行$ vcpkg integrate install
,xmake就能自动从系统中检测到vcpkg的根路径,然后自动适配里面包。
当然,我们也可以手动指定vcpkg的根路径来支持:
$ xmake f --vcpkg=f:\vcpkg
新版本实现了对conan的generator,来集成获取conan中的包信息,我们在xmake中使用也是非常的方便,并且可以传递conan包的所有配置参数。
add_requires("conan::zlib/1.2.11@conan/stable", {alias = "zlib", debug = true})
add_requires("conan::OpenSSL/1.0.2n@conan/stable", {alias = "openssl", configs = {options = "OpenSSL:shared=True"}})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("openssl", "zlib")
执行xmake进行编译后:
ruki:test_package ruki$ xmake
checking for the architecture ... x86_64
checking for the Xcode directory ... /Applications/Xcode.app
checking for the SDK version of Xcode ... 10.14
note: try installing these packages (pass -y to skip confirm)?
-> conan::zlib/1.2.11@conan/stable (debug)
-> conan::OpenSSL/1.0.2n@conan/stable
please input: y (y/n)
=> installing conan::zlib/1.2.11@conan/stable .. ok
=> installing conan::OpenSSL/1.0.2n@conan/stable .. ok
[ 0%]: ccache compiling.release src/main.c
[100%]: linking.release test