官方品质家居装修改造门户

斩获 3.4k+ Star 的 C++ Insights:用编译器的视角看源码!

CSDN 2025-05-02 09:24:42 60 次阅读
斩获 3.4k+ Star 的 C++ Insights:用编译器的视角看源码!


作者|AndreasFertig

翻译|郑丽媛

出品|程序人生(ID:coder_life)


C++Insights是什么?

C++Insights是一种基于Clang的工具,可进行源码到源码的转换,其目标是揭示通常情况下编译器在幕后为我们做的工作。它能帮我们看到编译器为了让代码正常运行而进行的一些神奇操作。

以下面这段代码为例:

classBase{};
classDerived:publicBase{};
intmain(){Derivedd;
Derivedd2=d;
d2=d;
Baseb=d;}

没有什么特别之处,当然也能编译。下面是编译器对它的看法:

classBase{public://inlineconstexprBase()noexcept=default;//inlineconstexprBase(constBase)noexcept=default;//inlineconstexprBaseoperator=(constBase)noexcept=default;};


classDerived:publicBase{public://inlineconstexprDerived()noexcept=default;//inlineconstexprDerived(constDerived)noexcept=default;//inlineconstexprDerivedoperator=(constDerived)noexcept=default;};
intmain(){Derivedd;Derivedd2=Derived(d);=(d);Baseb=static_castBase(d);return0;}

你可以看到所有由编译器提供的特殊成员函数,以及从Derived向Base的向上转型。


为什么要做C++Insights?

2017年,我开始研究C++11、C++14和C++17带来的一些新特性,如lambda表达式、基于范围的for循环和结构化绑定等。然而,所有这些研究以及我的一些培训和教学经历让我开始思考:如果我们能以编译器的视角来洞悉代码,那将会是怎样一番景象?当然,至少对于Clang来说,是有AST(抽象语法树)转储功能的,我们可以用CompilerExplorer等工具查看编译器从C++源代码片段生成的代码。不过,我们看到的是汇编程序,AST和CompilerExplorer的输出并不是我写代码的语言,因此我对这些输出并不熟悉。另外,在教学生C++时,如果跟他们展示AST并解释说这就是全部内容,我自己感觉也不太满意。

于是,我开始着手编写一个基于Clang的工具,可将基于范围的for循环转换为编译器内部版本。接着,我对结构化绑定和lambda也做了同样的处理。最终,我的工作超出了最初计划。

C++Insights这个工具显示了运算符的调用位置,以及编译器进行类型转换的情况,可以推断出auto或decltype背后的类型。我的目标是生成可编译的代码,然而,并非所有情况都能实现这一点。

例如,你可以看到lambda、基于范围的for循环或auto的转换。当然,你也可以转换任何其他C++代码段。

感兴趣的话,你可以亲自试试看。C++Insights在线使用网址:

不过,还有很多工作要做。我不敢说我做的一切都是正确的,目前我还在努力支持C++20等新标准的特性。请记住,C++Insights是基于Clang及其对AST的理解而建立的。


如何构建?

C++Insights可以在Clang源代码树内部或外部进行构建。

(1)在Windows上构建

已测试(支持的编译器)


注意:仅支持在LLVM外部构建。不支持x86,因为没有针对x86的LLVM/Clang库。

对于带有VS的Clang:

前往LLVM下载页面;

从“Pre-BuiltBinaries”部分安装“Windows(64位)”;

安装程序会自动将LLVM工具集添加到你所有VisualStudio实例中。

从源代码构建和安装Clang

需要有Clang库和来设置CMake。

将Clang/LLVM库安装到(例如)C:\Programs\LLVM_local2。

注意:

安装路径中不能有空格;

最好不要使用%ProgramFiles%,否则需要管理员权限来安装文件。

gitclonecdllvm-projectmkdirbuildcdbuildcmake-DLLVM_ENABLE_PROJECTS=clang^-DCMAKE_INSTALL_PREFIX=C:\Programs\LLVM_local2^-G"VisualStudio152017"^-Ax64^-Thost=x64^..\llvmcmake--build.--configRelease--targetinstall

你也可以在VisualStudio中打开build/解决方案,然后在其中构建所有内容,而不是使用cmake--build命令。

构建Insights

假设:

C++Insights源代码位于C:\dev\cppinsights,并且

LLVM/Clang已经构建并安装到C:\Programs\LLVM_local2(参见上面的步骤)

cdC:\dev\cppinsights\mkdirbuildcdbuildsetpath=%path%;C:\Programs\LLVM_local2\bincmake-G"VisualStudio162019"-Ax64-TLLVM_v142..cmake--build.--configRelease--targetinsights

除了带“VisualStudio162019”的Clang,你还可以选择其他适合你的。具体可参见上面的“已测试(支持的编译器)”,查看CMake命令列。另外,你也可以直接在VisualStudio中打开build/文件进行构建,而不必通过命令行。

(2)在ArchLinux上构建

要使用extra/clang构建,请使用以下额外标记:

-DINSIGHTS_USE_SYSTEM_INCLUDES=off-DCLANG_LINK_CLANG_DYLIB=on-DLLVM_LINK_LLVM_DYLIB=on

extra/clang和extra/llvm提供/usr/lib/{,libLLVM*.a,},需要,如果链接的是libLLVM*.a(而不是),就会发生冲突。

(3)在Clang外部构建

你需要在搜索路径中安装Clang。

gitclonemkdirbuildcdbuildcmake-G"Ninja"../cppinsightsninja

生成的二进制文件(insights)可以在build文件夹中找到。

(4)在Clang内部构建

在Clang源代码树中C++Insights最简单的方法,是使用LLVM_EXTERNAL_PROJECTS选项。

gitclonegitclone
mkdirbuildcdbuildcmake-GNinja-D=CMAKE_BUILD_TYPE=Release-DLLVM_EXTERNAL_PROJECTS=cppinsights-DLLVM_EXTERNAL_CPPINSIGHTS_SOURCE_DIR=PATH/TO/cppinsights[INSIGHTSCMAKEOPTIONS]../llvm-project/llvm
ninja

cmake选项

cmake可启用几个选项:

在macOS上构建ARM

似乎最好在配置时提供架构:

cmake-DCMAKE_OSX_ARCHITECTURES=arm64../cppinsights

使用方法

使用C++Insights非常简单:

insightsYOUR_CPP_FILE---std=c++17

当涉及到系统包含路径时,情况就变得复杂了。这些路径是二进制文件中的硬编码,似乎来自C++Insights的编译器。要解决这个问题,可查看scripts/,这个脚本会尝试从编译器中收集系统包含路径。如果没有选项,将默认使用g++,你也可以将其他编译器作为第一个参数传递。

下面是一个例子:

./scripts/-isystem/Applications//Contents/Developer/Toolchains//usr/bin/../include/c++/v1-isystem/usr/local/include-isystem/Applications//Contents/Developer/Toolchains//usr/bin/../lib/clang/7.3.0/include-isystem/Applications//Contents/Developer/Toolchains//usr/include-isystem/usr/include

该脚本可与C++Insights一起使用:

insightsYOUR_CPP_FILE---std=c++17`./scripts/`

自定义GCC安装

如果你用的是自定义版本的GCC编译器,例如,且未安装在编译器的默认系统路径中,那么在构建后,Clang将无法找到正确的libstdc++路径(即GCC的标准模板库)。如果遇到这种情况,你可以用“--gcc-toolchain=/path//installed/path”来告诉Clang/C++InsightsSTL的位置:

./=${GCC_11_2_0_INSTALL_PATH}-std=c++20

这里的“${GCC_11_2_0_INSTALL

_PATH}”是你定制构建的GCC安装目录。

随时可用的Docker容器

GitHub上还有另一个项目,可以在其中设置一个装有最新C++Insights版本的docker容

器:C++Insights-Docker()

C++Insights@Vim

Vim插件可在此处下载:

om/Freed-Wu/

C++Insights@VSCode

VisualStudioCode的扩展可在此处找到:

C++Insights@brew

至少在macOS上,你可通过Homebrew安装C++Insights,这要归功于这个公式:

brewinstallcppinsights

兼容性

我的目标是,能够与最新版本的Clang或者至少前一个版本保持兼容,在线网站尽量与Clang的最新版本保持一致。然而,由于某些问题(比如为Windows构建Clang),网站的版本经常会延迟几个月。

更多详细介绍,可参看C++Insights项目GitHub地址: