WSL2とVS CodeでC++を利用してみる

WSL2とVS CodeでC++を利用してみる Visual Studio Code
スポンサーリンク

前回はSynologyのNASをGitサーバにしたことを紹介しました。

今回はからは再びVisual Studio Code(VS Code)とWSL2を試してみたいと思います。

以前はWSL2+VS CodeでC言語を使ってみましたが、今回はC++を使ってみたいと思います。

スポンサーリンク

環境の確認

今回はWSL2を使って導入したLinux Mintを利用しています。

Linux MintをWindows11(WSL2)上で動かしてみる
今回はWindows Subsystem for Linux (WSL2)に人気ディストリビューションのLinux Mintを導入してみます。WSL用のLinux Mintはインストーラが用意されているため、比較的簡単に導入することができます。一度導入してしまえば、Ubuntuと同じように設定できるので、使いやすいのではないかと思います。

Linux MintはUbuntuとほぼ互換性があるので、Ubuntuでも同様のことができると思います。

UbuntuをWindows 11上で動かす その1: 準備とインストール
今回はWindows Subsystem for Linux (WSL2)を使ってWindows11にUbuntuをインストールしてみます。WSLを利用するためには以前は複数のステップが必要でしたが、ついにwslコマンド一発で導入できるようになりました。WSLを使う敷居がますます低くなったように感じます。

また、WindowsにVS Codeと「Remote – WSL」拡張機能を導入して、WSL2のLinuxと連携がとれるようにしています。

これは以前、C言語のために構築したものと同様です。

WSL2とVS CodeでC言語を利用してみる (Remote - WSL編)
今回はWSL2でLinuxを導入したWindowsにVS Codeをインストールして、C言語を使って見ます。拡張機能「Remote – WSL」を使ってVS CodeとWSL2を連携させると、Linuxのコマンドラインを一切使わずに、LinuxでC言語のプログラムをコンパイル・デバッグすることができます。かなり開発の敷居が下がるのではないでしょうか。

今回はこの環境でC++を使ってみようと言うことになります。

拡張機能としては「Remote – WSL」のほかに「C/C++拡張機能」が導入されていることを前提としています。

C/C++ - Visual Studio Marketplace
Extension for Visual Studio Code - C/C++ IntelliSense, debugging, and code browsing.

なお正直に白状すると、元ネタは下記の公式ブログだったりします。

Get Started with C++ and Windows Subsystem for Linux in Visual Studio Code
Configuring the C++ extension in Visual Studio Code to target g++ and GDB on WSL installation with Ubuntu
スポンサーリンク

ツールチェーンの導入

まずWSLのLinuxにログインして、C++をコンパイル・デバッグするためのパッケージ一式を導入しましょう。

下記のコマンドを実行すればOKです。

$ sudo apt-get update
$ sudo apt-get install build-essential gdb

これでコンパイラ(g++コマンド)とデバッガ(gdbコマンド)が利用できるようになったはずです。

ソースコードの準備

まずWSL2のLinuxでソースコードを格納するディレクトリを作成しましょう。

今回はホームディレクトリにprojectsというディレクトリを作成し、その中に今回のテスト用にhelloworldというディレクトリを作成します。

$ cd ~
$ mkdir –p projects/helloworld
$ cd projects/helloworld

次にこのディレクトリをWindows上のVS Codeで開きます。

WSL2側からVS Codeを起動する方法もありますが、今回は素直にWindows側でVS Codeを起動します。

そしてリモートエクスプローラで「WSL Targets」を選ぶと、インストールしているWSL2のディストリビューションが表示されているはずです。

そしてそのディストリビューションを右クリックして「Connect to WSL」を選択します。

WSLへ接続

これで新しいVS Codeのウィンドウが開き、左下の接続状態を示すエリアに「WSL: ディストリビューション名」と表示されます。

WSLと接続OK

あとは、VS Codeのメニューの「ファイル」→「フォルダーを開く」を選択し、先ほど作成したディレクトリを入力して「OK」を選択します。

フォルダを開く

これでエクスプローラエリアに「HELLOWORLD [WSL:ディストリビューション名]」と表示され、WSL2のLinuxのフォルダが開かれたことがわかります。

WSL上のフォルダを開いた状態

