首先,不得不承认,cmake很强大,发展了这么多年,整个生态已经相当完善,功能也相当丰富,这点xmake目前是比不了的。

当初我做xmake的目的,也并不是为了完全替代cmake,这没啥意义,只是觉得cmake的语法和易用性满足不了我,我还是更喜欢更简单直观的方式去描述和维护项目,在不同平台下提供近乎一致的使用体验。

因此,xmake的语法描述和使用体验还是非常好的,这也是xmake最大的亮点之一,我在这块设计上做了很多改进,为了降低学习和项目维护门槛,也更容易快速上手。

在这里,我只拿xmake中一些比较占优的特性去跟cmake作对比,仅仅只是为了突出说明xmake在某些方面的优势和易用性,并没有任何贬低cmake的意思。

如果大家看完此篇文章的对比分析,觉得xmake确实好用,能够满足部分项目维护上的需求,解决一些痛点,提高项目维护效率的话,不妨试试体验下。

  • 项目源码
  • 官方文档
  • xmake v2.2.6 发布, Qt/Android编译支持

特性支持

我先罗列下构建工具的一些主要基础特性对比,大部分特性两者都是支持的,而xmake的优势主要还是在:语法、包仓库管理、构建体验上

feature xmake cmake
语法 Lua语法,简洁直观,快速上手 DSL,复杂,学习成本高
自建包仓库管理 多仓库支持,可自建私有包仓库 不支持
第三方包管理集成 vcpkg/conan/brew vcpkg/conan/其他
构建行为 直接构建,无依赖 生成工程文件,调用第三方构建工具
依赖 仅依赖编译工具链 依赖编译工具链+第三方构建工具
查找依赖包 支持 支持
编译器特性检测 支持 支持
工程文件生成 支持 支持
跨平台 支持 支持
IDE/编辑器插件 支持 支持
模块和插件扩展 支持 支持

语法对比

空工程

xmake
target("test")set_kind("binary")add_files("src/main.c")
复制代码
cmake
add_executable(test "")
target_sources(test PRIVATE src/main.c)
复制代码

源文件添加

xmake

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接口文档

cmake

cmake似乎需要先遍历文件列表到对应变量,再添加到对应的target中去才行,稍微繁琐些。

add_executable(test "")
file(GLOB SRC_FILES "src/*.c")
file(GLOB TEST_FILES "test/*.c")
file(GLOB_RECURSE EXAMPLE_FILES "example/*.cpp")
target_sources(test PRIVATE ${SRC_FILES}${TEST_FILES}${EXAMPLE_FILES}
)
复制代码

条件编译

xmake
target("test")set_kind("binary")add_files("src/main.c")if is_plat("macosx", "linux") thenadd_defines("TEST1", "TEST2")endif is_plat("windows") and is_mode("release") thenadd_cxflags("-Ox", "-fp:fast")end
复制代码
cmake
add_executable(test "")
if (APPLE OR LINUX)target_compile_definitions(test PRIVATE TEST1 TEST2)
endif()
if (WIN32)target_compile_options(test PRIVATE $<$<CONFIG:Release>:-Ox -fp:fast>)
endif()
target_sources(test PRIVATEsrc/main.c
)
复制代码

自定义脚本

xmake

xmake可以在编译构建的不同阶段(包括编译、安装、打包、运行),方便的插入一段自定义脚本来处理自己的逻辑,比如编译完成之后打印一行输出:

target("test")set_kind("binary")add_files("src/*.c")after_build(function (target)print("target file: %s", target:targetfile())end)
复制代码

或者自定义运行和安装逻辑:

target("test")set_kind("binary")add_files("src/*.c")on_install(function (target)os.cp(target:targetfile(), "/usr/local/bin")end)on_run(function (target)os.run("%s --help", target:targetfile())end)
复制代码

在自定义脚本中,用户可以写各种复杂脚本,通过import接口,可以导入各种扩展模块来使用。

