【问题标题】:Clang: reliably detect supported C++ standard from command line or PythonClang:从命令行或 Python 可靠地检测支持的 C++ 标准
【发布时间】:2018-02-27 15:23:01
【问题描述】:

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

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

是否可以运行任何命令来测试某种方言是否可用无需实际编译任何东西

【问题讨论】:

  • 我会尝试编译我感兴趣的功能,这将是最强大的...如果 clang 像 gcc 一样工作,您也可以从 stdin 提供它的源代码并避免使用临时文件。
  • @Prof.Falken 是的。 Autoconf,./configure 不就是这样吗?
  • 并非给定标准的所有功能都受支持。我认为这取决于一个版本。这是C++ Support in Clang 文档和C++ compiler support 参考。
  • @gurka,是的。现在,Autoconf 是一个野兽,我理解在某些情况下是否有人想避免它。
  • "没有实际编译任何东西?" - 并非没有发布版本和功能的数据库。 cmake和autoconf这样做的方式是实际编译代码sn-ps并检查进程的返回码。

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


【解决方案1】:

是否可以运行任何命令来测试某种方言是否可用而无需实际编译任何东西?

是的。您可以要求编译器只预处理一个空文件。它会这样做 毫无怨言:

$ 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-values 列表进行调用以查找 最新支持。谨慎的做法不仅是测试返回代码,而且 也捕获标准错误,并在失败的情况下,将其解析为正确的 某种诊断,以防命令因某些意外原因而失败。

这是一个为 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
>>>

【讨论】:

    猜你喜欢
    • 2011-05-06
    • 2015-03-01
    • 2017-07-13
    • 2011-06-21
    • 2020-11-04
    • 1970-01-01
    • 2013-10-23
    • 2011-08-06
    • 1970-01-01
    相关资源
    最近更新 更多