xmake 新版本即将发布,带来大量新特性,欢迎大家试用哦 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
waruqi

xmake 新版本即将发布,带来大量新特性,欢迎大家试用哦

  •  1
     
  •   waruqi 2017 年 7 月 31 日 3270 次点击
    这是一个创建于 3188 天前的主题,其中的信息可能已经有所发展或是发生改变。

    新版本现已进入收尾阶段,此版本加入了一大波新特性,欢迎大家过来试用哦,目前正在进行稳定性测试和修复.

    在这里,先来介绍下新版本中引入了哪些新特性和改进:

    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, includedirslinkdirs等信息添加到 target 中去。

    实现包管理 2.0

    2.1.4 版本之前,xmake 对于包管理,是通过在项目内置pkg/zlib.pkg方式,来检测链接的,虽然也支持自动检测,但是查找功能有限,并且内置的各个架构的二进制库到项目,对 git 并不是很友好。

    现在通过find_packageoption,我们可以实现更好的包管理:

    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("[email protected]: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的查找顺序:

    1. 如果指定{packagedirs = ""}参数,优先从这个参数指定的路径中查找本地包*.pkg
    2. 如果在xmake/modules下面存在detect.packages.find_xxx脚本,那么尝试调用此脚本来改进查找结果
    3. 如果系统存在pkg-config,并且查找的是系统环境的库,则尝试使用pkg-config提供的路径和链接信息进行查找
    4. 如果系统存在homebrew,并且查找的是系统环境的库,则尝试使用brew --prefix xxx提供的信息进行查找
    5. 从参数中指定的 pathes 路径和一些已知的系统路径/usr/lib, /usr/include中进行查找
    6. 快速判断编译器特性检测支持

      通过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_cincludesdetect.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 命令行进行直接编译,那么上面的设置足够了,并且已经对各个编译器进行支持,但是有些情况下,上面的设置还不能满足需求:

      1. 如果要使用xmake project工程插件生成 vs 工程文件,那么还缺少一个类似stdafx.cpp的文件(上面的设置在 msvc 编译的时候会自动生成一个临时的,但是对 IDE 工程不友好)。
      2. 如果 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.cppstdafx.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的详细说明见: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_includedirsadd_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的查找流程:

      1. 优先通过{program = "xxx"}的参数来尝试运行和检测。
      2. 如果在xmake/modules/detect/tools下存在detect.tools.find_xxx脚本,则调用此脚本进行更加精准的检测。
      3. 尝试从/usr/bin/usr/local/bin等系统目录进行检测。

      我们也可以在工程xmake.luaadd_moduledirs指定的模块目录中,添加自定义查找脚本,来改进检测机制:

      projectdir - xmake/modules - detect/tools/find_xxx.lua 

      更加安全的 root 权限编译

      由于 xmake 提供强大的自定义模块和脚本支持,并且内置安装、卸载等 action,如果xmake.lua里面的脚本描述不当,容易导致覆写系统文件,因此新版本对此作了改进:

      1. 在 root 下编译工程,先判断工程目录的用户权限属性,尝试降权到非 root 用户进行编译。
      2. 如果需要写一些系统文件,会提示用户当前权限不安全,禁止继续运行,除非加--root参数强制 root 运行。
      3. 如果当期工程目录是 root 用户权限,则同 2。

      具体详情见:pull#113

      API 接口改进

      使用includes替代老的add_subdirsadd_subfiles接口。

      使用set_config_header替代老的set_config_hset_config_h_prefix接口。

      新增大量扩展模块

      • 文件下载
      • 解压缩
      • git 操作等接口

      具体详情见文档:扩展模块

    1 条回复    2017-07-31 16:23:25 +08:00
    meepo3927
        1
    meepo3927  
       2017 年 7 月 31 日
    前端表示不懂, 帮顶
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3488 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSON: 3.9.8.5 92ms UTC 04:55 PVG 12:55 LAX 21:55 JFK 00:55
    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