xmake的简易学习

文章目录

      • 1. xmake是什么
      • 2. 一个可执行程序
      • 3. 一个库文件
      • 4. 遍历文件用法
      • 5. 第三方库
        • 3.1 系统安装库
        • 3.2 独立库
      • 6. 后续

由于前一篇博客的最后说要做一些rknn的优化,其实这个工作很早就完成了,但是我是使用 xmake这个来做我的工程的构建的,不管是出于对之后的博客的铺垫,还是对 xmake的欣赏和喜欢,我觉得有必要写这么一篇博客。

1. xmake是什么

相信我们写C/C++的更多的都知道CMake,也大致知道这个东西在当前跨平台编译的地位。或者还会了解其他的,比如:makefileninjia等等。

但是不知道你有没有像我一样,在写CMakeLists.txt的时候,总是吐槽这凌乱的语法,不关心大小写就算了,然后各种东西又臭又长,尤其是写面向对象多了以后,就更讨厌CMake这丑陋的语法。尤其是看到gopython这些语言中,特别好用方便的包管理的时候,就更嫌弃了。

我也是偶然间看到了xmake的,有中文的文档,简洁的语法(如果你有lua语言的基础,就更喜欢这样的语法),还有一个特别方便的包管理,我是就自个儿看着文档学了起来。

后来我自己的github上一些小代码也都使用xmake进行构建,还有自己本地的gitlab的代码也都使用xmake了,可能写的水平不是很高,但带来的方便是让我很受用的。

OK,废话说完,真心希望大家可以看看xmake,也许你也会喜欢上用这个工具。

2. 一个可执行程序

由于xmake官方的文档已经非常详细了,而且还有中文的文档,非常适合我们自学和使用,我就不卖弄知识,就简单根据自己的使用,写几个很简单的demo来介绍一下xmake的基础用法。

首先就是一个可执行程序,我还是用最经典的HELLO WORLD来说。

有这样一个目录结构:

- src
-- main.cpp
- xmake.lua

就这样的一个简单的示例,注意到这里有一个xmake.lua,这个就是我们进行构建的核心。那么我们这个xmake.lua怎么写?我直接给一个很简单的demo

-- 设置项目名称,可有可无
set_project("xmake_exec")
-- 设置支持的编译模式
add_rules("mode.debug", "mode.release")-- 配置 debug 下的一些编译选项
if is_mode("debug") then    -- 启用 debug 时的调试符号set_symbols("debug")-- 禁用优化set_optimize("none")
end-- 配置 release 下的一些编译选项
if is_mode("release") then-- 隐藏调试符号set_symbols("hidden")-- 设置优化set_optimize("fastest")-- 删除所有的调试符号set_strip("all")
end-- 将所有的警告都视为错误
set_warnings("all", "error")-- 设置 c99 c++11
set_languages("c99", "c++11") -- cxx11-- 添加一些宏定义
-- add_defines("NDEBUG", "_GNU_SOURCE=1")-- 设置包含目录
-- add_includedirs("/usr/include", "/usr/local/include")-- 设置依赖的库和目录
-- add_links("tbox")
-- add_linkdirs("/usr/local/lib", "/usr/lib")-- 添加系统链接库
-- add_syslinks("z", "pthread")-- 添加编译链接的参数
-- add_cxflags("-stdnolib", "-fno-strict-aliasing")
-- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true})target("xmake_exec")set_kind("binary")add_files("src/*.cpp")

这里面写了很多注释的东西,都是一些暂时没用上的,可以供后续使用的时候添加。这里的各种“函数”,其实都可以在xmake官方文档中有详细的介绍和demo,我肯定没有作者写的深入和详细,所以如果想要了解每一个“函数”的作用,还请认真看一下。

我这里直接说target这个部分。

顾名思义,target就是目标,也就是我们当前这个xmake.lua所要构建的目标,只需要上述那么简单的三行就可以搞定,我们可以对应的理解CMake中的:

add_executable(xmake_exec src/main.cpp)

