xmake 入门,构建项目原来可以如此简单 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
waruqi
V2EX    程序员

xmake 入门,构建项目原来可以如此简单

  •  2
     
  •   waruqi
    waruqi 2018-03-29 08:30:50 +08:00 4117 次点击
    这是一个创建于 2808 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前言

    在开发xmake之前,我一直在使用 gnumake/makefile 来维护个人 C/C++项目,一开始还好,然而等项目越来越庞大后,维护起来就非常吃力了,后续也用过一阵子 automake 系列工具,并不是很好用。

    由于 C/C++程序的构建过程比较繁琐,如果不借助 IDE 工具,很难快速构建一个新的 C/C++程序,想要跨平台构建就更加麻烦了。

    虽然 IDE 很好用,也很强大,但是还是有很多不足的地方,例如:

    • 跨平台开发支持不完善
    • 自身环境不一定跨平台
    • 过于臃肿
    • 不利于服务端自动化部署构建
    • 不够灵活,定制化配置构建过程有局限性

    当然如果你熟悉 makefile 的话,也可以手敲 makefile,不过不同平台用的 make 也不相同,比如: gnumake, nmake 等,导致 makefile 语法存在差异性,无法做到一致性编译,而且对开发者有一定的使用门槛。

    在 win 上使用 gnumake 还得装 cygwin,mingw-msys 等环境,也非常麻烦,折腾完环境就得半天时间。

    目前已经有了很多现代化的构建工具,方便开发者构建和维护 C/C++项目,例如:cmake, scons, premake, bazel, gn, gyp 等等。

    其中很多只能生成对应的 IDE 工程,然后再通过对应 IDE 来维护和构建,这种只是解决了 C/C++项目的一致性维护问题,但是构建方式不一致,因此还是没解决之前列举的大部分不足点,也无法直接快速构建。

    而 cmake, scons 虽然很强大,但是 cmake 语法怪异不直观,本人实在是不习惯,scons 使用还需要依赖 python,py2/py3 的问题折腾起来也比较蛋疼。

    鉴于此,我采用了 lua 来描述工程,利用 lua 的轻量,简洁,灵活,跨平台等特性,来解决上述遇到的各种问题,使用 xmake 将会带来不一样的构建体验:

    • 轻量,跨平台,无依赖,无需额外安装 python 等第三方环境,直接内置 lua 运行时,一个安装包(或者命令)直接搞定
    • 工程描述直观简洁,更符合用户正常的思维习惯
    • 支持直接构建,强大的命令行工具,终端用户的福音,装逼用户必备
    • vscode, idea, clion, sublime, vim 等编辑器插件支持
    • 智能检测支持,简化用户编译配置过程
    • 插件支持,灵活的用户可扩展性
    • vcproj 等 IDE 项目文件生成也支持的哦
    • 更多隐藏特性等你来体验

    xmake-compilation

    快速上手

    不会写 makefile ?没关系,直接在源码目录运行以下命令即可直接编译:

    xmake 

    xmake 会自动扫描在当前目录下的源码结构,生成一个xmake.lua工程描述文件,然后尝试直接编译。

    想要直接运行编译后的可执行程序,简单,直接敲:

    $ xmake run 

    更多相关信息,请参考文章: xmake 新增智能代码扫描编译模式,无需手写任何 make 文件

    快速入门

    如果想要更进一步描述工程,调整源码结构,添加一些编译选项什么的,还是需要维护一个名叫 xmake.lua 的工程描述文件,类似 makefile, cmakelist.txt ,但是其语法和 api 经过不断地改进简化,已经相当易用。

    最简单的描述例子只需要三行:

    target("test") set_kind("binary") add_files("src/*.c") 

    就可以构建一个可执行程序,编译所有在 src 目录下的 c 源文件。

    然后直接执行 xmake 即可编译。

    add_files()支持通配符文件模式匹配,并且支持.c, .cpp, .go, .d, .m, .mm, .S, .swift, .rc, .rs等各种 native 语言的代码文件,大部分都能支持混编。

    我们甚至可以添加.a 和.o, .obj 文件到add_files(),例如:

    target("test") set_kind("static") add_files("src/*.c") add_files("lib/libxxx.a", "obj/bbb.o") 

    上述描述会编译生成一个 libtest.a 库,在编译归档的时候,会自动将 libxxx.a 库反解出来,合并到 libtest.a 中去,并且同时将 bbb.o 也加进去。

    xmake 提供的add_files是非常强大的,我们还可以再添加一批文件的同时,指定排除某些文件,例如:

    add_files("src/**.cpp|test.cpp|arm/*.cpp") 

    上述描述,在递归添加源文件的同时,排除掉了 test.cpp 以及 arm 目录下的源文件。

    更多add_files用法,请参考文档:add_files 接口使用文档

    使用演示

    命令行下的使用过程,大家可以通过一个视频直观的体验下:

    创建工程

    更加省事的方式就是通过上节所说傻瓜式操作方式,自动生成一个 xmake.lua ,然后在这基础下修修改改就行了。

    当然如果没有现成源码,想从新工程创建开始编译,那么可以使用 xmake 提供的工程模板进行创建:

    $ xmake create test 

    默认创建一个名为 test 的 c 可执行项目,源码结构如下:

    . ├── src │ └── main.c └── xmake.lua 

    当然你也可以选择语言和模板类型:

    $ xmake create -l c++ -t shared test 

    上述命令创建了一个 c++动态库项目,就这么简单。

    运行和调试

    编译完的可执行程序,直接敲xmake run就能运行,xmake 会自动找到对应的 target 目标文件,你也可以传递参数给程序。

    如果有多个 target 目标,你可以指定需要运行的 target 名,例如:

    $ xmake run test 

    想要快速调试程序?加上-d参数即可

    $ xmake run -d test 

    xmake 默认会去找系统自带的调试器,然后加载运行,windows 上使用 vsjitdebugger,linux 上 gdb,macos 上 lldb,当然你也可以随意切换到其他调试器。

    配合 debug 模式编译,就能做到使用 xmake 进行源码调试。

    可视化配置和构建

    xmake 提倡使用命令行的方式来操作,用习惯后效率非常高,而且在 windows 上,即使没有 cygwin,也可以直接在 cmd 下正常运行。

    当然,并不是所有用户习惯命令行,因此 xmake 也提供了编辑器插件,与各大编辑器进行集成,例如:

    xmake-vscode 插件

    xmake-idea 插件

    xmake-sublime 插件

    xmake-tui 界面

    除了编辑器插件,xmake 甚至自己封装实现了一整套跨平台 tui 字符界面库,然后仿 kconfig/menuconf 的界面风格,实现了一个类似的可视化字符界面菜单配置。

    这个不需要额外的插件,只需要在终端下执行:

    $ xmake f --menu 

    就可以显示菜单配置界面进行编译配置,配置完即可根据当前配置进行编译,效果如下:

    定制化编译

    想要更加灵活的编译配置?那就得要修改 xmake.lua 啦,不过还是很简单的。

    添加编译选项

    target("test") set_kind("binary") add_files("src/*.c") if is_mode("debug") then add_cxflags("-DDEBUG") end 

    上面代码中,add_cxflags接口就是同时配置 C/C++代码的编译选项,并且只在 debug 模式下生效,也就是执行下面命令的时候:

    $ xmake f -m debug $ xmake 

    使用内置选项

    像添加宏定义,设置警告级别,优化级别,头文件搜索目录什么的,完全没必要使用原始的add_cxflags接口,xmake 有提供更加方便的接口,更加智能化的处理来简化配置,也更加通用跨平台,例如:

    add_defines("DEBUG") set_optimize("fast") set_warnings("all", "error") target("test") set_kind("binary") add_files("src/*.c") target("test2") set_kind("binary") add_files("src2/*.c") 

    跟刚才的配置不同的是,此处设置放在了 target 的上面,此处不属于 target 域,是 root 全局设置,会影响下面的所有 target 目标程序的编译设置,这样可以简化配置,避免冗余。

    灵活的脚本控制

    对于高端用户,构建需求复杂多变,xmake 也提供了对应解决方案,各个构建阶段都可以灵活定制:

    target("test") set_kind("binary") add_files("src/*.c") after_build(function (target) os.exec("file %s", target:targetfile()) end) 

    上述代码在编译程序结束后,执行 file 命令查看目标程序相关信息,目前 xmake 可以在 build, clean, run, install, uninstall 等各个阶段的前后插入自定义的脚本,也可以直接内置 action,例如: on_install 会覆盖内置的安装逻辑,提供给用户足够的灵活性。

    方便的多目标依赖

    很多时候,一个项目会有多个 target 目标程序,之间存在依赖关系,例如: 一个可执行程序 hello,依赖一个静态库 libtest.a,我们只需要通过 add_deps 将两个 target 做个关联就行了,libtest.a 的搜索目录,头文件目录设置什么的都不需要关心,xmake 会自动处理:

    target("test") set_kind("static") add_files("src/test/*.c") target("hello") add_deps("test") --添加依赖 set_kind("binary") add_files("src/hello/*.c") 

    预编译头文件支持

    xmake 支持通过预编译头文件去加速 c/c++程序编译,目前支持的编译器有:gcc, clang 和 msvc。

    target("test") -- ... set_pcxxheader("header.h") 

    各大编译器对预编译头的处理方式存在很大差异,而 xmake 将其差异性隐藏了起来,提供一致性的描述设置,简化用户在跨平台编译时候的处理, 具体关于编译器对预编译头文件的处理,可参考相关文章:不同编译器对预编译头文件的处理

    自定义编译规则

    xmake 不仅原生内置支持多种语言文件的构建,而且还可以通过自定义构建规则,让用户自己来实现复杂的未知文件构建。

    我们可以通过预先设置规则支持的文件后缀,来扩展其他文件的构建支持:

    -- 定义一个 markdown 文件的构建规则 rule("markdown") set_extensions(".md", ".markdown") on_build(function (target, sourcefile) os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".html")) end) target("test") set_kind("binary") -- 使 test 目标支持 markdown 文件的构建规则 add_rules("markdown") -- 添加 markdown 文件的构建 add_files("src/*.md") add_files("src/*.markdown") 

    我们也可以指定某些零散的其他文件作为 markdown 规则来处理:

    target("test") -- ... add_files("src/test/*.md.in", {rule = "markdown"}) 

    注:通过add_files("*.md", {rule = "markdown"})方式指定的规则,优先级高于ad_rules("markdown")设置的规则。

    IDE 工程文件生成

    xmake 提供了丰富的插件扩展,其中 vcproj, makefile 等工程文件的生成就是作为插件提供,使用起来也非常简单:

    $ xmake project -k vs2017 -m "debug,release" 

    即可生成带有 debug, release 两种编译模式的 vc 工程,同时支持 x86 和 x64。

    生成的工程目录结构会根据添加的所有源文件的目录结构,自动分析生成直观的文件树,方便 vs 去浏览查看。

    makefile 的生成如下:

    $ xmake project -k makefile 

    后续会陆续更多其他工程文件,也欢迎大家来贡献哦。

    灵活简单的插件扩展

    上节的 IDE 工程文件生成,在 xmake 中就是作为插件来提供,这样更加方便扩展,也能让用户快速定制自己的插件,只需要定义个 task 插件任务就行了:

    -- 定义一个名叫 hello 的插件任务 task("hello") -- 设置类型为插件 set_category("plugin") -- 插件运行的入口 on_run(function () print("hello xmake!") end) -- 设置插件的命令行选项,这里没有任何参数选项,仅仅显示插件描述 set_menu { -- usage usage = "xmake hello [options]" -- description , description = "Hello xmake!" -- options , optiOns= {} } 

    上述代码就是一个最为简单的hello xmake!插件,运行$xmake hello就可看到执行输出,set_menu用于配置插件命令行选项,这个不设置就是内部 task,无法在命令行下调用。

    更加详细的插件说明以及内置插件列表可参考文档:插件手册

    查找依赖包

    xmake 参考了 cmake 对于find_*系列接口的设计,实现在项目中动态的查找和添加包依赖。

    target("test") set_kind("binary") add_files("*.c") on_load(function (target) import("lib.detect.find_package") target:add(find_package("zlib")) end) 

    上述描述代码,通过lib.detect.find_package来查找包,如果找到 zlib 包,则将 links, includedirs 和 linkdirs 等信息添加到 target 中去。

    交互式命令执行(REPL)

    有时候在交互模式下,运行命令更加的方便测试和验证一些模块和 api,也更加的灵活,不需要再去额外写一个脚本文件来加载,不过我一般用来做计算器用用(好吧。。)

    # 不带任何参数执行,就可以进入 $ xmake lua > # 进行表达式计算 > 1 + 2 3 # 赋值和打印变量值 > a = 1 > a 1 # 多行输入和执行 > for _, v in pairs({1, 2, 3}) do >> print(v) >> end 1 2 3 

    我们也能够通过 import 来导入扩展模块:

    > task = import("core.project.task") > task.run("hello") hello xmake! 

    编译环境支持

    当前 xmake 的最新版本已经支持很多 sdk 环境的集成编译,例如:

    • [x] Visual Studio 编译环境
    • [x] mingw 编译环境
    • [x] cygwin 编译环境
    • [x] Android NDK 编译环境
    • [x] Xcode 编译环境(支持 iPhoneos/Macosx 构建)
    • [x] 系统 gcc/clang 编译环境
    • [x] 交叉工具链编译环境
    • [x] Cuda 编译环境
    • [ ] Qt 编译环境(正在支持中)
    • [ ] Windows WDK 编译环境(正在支持中)

    FAQ

    xmake 有哪些用途?

    1. 跨平台维护和编译 C/C++项目
    2. CI 上部署自动化构建
    3. 开源代码的快速移植
    4. 临时的测试代码编写和快速运行
    5. 与自己喜欢的编辑器集成,打造属于自己的 C/C++开发环境
    6. 与其他 native 语言的混合编译
    7. 嵌入式开发下的交叉编译
    8. 提升逼格

    对于第三点的用途,我平常用的最多,因为我经常需要移植第三方的开源项目,它们使用的构建工具各不相同,有 automake,cmake 等等,其支持的构建平台力度也都不相同,经常会遇到需要的平台不支持的问题。

    没办法,只好自己敲 makefile 来移植代码,然后适配自己需要支持的那些平台,还有交叉工具链,很蛋疼,自从写了 xmake 后,我现在平常移植代码方便了很多,效率提升非常明显。

    怎样看实时编译警告信息?

    为了避免刷屏,在构建时候,默认是不实时输出警告信息的,如果想要看的话可以加上-w选项启用编译警告输出就行了。

    $ xmake [-w|--warning] 

    怎样看详细的编译参数信息?

    请加上 -v 或者 --verbose 选项重新执行 xmake 后,获取更加详细的输出信息

    例如:

    $ xmake [-v|--verbose] 

    如果加上 --backtrace 选项也可以获取出错时的 xmake 的调试栈信息

    $ xmake -v --backtrace 

    xmake-verbose

    快速安装

    最后我们讲下,如何安装 xmake,通常只需要一个脚本命令就能搞定。

    一键安装脚本

    bash <(curl -fsSL https://raw.githubusercontent.com/tboox/xmake/master/scripts/get.sh) 

    windows 安装包

    对于 windows 用户,提供了安装包来快速安装,可到Github Releases上下载对应版本。

    更加详细的安装过程,见相关文档: 安装说明

    结语

    xmake 还有很多非常有用的特性,例如:编译器特性检测、丰富的模块库、依赖包管理、自定义选项等等,一篇文章讲不完这么多,大家有兴趣的话,可以去官方文档里面看看,还有很多隐藏特性等着你哦。

    18 条回复    2018-03-29 17:48:10 +08:00
    wuhau
        1
    wuhau  
       2018-03-29 08:51:30 +08:00 via iPhone
    Mark 前排广告位
    urmyfaith
        2
    urmyfaith  
       2018-03-29 08:59:20 +08:00   1
    可以啊
    V4Exp
        3
    V4Exp  
       2018-03-29 09:54:09 +08:00   1
    很不错的样子!
    devtiange
        4
    devtiange  
       2018-03-29 10:12:25 +08:00   1
    感觉要火
    lniwn
        5
    lniwn  
       2018-03-29 10:17:59 +08:00 via Android   1
    关注好久了,作者确实厉害
    waruqi
        6
    waruqi  
    OP
       2018-03-29 10:22:57 +08:00
    多谢大家支持,有兴趣的同学可以尝试下,也可加 QQ 群(343118190)互相交流。:)
    ivechan
        7
    ivechan  
       2018-03-29 11:29:52 +08:00
    谢谢楼主, 试用了一下 scons 感觉不错。。。
    以后再尝试下 xmake
    ytlm
        8
    ytlm  
       2018-03-29 11:30:03 +08:00   1
    star
    abmin521
        9
    abmin521  
       2018-03-29 11:49:38 +08:00 via Android
    支持 官方加个证书吧
    waruqi
        10
    waruqi  
    OP
       2018-03-29 11:56:37 +08:00 via Android
    @abmin521 嗯嗯 有时间加个
    LeoQian
        11
    LeoQian  
       2018-03-29 16:57:59 +08:00 via iPhone
    mark
    csl1995
        12
    csl1995  
       2018-03-29 16:58:01 +08:00
    苯垃圾只会改 makefile,已收藏学习,
    waruqi
        13
    waruqi  
    OP
       2018-03-29 17:09:07 +08:00
    @csl1995 手敲 makefile,厉害。。
    itfanr
        14
    itfanr  
       2018-03-29 17:13:19 +08:00
    @csl1995 大规模项目,手敲会累死人的
    coderluan
        15
    coderluan  
       2018-03-29 17:17:10 +08:00
    cmake 的怪异语法已经用习惯了,心理支持个。
    omph
        16
    omph  
       2018-03-29 17:21:38 +08:00
    和什么 CI 兼容比较好?
    waruqi
        17
    waruqi  
    OP
       2018-03-29 17:46:26 +08:00
    @coderluan 看个人喜好,自己习惯了就好。
    waruqi
        18
    waruqi  
    OP
       2018-03-29 17:48:10 +08:00
    @omph 基本上只要 ci 上 gcc 什么的不缺,基本上都兼容,我实测过的有 travis-ci, appveyor (win)
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     900 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 19:56 PVG 03:56 LAX 11:56 JFK 14:56
    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