如果我们要写跨平台的c/c++代码,很多时候需要处理由于不同编译器对c/c++各个标准支持力度不同导致的兼容性问题,一般通常的解决办法是:自己在代码中通过宏去判断各个编译器的版本、内置宏、标准库宏、__has_feature等来检测处理。

自己如果在代码中按上述的方式检测,会很繁琐,尤其是像c++这种存在大量语法特性,如果一一检测过来,工作量是非常大的。

通过构建工具预先检测编译特性

另外比较省事的方式,就是依赖构建工具提前做好检测,然后把检测结果作为宏添加到编译中去,这样代码只需要判断对应的特性宏是否存在,就可以进行处理了。

在cmake中就有类似的检测机制,非常强大,因此xmake也对其进行了支持,提供更加灵活强大的编译器特性预先检测支持:

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)

通过core.tool.compiler模块的compiler.has_features接口,在xmake.lua中预先判断当前编译期支持的语言特性,实现条件编译。

此处也是参考了cmake的设计,具体详情见:issues#83

上述代码,在加载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++的语言特性非常多,这个时候我们可以通过脚本实现快速的批量检测:

target("test")

    on_load(function (target)
import("core.tool.compiler")
for feature, _ in pairs(compiler.features("cxx", {target = target})) do -- 传入target在检测特性时继承target的所有编译配置
target:add("defines", "has_feature_" .. feature)
end
end)

上述代码,会在加载target的时候,把当前编译器对c++的所有支持特性,都添加到target的宏定义中进行编译,例如:-Dhas_feature_cxx_constexpr
我们只需要在代码中,通过判断对应的特性宏是否存在就行了:

#ifdef has_feature_cxx_constexpr
// TODO
#endif

目前支持的所有c/c++编译器特性列表,见:compiler.features

更加底层的检测接口

如果我们要指定获取具体哪个编译器的特性支持,则需要更加底层的接口支持了,例如:

import("lib.detect.has_features")

local features = has_features("clang", "cxx_constexpr")
local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = {"-g", "-O0"}, program =www.rcsx.org "xcrun -sdk macosx clang"})
local features = has_features("clang", {"cxx_constexpr", "c_static_assert"}, {flags = "-g"})

lib.detect.has_features属于探测模块的接口,可以指定需要检测的工具名,例如这里通过传入clang,只对clang编译器进行检测。

当然此接口,还可以检测其他非编译器的工具特性,更加的通用。

通过自定义c/c++代码片段来检测特性

对于一些复杂的编译器特性,连compiler.has_features都无法检测到的时候,可以通过自定义代码片段尝试编译来检测它。

import("lib.detect.check_cxsnippets")

local ok = check_cxsnippets("constexpr int f(int x) { return x ? x+f(x-1) : 0; } constexpr int x = f(5); static_assert(x == 15);", {sourcekind = "cxx", languages = "cxx11"})

上述代码通过自定义一个constexpr的测试代码,去检测c++11的constexpr支持。

此接口是detect.has_cfuncsdetect.has_cincludesdetect.has_ctypes等接口的通用版本,也更加底层。

因此我们可以用它来检测:types, functions, includes 还有 links,或者是组合起来一起检测。

第一个参数为代码片段列表,一般用于一些自定义特性的检测,如果为空,则可以仅仅检测可选参数中条件,例如:

 
local ok = check_cxsnippets({"void test() {}", "void test2() {}"}, {types = {"wchar_t", "char*"},www.rcsx.org includes ="stdio.h", funcs = {"sigsetjmp", "sigsetjmp((void*)0, 0)"}})

上面那个调用,会去同时检测types, includes和funcs是否都满足,如果通过返回true。