当然,如果你的文件特别多的时候,你就只能使用CMakefile(GLOB ...)来实现了,但是xmake就是上述简单的add_files("src/*.cpp)来实现,是不是很优雅,尤其是你在Linux下使用shell命令习惯了之后的写法?

题外话,我觉得xmake使用的特别舒服的一点就是,它能让你觉得“就应该是这样的嘛”,而不是CMake那样很繁琐且难用的方式。

3. 一个库文件

如果只是写一个可执行程序,那也太没水平了,只能用来做做测试,那么如何生成一个库文件?

在这里插入图片描述

OK,这样一个目录结构,有头文件,有源文件,然后还有我们的xmake.lua,那我们的xmake.lua也很简单:

-- 设置项目名称
set_project("xmake_lib")-- 设置版本
set_version("1.0.0")-- 设置xmake的最低要求版本
set_xmakever("2.6.9")-- 设置支持的编译模式
add_rules("mode.debug", "mode.release")-- 配置 debug 下的一些编译选项
if is_mode("debug") then    -- 启用 debug 时的调试符号set_symbols("debug")-- 禁用优化set_optimize("none")
end-- 配置 release 下的一些编译选项
if is_mode("release") then-- 隐藏调试符号set_symbols("hidden")-- 设置优化set_optimize("fastest")-- 删除所有的调试符号set_strip("all")
end-- 将所有的警告都视为错误
set_warnings("all", "error")-- 设置 c99 c++11
set_languages("c99", "c++11") -- cxx11-- 添加一些宏定义
add_defines("DREAMSKY_EXPORTS")-- 设置包含目录
-- add_includedirs("/usr/include", "/usr/local/include")-- 设置依赖的库和目录
-- add_links("tbox")
-- add_linkdirs("/usr/local/lib", "/usr/lib")-- 添加系统链接库
-- add_syslinks("z", "pthread")-- 添加编译链接的参数
-- add_cxflags("-stdnolib", "-fno-strict-aliasing")
-- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true})target("xmake_lib")    -- 这样可以在外部直接传参,从而构建需要的set_kind("$(kind)")-- set_kind("shared")-- set_kind("static")-- 如果需要外部配置是否需要进行传参,比如 --var=val 的时候,可以使用-- add_defines("-DTEST=$(var)")add_includedirs("include", {public = true})-- 如果头文件的目录比较复杂,那么就需要这样进行处理-- 通配符include/**.h匹配include目录及其子目录的所有.h后缀文件。-- 对于add_headerfiles语句,如果不加括号,则所有文件都会被直接安装到include文件夹下,-- 目录结构将会丢失;而括号的作用在于保持括号内的目录结构。-- 例如a/(b/c.h)安装后会变成include/b/c.h。-- 而在设置中的prefixdir选项则将所有头文件放在include的子目录中。-- 如对于上述设置{prefixdir = "mylib"},a/(b/c.h)安装后会变成include/mylib/b/c.h-- add_headerfiles("include/(**.h)", {prefixdir = "DreamSky"})add_headerfiles("include/*.h")add_files("src/*.cpp")-- 有时候使用xmake构建的库需要导出给使用其他构建系统的项目使用,-- 这就需要对应构建工具的配置文件。xmake提供pkg-config配置文件和cmake配置文件的生成。-- 对于需要导出的target,使用如下语句:add_rules("utils.install.pkgconfig_importfiles")add_rules("utils.install.cmake_importfiles")-- 对于头文件之外的安装文件,xmake提供了类似的接口add_installfiles,-- 它与add_headerfiles的区别在于,prefixdir将直接放在安装目录下而不是include文件夹下。-- 例如文档安装可以写-- add_installfiles("doc/*.md", {prefixdir = "share/doc"})if is_plat("windows") and is_kind("shared") thenprint("windows shared")end-- 有时候,项目生成的库和二进制不要按约定的bin和lib目录存放,甚至不需要被安装。-- 还有时候,安装的文件需要根据安装目录做一定的更改。-- 这时可以使用on_install语句来重载target的安装过程。例如,将生成的库文件安装到xmake_lib文件夹:-- on_install(function (target)--     local libdir = path.join(target:installdir(), "xmake_lib")--     os.mkdir(libdir)--     os.cp(target:targetfile(), libdir)--     local includedir = path.join(target:installdir(), "xmake_lib_include")--     os.mkdir(includedir)--     for _, headerfile in ipairs(target:headerfiles()) do--         os.cp(headerfile, includedir)--     end-- end)-- 编译安装命令示例:
-- 清除编译配置: xmake clean
-- 清除所有:     xmake clean --all
-- 指定编译器:   xmake f -p mingw       xmake f -p windows
-- 指定编译模式: xmake f -m debug       xmake f -m release
-- 指定库类型:   xmake f -k shared      xmake f -k static
-- 指定安装目录:  xmake install -o "D:/install/xmake_lib"-- 简短示例:
-- xmake f -p mingw -m debug -k shared
-- xmake
-- xmake install -o "D:/install/xmake_lib"

我也是加了一些注释,我觉得似乎都不需要额外的说明了,就很清晰了。

当然新版本的xmake已经支持给so文件加上版本号了,也就是很简单的:

set_version("1.0.0", {soname = true})

4. 遍历文件用法

很多时候我们需要写很小的demo来验证某个函数,或者某个小算法,好吧,总不能每个文件写一个xmake工程吧?不仅要新建工程,还得写xmake.lua,就很麻烦。

能不能我随意添加文件,然后又能够根据我的文件名自动生成对应的target,然后每次只需要在工程中新建一个.cpp文件就可以了呢?

当然可以!

假设,有这样的目录:

在这里插入图片描述

以后我要是再随便增加test_04.cpp,不用改xmake.lua可不可以做到?答案是肯定的。

那这里的xmake.lua就可以这样写:

-- 遍历和生成部分参考:
-- https://github.com/idealvin/coost/blob/master/test/xmake.lua-- 设置项目名称
set_project("xmake_foreach")-- 设置版本
set_version("1.0.0")-- 设置xmake的最低要求版本
set_xmakever("2.6.9")-- 设置支持的编译模式
add_rules("mode.debug", "mode.release")-- 配置 debug 下的一些编译选项
if is_mode("debug") then    -- 启用 debug 时的调试符号set_symbols("debug")-- 禁用优化set_optimize("none")
end-- 配置 release 下的一些编译选项
if is_mode("release") then-- 隐藏调试符号set_symbols("hidden")-- 设置优化set_optimize("fastest")-- 删除所有的调试符号set_strip("all")
end-- 将所有的警告都视为错误
set_warnings("all", "error")-- 设置 c99 c++11
set_languages("c99", "c++11") -- cxx11-- 使用函数来遍历cpp文件夹,后续根据遍历的结果来处理
function all_tests()local res = {}for _, x in ipairs(os.files("**.cpp")) dolocal item = {}local s = path.filename(x)table.insert(item, s:sub(1, #s - 4))       -- 取文件名来作为target的名字table.insert(item, path.relative(x, "."))  -- 利用path.relative来转换相对路径,即将 x 转换为相对于 . 的相对路径table.insert(res, item)endreturn res
endfor _, test in ipairs(all_tests()) do
target(test[1])set_kind("binary")-- set_default(false)add_files(test[2])
end

这是直接参考xmake作者的coost来进行实现的,额外说一句,作者的coost库也很强,而且没有Boost那么庞大复杂,如果想学习一些编程的思路,可以阅读这个源码,还是很容易看明白的。

5. 第三方库

当然xmake有一个特别好用的仓库,你添加opencv这些依赖的时候,只需要:

add_requires("opencv")target("test")add_files("src/*.cpp")add_packages("opencv")

就可以了,而且可以自动从网络上下载相关的库文件。

3.1 系统安装库

当然,如果你系统上已经安装了这个opencv库,你就是不想用xmake repo的库,也是可以的。

add_requires("cmake::OpenCV", {alias = "opencv", system = true})target("test")add_files("src/*.cpp")add_packages("opencv")

是不是很简单,可以调用cmake的库,当然xmake支持的可多了,具体的参考官方文档。

3.2 独立库

这些都是安装的,那么对于我们使用rknn来说,他就是提供了头文件和库文件,我们怎么来加入到编译呢?当然你可以直接将头文件和库文件加到target的编译中来,可是那也太不优雅了,而且工程多了起来就乱。所以我们需要一个优雅的使用方法,有没有呢?有!

我们可以通过创建一个本地的xmake repo来实现,将他们按照xmake的语法来进行描述,然后就可以在我们的工程中直接使用了,下一篇写rknn的优化的时候将详细说如何将rknnrtrga来优雅地写到我们的xmake repo中。

假设我们已经能将rknnrt按照xmake语法写好了,并且我们的xmake repo地址是/home/xxx/xmake_repo,那么我们工程中直接就可以:

add_repositories("local-repo /home/xxx/xmake_repo")
add_requires("rknnrt", "librga")target("rknn_engine")add_includedirs("include", {public = true})add_headerfiles("include/(**.h)")add_files("src/**.cpp")add_packages("rknnrt", "librga")

是不是很优雅了?

6. 后续

xmake的官方文档已经足够详细了,我觉得没有那个水平能超过作者的文档,只是在自己的使用过程中有一些心得体会,也在自己的githubgitlab和工作中使用了xmake,水平也不算高,如果你也恰好是入门,有一些我也恰好知道的问题,欢迎一起交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85573.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ArcGIS微课1000例】0147:Geographic Imager6.2下载安装教程

文章目录 一、软件功能二、下载地址三、安装教程Geographic Imager地图工具使Adobe Photoshop空间图像可以快速高效地工作。它增加了导入,编辑,操作和导出地理空间图像的工具,例如航空和卫星图像。Geographic Imager Mac功能非常强大,拥有栅格数据输出、投影信息修改、基于…

【 java 集合知识 第一篇 】

1.概念 1.1.集合与数组的区别 集合:长度不固定,动态的根据数据添加删除改变长度,并且只能存入引用类型,读取采用迭代器或其他方法 数组:长度固定,不可改变,既可以存入基本类型也可以存入引用…

嵌入式开发学习日志(linux系统编程--系统编程之 进程间通信IPC)Day32

一、引言 空间独立,需要一些操作; 分为三大类: 1、古老的通信方式 无名管道 有名管道 信号 2、IPC对象通信 system v BSD suse fedora kernel.org 消息队列(用的相对少,这里不讨论) …

metersphere不同域名的参数在链路测试中如何传递?

域名1:https://api.domain1.com 域名2:https://api.domain2.com 域名1的返回参数stteid会作为域名2的入参 步骤: 1)先在metersphere—接口测试—接口定义中创建域名1和域名2的接口 2)接口创建好后,在接口测…

使用Process Explorer、System Informer(Process Hacker)和Windbg工具排查软件高CPU占用问题

目录 1、问题现象 2、使用Process Explorer和System Informer(该工具原先叫Process Hacker)查看占用CPU高的线程 3、使用System Informer工具时发现了一个关键细节 4、将Windbg附加到软件进程上,根据System Informer中显示的线程id到Wind…

Linux(线程概念)

目录 一 虚拟地址到物理地址的转换 1. 操作系统如何管理物理内存: 2. 下面来谈谈虚拟地址如何转换到物理地址: 3. 补充字段: 二 Linux中的线程 1. 先来说说进程: 2. 线程: 3. 线程相比较于进程的优缺点&#x…

阿里云为何,一个邮箱绑定了两个账号

阿里云“幽灵账号”之谜:同一个邮箱注销后仍有两个账号?深度揭秘成因与终极解决方案! 你是否曾在阿里云上使用同一个邮箱注册过多个账号,明明已经**“彻底”注销了其中一个**,却惊愕地发现系统里依然**“幽灵般”挂着…

动态规划-数位DP

今天开始做关于数位DP的问题,首先对于数位DP来说,这类问题难度较大,比较难理解,所以博主也会尽量讲的更加详细一些,来帮助大家更好地理解这里的相关知识。 前置知识: 1.首先对于数位DP来说,主…

总览四级考试

别被“四级”这个庞然大物吓到!我们一起拆解它:​​ 📍 ​​核心认知:四级是一场策略性考试!​​ 它不考智商,考的是​​基础英语能力 考试技巧 时间管理​​。基础可以通过努力补,技巧可以…

BSRR对比BRR对比ODR

✅ 三种操作方式的本质区别 寄存器功能原子操作特点BSRR同时支持置位(1)和复位(0)✔️ 是单指令完成任意位操作,无竞争风险ODR直接读写输出状态❌ 否需"读-改-写",多线程/中断中需关中断保护BRR只能复位(0)✔️ 是仅清零功能,无置…

职坐标精选嵌入式AI物联网开源项目

随着嵌入式、AI与物联网技术的深度融合,开源生态已成为开发者构建智能硬件解决方案的核心驱动力。本文将从嵌入式实时操作系统、多模态AI数据集及物联网接入平台三大维度切入,系统性梳理技术选型要点与实践路径。在嵌入式领域,重点解析低功耗…

Ubuntu系统 | 本地部署ollama+deepseek

1、Ollama介绍 Ollama是由Llama开发团队推出的开源项目,旨在为用户提供高效、灵活的本地化大型语言模型(LLM)运行环境。作为Llama系列模型的重要配套工具,Ollama解决了传统云服务对计算资源和网络连接的依赖问题,让用户能够在个人电脑或私有服务器上部署和运行如Llama 3等…

【数据库】关系数据库标准语言-SQL(金仓)下

4、数据查询 语法&#xff1a; SELECT [ALL | DISTINCT] <目标列表达式> [,<目标列表达式>] … FROM <表名或视图名>[, <表名或视图名> ] … [ WHERE <条件表达式> ] [ GROUP BY <列名1> [ HAVING <条件表达式> ] ] [ ORDER BY <…

基于YOLO-NAS-Pose的无人机象群姿态估计:群体行为分析的突破

【导读】 应对气候变化对非洲象的生存威胁&#xff0c;本研究创新采用无人机航拍结合AI姿态分析技术&#xff0c;突破传统观测局限。团队在肯尼亚桑布鲁保护区对比测试DeepLabCut与YOLO-NAS-Pose两种模型&#xff0c;首次将后者引入野生动物研究。通过检测象群头部、脊柱等关键…

8.RV1126-OPENCV 视频中添加LOGO

一.视频中添加 LOGO 图像大体流程 首先初始化VI,VENC模块并使能&#xff0c;然后创建两个线程&#xff1a;1.把LOGO灰度化&#xff0c;然后获取VI原始数据&#xff0c;其次把VI数据Mat化并创建一个感兴趣区域&#xff0c;最后把LOGO放感兴趣区域里并把数据发送给VENC。2.专门获…

AI+3D 视觉重塑塑料袋拆垛新范式:迁移科技解锁工业自动化新高度

在工业自动化浪潮席卷全球的当下&#xff0c;仓储物流环节的效率与精准度成为企业降本增效的关键战场。其中&#xff0c;塑料袋拆垛作为高频、高重复性的作业场景&#xff0c;传统人工或机械臂操作面临着诸多挑战。迁移科技&#xff0c;作为行业领先的 3D 工业相机和 3D 视觉系…

MATLAB实战:视觉伺服控制实现方案

以下是一个基于MATLAB的视觉伺服控制项目实现方案&#xff0c;结合实时图像处理、目标跟踪和控制系统设计。我们将使用模拟环境进行演示&#xff0c;但代码结构可直接应用于真实硬件。 系统架构 图像采集 → 目标检测 → 误差计算 → PID控制器 → 执行器控制 完整代码实现 …

RequestRateLimiterGatewayFilterFactory

一、功能说明 RequestRateLimiterGatewayFilterFactory 是 Spring Cloud Gateway 的流量控制组件&#xff0c;用于实现 API 请求速率限制&#xff0c;核心功能包括&#xff1a; 限制单位时间内的请求数量&#xff08;如每秒10次&#xff09;防止服务被突发流量击垮&#xff0…

鸿蒙仓颉语言开发实战教程:购物车页面

大家上午好&#xff0c;仓颉语言商城应用的开发进程已经过半&#xff0c;不知道大家通过这一系列的教程对仓颉开发是否有了进一步的了解。今天要分享的购物车页面&#xff1a; 看到这个页面&#xff0c;我们首先要对它简单的分析一下。这个页面一共分为三部分&#xff0c;分别是…

AXURE安装+汉化-Windows

安装网站&#xff1a;https://www.axure.com/release-history/rp9 Axure中文汉化包下载地址 链接:https://pan.baidu.com/s/1U62Azk8lkRPBqWAcrJMFew?pwd5418 提取码:5418 下载完成之后&#xff0c;crtlc lang文件夹 到下载的Axure路径下 双击点进这个目录里面。ctrlv把lan…