xmake vs cmake 对比分析 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
waruqi
V2EX    程序员

xmake vs cmake 对比分析

  •  
  •   waruqi
    waruqi 2019-06-03 08:21:04 +08:00 6591 次点击
    这是一个创建于 2373 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

    特性支持

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

    语法对比

    空工程

    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") then add_defines("TEST1", "TEST2") end if is_plat("windows") and is_mode("release") then add_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 PRIVATE src/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("[email protected]: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_BUILD COMMENT "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.cmak 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/stable BASIC_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 [email protected]:myrepo/xmake-repo.git") 

    或者直接命令行添加:

    xmake repo --add my-repo [email protected]:myrepo/xmake-repo.git 

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

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

    cmake

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

    23 条回复    2020-02-01 12:38:36 +08:00
    xiangchen2011
        1
    xiangchen2011  
       2019-06-03 08:34:55 +08:00
    挺好用的,就是没机会用。。。。。。。。
    sagaxu
        2
    sagaxu  
       2019-06-03 08:39:22 +08:00 via Android
    clion 用什么我就用什么
    waruqi
        3
    waruqi  
    OP
       2019-06-03 08:42:20 +08:00 via Android
    @sagaxu clion 也可以装 xmake 插件的
    sky2017
        4
    sky2017  
       2019-06-03 09:32:46 +08:00
    厉害了,关注一下
    webdisk
        5
    webdisk  
       2019-06-03 09:40:06 +08:00
    还是希望能替代 cmake,
    只要能做到系统不需要安装 cmake, 就能用 xmake 编译那几个主要的只能用 cmake 编译的软件就好了
    xiangbu 明白 cmake 为什么要那么大的体积, 就实现那么点功能, 哪怕它能拆分开也行啊.

    cmake 是最讨厌的软件了, 如果你制作过 FinuxFromScratch 你就知道了.
    另外一个讨厌的软件是 systemd, 还好这个已经摆脱了
    div id="r_7422985" class="cell">
    waruqi
        6
    waruqi  
    OP
       2019-06-03 09:47:49 +08:00
    @webdisk xmake 暂时还不支持直接编译 cmake 的项目哦,cmake 功能太多了,难免会臃肿哦,也许很多功能也许我们平常用不到吧
    Icarooooos
        7
    Icarooooos  
       2019-06-03 09:51:21 +08:00
    一直在用,支持大佬!
    omph
        8
    omph  
       2019-06-03 09:55:36 +08:00
    支持一下,如何取代 cmake 是个问题,需要哪些基金会支持?
    darknoll
        9
    darknoll  
       2019-06-03 10:06:38 +08:00
    没听说过..
    zycpp
        10
    zycpp  
       2019-06-03 10:22:18 +08:00 via iPhone
    膜拜大佬
    newlifeinsc
        11
    newlifeinsc  
       2019-06-03 10:31:40 +08:00
    不是写 c/c++,偶尔学习用一些,用这 xmake 挺好的,点赞
    zhonghua
        12
    zhonghua  
       2019-06-03 10:33:25 +08:00
    自己用的用于生成 makefile 的 python 文件
    用 python,可以自己随意编程

    https://gist.github.com/zhuzhonghua/f96c22e7a3265d7dee67264c1fc7a850
    vexjoe
        13
    vexjoe  
       2019-06-03 10:35:39 +08:00
    支持
    amaranthf
        14
    amaranthf  
       2019-06-03 10:57:46 +08:00
    列一些我在使用 cmake 时的痛点,但是看起来 xmake 也没有解决的部分:
    1. 编译选项!编写跨平台工程时,基本上都要写一个专门的文件用于配置不同编译器下的编译选项,非常繁琐。当然我也没想出什么很好的方式来解决这个问题,只是提一下。
    2. command 很多,就像 add_executable 这类的东西,你说到 cmake 的学习成本高,高是没错的,但是主要不是高在语法上,语法非常简单,难点在于那各种命令的学习,也就是对应 xmake 的各种函数。
    amaranthf
        15
    amaranthf  
       2019-06-03 11:00:55 +08:00
    另外我觉得 cmake 的生成其他 IDE 工程文件的功能是非常有用的,要不然我在哪儿写代码、看代码?编辑器和 IDE 毕竟还是不能比的。虽然现在新版的 VS 已经支持直接打开 cmake 工程了,但是不能指望短期内也能支持 xmake 吧。
    waruqi
        16
    waruqi  
    OP
       2019-06-03 11:12:22 +08:00
    > 1. 编译选项!编写跨平台工程时,基本上都要写一个专门的文件用于配置不同编译器下的编译选项,非常繁琐。当然我也没想出什么很好的方式来解决这个问题,只是提一下。

    xmake 有提供常用设置,都是跨平台的一致的,不需要分平台处理,自动会去适配,比如:

    set_optimize("fastest")
    set_warnings("more", "all")
    set_symbols("debug")
    set_languages("c++17")
    add_linkdirs("xxx")

    还有其他的一些原始 flags,可以直接通过 add_cxflags("-O2")等方式添加,但是 xmake 有提供自动检测机制,即使不分平台添加,你再其他平台设置的不支持的 flags,也会自动检测忽略掉

    如果支持的 flags,会自动映射为对应编译的 flags

    flags 可以以 gcc 的 flags 位规范基准做映射,比如你设置:`add_cflags("-Werror")` , 在 windows/cl 编译器下,会自动映射成:-WX, 用户也不需要做分平台处理,一切描述还是一致的

    虽然这种映射方案还不完善,目前只映射了一些常用的 flags,但是后续会不断完善映射规则,支持更多的 flags。

    2. command 很多,就像 add_executable 这类的东西,你说到 cmake 的学习成本高,高是没错的,但是主要不是高在语法上,语法非常简单,难点在于那各种命令的学习,也就是对应 xmake 的各种函数。

    cmake 的命令多,且杂,每种使用方式差异都很大,这块 xmake 对基础设置 api 都是精简过的,并且有自己的命名规范,只要记住 api 的命名规范,大部分 api 的使用,即使不看文档,用法都能猜个大概,甚至都能猜出来还有其他哪些类似的 Api

    这块,你可以看下 xmake 的接口规范描述: https://xmake.io/#/zh/manual?id=%E6%8E%A5%E5%8F%A3%E8%A7%84%E8%8C%83

    xmake 的所有设置 api,都是基于这个,api 虽多,但用法和参数传递都是基于此,了解了规范,不管用哪个 api 都是类似的。。一通百通
    waruqi
        17
    waruqi  
    OP
       2019-06-03 11:13:46 +08:00
    @amaranthf xmake 可以支持 生成 vs/makefile/cmakelists 的工程文件,你也可以生成 vcproj 后用 vs 打开,或者生成 cmakelists 后用 vs/clion 打开
    amaranthf
        18
    amaranthf  
       2019-06-03 11:31:56 +08:00
    @waruqi 感谢回复,flags 的通用化我也想了下,如果是对于用户级别的优化我想是足够了的,但是针对开发者的话,就可能让人产生一些疑惑,比如 fastest,在 gcc 下仅指 O3 么,在 cl 下是否包括了强制内联等参数呢?只是举个例子,就是开发者可能因此还是需要进一步查阅文档,某些时候反倒不如直接写一个-O3 来得直接,映射也同理。当然我提这个问题的时候,其实理想中的最优解法还是让各种编译器开发者共同立一个标准,实际上也是不可能的。
    能生成 vs 工程的话,我自己开发小工程的时候是会考虑用一下了,将来如果推广得更好了再考虑生产环境吧。
    waruqi
        19
    waruqi  
    OP
       span class="ago" title="2019-06-03 11:37:08 +08:00">2019-06-03 11:37:08 +08:00
    @amaranthf 这个就看用户自己的需求了,反正 xmake 提供通用化 api 设置,也支持直接设置原始 flags,如果用户不敏感这些,大部分情况下,直接 设置 fastest 就行了,如果用户觉得这样 不满足需求,大可自己设置 原始 flags

    xmake 也不强制用户必须使用哪种,就看用户自己觉得哪个更适合,就用哪种方式,xmake 只是提供了一种大部分情况下更加通用便捷的设置方式而已。

    vs 生成这种肯定支持的哦。
    Akalusi
        20
    Akalusi  
       2019-06-03 12:37:38 +08:00
    好用,常用,膜拜~
    xflcx1991
        21
    xflcx1991  
       2020-02-01 11:33:26 +08:00
    有个奇怪的问题。xmake update master 这条命令接连执行三遍,每次都会更新,版本号也会增长
    xmake v2.2.9+202002011120
    xmake v2.2.9+202002011123
    xmake v2.2.9+202002011125
    这是怎么回事?不可能我刚巧执行的时候作者都在更新吧。
    waruqi
        22
    waruqi  
    OP
       2020-02-01 12:35:56 +08:00 via Android
    最后的是 build version,每次更新安装 lua vm/core 部分代码是 c 写的的,都需要本机编译,所以这个是这块的编译版本,也就是当前的构建时间,精确到分钟

    如果确定当前 master 上 core 没啥大改动 可以执行 xmake update -s master 仅仅更新 lua 脚本,这样 build version 不会变
    waruqi
        23
    waruqi  
    OP
       2020-02-01 12:38:36 +08:00 via Android
    @xflcx1991 这个帖子好久了 居然还能翻出来 = = 之后有问题建议还是到 github issues 上反馈吧
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     970 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 22:40 PVG 06:40 LAX 14:40 JFK 17:40
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86