次にこのフォルダ部分にマウスポインタを持って行き「新しいファイル」で「helloworld.cpp」というファイルを作成しましょう。

新しいファイルの作成

ここで「C/C++拡張機能」をオススメされた場合(=まだインストールしていない場合)は、インストールしましょう。

次に作成したhelloworld.cppに次のようなソースコードを入力して保存しましょう。

#include <iostream> #include <vector> #include <string> using namespace std; int main() { vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"}; for (const string& word : msg) { cout << word << " "; } cout << endl; return 0; }

VS Codeの画面は次のようになります。

ソースコードを入力した状態

VS Codeはソースコードの入力を保持してくれるIntelliSenseという機能に対応しています。

例えば、10行目にmsgに続いて「.」を入力すると、利用できるメンバ関数の一覧が表示され、上下キーで選択・タブキーで入力することができます。

IntelliSenseによるアシスト

上下キーで選択するだけでなく、メンバ関数名を入力していくと、候補が絞り込まれるので、選択がしやすくなります。

またサイドにそのメンバ関数の説明も表示されます(この画面では横幅が狭いため、左側にメンバ関数の説明が表示されます)。

このようにVS Codeを使うと効率的にコーディングすることができます。

helloworld.cppのビルド(コンパイル)と実行

VS Codeではビルド時の処理はtasks.jsonというファイルの記述します。

従って、手順は

  1. helloworld.cppをビルドするためのtasks.jsonの作成
  2. tasks.jsonに従いタスクの実行(ビルド)
  3. ビルドで生成されたファイルの実行

tasks.jsonの作成

このファイルの作成にはまず「ターミナル」→「既存のビルドタスクの構成」を選択します。すると使用するタスクの選択肢が表示されるので「C/C++: g++アクティブなファイルのビルド (コンパイラ: /usr/bin/g++)」を選択します。

アクティブなファイルのビルド

これでtasks.jsonというファイルが.vscodeフォルダに作成されます。また、このファイルは自動的にエディタで開かれます。

生成されたtasks.json

生成されたtasks.jsonは私の場合は次のようになりました。

{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "cppbuild",
			"label": "C/C++: g++ アクティブなファイルのビルド",
			"command": "/usr/bin/g++",
			"args": [
				"-fdiagnostics-color=always",
				"-g",
				"${file}",
				"-o",
				"${fileDirname}/${fileBasenameNoExtension}"
			],
			"options": {
				"cwd": "${fileDirname}"
			},
			"problemMatcher": [
				"$gcc"
			],
			"group": {
				"kind": "build",
				"isDefault": true
			},
			"detail": "コンパイラ: /usr/bin/g++"
		}
	]
}

重要なキーは次の通りです。

  • command
    このタスクで実行されるコマンド。この場合は「g++」になります。
  • args
    コマンド(g++)に渡す引数です。ここで記載した順番で引数は渡されるので記述する順番も重要です。
    この例では、アクティブなファイル(${file})がコンパイラ(g++)に渡され、カレントディレクトリ(${fileDirname})にアクティブなファイル名から拡張子をのぞいた名前(${fileBasenameNoExtension})で実行ファイルが生成されます。
    従って、helloworld.cppに対してこのタスクを実行すると、g++によりコンパイルされhelloworldという実行ファイルが生成されます。
  • label
    この設定を識別するための名前です。自由に変更可能です。
  • isDefault
    この値がtrueだとCtrl+Shift+Bのショートカット(あるいは「ターミナル」→「ビルドタスクの実行」)で、このタスクが実行されるようになります。
    なお、値がfalseの場合でも、「ターミナル」→「タスクの実行」で表示されるタスクから選択することでこのタスクを実行可能です。

今回用意したhelloworld.cppをコンパイルするためには、このままで良さそうです。

タスクの実行

tasks.jsonファイルで定義されたタスクを実行するためには、helloworld.cppをエディタで表示させている状態でCtrl+Shift+Bをするか、「ターミナル」→「タスクの実行」を選択します。

するとタスクが実行され、VS Codeのターミナルエリアに実行状況が表示されます。

ビルドした結果

今回は「ビルドが正常に完了しました」となっているので、コンパイルエラーが発生しなかったことがわかります。

コンパイルエラーが発生した場合は、内容を確認し、エラーがなくなるまでソースコードを修正することになります。

また、エクスプローラ領域では「helloworld」というファイルが増えていることがわかります。これがビルドにより作成された実行ファイルになります。

helloworldの実行

それではビルドしてできたhelloworldを実行してみましょう。

まずターミナル領域の「+」を選択してみましょう。

ターミナルを追加

これでWSL上のBashによるターミナルが開きますので「./helloworld」と入力すれば実行されます。

helloworldの実行

helloworld.cppのデバッグ

ビルドができたら次はデバッグをしてみます。

VS Codeではデバッグ(実行)時の処理はlaunch.jsonというファイルの記述します。

従って、手順は

  1. helloworld.cppをデバッグするためのlaunch.jsonの作成
  2. launch.jsonに従いデバッグの開始
  3. VS Codeでデバッガの操作

となります。

launch.jsonの作成

このファイルもtasks.jsonと同様にVS Codeがテンプレートを生成してくれます。

「実行」→「構成の追加」を選び、表示された選択肢の中から「C++ (GDB/LLDB)」を選択しましょう。

構成の選択

これでlaunch.jsonが.vscodeディレクトリに作成されますが、このlaunch.jsonはほとんど中身がありません。

生成されたlaunch.json

そこで右下に表示されている「構成の追加」ボタンを選択しましょう。 そして表示される選択肢の中から「C/C++: (gdb) 起動」を選択します。

構成の追加

これで次のようにlaunch.jsonにgdbを起動するための設定が追加されます。

gdbを起動する構成の追加

ここで作成された設定は実はそのままでは動かず、いくつか修正する必要があります。

修正ポイントは次の点です。

  • name
    わかりやすい名前に変更する。
  • program
    ビルドして生成されたプログラムを実行するようにする。具体的には「${fileDirname}/${fileBasenameNoExtension}」とすることで、tasks.jsonで生成されたhelloworldを指定したことになります。
  • preLaunchTask
    このキーは生成されたlaunch.jsonにはないので追加することになります。
    事前にtasks.jsonで定義したビルドが動くようにしておくと便利です。

これらの点を修正したlaunch.jsonは次のようになります。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [   
        {
            "name": "g++ アクティブファイルのビルドとデバッグ",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description":  "逆アセンブリ フレーバーを Intel に設定",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "C/C++: g++ アクティブなファイルのビルド"
        }
    ]
}

preLaunchTaskキーに指定しているのは、tasks.jsonで定義したビルドタスクのlabelになります。

プログラムの実行

それではプログラムを実行してみましょう。

まずhelloworld.cppをアクティブにした状態で、「実行」→「デバッグの開始」を選択します。F5でもOKです。

「helloworld.cpp」をアクティブにするのは忘れがちなので注意しましょう。

実行完了

すると右下の「デバッグコンソール」にいろいろ表示が出て、最終的に「The program helloworld has exited with code 0 (helloworldプログラムは戻り値0で終了しました)」という結果になっています。

これではわかりにくいので「ターミナル」で出力を確認してみましょう。

helloworldの出力

すると「Hello C++  world form VS Code and the C++ extension!」と表示され、helloworld.cppが正常に動作したことがわかります。

デバッグしてみる

実は先ほどの「プログラムの実行」もデバッガ(gdb)で動作していたのですが、実行完了してしまいデバッグらしい操作をしていませんでした。

そこでいかにもデバッグらしい操作をしてみます。その準備としてブレークポイントを9行目に設定しておきます。

ブレークポイントの設定

ブレークポイントは行番号の左となりをクリックすると設定することができます。設定したブレークポイントは赤丸で表示されます。

ブレークポイントが設定できたら、「実行」→「デバッグの開始」で再び実行してみます

ブレークした状態

するとブレークポイントを設定した9行目がハイライトされ、ここで処理が止まったこと(ブレークしたこと)がわかります。

また、画面上部には実行状態を制御するためのパネルが表示されます。

デバッグ用のパネル

このパネルは左端をドラッグすると自由に動かせます。

ステップ実行

まずステップ実行をしてみます。

ステップ実行には、次の行に進むステップオーバー、関数があった場合に関数内に入っていくステップイン、関数を脱出するステップアウト、があります。

デバッグ用のパネルの左から2番目のボタンを選択しましょう。これがステップオーバーになります。F10キーでも同様です。

ステップオーバーのボタン

