Clang:从命令行或Python可靠地检测支持的C ++标准

时间:2018-02-27 15:23:02

标签: c++ clang clang++ llvm-clang

在Python脚本中,我试图确定已安装的Clang支持的最高C ++标准

一个问题是我不能依赖clang --version的输出始终相同 - 最好的例子是OSX上的AppleClang。 尝试编译带有.cpp-std=c++11等测试标志的hello world -std=c++14文件似乎不是最强大的方法,需要创建临时文件。

是否有任何命令可以运行以测试某个方言是否可用而不实际编译任何东西

1 个答案:

答案 0 :(得分:2)

  

是否有任何命令可以运行以测试某个方言是否可用而没有实际编译任何内容?

是。您可以要求编译器只预处理一个空文件。它会做到这一点 无怨无悔:

$ clang++ --version
clang version 4.0.1-6 (tags/RELEASE_401/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

$ echo '' | clang++ -x c++ -E -
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 329 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2

$ echo $?
0

然后您可以偶然添加-std选项。如果编译器支持它:

$ echo '' | clang++ -std=c++98 -x c++ -E -
# 1 "<stdin>"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 326 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2

$ echo $?
0

仍然没有抱怨。但如果没有:

$ echo '' | clang++ -std=c++17 -x c++ -E -
error: invalid value 'c++17' in '-std=c++17'
$ echo $?
1

在python脚本中,您可以方便地将空字符串形式的空输入文件提供给执行编译器探测命令的subprocess.run调用, 并同时吞下不需要的标准输出。你会迭代这样的 通过按时间顺序排序的-std - 值列表进行调用以查找 最新支持。谨慎的做法不仅仅是测试返回代码而是 也是为了捕获stderr,并在失败的情况下解析它的权利 如果命令由于某种意外原因而失败,则进行诊断。

这里有一个为GCC和clang服务的镜头:

$ cat std_max.py
#!/usr/bin/python3
import subprocess

standards = ['98','03','11','14','17']
gpp_barf_pattern = "error: unrecognized command line option ‘-std=c++{0}’"
clangpp_barf_pattern = "error: invalid value 'c++{0}'"

def has_standard(compiler, std_year, barf_pattern):
    std_opt = '-std=c++' + std_year
    try:
        subprocess.run([compiler,std_opt,'-x','c++','-E','-'],\
            check=True,input=b'',stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    except subprocess.CalledProcessError as e:
        barf = barf_pattern.format(std_year)
        strerr = e.stderr.decode('utf8','strict')
        if barf in strerr:
            return False
        raise
    return True

def get_std_max(compiler,standards,barf_pattern):
    max_std = standards[0] if len(standards) else ''
    for std_year in standards:
        if not has_standard(compiler,std_year,barf_pattern):
            break
        max_std = 'c++' + std_year
    return max_std

会正确地告诉我:

$ python3
Python 3.6.3 (default, Oct  3 2017, 21:45:48) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from std_max import *
>>> get_std_max('clang++',standards,clangpp_barf_pattern)
'c++14'
>>> get_std_max('g++',standards,gpp_barf_pattern)
'c++17'
>>>

还没有C ++ 20:

>>> has_standard('g++','20',gpp_barf_pattern)
False
>>>