做公众号封面图的网站,凡客精选app,微信网页版官网手机版,北京网站页设计制作文章目录 0. 环境准备1. 子命令create - 快速创建项目build - 构建程序config - 配置编译需要的参数show - 查看当前工程基本信息update - 程序自更新 2. C/C 项目常用配置2.1 项目目标类型2.2 添加宏定义2.3 头文件路径和链接库配置2.4 设置语言标准2.5 设置编译优化2.6 添加源… 文章目录 0. 环境准备1. 子命令create - 快速创建项目build - 构建程序config - 配置编译需要的参数show - 查看当前工程基本信息update - 程序自更新 2. C/C 项目常用配置2.1 项目目标类型2.2 添加宏定义2.3 头文件路径和链接库配置2.4 设置语言标准2.5 设置编译优化2.6 添加源文件 3. C/C 依赖库3.1 直接使用系统库3.2 自动查找系统库 对于需要详细解释的请参考官网下面红框位置可全局搜索关键字。
对于本系列建议搭配官网食用。
xmake 使用文档官方网址 0. 环境准备
系统环境centos7xmake安装 升级当前的 gitsudo add-apt-repository ppa:git-core/ppa
sudo apt update
sudo apt install -y gitxmake 安装bash (curl -kfsSL https://labfile.oss.aliyuncs.com/courses/2764/get.sh) v2.3.7
source ~/.xmake/profile #如果是在当前终端下继续操作使用 xmake需要关联 xmake 环境否则会提示 xmake 找不到打开新的终端不需要这步。安装验证xmake --version 1. 子命令 xmake语法格式xmake [task] [options] [target] task子命令任务名xmake 提供了很多的内置子命令以及插件任务子命令 部分子命令有简写在帮助菜单中查看本文中不再对子命令的简写形式重复解释。xmake --help 可以在主菜单里面查看具体有哪些子命令 xmake 子命令 --help 就是子命令的帮助菜单。 create - 快速创建项目
快速创建项目生成可运行最小项目。
-l参数指定创建工程的语言
build - 构建程序
默认命令与仅仅执行 xmake 等价。
-v/--verbose查看详细完整的编译命令。-r/--rebuild强制重新编译所有代码。-j/--jobs指定多任务编译的并行任务数。-w/--warning编译过程中显示编译警告信息。
通过添加 -v 参数在编译过程中查看完整的编译选项这是非常有用的可以排查和确认设置的编译选项是否生效和 -r 一起使用可以写做 -rv。
config - 配置编译需要的参数
配置编译需要的参数比如平台、架构等。
-m切换编译模式如 debug、release默认…xmake f -m debug-o切换编译输出目录。 默认编译 xmake 会在当前项目根目录下生成 build 子目录作为编译输出目录如果不想生成到当前目录下我们可以通过下面的配置命令切换到其它输出目录下。xmake f -o /tmp/build-v查看详细配置信息。--cflags仅仅添加 C 编译选项。 --cxxflags仅仅添加 C 编译选项。 --cxflags同时添加 C/C 编译选项。 一般如果我们设置编译flags传给gcc/clang都是要配置-DXXX也可以浏览后文使用代码的方式配置add_defines()xmake f --cxflags-DXXX #添加C/C编译选项为其添加宏定义XXX
xmake -rv #输出详细编译命令显示-DXXX 说明我们添加的 XXX 宏定义确实传入了编译器-ldflags添加链接库和搜索路径。xmake f --ldflags-L/tmp -lpthread #添加额外的 pthread 链接库同时新增了 /tmp 的库搜索目录
xmake -rv #输出详细编译命令显示新增库和新增搜索目录另外我们也可以通过 --links 和 --linkdirs 达到同样的效果。xmake f --linkspthread --linkdirs/tmp-c清空编译配置回到初始默认状态。
show - 查看当前工程基本信息 查看当前工程的基本信息以及 xmake 自身的一些基本信息 [adminhehe hello]$ xmake show
The information of xmake:version: 2.9.520241008 #xmake版本号host: linux/x86_64 #当前主机平台架构programdir: /home/admin/.local/share/xmake #xmake的lua脚本路径programfile: /home/admin/.local/bin/xmake #xmake的主程序路径globaldir: /home/admin/.xmake # 全局配置存储目录tmpdir: /tmp/.xmake1001/241008 # 临时目录workingdir: /home/admin/Documents/Code/hello # 当前工作目录packagedir: /home/admin/.xmake/packages #C/C依赖包的安装和packagedir(cache): /home/admin/.xmake/cache/packages/2410The information of project: plat: linux #目标编译平台arch: x86_64 #目标编译架构mode: release #目标编译模式buildir: build #编译输出目录configdir: /home/admin/Documents/Code/hello/.xmake/linux/x86_64 # 配置缓存目录projectdir: /home/admin/Documents/Code/hello #当前工程根目录projectfile: /home/admin/Documents/Code/hello/xmake.lua #当前工程xmake.lua路径-t显示指定 target 目标的基本信息查看 xmake.lua 文件中定义的 target(“hello”) 目标程序的基本信息。 [adminhehe hello]$ tree
.
├── build
│ └── linux
│ └── x86_64
│ ├── debug
│ │ └── hello
│ └── release
│ └── hello
├── src
│ └── main.cpp
└── xmake.lua6 directories, 4 files
[adminhehe hello]$ xmake show -t hello
The information of target(hello):at: /home/admin/Documents/Code/hello/xmake.luakind: binarytargetfile: build/linux/x86_64/debug/hello rules:- mode.debug - ./xmake.lua:1- mode.release - ./xmake.lua:1files:- src/*.cpp - ./xmake.lua:5compiler (cxx): /bin/gcc- -m64linker (ld): /bin/g- -m64compflags (cxx):- -m64linkflags (ld):- -m64update - 程序自更新
快速更新版本至最新。
-f/--force强制更新 2. C/C 项目常用配置
2.1 项目目标类型
类型关键字类型binary二进制程序static静态库程序shared动态库程序phony空目标程序 可执行程序
set_kind()就可以设置目标编译类型。一个最简单的工程描述如下。
target(hello) #目标项目set_kind(binary) #目标类型add_files(src/*.c) #添加源文件静态库程序
想要编译生成一个带有静态库的目标程序可以这样建工程。
xmake create -t static hello_static
# -t static 参数用于指定当前工程类型为静态库执行入后xmake 会生成如下文件其中 interface.cpp 用作静态库编译main.cpp 生成可执行程序。 查看xmake.lua的代码内容如下。 里面两个编译目标通过 target() 定义维护一个是 static 静态库类型一个是 binary 可执行程序类型它们之间通过 add_deps(hello_static) 进行依赖关联这样 xmake 在编译的时候会优先编译依赖的静态库并且把静态库自动集成到对应的可执行程序上去。
输入xmake进行编译详情如下。 动态库程序
与静态库类似把类型名改成 shared 即可。
xmake create -t shared hello_shared看看他的 xmake.lua也是同样使用 set_kind() 设置类型add_deps() 添加依赖。 输入xmake进行编译详情如下。 Phony 目标类型
phony 是一个特殊的目标程序类型使用它定义的 target 目标不实际生成任何文件只是执行指定的操作。 通常用于组合其它目标程序的依赖关系实现关联编译。
这里举例如下是我的项目结构
root/
├── build/
│ └── 中间文件...
├── include/
│ └── 头文件...
├── src/
│ └── 源文件...
├── project1/
│ ├── build/
│ │ ├── bin/ # project1 的最终可执行文件
│ │ └── obj/ # project1 的中间文件
│ └── xmake.lua # project1 的 xmake 配置
├── project2/
│ ├── build/
│ │ ├── bin/ # project2 的最终可执行文件
│ │ └── obj/ # project2 的中间文件
│ └── xmake.lua # project2 的 xmake 配置
└── xmake.lua # 根目录的 xmake 配置如果是跟我的文章学习的同学读到这里会有点超纲。也不要紧笔者在此不会涉及过度的内容只针对 phony 进行解释。
先提出一个小知识点xmake.lua 在构建时会默认生成 build 文件夹存放生成的 目标文件 和 过程文件这个存放数据的文件夹当然是可以指定的。
例如示例中子项目就指定了输出目录 root/project1/build/bin 和中间目录 root/project1/build/obj 。否则当在根目录下执行 xmake 时build 文件夹会默认生成在根目录下。
然而当如上项目嵌套时固然我们对子项目的输出路径做了设置但根目录下仍然会生成 build 目录存放所有子项目的中间文件。
对付这个多余的文件夹就可以空虚构建一个 Target执行我们想要的命令保证在 proj1 和 proj2 完成构建后删除根目录下的 build 目录。
root/xmake.lua 我们可以这样写
-- 定义根项目
set_project(MyProjects)-- 包含子项目的构建文件
includes(project1/xmake.lua)
includes(project2/xmake.lua)-- 定义一个伪目标确保在所有子项目完成后才执行清理任务
target(clean_build)set_kind(phony) -- 定义一个虚目标不实际编译任何东西-- 将它依赖于所有子项目以确保它最后执行after_build(function()if os.isdir(build) thenos.rm(build)print(Root build directory deleted.)endend)-- 设置此虚目标依赖于所有其他真实目标add_deps(proj1, proj2)其中 add_deps() 用来设置依赖关系的接口after_build() 用于在构建后执行其中的脚本命令。 2.2 添加宏定义
回顾子命令 config可以让我们在命令行中快速添加 C/C 的编译选项但这样的方式无法永久保存仅仅用于本地编译。如果我们想将自己的项目发布后提供给其他用户编译那么就需要在 xmake.lua 中去设置这些编译选项。
比如我们之前举例用命令行给编译器提供一个宏定义在xmake.lua中就要这样写了
add_rules(mode.debug, mode.release)target(hello)set_kind(binary)add_files(src/*.c)add_cxflags(-DTEST1)除了可以通过 add_cxflags() 方式添加宏定义其实 xmake 还提供了内置的配置接口 add_defines() 去更方便设置它。
这个配置接口相比 add_cxflags 使用原始编译选项的方式更加的通用跨编译器也是官方更加推荐的配置方式。这个接口会自动处理各种编译的支持方式所以不会触发 flags 的自动检测机制更加的快速可靠。
使用 add_defines() 添加新的宏定义开关 TEST2
add_rules(mode.debug, mode.release)target(hello)set_kind(binary)add_files(src/*.cpp)add_cxflags(-DTEST1)add_defines(TEST2)可以通过执行 xmake -rv 去编译查看新增的宏定义是否生效。 2.3 头文件路径和链接库配置 add_includedirs()添加头文件搜索目录。 add_linkdirs()添加库搜索目录。 add_links()添加链接库。 add_syslinks()添加系统链接库。
上述几个接口都是跨编译器配置相比直接设置到 ldflags 更加的通用。 add_syslinks 和 add_links 的区别 add_syslinks 通常用于添加一些系统依赖库比如 pthread这样 xmake 会把这些系统库链接放置的更靠后些。 要知道链接器在处理库链接时候是会依赖顺序的放置在最左边的链接会优先处理例如 libfoo 库依赖 libpthread 库中的符号那么我们必须严格按照这个顺序添加链接库依赖 -lfoo -lpthread否则链接器就会报找不到 pthread 库符号的错误。 更新 xmake.lua 的代码内容
add_rules(mode.debug, mode.release)
target(hello)set_kind(binary)add_files(src/*.cpp)add_cxflags(-DTEST1)add_defines(TEST2)add_links(z)add_syslinks(pthread)add_linkdirs(/tmp)add_includedirs(/tmp)然后执行 xmake -rv 查看编译输出里面的红框部分就是新设置的编译选项 -I/tmp添加头文件搜索路径。-L/tmp添加链接库搜索路径。-lz -lpthread添加的链接库由于我们是通过 add_links 添加的 zlib 库而 pthread 库是作为系统库添加的所以被放置在 pthread 的左边优先链接。
2.4 设置语言标准
set_languages()接口设置目标代码编译时候的语言标准比如是基于 c99 标准还是 c11、c14 标准等。
具体支持详情官方设置代码语言标准
C标准和 C 标准可同时进行设置例如
# 设置 c 代码标准c99 c 代码标准c11
set_languages(c99, c11)同样执行 xmake -v 编译输出结果能看到选项 -stdc11 生效当前案例没有C代码所以只有C11生效。
2.5 设置编译优化
xmake 默认创建的工程 xmake.lua 文件中已经设置了 add_rules(mode.debug, mode.release) 这两个编译规则而默认 xmake 编译就是 release 模式编译它会开启所有内置的编译优化选项并不需要用户设置什么。 上图红框的部分都是编译优化相关的一些选项比如最直接的 -O3 优化还有 -fvisibilityhidden -fvisibility-inlines-hidden 用于去重一些符号字符串数据使得编译后的程序更小。
当然我们也可以不使用 xmake 提供的内置编译规则自己控制应该如何优化编译 ...if is_mode(release) thenset_optimize(fastest)set_strip(all)set_symbols(hidden)end通过 is_mode(release) 自己判断和控制优化编译可以达到跟之前一样的优化效果。
set_optimize(fastest) 对应 -O3 的编译优化开关 set_strip(all) 和 set_symbols(hidden) 用于去掉调试符号数据使得程序更小。
配置完成以后再执行 xmake -v最后的编译输出里面这些编译优化选项还是同样存在的。 2.6 添加源文件
add_files() 接口用于添加源文件。
该接口不仅仅支持单个源文件的添加还可以支持通过模式匹配的方式批量添加源文件并且支持同时添加不同语言的源文件这里主要讲解对 C/C 源文件的添加。
举个例子
add_files(src/test_*.c, src/**.cpp)其中通配符 * 表示匹配当前目录下源文件而 ** 则递归匹配多级目录下的源文件。
示例目录结构创建如下。 在结构复杂的源码目录层级中难免需要排除一些不需要的文件xmake 提供了在模式匹配过程中手动排除一批文件的方式同样还是这个配置接口我们只需要通过 | 符号指定后面的排除匹配模式即可例如。
add_files(src/**.cpp|test/*.cpp|test1/*.cpp)
# 在 src/**.cpp 基础上忽略掉其中 test 和 test1 子目录下所有的 C 源文件
# test 和 test1 可以作 test*这里为了方便展示多个过滤模式其中分隔符 | 之后的都是需要排除的文件这些文件也同样支持匹配模式并且可以同时添加多个过滤模式只要中间用 | 分割就行了。
注意为了使得描述上更加的精简| 之后的过滤描述都是基于前一个模式src/**.cpp 中 * 所在的目录作为根目录也就是 src 目录的基础上来过滤匹配的所以后面的过滤子模式只需要设置 test/*.cpp 而不是 src/test/*.cpp。
对 add_files 更细粒度的编译选项控制
add_files(test/*.c, test2/test2.c, {defines TEST2, languages c99, includedirs ., cflags -O0})可以在add_files的最后一个参数传入一个配置table去控制指定files的编译选项里面的配置参数跟target的一致并且这些文件还会继承target的通用配置。
支持添加未知的代码文件
通过设置 rule 自定义规则实现这些文件的自定义构建例如
add_files(src/test/*.md, {rule markdown})并且可以通过 force 参数来强制禁用 cxflags, cflags 等编译选项的自动检测直接传入编译器哪怕编译器有可能不支持也会设置
add_files(src/*.c, {force {cxflags -DTEST, mflags -framework xxx}})3. C/C 依赖库
xmake 内置了对 C/C 的第三方包管理仓库的集成另外 xmake 还有自己的包依赖仓库 来更好的解决依赖包集成问题。
3.1 直接使用系统库
这里用 zlib 库举例首先创建一个快速工程。
xmake create -l c crc32如果我们要在代码中使用 crc32() 接口就要包含头文件 #include zlib.h。
要想使用该接口就要在 xmake.lua 中添加以下配置以找到这个系统库。
add_links(z)
add_linkdirs(/usr/lib/x86_64-linux-gnu)引入 zlib 库需要添加链接库、添加链接库搜索路径、添加头文件搜索路径。这里没有额外添加头文件搜索路径是因为 zlib.h 是在 /usr/include 目录下这个目录 xmake 会内置自动添加对应的 -I 选项到 gcc。 3.2 自动查找系统库
上小节通过 add_linkdirs() 方式来集成系统依赖库这个方式弊端很大因为带有 xmake.lua 的 C/C 项目有可能会在其它 Linux 环境甚至在其它系统上编译zlib 库并不一定安装在这个目录下。为了更加通用化的适配系统库路径推荐使用可以动态查找的接口
2.6.x 以前的版本的做法
find_packages()自动查找系统库所在的位置。
find_packages 来自动查找 zlib 库所在的位置通过这种方式集成之前我们可以先尝试直接执行下面的命令来探测 zlib 库的位置信息对这个接口返回的信息有个大概的了解。
xmake l find_packages zlib结构能得到链接库名、链接库的搜索路径有可能还会有头文件的搜索路径等信息因此我们只需要把这些信息自动探测到后设置到对应的目标程序中就可以实现自动集成安装在系统环境的依赖库了。
在 xmake.lua 下添加代码意为新增一个 on_load() 脚本块在里面调用 find_packages()将探测到的 zlib 库信息直接动态设置到 target 里。
on_load(function (target)target:add(find_packages(zlib))end)修改完成后执行 xmake -rv其编译输出应该跟之前的输出完全一致才对。
不过需要注意的一点是xmake 默认会缓存依赖包的检测结果并不是每次编译都会重新检测如果之前检测失败那么结果也会缓存这个时候我们可以执行 xmake f -c在配置时候忽略之前的缓存内容就会自动重新触发各种检测。
现在的版本有更便捷的做法
如果需要的库在当前环境中还没有安装xmake 提供了依赖包的自动远程下载以及安装集成功能
add_requires()接口指定当前项目需要哪些包配置这个编译时候会触发一次依赖包的安装。add_packages()用来配置对特定 target 目标集成指定的依赖包这两者需要配合使用缺一不可。
add_requires(zlib, {system false}) # 当前的实验环境中已经存在了 zlib 库所以 add_requires(zlib) 默认会优先自动检测系统环境中的 zlib 库如果存在就直接使用也就是内置了 find_packages(zlib) 的逻辑。# 而这里出于演示远程下载的逻辑配置 {system false} 强制触发远程下载人为忽略了系统库的探测逻辑在实际项目中可根据自己的需求来决定是否配置这个选项。
target(crc32)set_kind(binary)add_files(src/*.c)add_packages(zlib)执行 xmake 重新来编译项目如果安装和编译成功会有信息提示说明我们配置的 zlib 包有在官方仓库中被收录并且当前平台支持这个依赖包的集成。
另外我们的包检测结果都是有本地缓存的第二次编译并不会再触发依赖包的下载安装会直接参与集成编译。如果再次执行 xmake -rv 重新编译就不会再去安装 zlib 库了不过同样可以正常集成 zlib 来重新编译项目。
对于下载的依赖包可以执行卸载命令进行卸载。
xmake require --uninstall zlib同样虽然卸载了包但是当前项目的配置缓存还在如果继续执行 xmake 命令还是会使用缓存的 zlib 包信息。
因此可以执行下 xmake f -c 命令强制忽略缓存配置触发依赖包的重新检测逻辑。
集成第三方库中的包
TODO