するとハイライトが11行目に進みます。

ステップオーバー実行後

このとき右側の「変数」を確認してみると次のようになっています。

変数の状態

変数msgはvectorなので、0~5の6つの文字列が格納されていることがわかります。

一方、for文はまだ実行していないので、for文で利用される変数wordや、for文を制御するためにコンパイラによって生成された変数__for_rangeと変数__for_begin, 変数__for_endは正常に表示されていません。

ここでもう一度ステップオーバーを実行すると、ハイライトは13行目(coutの行)へ進み、変数は次のように変ります。

さらにステップオーバーしたときの変数の状態

for文のループ範囲を示す変数__for_rangeには変数msgの値がセットされ、変数wordの値はその最初の要素である”hello”になっています。

このようにステップ実行や表示される変数の値を駆使することで、プログラムが意図通りに動作しているのかを確認していくことになります。

変数のウォッチ

プログラムの実行中に特定の変数の値を確認し続けたいケースもあると思います。このような場合に便利なのがウォッチです。

ウォッチする変数を追加するには「ウォッチ式」のエリアの「+」を選択します。

ウォッチする変数の追加

今回はforループの中で利用されている変数wordをウォッチしてみます。

プログラムの実行前では、ウォッチに変数wordをついかしても「使用不可」と表示されます。

プログラム実行前の状態

この状態でデバッグを開始してみます。9行目でブレークした時点では変数wordはまだスコープ外なので値は表示されていません。

スコープ外の状態

そのままステップオーバーを繰り返し、for文の中に入っていくとウォッチ式のエリアに表示されている変数wordの値が次々と変っていきます。

スコープ内の状態

その他の変数確認方法

実はVS Codeにはもっと簡単に変数の値を確認する方法が用意されています。

それはみたい変数の上にマウスカーソルを持って行くというものです。

例えば、for文の内部をステップ実行している状態で変数wordにカーソルを乗せてみます。

マウスでの変数の確認

すると変数の値が表示されます。

変数msgにマウスカーソルを合わせると、vectorの要素が表示されます。

マウスでの変数の確認(vector)

これはかなりお手軽で便利ではないかと思います。

C/C++拡張機能のカスタマイズ

これまでの説明で、「VS Code」+「Remote – WSL拡張機能」+「C/C++拡張機能」という組み合わせで、C++のコーディング・ビルド・デバッグができました。

ただ、C++の対応規格などを変更したいなど、細かい設定をしたいという場合もあると思います。

そのような場合は、VS Codeのコマンドパレットで「C++」と入力して表示されるコマンドから、「構成の編集 (UI)」を選ぶとカスタマイズすることができます。

C/C++拡張機能の編集

これでエディタに「C/C++ Configurations」というタブが開き、C/C++拡張機能設定項目が表示されます。

C/C++拡張機能の設定項目

例えば、C++の言語規格として「ISO 2011 C++ Standard (いわゆるC++ 11)」を利用したい場合は、C++基準を「C++11」に変更すると良いでしょう。

C++の言語規格の変更

これでIntelliSenseでの補完がC++11に従って行われるようになります。

ただ、これだけだとコンパイラに対する言語規格指定が行われないようです。tasks.jsonを開き、argsに「-std=c++11」を追加する必要があります。

変更したtasks.jsonのargs部分は次のようになります。

			"args": [
				"-std=c++11",
				"-fdiagnostics-color=always",
				"-g",
				"${file}",
				"-o",
				"${fileDirname}/${fileBasenameNoExtension}"
			],

なおC/C++拡張機能の設定を変更すると、その内容は.vscodeディレクトリにc_cpp_properties.jsonというファイルで保存されます。

c_pp_properties.json

このように.vscodeディレクトリには作成しているプログラムに関する様々な情報が保持されるので、ソースコードをコピーする際には.vscodeディレクトリも一緒にコピーしておくと設定も維持されるので便利と思います。

まとめ

今回はVisual Studio Code + WSL2という環境でC++のコーディング・ビルド・デバッグを試してみました。

多少は手で設定する項目は有りますが、VS Codeによってビジュアルでデバッグできるのはかなり使いやすいのではないかと思います。

次回はWSL2+VS Codeという環境でOpenCV(C++)を使ってみたいと思います。

コメント

タイトルとURLをコピーしました