本記事はVisual Studio Code上にD言語のデバッグ環境を整えるという趣旨の記事です。D言語に興味のない方は人生最良の行動を促すこちらの記事からご確認ください。逃がさないよ?
Windowsのデバッグ環境
必要なもの
本記事はインストール方法を紹介するものではないので、各自インストールしてください。
- Visual Studio Code
- C/C++ ※Visual Studio CodeのC/C++言語拡張。デバッグ実行はこれを流用する。
- dlang_cpp.natviz ※C/C++言語拡張でD言語の型を取り扱えるようにする設定ファイル。ダウンロードしてプロジェクトフォルダのどこかに置く。
- code-d ※Visual Studio CodeのD言語拡張。プログラミング教育サービスでも映画でもないので注意。
- ldc2 ※LLVMベースのD言語コンパイラ
ポイント
デバッグを行うには、以下について注意が必要です。
- LDC2コンパイラを使用してビルドを行う。
- ビルドの際64bitのバイナリにC言語形式のデバッグ情報を仕込む。
具体的にはdubのプロジェクト設定にてdebugInfoC
というbuildOptions
を設定します。 - デバッガにはVisual Studio CodeのC/C++拡張のデバッグ機能を使う。
- C/C++拡張のデバッグ機能にD言語設定を施す。
具体的にはvisualizerFile
に、ダウンロードしたdlang_cpp.natvis
を指定します。
上記ポイントについて、以降の章で詳細な手順を示します。
ちなみに、コンパイラにldc2
ではなくdmd
を使用したり、dubのプロジェクト設定にてdebugInfoC
の設定を行わなかったり、dlang_cpp.natvis
ファイルを指定しなかったりしても、ブレークポイントを張ってステップ実行したりするくらいはできます。では、上記をすると何が強くなるかというと、以下の点がサポートされるようになります。
- 文字列がちゃんとウォッチできるようになる。ゼロ終端しなくてもちゃんと長さを解釈してくれる。
- 配列がちゃんとウォッチできるようになる。長さも、要素ごとの展開も可能になります。
- 連想配列もちゃんとウォッチできるようになる。
上記画面では連想配列の変数aa
の中身や、文字列の変数str
の中身がキチンと表示されていることがわかります。
ビルド方法の手順
dubを使用してビルドを行います。その際、C言語形式のデバッグ情報を仕込むため、debugInfoC
のオプションを設定します。
{
"name": "testapp",
"targetType": "executable",
"buildTypes": {
"vscode-unittest": { "buildOptions": ["debugMode", "debugInfoC", "unittests"] },
"vscode-unittest-cov": { "buildOptions": ["debugMode", "debugInfoC", "unittests", "coverage"] },
"vscode-debug": { "buildOptions": ["debugMode", "debugInfoC"] },
"vscode-debug-cov": { "buildOptions": ["debugMode", "debugInfoC", "coverage"] }
}
}
上記のように、buildTypes
にて各デバッグ用ビルドタイプのビルドオプションに"debugMode", "debugInfoC"
を与えます。これにより、
そして、以下のようにビルドを行います。
dub build --arch=x86_64 --build=vscode-debug --compiler=ldc2
ちなみに、カバレッジ付きの単体テストが実行されるバイナリを作るには以下のようにします。
dub build --arch=x86_64 --build=vscode-unittest-cov --config=unittest --compiler=ldc2
これをVisual Studio Codeから実行するため、tasks.json
を設定します。
以下のようになるでしょう。
{
"version": "2.0.0",
"tasks": [
{
"label": "DebugBuild",
"group": "build",
"command": "dub build --arch=x86_64 --build=vscode-debug --compiler=ldc2",
"type": "shell",
"problemMatcher": "$dmd",
},
{
"label": "UnittestBuild",
"group": "build",
"command": "dub build --arch=x86_64 --build=vscode-unittest-cov --config=unittest --compiler=ldc2",
"type": "shell",
"problemMatcher": "$dmd",
}
]
}
あるいは、code-dが用意してくれているdub
のビルドタイプを使用して以下のようにしてもよいかもしれません。
{
"version": "2.0.0",
"tasks": [
{
"label": "DebugBuild",
"group": "build",
"type": "dub",
"compiler": "ldc2",
"archType": "x86_64",
"buildType": "vscode-debug",
"problemMatcher": "$dmd"
},
{
"label": "UnittestBuild",
"group": "build",
"type": "dub",
"compiler": "ldc2",
"archType": "x86_64",
"buildType": "vscode-unittest-cov",
"problemMatcher": "$dmd"
}
]
}
デバッグ方法の手順
デバッグ方法のlaunch.json
の設定は以下のようになります。
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "cppvsdbg",
"request": "launch",
"preLaunchTask": "DebugBuild",
"program": "${workspaceRoot}/testapp.exe",
"cwd": "${workspaceRoot}",
"visualizerFile": "${workspaceRoot}/dlang_cpp.natvis",
},
{
"name": "Unittest",
"type": "cppvsdbg",
"request": "launch",
"preLaunchTask": "UnittestBuild",
"program": "${workspaceRoot}/testapp.exe",
"cwd": "${workspaceRoot}",
"args": ["--DRT-covopt=dstpath:cov"],
"visualizerFile": "${workspaceRoot}/dlang_cpp.natvis",
}
]
}
"visualizerFile": "${workspaceRoot}/dlang_cpp.natvis"
として、D言語用の設定ファイルを指定してあげるのがポイントです。このファイルとdebugInfoC
のついたバイナリを使用することで、快適にデバッグができるようになります。また、単体テストでカバレッジを出す場合は、引数に --DRT-covopt=dstpath:cov
を与えることでカバレッジファイルの出力先を指定することができます。
以下が上記設定を適用したデバッグの様子です。
各設定を確認→デバッグ実行→ブレーク確認→連想配列の中身確認→単体テスト実行→ブレーク確認→カバレッジ確認を行っています。
Linuxのデバッグ環境
必要なもの
本記事はインストール方法を紹介するものではないので、各自インストールしてください。
- Visual Studio Code
- lldb ※LLVMのデバッガ
- CodeLLDB ※Visual Studio CodeのLLDB拡張。デバッグ実行はこれを使用する。
- lldb_dlang.py ※LLDB拡張でD言語の型を取り扱えるようにする設定ファイル。ダウンロードしてプロジェクトフォルダのどこかに置く。
- code-d ※Visual Studio CodeのD言語拡張。プログラミング教育サービスでも映画でもないので注意。
- ldc2 ※LLVMベースのD言語コンパイラ
ポイント
デバッグを行うには、以下について注意が必要です。
- LDC2コンパイラを使用してビルドを行う。
- デバッガにはVisual Studio CodeでLLDBを動かすためのCodeLLDBを使う。
- LLDBにD言語設定(lldb_dlang.py)を施す。ただし、修正が必要(2022/12/20現在)。
上記ポイントについて、以降の章で詳細な手順を示します。
ちなみに、コンパイラにldc2
ではなくdmd
を使用したり、lldb_dlang.py
ファイルを指定しなかったりしても、ブレークポイントを張ってステップ実行したりするくらいはできます。では、上記をすると何が強くなるかというと、以下の点がサポートされるようになります。
- 文字列がちゃんとウォッチできるようになる。ゼロ終端しなくてもちゃんと長さを解釈してくれる。
- 配列がちゃんとウォッチできるようになる。長さも、要素ごとの展開も可能になります。
- 連想配列もちゃんとウォッチできるようになる。
上記画面では連想配列の変数aa
の中身や、文字列の変数str
の中身がキチンと表示されていることがわかります。
ビルド方法の手順
dubを使用してビルドを行います。これといって特別な設定は必要ありません。
{
"name": "testapp",
"targetType": "executable"
}
そして、以下のようにビルドを行います。
dub build --arch=x86_64 --build=debug --compiler=ldc2
ちなみに、カバレッジ付きの単体テストが実行されるバイナリを作るには以下のようにします。
dub build --arch=x86_64 --build=unittest-cov --config=unittest --compiler=ldc2
これをVisual Studio Codeから実行するため、tasks.json
を設定します。
以下のようになるでしょう。
{
"version": "2.0.0",
"tasks": [
{
"label": "DebugBuild",
"group": "build",
"command": "dub build --arch=x86_64 --build=debug --compiler=ldc2",
"type": "shell",
"problemMatcher": "$dmd",
},
{
"label": "UnittestBuild",
"group": "build",
"command": "dub build --arch=x86_64 --build=unittest-cov --config=unittest --compiler=ldc2",
"type": "shell",
"problemMatcher": "$dmd",
}
]
}
あるいは、code-dが用意してくれているdub
のビルドタイプを使用して以下のようにしてもよいかもしれません。
{
"version": "2.0.0",
"tasks": [
{
"label": "DebugBuild",
"group": "build",
"type": "dub",
"compiler": "ldc2",
"archType": "x86_64",
"buildType": "debug",
"problemMatcher": "$dmd"
},
{
"label": "UnittestBuild",
"group": "build",
"type": "dub",
"compiler": "ldc2",
"archType": "x86_64",
"buildType": "unittest-cov",
"problemMatcher": "$dmd"
}
]
}
デバッグ方法の手順
デバッグ方法のlaunch.json
の設定は以下のようになります。
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "lldb",
"request": "launch",
"preLaunchTask": "DebugBuild",
"program": "${workspaceRoot}/testapp",
"cwd": "${workspaceRoot}",
"initCommands": ["command script import \"${workspaceRoot}/lldb_dlang.py\""]
},
{
"name": "Unittest",
"type": "lldb",
"request": "launch",
"preLaunchTask": "UnittestBuild",
"program": "${workspaceRoot}/testapp",
"cwd": "${workspaceRoot}",
//"args": ["--DRT-covopt=dstpath:${workspaceRoot}/cov"],
"initCommands": ["command script import \"${workspaceRoot}/lldb_dlang.py\""]
}
]
}
"initCommands": ["command script import \"${workspaceRoot}/lldb_dlang.py\""]
として、D言語用の設定ファイルを指定してあげるのがポイントです。このファイルを使用することで、快適にデバッグができるようになります。
しかし、lldb_dlang.pyはそのままではうまく機能しないようでした。size_tが検索できないとかのエラーが出るようです。仕方ないのでlldb_dlang.py内に出てくるsize_t
をすべてulong
に書き換えます。
また、単体テストでカバレッジを出す場合は、引数に --DRT-covopt=dstpath:${workspaceRoot}/cov
を与えることでカバレッジファイルの出力先を指定することができ…るのですが、VSCodeにカバレッジが表示されなくなるのでコメントアウトしています。
以下が上記設定を適用したデバッグの様子です。
各設定を確認→デバッグ実行→ブレーク確認→連想配列の中身確認→単体テスト実行→ブレーク確認→カバレッジ確認を行っています。