target("test")set_kind("binary")add_files("src/*.c")before_build(function (target)import("net.http")import("devel.git")http.download("https://xmake.io", "/tmp/index.html")git.clone("git@github.com:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})end)
复制代码
cmake

cmake也可以通过add_custom_command来实现:

add_executable(test "")
target_sources(test PRIVATE src/main.c)
add_custom_command(TARGET test POST_BUILDCOMMENT "hello cmake!"
)
复制代码

不过看了下,不同阶段,自定义脚本的方式并不完全一样,add_custom_command只能用于构建阶段的自定义,如果要对安装阶段进行自定义,得:

install(SCRIPT cmake_install.cmake)
复制代码

并且只能整个替换安装逻辑,无法对安装前后的实现一些自定义逻辑,另外像打包、运行等其他阶段的自定义似乎不支持。

构建方式

编译默认平台

xmake

通常情况,编译默认平台执行敲xmake,执行构建期间,xmake不会依赖其他第三方构建工具,连make也不依赖,也不会生成IDE/Makefile文件, 而是直接调用的编译工具链进行编译,默认会根据cpu核数自动开启多任务加速构建。

xmake
复制代码
cmake

而cmake的通常是先生成对应IDE/Makefile等第三方构建文件,然后调用make/msbuild等第三方构建工具去编译。

cmake .
cmake --build .
复制代码

编译指定平台

xmake

xmake可以以近乎一致的方式快速切换不同平台和架构来编译。

xmake f -p [iphoneos|android|linux|windows|mingw] -a [arm64|armv7|i386|x86_64]
xmake
复制代码
cmake

cmake似乎对不同平台和架构的编译配置方式,差异性还是有些的,需要花点时间研究下才行。

cmake -G Xcode -DIOS_ARCH="arm64" .
cmake --build .
复制代码
cmake -G "Visual Studio 9 2008" -A x64
cmake --build .
复制代码

像android平台编译,配置ndk的方式似乎也很繁琐。

cmake .. -DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%\build\cmake\android.toolchain.cmake -DCMAKE_SYSTEM_NAME="Android" -DANDROID_NDK=%ANDROID_NDK% -DANDROID_TOOLCHAIN=clang -DANDROID_PLATFORM=android-24
复制代码

安装目标

xmake
xmake install
复制代码
cmake
cmake -P cmake_install.cmake
复制代码

运行目标

xmake

大部分情况下,xmake不需要写自定义脚本就可以直接加载运行编译生成的目标程序。

xmake run
复制代码
cmake

cmake我没找到可以快速运行指定目标程序的方式,但是应该可以通过写一个自定义脚本去加载运行它。

cmake -P cmake_run.cmake
复制代码

依赖支持

查找依赖库

xmake

xmake也是支持跟cmake的find_package类似的接口去直接查找系统库,然后集成使用,找到库后,会自动追加includedirs, links, linkdirs等相关设置。

target("test")set_kind("binary")add_files("src/*.c")on_load(function (target)target:add(find_packages("openssl", "zlib"))end)
复制代码
cmake
add_executable(test main.c)find_package(OpenSSL REQUIRED)
if (OpenSSL_FOUND)target_include_directories(test ${OpenSSL_INCLUDE_DIRS})target_link_libraries(test ${OpenSSL_LIBRARIES})
endif() find_package(Zlib REQUIRED)
if (Zlib_FOUND)target_include_directories(test ${Zlib_INCLUDE_DIRS})target_link_libraries(test ${Zlib_LIBRARIES})
endif()
复制代码

使用第三方库(Conan)

xmake

xmake会自动调用conan工具去下载安装openssl库,然后集成使用,只需要执行xmake命令即可完成编译。

add_requires("conan::OpenSSL/1.0.2n@conan/stable", {alias = "openssl"})
target("test")set_kind("binary")add_files("src/*.c")add_packages("openssl")
复制代码
cmake
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.14/conan.cmake""${CMAKE_BINARY_DIR}/conan.cmake")
endif()include(${CMAKE_BINARY_DIR}/conan.cmake)conan_cmake_run(REQUIRES OpenSSL/1.0.2n@conan/stableBASIC_SETUP BUILD missing)add_executable(test main.c)
target_link_libraries(main ${CONAN_LIBS})
复制代码

使用内建包仓库

xmake

xmake有自建的包仓库,虽然现在里面包还不是很多,但后期会不断完善:xmake-repo

我们只需要添加相关需要的包就行了,非常方便,并且支持多版本选择和语义版本控制哦。

甚至有些常用包支持多平台集成使用,例如:zlib库等,即使编译android/iphoneos/mingw等平台,也都可以直接下载安装使用。

add_requires("libuv master", "ffmpeg", "zlib 1.20.*")
add_requires("tbox >1.6.1", {optional = true, debug = true})
target("test")set_kind("shared")add_files("src/*.c")add_packages("libuv", "ffmpeg", "tbox", "zlib")
复制代码

执行xmake命令后,会去自动从仓库中下载对应的包然后编译安装,集成链接进来,效果如下:

除了官方的包仓库,用户也可以自己创建多个私有仓库,用来集成使用一些私有包,这对于公司内部项目的依赖维护还是很有帮助的。

我们只需要在xmake.lua加上自己的私有仓库地址就行了:

add_repositories("my-repo git@github.com:myrepo/xmake-repo.git")
复制代码

或者直接命令行添加:

xmake repo --add my-repo git@github.com:myrepo/xmake-repo.git
复制代码

关于这块的详细说明可以看下相关文档:

  • 远程依赖模式
  • add_requires接口说明

最后,附带一张xmake的依赖包管理架构图:

cmake

这块我没看到cmake有支持,不过cmake我用得并不多,如果有写的不对的地方,大家可以指正。

原文出处:tboox.org/cn/2019/05/…

xmake vs cmake对比分析相关推荐

  1. 编译工具:XMake 和 CMake对比分析

    关注+星标公众号,不错过精彩内容 来源 | TBOOX开源工程 首先,不得不承认,cmake很强大,发展了这么多年,整个生态已经相当完善,功能也相当丰富,这点xmake目前是比不了的. 当初作者(我, ...

  2. JDBC与数据库连接工具对比分析

    JDBC 使用步骤: 注册数据库驱动 通过DriverManager获取数据库连接 通过Connection对象获取Statement对象 使用Statement执行SQL语句 操作ResultSet ...

  3. Apache 流框架 Flink,Spark Streaming,Storm对比分析(一)

    https://bigdata.163.com/product/article/5 Apache 流框架 Flink,Spark Streaming,Storm对比分析(一) 转载于:https:// ...

  4. php遍历数组哪个效率高,PHP遍历数组的三种方法及效率对比分析

    PHP遍历数组的三种方法及效率对比分析 发布于 2015-03-04 21:55:27 | 129 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文名: Hypertext ...

  5. R语言决策树、bagging、随机森林模型在训练集以及测试集的预测结果(accuray、F1、偏差Deviance)对比分析、计算训练集和测试集的预测结果的差值来分析模型的过拟合(overfit)情况

    R语言决策树.bagging.随机森林模型在训练集以及测试集的预测结果(accuray.F1.偏差Deviance)对比分析.计算训练集和测试集的预测结果的差值来分析模型的过拟合(overfit)情况 ...

  6. python计算多个模型在不同数据集上的预测概率、获取每个数据集上的最优模型、多个最优模型的ROC曲线进行对比分析

    pytyon计算多个模型在不同数据集上的预测概率.获取每个数据集上的最佳模型.多个最优模型的ROC曲线进行对比分析 目录

  7. R语言e1071包中的支持向量机:仿真数据(螺旋线性不可分数据集)、简单线性核的支持向量机SVM(模型在测试集上的表现、可视化模型预测的结果、添加超平面区域与原始数据标签进行对比分析)、如何改进核函数

    R语言e1071包中的支持向量机:仿真数据(螺旋线性不可分数据集).简单线性核的支持向量机SVM(模型在测试集上的表现.可视化模型预测的结果.添加超平面区域与原始数据标签进行对比分析).如何改进核函数 ...

  8. R语言螺旋线型线性不可分数据xgboost分类:使用xgboost模型来解决螺旋数据的分类问题、可视化模型预测的结果、添加超平面区域渲染并与原始数据标签进行对比分析

    R语言螺旋线型线性不可分数据xgboost分类:使用xgboost模型来解决螺旋数据的分类问题.可视化模型预测的结果.添加超平面区域渲染并与原始数据标签进行对比分析 目录

  9. 数据库防护技术对比分析

    过去,信息安全工作主要围绕着网络层.主机层等边界防护采取了一系列的安全措施,已建立起相对安全的数据应用环境,但由于技术局限和相关安全产品匮乏等原因,数据库安全建设一直未能得到有效开展,这就造成了数据能 ...

  10. 【深度学习】Swin-Transformer和EfficientNet对比分析

    [深度学习]Swin-Transformer和EfficientNet对比分析 文章目录 1 概述 2 算法解析2.1 Speed2.2 EfficientNet v2算法详解2.3 渐进学习 3 E ...

最新文章

  1. SpringBoot-web开发(四): SpringMVC的拓展、接管(源码分析)
  2. linux c++ 得到 指定进程名 线程数
  3. 2021年科研学术海报Poster模板
  4. 【C#】【Thread】上下文同步域SynchronizationAttribute
  5. 小程序 | 微信小程序二级选择器
  6. C++标准库:bitset 用法整理 (来自网易 happyboy200032的博客)
  7. python编写登录接口_使用python编写一个登录接口
  8. php 32位检签,php crc32 计算字符串的 32 位 CRC(循环冗余校验)
  9. cocos2d-x(概括)
  10. 用正则表达式抓取网页图片
  11. wps参考文献乱码。英文的行间距怎么调?
  12. SQLServer阻止保存要求重新创建表的更改,sql在一列数据前统一加字符
  13. Cascading Convolutional Color Constancy
  14. 栈和队列以及线性表的区别
  15. 什么样的需求评审会是高效的?
  16. vs2019生成dll文件及(C#)使用
  17. 考研结束,一起聊聊考研中的故事
  18. 怎么样打开.blg文件
  19. Mysql出现问题:ERROR 1091 (42000): Can‘t DROP ‘**‘; check that column/key exists解决方案
  20. 虚商两年仅2000万用户 2016发展前景不明

热门文章

  1. jquery可拖拽式内容模块gridder
  2. android 定时请求(两种实现方式)
  3. C++对象池技术剖析
  4. [转]使用.NET实现断点续传
  5. 【数码管识别】感兴趣区域提取和缩放的顺序问题
  6. wxpython记录生词GUI程序
  7. scikit-learn学习笔记
  8. 基于FVC_MSAVI_EVI的荒漠化等级分类方法
  9. python打开其他文件_python打开通达信,如何在python中打开其他文件
  10. C语言中的`sprintf`和`sscanf`两个函数介绍