ESC
开源 2 分钟阅读

C++ Insights:用编译器的视角审视你的源代码

C++ Insights是一款基于Clang的开源工具,可将range-based for循环、结构化绑定、lambda等C++代码转换为编译器内部的实现形式,帮助开发者理解auto、decltype背后的类型推导及隐式转换发生的位置。工具支持在线使用,可在Clang源码树内外构建,并提供Vim、Neovim、VS Code插件及Homebrew安装方式,作者正致力于支持C++20等新标准特性。

来源:Hacker News

我着手编写一个基于 Clang 的工具,可以将 range-based for 循环转换为编译器内部的版本。随后,我对结构化绑定(structured bindings)和 lambda 也做了同样的处理。最终,我完成的内容远远超出了最初的计划。它可以展示运算符在何处被调用,以及编译器在哪些位置进行了类型转换。C++ Insights 能够推导出 auto 或 decltype 背后的类型。其目标是生成可编译的代码,不过并非在所有情况下都能实现。

例如,你可以查看 lambda、range-based for 循环或 auto 的转换结果。当然,你也可以转换任何其他 C++ 代码片段。

亲自试试吧。C++ Insights 可在线使用:cppinsights.io。

我并不声称所有内容都完全正确。我目前也正在致力于支持新标准的特性,例如 C++20。请记住,C++ Insights 基于 Clang 及其对 AST 的理解。

自发布 C++ Insights 以来,我做过几场关于它的演讲,例如在 C++ now 大会上。以下是幻灯片和视频。

C++ Insights 既可以在 Clang 源码树内构建,也可以在其外部构建。

使用 extra/clang 构建时,需要添加以下额外标志:-DINSIGHTS_USE_SYSTEM_INCLUDES=off -DCLANG_LINK_CLANG_DYLIB=on -DLLVM_LINK_LLVM_DYLIB=on

关于为什么需要关闭 INSIGHTS_USE_SYSTEM_INCLUDES 的解释,请参见 #186。

extra/clang 和 extra/llvm 提供了 /usr/lib/{libclangAST.so,libLLVM*.a,libLLVM.so}。libclangAST.so 依赖 libLLVM.so,如果链接的是 libLLVM*.a(而非 libLLVM.so),就会产生冲突。详见 https://bugs.archlinux.org/task/60512。

你需要确保搜索路径中已安装 Clang。

git clone https://github.com/andreasfertig/cppinsights.git
mkdir build && cd build
cmake -G"Ninja" ../cppinsights
ninja

生成的二进制文件(insights)位于 build 文件夹中。

在 Clang 源码树内构建 C++ Insights 的最简单方法是使用 LLVM_EXTERNAL_PROJECTS 选项。

git clone https://github.com/llvm/llvm-project.git
git clone https://github.com/andreasfertig/cppinsights.git

mkdir build
cd build
cmake -G Ninja -D=CMAKE_BUILD_TYPE=Release -DLLVM_EXTERNAL_PROJECTS=cppinsights -DLLVM_EXTERNAL_CPPINSIGHTS_SOURCE_DIR=<PATH/TO/cppinsights> [INSIGHTS CMAKE OPTIONS] ../llvm-project/llvm

ninja

cmake 选项

有几个可以通过 cmake 启用的选项:

最好在配置时指定架构:

cmake -DCMAKE_OSX_ARCHITECTURES=arm64 ../cppinsights

与 Cevelop 配合使用

git clone https://github.com/andreasfertig/cppinsights.git
mkdir build_eclipse
cd build_eclipse
cmake -G"Eclipse CDT4 - Unix Makefiles" ../cppinsights/

然后,在 Cevelop 中选择 Import -> General -> Existing Project into Workspace,选中 build_eclipse。尽情享受使用 Cevelop 编辑的乐趣吧。

insights <YOUR_CPP_FILE> -- -std=c++17

当涉及系统头文件包含路径(system-include paths)时,事情会变得复杂。这些路径被硬编码在二进制文件中,似乎来自于构建 C++ Insights 时所用的编译器。为解决这个问题,请查看 scripts/getinclude.py。该脚本尝试从编译器收集系统头文件包含路径。不带选项时,getinclude.py 使用 g++。你也可以将其他编译器作为第一个参数传入。

./scripts/getinclude.py -isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1 -isystem/usr/local/include -isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/7.3.0/include -isystem/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -isystem/usr/include

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

insights <YOUR_CPP_FILE> -- -std=c++17 ./scripts/getinclude.py``

自定义 GCC 安装

如果你自行构建了 GCC 编译器(例如 gcc-11.2.0),且没有安装在默认系统路径中,那么构建完成后,Clang 将无法找到正确的 libstdc++ 路径(GCC 的 STL)。如果遇到这种情况,可以使用 “--gcc-toolchain=/path/GCC-1x.x.x/installed/path” 告诉 Clang/C++ Insights STL 的位置:

./cppinsights Insights.cpp -- --gcc-toolchain=${GCC_11_2_0_INSTALL_PATH} -std=c++20

其中 “${GCC_11_2_0_INSTALL_PATH}” 是你自行构建的 GCC 的安装目录。Clang 的该选项说明见这里。

还有一个 GitHub 项目设置了包含最新 C++ Insights 版本的 Docker 容器:C++ Insights - Docker

C++ Insights @ Vim

Vim 插件可在这里获取。

Neovim 插件可在这里获取。

Visual Studio Code 扩展可在 VS Code 插件市场获取:C++ Insights - VSCode Extension。

至少在 macOS 上,你可以通过 Homebrew 安装 C++ Insights,感谢这个 formula。