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

GPM*_*ler 6 c++ clang llvm-clang clang++

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

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

是否有任何命令可以运行来测试某种方言是否可用,而无需实际编译任何内容

Mik*_*han 4

\n

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

\n
\n\n

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

\n\n
$ clang++ --version\nclang version 4.0.1-6 (tags/RELEASE_401/final)\nTarget: x86_64-pc-linux-gnu\nThread model: posix\nInstalledDir: /usr/bin\n\n$ echo \'\' | clang++ -x c++ -E -\n# 1 "<stdin>"\n# 1 "<built-in>" 1\n# 1 "<built-in>" 3\n# 329 "<built-in>" 3\n# 1 "<command line>" 1\n# 1 "<built-in>" 2\n# 1 "<stdin>" 2\n\n$ echo $?\n0\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后你可以顺便添加一个-std选项。如果编译器支持:

\n\n
$ echo \'\' | clang++ -std=c++98 -x c++ -E -\n# 1 "<stdin>"\n# 1 "<built-in>" 1\n# 1 "<built-in>" 3\n# 326 "<built-in>" 3\n# 1 "<command line>" 1\n# 1 "<built-in>" 2\n# 1 "<stdin>" 2\n\n$ echo $?\n0\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
$ echo \'\' | clang++ -std=c++17 -x c++ -E -\nerror: invalid value \'c++17\' in \'-std=c++17\'\n$ echo $?\n1\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 python 脚本中,您可以方便地以空字符串的形式提供一个空输入文件来subprocess.run执行编译器探测命令的调用,\n并同时吞掉不需要的标准输出。您可以在按时间顺序排序的-std值列表上迭代此类调用,以找到支持的最新值。谨慎的做法不仅是测试返回代码,\n还要捕获 stderr,并在失败的情况下解析它以进行正确\n的诊断,以防命令因某些意外原因失败。

\n\n

这是一个适用于 GCC 和 clang 的镜头:

\n\n
$ cat std_max.py\n#!/usr/bin/python3\nimport subprocess\n\nstandards = [\'98\',\'03\',\'11\',\'14\',\'17\']\ngpp_barf_pattern = "error: unrecognized command line option \xe2\x80\x98-std=c++{0}\xe2\x80\x99"\nclangpp_barf_pattern = "error: invalid value \'c++{0}\'"\n\ndef has_standard(compiler, std_year, barf_pattern):\n    std_opt = \'-std=c++\' + std_year\n    try:\n        subprocess.run([compiler,std_opt,\'-x\',\'c++\',\'-E\',\'-\'],\\\n            check=True,input=b\'\',stdout=subprocess.PIPE,stderr=subprocess.PIPE)\n    except subprocess.CalledProcessError as e:\n        barf = barf_pattern.format(std_year)\n        strerr = e.stderr.decode(\'utf8\',\'strict\')\n        if barf in strerr:\n            return False\n        raise\n    return True\n\ndef get_std_max(compiler,standards,barf_pattern):\n    max_std = standards[0] if len(standards) else \'\'\n    for std_year in standards:\n        if not has_standard(compiler,std_year,barf_pattern):\n            break\n        max_std = \'c++\' + std_year\n    return max_std\n
Run Code Online (Sandbox Code Playgroud)\n\n

这会正确地告诉我:

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

还没有 C++20:

\n\n
>>> has_standard(\'g++\',\'20\',gpp_barf_pattern)\nFalse\n>>>\n
Run Code Online (Sandbox Code Playgroud)\n