xmake v2.1.5版本新特性介绍
2.1.5版本现已进入收尾阶段,此版本加入了一大波新特性,目前正在进行稳定性测试和修复,在这里,先来介绍下新版本中引入了哪些新特性和改进。
1. 提供类似cmake的find_*系列接口,实现各种查找,例如:find_package, find_library, find_file, ...
2. 提供模块接口,实现编译器的各种检测,例如:has_features, has_flags, has_cincludes, has_cfuncs, ...
3. 实现大量扩展模块,提供文件下载、解压缩、git操作等接口
4. 支持预编译头文件支持,改进c++编译效率
5. 支持在工程中自定义模块进行扩展
6. 提供代码片段检测接口,实现更加灵活定制化的检测需求
7. 改进option和target,提供更加动态化的配置
8. 通过find_package实现包依赖管理2.0版本
9. 改进root权限问题,实现更加安全的root下运行
10. 提供compile_commands.json导出插件
11. 改进vs201x工程生成插件,支持多模式、多架构同时构建和自由切换不干扰
利用find_package查找依赖包
此接口参考了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中去。
实现包管理2.0
2.1.4版本之前,xmake对于包管理,是通过在项目内置pkg/zlib.pkg
方式,来检测链接的,虽然也支持自动检测,但是查找功能有限,并且内置的各个架构的二进制库到项目,对git并不是很友好。
现在通过find_package
和option
,我们可以实现更好的包管理:
option("zlib")
set_showmenu(true)
before_check(function (option)
import("lib.detect.find_package")
option:add(find_package("zlib"))
end)
target("test")
add_options("zlib")
通过定义一个名为zlib的选项作为包,关联到target,在选项被检测之前,先从系统中查找zlib包,如果存在,则添加对应的links
, linkdirs
等配置信息,然后进行选项检测,如果选项检测通过,这个target在编译的时候就会启用zlib。
如果要手动禁用这个zlib包,使其不参与自动检测和链接,只需要:
$ xmake f --zlib=n
$ xmake
注:2.2.1版本将会实现包管理3.0,更加自动化的依赖包管理和使用,具体详情见:Remote package management。
例如:
add_requires("mbedtls master optional")
add_requires("pcre2 >=1.2.0", "zlib >= 1.2.11")
add_requires("git@github.com:glennrp/libpng.git@libpng >=1.6.28")
target("test")
add_packages("pcre2", "zlib", "libpng", "mbedtls")
目前正在努力开发中,尽情期待。。
模块的自定义扩展
我们可以通过在工程的xmake.lua
文件的开头指定下扩展modules的目录:
add_moduledirs("$(projectdir)/xmake/modules")
这样xmake就能找到自定义的扩展模块了,例如:
projectdir
- xmake
- modules
- detect/package/find_openssl.lua
通过在自定义的工程模块目录,添加一个find_openssl.lua
的脚本,就可以扩展find_package
,使得包查找更加精准。
这里顺便总结下,find_package
的查找顺序:
- 如果指定
{packagedirs = ""}
参数,优先从这个参数指定的路径中查找本地包*.pkg
- 如果在
xmake/modules
下面存在detect.packages.find_xxx
脚本,那么尝试调用此脚本来改进查找结果 - 如果系统存在
pkg-config
,并且查找的是系统环境的库,则尝试使用pkg-config
提供的路径和链接信息进行查找 - 如果系统存在
homebrew
,并且查找的是系统环境的库,则尝试使用brew --prefix xxx
提供的信息进行查找 - 从参数中指定的pathes路径和一些已知的系统路径
/usr/lib
,/usr/include
中进行查找
快速判断编译器特性检测支持
通过core.tool.compiler
模块的compiler.has_features接口,在xmake.lua
中预先判断当前编译期支持的语言特性,实现条件编译。
此处也是参考了cmake的设计,具体详情见:issues#83。
target("test")
on_load(function (target)
import("core.tool.compiler")
if compiler.has_features("cxx_constexpr") then
target:add("defines", "HAS_CXX_CONSTEXPR=1")
end
end)
上述代码,在加载target的时候,判断当前编译器是否支持c++的常量表达式语法特性,如果支持则添加宏定义:HAS_CXX_CONSTEXPR=1
。
我们也可以在判断时候,追加一些参数控制编译选项,例如上述特性需要c++11
支持,我们可以启用它:
if compiler.has_features({"c_static_assert", "cxx_constexpr"}, {languages = "cxx11"}) then
-- ok
end
如果之前对这个target已经设置了c++11
,那么我们也可以传入target对象,继承target的所有设置:
if compiler.has_features("cxx_constexpr", {target = target, defines = "..", includedirs = ".."}) then
-- ok
end
所有的c/c++编译器特性列表,见:compiler.features
判断指定c/c++头文件是否存在
通过lib.detect.has_cincludes来检测c头文件是否存在。
import("lib.detect.has_cincludes")
local ok = has_cincludes("stdio.h")
local ok = has_cincludes({"stdio.h", "stdlib.h"}, {target = target})
local ok = has_cincludes({"stdio.h", "stdlib.h"}, {defines = "_GNU_SOURCE=1", languages = "cxx11"})
c++头文件的检测,见:lib.detect.has_cxxincludes
判断指定c/c++函数是否存在
通过lib.detect.has_cfuncs来检测c函数是否存在。
import("lib.detect.has_cfuncs")
local ok = has_cfuncs("setjmp")
local ok = has_cfuncs({"sigsetjmp((void*)0, 0)", "setjmp"}, {includes = "setjmp.h"})
c++函数的检测,见:lib.detect.has_cxxfuncs。
判断指定c/c++类型是否存在
通过lib.detect.has_ctypes来检测c函数是否存在。
import("lib.detect.has_ctypes")
local ok = has_ctypes("wchar_t")
local ok = has_ctypes({"char", "wchar_t"}, {includes = "stdio.h"})
local ok = has_ctypes("wchar_t", {includes = {"stdio.h", "stdlib.h"}, "defines = "_GNU_SOURCE=1", languages = "cxx11"})
c++类型的检测,见:lib.detect.has_cxxtypes。
检测c/c++代码片段是否能够编译通过
通用的c/c++代码片段检测接口,通过传入多个代码片段列表,它会自动生成一个编译文件,然后常识对它进行编译,如果编译通过返回true。
对于一些复杂的编译器特性,连compiler.has_features都无法检测到的时候,可以通过此接口通过尝试编译来检测它。
import("lib.detect.check_cxsnippets")
local ok = check_cxsnippets("void test() {}")
local ok = check_cxsnippets({"void test(){}", "#define TEST 1"}, {types = "wchar_t", includes = "stdio.h"})
此接口是detect.has_cfuncs, detect.has_cincludes和detect.has_ctypes等接口的通用版本,也更加底层。
因此我们可以用它来检测:types, functions, includes 还有 links,或者是组合起来一起检测。
第一个参数为代码片段列表,一般用于一些自定义特性的检测,如果为空,则可以仅仅检测可选参数中条件,例如:
local ok = check_cxsnippets({}, {types = {"wchar_t", "char*"}, includes = "stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}})
上面那个调用,会去同时检测types, includes和funcs是否都满足,如果通过返回true。
更加强大的xmake lua插件
2.1.4版本的时候,此插件就已经支持REPL(read-eval-print),实现交互式运行来方便测试模块:
$ xmake lua
> 1 + 2
3
> a = 1
> a
1
> for _, v in pairs({1, 2, 3}) do
>> print(v)
>> end
1
2
3
现在可以通过一行命令,更加快速地测试模块接口:
$ xmake lua lib.detect.find_package openssl
返回结果如下:{links = {"ssl", "crypto", "z"}, linkdirs = {"/usr/local/lib"}, includedirs = {"/usr/local/include"}}
预编译头文件支持
xmake新增通过预编译头文件去加速c/c++
程序编译,目前支持的编译器有:gcc, clang和msvc。
使用方式如下:
target("test")
set_precompiled_header("header.h")
通常情况下,设置c头文件的预编译,这需要加上这个配置即可,如果是对c++头文件的预编译,改成:
target("test")
set_precompiled_header("header.hpp")
其中的参数指定的是需要预编译的头文件路径,相对于当前xmake.lua
所在的目录。
如果只是调用xmake命令行进行直接编译,那么上面的设置足够了,并且已经对各个编译器进行支持,但是有些情况下,上面的设置还不能满足需求:
- 如果要使用
xmake project
工程插件生成vs工程文件,那么还缺少一个类似stdafx.cpp
的文件(上面的设置在msvc编译的时候会自动生成一个临时的,但是对IDE工程不友好)。 - 如果gcc/clang下,
header.h
想作为c++的预编译头文件就不支持了,除非改成header.hpp
(默认会当做c头文件进行预编译)。
因此为了更加地通用跨平台,可以在工程里面创建一个类似vc中stdafx.cpp
的源文件:header.cpp
。
target("test")
set_precompiled_header("header.h", "header.cpp")
header.cpp
的内容如下:
#include "header.h"
上面的设置,就可以很好地处理各种情况下的预编译处理,追加的header.cpp
也告诉了xmake:header.h
是作为c++来预编译的。
相对于经典的vc工程中的stdafx.cpp
和stdafx.h
,也能完美支持:
target("test")
set_precompiled_header("stdafx.h", "stdafx.cpp")
生成compiler_commands插件
扩展xmake project
工程生成插件,支持compiler_commands.json
文件输出,用于导出每个源文件的编译信息,生成基于clang的编译数据库文件,json格式,可用于跟ide,编辑器,静态分析工具进行交互。
$ xmake project -k compile_commands
输出的内容格式如下:
[
{ "directory": "/home/user/llvm/build",
"command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc",
"file": "file.cc" },
...
]
一般用于跟IDE、编辑器插件、静态分析工具进行集成,对于compile_commands
的详细说明见:https://clang.llvm.org/docs/JSONCompilationDatabase.html“>JSONCompilationDatabase
自定义选项检测脚本
在选项检测之前,动态增加一些配置条件:
option("zlib")
before_check(function (option)
import("lib.detect.find_package")
option:add(find_package("zlib"))
end)
通过覆写检测脚本,控制选项的检测结果:
option("test")
add_deps("small")
set_default(true)
on_check(function (option)
if option:dep("small"):enabled() then
option:enable(false)
end
end)
如果test依赖的选项通过,则禁用test选项。
在选项检测完成后,执行此脚本做一些后期处理,也可以在此时重新禁用选项:
option("test")
add_deps("small")
add_links("pthread")
after_check(function (option)
option:enable(false)
end)
自定义目标加载脚本
在target初始化加载的时候,将会执行on_load,在里面可以做一些动态的目标配置,实现更灵活的目标描述定义,例如:
target("test")
on_load(function (target)
target:add("defines", "DEBUG", "TEST=\"hello\"")
target:add("linkdirs", "/usr/lib", "/usr/local/lib")
target:add({includedirs = "/usr/include", "links" = "pthread"})
end)
可以在on_load
里面,通过target:set
, target:add
来动态添加各种target属性。
目标自定义构建脚本支持分平台架构
通过设置平台|架构
参数,控制自定义脚本的执行条件,实现在不同平台、架构下,调用不同的脚本进行构建:
target("test")
on_build("iphoneos|arm*", function (target)
-- TODO
end)
或者对所有macosx平台,执行脚本:
target("test")
after_build("macosx", function (target)
-- TODO
end)
其他脚本,例如:on_clean
, before_package
等也都是支持的哦,而在2.1.4之前,只支持:
target("test")
on_package(function (target)
-- TODO
end)
并不能对不同架构、平台分别处理。
获取内置变量的值
内置变量可以通过此接口直接获取,而不需要再加$()
的包裹,使用更加简单,例如:
print(val("host"))
print(val("env PATH"))
local s = val("shell echo hello")
而用vformat就比较繁琐了:
local s = vformat("$(shell echo hello)")
不过vformat
支持字符串参数格式化,更加强大,所以应用场景不同。
目标依赖实现属性继承
2.1.4之前的版本,target.add_deps仅用于添加依赖,修改编译顺序:
target("test1")
set_kind("static")
set_files("*.c")
target("test2")
set_kind("static")
set_files("*.c")
target("demo")
add_deps("test1", "test2")
add_links("test1", "test2")
add_linkdirs("test1dir", "test2dir")
2.1.5版本后,target还会自动继承依赖目标中的配置和属性,不再需要额外调用add_links
, add_includedirs
和add_linkdirs
等接口去关联依赖目标了,上述代码可简化为:
target("test1")
set_kind("static")
set_files("*.c")
target("test2")
set_kind("static")
set_files("*.c")
target("demo")
add_deps("test1", "test2") -- 会自动链接依赖目标
并且继承关系是支持级联的,例如:
target("library1")
set_kind("static")
add_files("*.c")
add_headers("inc1/*.h")
target("library2")
set_kind("static")
add_deps("library1")
add_files("*.c")
add_headers("inc2/*.h")
target("test")
set_kind("binary")
add_deps("library2")
新增查找工具接口
lib.detect.find_tool接口用于查找可执行程序,比lib.detect.find_program更加的高级,功能也更加强大,它对可执行程序进行了封装,提供了工具这个概念:
- toolname: 工具名,可执行程序的简称,用于标示某个工具,例如:
gcc
,clang
等 - program: 可执行程序命令,例如:
xcrun -sdk macosx clang
lib.detect.find_program
只能通过传入的原始program命令或路径,去判断该程序是否存在。
而find_tool
则可以通过更加一致的toolname去查找工具,并且返回对应的program完整命令路径,例如:
import("lib.detect.find_tool")
local tool = find_tool("clang")
我们也可以指定{version = true}
参数去获取工具的版本,并且指定一个自定义的搜索路径,也支持内建变量和自定义脚本哦:
local tool = find_tool("clang", {check = "--help"})
local tool = find_tool("clang", {check = function (tool) os.run("%s -h", tool) end})
local tool = find_tool("clang", {version = true, {pathes = {"/usr/bin", "/usr/local/bin", "$(env PATH)", function () return "/usr/xxx/bin" end}})
最后总结下,find_tool
的查找流程:
- 优先通过
{program = "xxx"}
的参数来尝试运行和检测。 - 如果在
xmake/modules/detect/tools
下存在detect.tools.find_xxx
脚本,则调用此脚本进行更加精准的检测。 - 尝试从
/usr/bin
,/usr/local/bin
等系统目录进行检测。
我们也可以在工程xmake.lua
中add_moduledirs
指定的模块目录中,添加自定义查找脚本,来改进检测机制:
projectdir
- xmake/modules
- detect/tools/find_xxx.lua
更加安全的root权限编译
由于xmake提供强大的自定义模块和脚本支持,并且内置安装、卸载等action,如果xmake.lua
里面的脚本描述不当,容易导致覆写系统文件,因此新版本对此作了改进:
- 在root下编译工程,先判断工程目录的用户权限属性,尝试降权到非root用户进行编译。
- 如果需要写一些系统文件,会提示用户当前权限不安全,禁止继续运行,除非加
--root
参数强制root运行。 - 如果当期工程目录是root用户权限,则同2。
具体详情见:pull#113
API接口改进
使用includes替代老的add_subdirs和add_subfiles接口。
使用set_config_header替代老的set_config_h和set_config_h_prefix接口。
新增大量扩展模块
- 文件下载
- 解压缩
- git操作等接口
具体详情见文档:扩展模块
xmake v2.1.5版本新特性介绍的更多相关文章
- EOS1.1版本新特性介绍
EOSIO/eos 目前在github的项目活跃度方面排名第一,release版本更新的速度让人应接不暇.今天EOS的大版本1.1发布,我也有幸参与了贡献,本篇文章重点介绍1.1版本的重大功能升级. ...
- xmake v2.1.5版本正式发布,大量新特性更新
此版本带来了大量新特性更新,具体详见:xmake v2.1.5版本新特性介绍. 更多使用说明,请阅读:文档手册. 项目源码:Github, Gitee. 新特性 #83: 添加 add_csnippe ...
- GrapeCity Documents for Excel 文档API组件 V2.2 新特性介绍
GrapeCity Documents for Excel 文档API组件 V2.2 正式发布,本次新版本包含诸多重量级产品功能,如:将带有形状的电子表格导出为 PDF.控制分页和电子表格内容.将Ex ...
- atitit.atiOrm.js v2 q61 版本新特性.docx
atitit.atiOrm.js v2 q61 版本新特性.docx 1. V1新特性如下1 1.1. V2规划,直接生成sql在js端1 2. Orm设计框架图1 2.1. atiOrm.js的原理 ...
- Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性
Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性 Apache hadoop 项目组最新消息,hadoop3.x以后将会调整方案架构,将Mapreduce 基于内存+io+ ...
- xmake v2.1.9版本发布,增加可视化图形菜单配置
此版本主要增加xmake f --menu实现用户自定义图形菜单配置,界面风格类似linux的make menuconfig: [图片上传失败-(image-505bc0-1517795319124) ...
- Atitit opencv版本新特性attilax总结
Atitit opencv版本新特性attilax总结 1.1. :OpenCV 3.0 发布,史上功能最全,速度最快的版1 1.2. 应用领域2 1.3. OPENCV2.4.3改进 2.4.2就有 ...
- 【开源】OSharp3.3框架解说系列:重新开源及3.3版本新特性
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- CentOS以及Oracle数据库发展历史及各版本新功能介绍, 便于构造环境时有个对应关系
CentOS版本历史 版本 CentOS版本号有两个部分,一个主要版本和一个次要版本,主要和次要版本号分别对应于RHEL的主要版本与更新包,CentOS采取从RHEL的源代码包来构建.例如CentOS ...
随机推荐
- dll和ocx的区别
ActiveX,OLE是基于COM的一种应用,其文件后缀一般以dll和ocx结尾:ocx作为一种特殊的dll文件,具有一定的用户界面和事件响应,而dll文件只是方法和属性的集合. 一.关于DLL的介绍 ...
- 强化学习(Reinfment Learning) 简介
本文内容来自以下两个链接: https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/ https: ...
- 复试笔试复习 & bd面试总结
计算机网络: 1.OSI模型中提供端到端服务的是传输层 2.波特率的含义是每秒钟信号变化的次数 3.非屏蔽双绞线中5类网线的数据速率为100Mbps,连接器是RJ-45 4.虚电路在数据链路层实现,电 ...
- SpringCloude学习脑图
SpringCloude学习脑图 http://naotu.baidu.com/file/3e619862813ac331c5d9806486771b42?token=1a7206b777280c6b
- Python核心技术与实战——四|Python黑箱:输入与输出
抽象的看,Python程序可以被看成一个黑箱:通过输入流将数据送达,经过处理后在输入,也就是说具备了一个图灵机运作的必要条件. 输入输出基础 最简单的输入是来自键盘的操作 name = input(' ...
- thinkphp5 yii2 laravel5.1 框架性能压测对比图
nginx+php7环境,opcache已经开启,每测试一个框架都重启服务器并且预热访问三次,压测工具ab.exe. laravel,thinkphp,yii都已关闭debug,该做的优化命令都搞了, ...
- flask项目中设置logo
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}&qu ...
- html+css 在图片上添加文字
html <view class="container"> <image class="" src="{{book.image}}& ...
- TCP/IP基础总结性学习(7)
确保 Web 安全的 HTTPS 在 HTTP 协议中有可能存在信息窃听或身份伪装等安全问题.使用 HTTPS 通信机制可以有效地防止这些问题. 一. HTTP 的缺点 HTTP 主要有这些不足,例举 ...
- Spring Security初识
Spring Security与Spring Boot集成 添加依赖: <dependency> <groupId>org.springframework.boot</g ...