プログラミング
C++ Insights – コンパイラの目でソースコードを見る
C++ Insights – See your source code with the eyes of a Compiler (github.com)
要約
C++ Insightsは、コンパイラがソースコードに対して行う内部的な変換や、通常は隠されている処理を可視化するClangベースのソース・トゥ・ソース変換ツールです。ラムダ式、範囲ベースforループ、autoキーワード、構造化束縛などのC++の機能を、コンパイラがどのように解釈・展開するかを、コンパイラが生成するコードに近い形で理解できるようにします。これにより、C++の学習者や開発者は、コードが実際にどのように機能するかをより深く理解することができます。
全文翻訳
C++ Insights - コンパイラの目でソースコードを見る。
目次
What
Why
Building
Usage
Get Involved
Support
What
C++ Insightsは、ソース・トゥ・ソース変換を行うClangベースのツールです。C++ Insightsの目標は、通常意図的にバックグラウンドで行われることを可視化することです。それは、コンパイラが私たちを機能させるために行う魔法についてのものです。
例えば、このコードを見てみましょう。
class Base {
};
class Derived : public Base {
};
int main() {
Derived d;
Derived d2 = d;
d2 = d;
Base& b = d;
}
特別なことは何もありません。もちろん、コンパイルされます。これはコンパイラからの視点です。
class Base {
public:
// inline constexpr Base() noexcept = default;
// inline constexpr Base(const Base &) noexcept = default;
// inline constexpr Base & operator=(const Base &) noexcept = default;
};
class Derived : public Base {
public:
// inline constexpr Derived() noexcept = default;
// inline constexpr Derived(const Derived &) noexcept = default;
// inline constexpr Derived & operator=(const Derived &) noexcept = default;
};
int main() {
Derived d;
Derived d2 = Derived(d);
d2.operator=(d);
Base & b = static_cast<Base&>(d);
return 0;
}
コンパイラ提供のすべての特殊メンバ関数と、DerivedからBaseへのアップキャストが見えます。
Why
C++ Insightsは、ソース・トゥ・ソース変換を行うClangベースのツールです。C++ Insightsの目標は、通常意図的にバックグラウンドで行われることを可視化することです。それは、コンパイラが私たちを機能させるために行う魔法についてのものです。あるいは、コンパイラのクラスを通して見ることです。
2017年、私はC++11、C++14、C++17で導入された新しい機能のいくつかを調べ始めました。ラムダ式、範囲ベースforループ、構造化束縛のような素晴らしい機能です。私はそれらをまとめて講演しました。スライドとビデオはオンラインで見つけることができます。
しかし、そのすべての研究と私のトレーニングや教育の一部が、コンパイラの目で物事を見ることができたらどうなるだろうかと考え始めさせました。確かに、ASTダンプはあります。少なくともClangには。Compiler Explorerのようなツールで、コンパイラがC++ソーススニペットから生成するコードを見ることができます。しかし、私たちが目にするのはアセンブラです。ASTもCompiler Explorerの出力も、私がコードを書く言語ではありません。そのため、私はこの出力にあまり慣れていません。さらに、学生にC++を教える際に、ASTを見せて、それがすべてであると説明しても、私にとってはあまり満足のいくものではありませんでした。
私は、範囲ベースforループをコンパイラの内部バージョンに変換できるClangベースのツールを書き始めました。次に、構造化束縛とラムダ式についても同様のことを行いました。最終的には、当初計画していた以上のことを行いました。演算子がどこで呼び出されるか、コンパイラがキャスティングを行う場所を示します。C++ Insightsは、autoまたはdecltypeの背後にある型を推測できます。目標は、コンパイル可能なコードを生成することです。しかし、これはすべての場所で可能ではありません。例えば、ラムダ式、範囲ベースforループ、またはautoの変換を見ることができます。もちろん、他のC++スニペットも変換できます。自分で見てください。
C++ Insightsはオンラインで利用可能です: cppinsights.io。それでも、やるべきことはあります。私はすべてを正しく行うと主張するわけではありません。現在、C++20のような新しい標準の機能もサポートするように取り組んでいます。C++ InsightsはClangとそのASTの理解に基づいていることを覚えておいてください。
私はC++ Insightsをリリースして以来、C++ Insightsについていくつかの講演を行いました。例えば、C++ Nowでです。ここにスライドとビデオがあります。
Building
C++ Insightsは、Clangソースツリーの内側または外側でビルドできます。
Windowsでのビルド
Readme_Windows.mdを参照してください。
Arch Linuxでのビルド
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の外側でのビルド
Clangのインストールが検索パスにある必要があります。
```bash
git clone https://github.com/andreasfertig/cppinsights.git
mkdir build && cd build
cmake -G"Ninja" ../cppinsights
ninja
```
結果のバイナリ(insights)はbuildフォルダにあります。
Clangの内側でのビルド
Clangソースツリーの内側でC++ Insightsをビルドする最も簡単な方法は、LLVM_EXTERNAL_PROJECTSオプションを使用することです。
```bash
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で有効にできるオプションがいくつかあります。
Option | Description | Default
INSIGHTS_STRIP | ビルド後にinsightをストリップ | ON
INSIGHTS_STATIC | 静的リンクを使用 | OFF
INSIGHTS_COVERAGE | コードカバレッジを有効にする | OFF
INSIGHTS_USE_LIBCPP | テストにlibc++を使用 | OFF
DEBUG | デバッグを有効にする | OFF
ARM on macOSでのビルド
設定時にアーキテクチャを指定するのが最善のようです。
```bash
cmake -DCMAKE_OSX_ARCHITECTURES=arm64 ../cppinsights
```
Cevelopでの使用
```bash
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での編集をお楽しみください。
Usage
C++ Insightsの使用は非常に簡単です。
```bash
insights <YOUR_CPP_FILE> -- -std=c++17
```
システムインクルードパスに関しては、状況は複雑になります。これらのパスはバイナリにハードコードされており、C++ Insightsがビルドされたコンパイラから来ているようです。これを支援するために、scripts/getinclude.pyを確認してください。このスクリプトは、コンパイラからシステムインクルードパスを収集しようとします。オプションなしの場合、getinclude.pyはg++を使用します。別のコンパイラを最初の引数として渡すこともできます。例を挙げます。
```bash
./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と組み合わせて使用できます。
```bash
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の場所を伝えることができます。
```bash
./cppinsights Insights.cpp -- --gcc-toolchain=${GCC_11_2_0_INSTALL_PATH} -std=c++20
```
ここで`${GCC_11_2_0_INSTALL_PATH}`は、カスタマイズビルドされたGCCのインストールディレクトリです。Clangのオプションについては、こちらで説明されています。
Dockerコンテナですぐに使用可能
最新のC++ Insightsバージョンを含むDockerコンテナを設定する別のGitHubプロジェクトもあります: C++ Insights - Docker
Plugins / Extensions / Packages
C++ Insights @ Vim
Vim用のプラグインはこちらで入手可能です。
C++ Insights @ Neovim
Neovim用のプラグインはこちらで入手可能です。
C++ Insights @ VSCode
VS CodeマーケットプレイスでVS Codeの拡張機能があります: C++ Insights - VSCode Extension。
C++ Insights @ brew
少なくともmacOSでは、このフォーミュラのおかげでHomebrew経由でC++ Insightsをインストールできます: brew install cppinsights
Shell autocomplete
bash、zsh、fish用の補完スクリプトがあります。これらは、C++ Insightsオプション(説明を含む)および--の後に続くClangオプションを補完します。ソースからビルドすると、補完スクリプトはシェルに自動的にインストールされます。