- 概要
- はじめに
- 環境
- VSCode のインストール
- Remote Development のインストール
- リモートマシンに公開鍵を追加する
- リモートマシンのVSCodeに拡張機能をインストールする
- インテリセンスを設定する
- VSCode でソースコードを確認する
- カーネルのビルド
- QEMUで指定したカーネルをブートする
- GDBでターゲットにアタッチする
- おわりに
- 変更履歴
- 参考
概要
Visual Studio Code (VSCode)では、短時間でエディタのセットアップすることができ、テキストエディタとして次の機能が使えることが判明した。
- 関数定義を参照する
- 関数呼び出し元を参照する
- 入力補完機能
- ホバーによるドキュメント表示
- シンタックスチェック
- シンボルの一斉置換
また、VSCodeではデバッグ機能が標準で提供されているので、VSCodeからGDBでアタッチしてデバッグすることもできた。
そこで本記事では、Linuxカーネルのコーディングに必要な設定手順について記載する。
はじめに
Visual Studio Code (VSCode)は、Microsoftが開発・提供しているオープンソースのエディタの一つである。
VSCodeでは、プログラマが必要とする機能 (補完機能やデバッグ機能など) がデフォルトで搭載されていることに加えて、拡張機能が豊富に提供されている。
そこで、VSCodeでソースコードリーディングするために、「初期設定に手間がかかるかどうか」と「実際に使ってみてどうなのか」を確認していくことにする。
環境
今回、Windows 10のローカルマシンからVSCodeを利用して、Ubuntu 20.04のリモートマシンにアクセスして、リモートマシン上にあるソースコードやツールチェーンを利用して、コードリーディングをすることを想定する。
ここでは、次のバージョンで動作を確認している。
Windows 10 Home
- VSCode v1.63.2
- Remote Development v0.21.0
Ubuntu 20.04.3
- C/C++ Extension Pack v1.1.0
VSCode のインストール
Visual Studio Code のサイト VSCodeは、WIndowsに加えてMacOSやLinuxにも対応している。
Remote Development のインストール
Remote Development は、コンテナ・リモートマシン・WSL内のファイルをアクセスできるVSCodeの拡張機能の一つ *1 である。
- アクティビティバーにある拡張機能アイコンを選択する
- 検索窓に「Remote Development」と入力する
- 検索候補にある「Remote Development」を選択する
- エディタグループにある「インストール」を選択する
インストールが完了すると、アクティビティバーに「リモート エクスプローラー」が追加される。
現在、ローカルマシンにはリモートマシンにアクセスするための設定をしていないため、サイドバーには何も表示されていない。
リモートマシンに公開鍵を追加する
既にローカルマシンからリモートマシンにSSHでリモートアクセスできる場合、公開鍵認証が必要ない場合には省略可能。
ここでは、Windows PowerShell を利用して公開鍵を生成をする。*2
コマンドが成功すると指定されたパスに秘密鍵と公開鍵がローカルマシンに生成される。 (ここでは、秘密鍵をid_rsa
、公開鍵をid_rsa.pub
とする)
公開鍵id_rsa.pub
を、何らかの手段(SSH, USBメモリ経由, クリップボードなど) でリモートマシンにコピーし、リモートマシンの.ssh/authorized_keys
に登録する。
その後、ローカルマシンのVSCodeに戻り、SSHの接続先を設定する。
- 「SSH TARGETS」にマウスオーバーすると表示される「Configure」を選択する
- SSH接続先を記述する
- サイドバーに記述したホスト名が出現するので、「Connect to Host in New Window」を選択する
SSH接続に成功した場合、新規ウインドウでリモートマシン内のファイルにアクセスすることができる。
- ステータスバーに接続先のホスト名が出力されていることを確認する
- アクティビティバーの「エクスプローラー」を選択する
- サイドバーから「フォルダーを開く」を選択し、Linuxのソースコードのトップディレクトリを選択する
リモートマシンのVSCodeに拡張機能をインストールする
Linuxカーネルのソースコードの多くはCプログラムとなっているため、リモートマシンにはC/C++開発用の拡張機能をインストールしていく。
その後、再読み込みを促されるので、「再読み込み」を選択する。
インテリセンスを設定する
Linuxカーネルでは、かなり複雑な依存関係を持つため、手動でコンパイルフラグを作成することは難しい。
幸いにも、Linuxカーネルではgen_compile_commands.py
と呼ばれるスクリプトが用意されている。
~/linux:$ ./scripts/clang-tools/gen_compile_commands.py
ビルド済みのカーネルツリーに対して、上記のコマンドを実行することでcompile_commands.json
ファイルが生成される。
上記の情報を渡してあげるためには、VSCodeの設定を変更する必要がある。
デフォルトのc_cpp_properities.json
が表示されるので、compileCommands
フィールドを追加する。
- {
- "configurations": [
- {
- "name": "Linux",
- "includePath": [
- "${workspaceFolder}/**"
- ],
- "defines": [],
- "compilerPath": "/usr/bin/gcc",
- "cStandard": "gnu17",
- "cppStandard": "gnu++14",
- "intelliSenseMode": "linux-gcc-x64",
- "compileCommands": "${workspaceFolder}/compile_commands.json",
- }
- ],
- "version": 4
- }
またクロスコンパイルを検討している場合には、compilerPath
やintelliSenseMode
を設定する。
これによりVSCodeでは、プロジェクト内にあるcompile_commands.json
を用いてインテリセンスを設定する。
VSCode でソースコードを確認する
関数定義を参照する
<Alt>
+<F12>
関数名や変数名にカーソルを合わせ、<Alt>
+ <F12>
を押下すると、その関数の定義元が表示される。
関数呼び出し元を参照する
<Shift>
+<F12>
関数名や変数名にカーソルを合わせ、<Shift>
+ <F12>
を押下すると、その関数の呼び出し元が表示される。
入力補完機能
<Ctrl>
+<Space>
関数や変数を入力すると、自動でポップアップが表示される。また、<Ctrl>
+ <Space>
を入力でも同様にポップアップが表示される。
ホバーによるドキュメント表示
マウスオーバー
シンタックスチェック
シンボルの一斉置換
<Ctrl>
+<F2>
カーネルのビルド
規模が大きい場合には、コードリーディングだけでプログラムの仕様を完全に理解することは難しい。
そこで、実際にプログラムを動かしてみることで、より詳細な挙動を確認することができる。
まずは、VSCodeからカーネルをビルドできるような設定をしていく。
VSCodeでは、"タスク"と呼ばれる単位で何かしらの処理を実行することができる。
まず初めに、カーネルのビルド/クリーンアップするタスクを追加していく。
- 「ターミナル」を選択する
- 「タスクの構成」を選択する
- 「テンプレートからtasks.jsonを生成する」を選択する
これにより、新規エディタが立ち上がり、tasks.jsonのテンプレートが表示される。
次のようなmake -j$(nproc) bzImage
を実行する Build bzImage
タスクとmake clean
を実行するClean
タスクを追加する。
- {
- // See https://go.microsoft.com/fwlink/?LinkId=733558
- // for the documentation about the tasks.json format
- "version": "2.0.0",
- "type": "shell",
- "echoCommand": true,
- "tasks": [
- {
- "label": "Build bzImage",
- "command": "make",
- "args": [
- "-j$(nproc)",
- "bzImage"
- ],
- "group": {
- "kind": "build",
- "isDefault": true
- },
- },
- {
- "label": "Clean",
- "command": "make",
- "args": [
- "clean"
- ],
- "group": "none"
- },
- ]
- }
これにより、ビルドタスクとしてデフォルトでmake -j$(nproc) bzImage
が実行されるようになった。
ビルドタスクを実行するためには、<Ctrl>
+ Shift
+ B
がショートカットとして割り当てられている。
QEMUで指定したカーネルをブートする
ビルドしたカーネルをお試しで動作確認する場合、QEMU*3でエミュレートすると効率が良い。
そこで、VSCodeからQEMUを利用して、カーネルをブートできるような設定をしておく。
カーネルのビルドと同様にQEMUでブートするようなタスクを作成する。
- {
- // See https://go.microsoft.com/fwlink/?LinkId=733558
- // for the documentation about the tasks.json format
- "version": "2.0.0",
- "type": "shell",
- "echoCommand": true,
- "tasks": [
- {
- "label": "Build bzImage",
- "command": "make",
- "args": [
- "-j$(nproc)",
- "bzImage"
- ],
- "group": {
- "kind": "build",
- "isDefault": true
- },
- },
- {
- "label": "Clean",
- "command": "make",
- "args": [
- "clean"
- ],
- "group": "none"
- },
- {
- "label": "Boot kernel in QEMU",
- "command": "qemu-system-x86_64",
- "args": [
- "-kernel",
- "arch/x86_64/boot/bzImage",
- "-drive",
- "file=rootfs.ext4,if=ide,format=raw",
- "-nographic",
- "-append",
- "'root=/dev/sda console=ttyS0 init=/bin/sh'",
- "-s",
- "-S"
- ],
- "group": "none"
- },
- ]
- }
- タブバーから「ターミナル」を選択する
- 「タスクの実行」を選択する
作成したタスクのラベル (Boot kernel in QEMU) を選択すると、ターミナルに実行結果が出力される。
GDBでターゲットにアタッチする
上記の手順にて、ビルドしたカーネルを起動させているのでVSCodeからGDBにアタッチしてみる。
VSCodeでは、デバッグ機能が標準として提供されており、GDBを用いたテンプレートが用意されている。
今回は、そのテンプレートを利用して、QEMUで起動させたカーネルにアタッチする。
127.0.0.1:1234
にGDBで接続するためにlaunch.json
を編集する。
- {
- // IntelliSense を使用して利用可能な属性を学べます。
- // 既存の属性の説明をホバーして表示します。
- // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "name": "kernel-debug",
- "type": "cppdbg",
- "request": "launch",
- "miDebuggerServerAddress": "127.0.0.1:1234",
- "program": "${workspaceFolder}/vmlinux",
- "args": [],
- "stopAtEntry": false,
- "cwd": "${workspaceFolder}",
- "environment": [],
- "externalConsole": false,
- "logging": {
- "engineLogging": false
- },
- "MIMode": "gdb",
- }
- ]
- }
上記のファイルを保存した結果、launch.jsonで作成したサイドバーが更新される。
試しに、ext4_fill_super
関数にブレークポイントを設置して、GDBでデバッグしてみる。
おわりに
VSCodeは非常に便利なテキストエディタであり、豊富な機能が提供されている。
今回の場合では、1時間足らずで次のような機能が有効で確認することができた。
- 関数定義を参照する
- 関数呼び出し元を参照する
- 入力補完機能
- ホバーによるドキュメント表示
- シンタックスチェック
- シンボルの一斉置換
変更履歴
- 2022/2/1: 記事公開