使用xmake检测编译器特性支持的更多相关文章

  1. objective-c 语法快速过(7)编译器特性ARC

    ARC(是编译器特性) ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain.release.autorelease语句.你不再需要担心内 ...

  2. 链接脚本在编程中的高级运用之二——执行时库和C++特性支持

    我们在链接脚本在编程中的高级运用之中的一个可变长数组中已经讲述了编译链接的原理,并且以uboot命令为例具体介绍链接脚本怎样实现可变长数组. 本章在前者的基础上继续讲述链接脚本在执行时库中的高级应用技 ...

  3. C 如何判断编译器是否支持C90 C99?

    参考:<C Primer Plus>,Stephen Prata著,姜佑译. ANSI/ISO C标准 美国ANSI成立委员会X3J11,于89/90年,99年,11年,发布C标准:C89 ...

  4. 华为方舟编译器正式支持C语言:完全开源

    投递人 itwriter 发布于 2020-10-14 19:08 评论(15) 有1938人阅读 原文链接 2019 年 8 月底,华为方舟编译器(OpenArkCompiler)正式开源,迈出了跨 ...

  5. MindSpore特性支持类

    MindSpore特性支持类 Q:请问MindSpore支持梯度截断吗? A:支持,可以参考梯度截断的定义和使用. Q:如何在训练神经网络过程中对计算损失的超参数进行改变? A:暂时还未有这样的功能. ...

  6. js检测浏览器是否支持某属性

    以检测浏览器是否支持 input 标签的 required 属性为例: var isSupport = 'required' in document.createElement('input');

  7. Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...

  8. WebSocket API使用篇检测浏览器是否支持WebSocket(4)

    WebSocket API是下一代客户端-服务器的异步通信方法.前面有三篇文章已经对WebSocket有了一些介绍,这里我总结了一下.我在使用WebSockets API过程中遇到的问题. 1.检测浏 ...

  9. 自动检测GD库支持的图像类型

    以下代码通过自动检测GD库支持的图像类型 来写出移直性更好的PHP代码 <?php if(function_exists("imagegif")){ header(" ...

随机推荐

  1. LaTeX小技巧——File ended while scanning use of \@writefile错误的

    早上在修改编译论文时发现了这个问题,仔细检查代码并没发现错误,一时也找不到具体的解决办法.我一直以为是因为runaway argument的错误提示,可实际上就是因为aux文件没有完整输入,导致上次编 ...

  2. ubuntu下安装ffmpeg扩展

    可通过PPA进行安装 sudo add-apt-repository ppa:kirillshkrogalev/ffmpeg-next sudo apt-get update sudo apt-get ...

  3. ios中frame设置宽高计算的Demo

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ int totalHeightOfScrollView = scrollView.con ...

  4. 一键部署joomla开源内容管理平台

    https://market.azure.cn/Vhd/Show?vhdId=10896&version=12949 产品详情 产品介绍Joomla是一套自由.开放源代码的内容管理系统,以PH ...

  5. JAVA-Web05

    1 HTTP协议特点   1)客户端->服务端(请求request)有三部份 a)请求行 b)请求头 c)请求的内容,如果没有,就是空白字符     2)服务端->客户端(响应respon ...

  6. Kippo-Failed to load application: 'module' object has no attribute 'IPluggableAuthenticationModules'

    Kippo-Failed to load application: 'module' object has no attribute 'IPluggableAuthenticationModules' ...

  7. Spring 和 Mybatis 整合

    Spring 和 Mybatis 整合 Spring本身的Config文件: 在IDEA下面配置好文件后, 在WEB-INF下面有三个配置文件分别是web.xml, applicationContex ...

  8. java中的String对象的创建及堆栈的解释

    java中的string真的是很令人头疼呢!!! 请看这里 看这里

  9. iOS下的2D仿射变换机制(CGAffineTransform相关)

    仿射变换简介 仿射变换源于CoreGraphics框架,主要作用是绘制2D级别的图层,几乎所有iOS设备屏幕上的界面元素都是由CoreGraphics来负责绘制.而我们要了解的2D仿射变换是其下负责二 ...

  10. Codeforces 517 #B

    http://codeforces.com/contest/1072/problem/B 开始想的只有搜索,时间复杂度$O(4^n)$,明显有问题. 想了半个小时没有思路,然后想到了正难则反,就开始步 ...