WSL2とVS CodeでC言語を利用してみる (Remote – WSL編)

WSL2とVS CodeでC言語を利用してみる (Remote - WSL編) Visual Studio Code
スポンサーリンク

前回はWSL2にLinux Mintを導入してみたことを紹介しました。

今回はこの環境とVisual Studio Code (VS Code)を使って、C言語の開発を行えるようにしたいと思います。

スポンサーリンク

Visual Studio Code (VS Code)

Visual Studio Code(VS Code)はMicrosoftが開発するエディタです。

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

特徴はいろいろあるのですが、拡張機能による高い柔軟性と、クロスプラットフォームであることが上げられると思います。

VS Codeがサポートしているプログラミング言語はC、C++、Python、Javaなど非常に多くあります。

実際にコンパイルや実行を行うためには、VS Code以外にそれぞれの言語の環境の導入が必要です。

現在では最も人気の開発者環境ツールの1つかもしれません。

スポンサーリンク

構築したい環境

WSL2を利用してWindows上でLinuxを利用できるようにした目的の1つは、Linuxの豊富なプログラミング環境(コンパイラ・デバッガ・インタープリタなど)を利用できるようにするためです。

Windowsでもプログラミング環境をそろえることはできると思います。

しかし、Windows向けのプログラムを作成するのでなければ、Linuxの方が便利ではないかと思います。

従って、C言語のコンパイラはWSL2のLinux上のものを利用します。

一方、プログラムを作成する環境であるVS CodeはWindows上のものを利用します。VS CodeはクロスプラットフォームなのでLinux版もありますが、日本語入力などを考えるとWindowsの方が優れているためWindows版を利用します。

つまり、Windows上のVS Codeでプログラムを入力しつつ、WSL2のLinuxでコンパイル・実行・デバッグ(リモート開発)を行うというのが、構築したい環境になります。

VS Codeの導入と日本語化

まずはWindowsにVS Codeをインストールしていきましょう。

インストール

インストーラは下記から取得できます。

Download Visual Studio Code - Mac, Linux, Windows
Visual Studio Code is free and available on your favorite platform - Linux, macOS, and Windows. Download Visual Studio Code to experience a redefined code editor, optimized for building and debugging modern web and cloud applications.

インストーラにはインストーラを実行したユーザアカウントのみがVS Codeを利用できる「User Installer」と、アカウントを持っている人のすべてがVS Codeを利用することができる「System Installer」の2つがあります。

どちらを選んでも問題ありません。

インストーラをダウンロードしたら実行してVS Codeをインストールします。

インストーラは日本語化されていますし、それほど難しくないと思います。オススメとしては途中で表示される「PATHへの追加」を有効にしておくことです(デフォルトで有効になっています)。

なお、PATHへの追加は再起動後に有効になるので、インストールが完了したら一度Windowsを再起動しておきましょう。

日本語化

次にVS Codeを実行してみます。

最初は表示されているメッセージがすべて英語ですが、右下に日本語の言語パックをインストールするメッセージが表示されるはずです。

日本語の拡張機能の導入

この「インストールして再起動」を選択しましょう。

VS Codeが再起動され、表示されているメニュー・メッセージが日本語になっているはずです。

日本語化されたVS Code

日本語化は「Japanese Language Pack for Visual Studio Code」という拡張機能により実現されています。

もし初回起動時に言語パックを入れ損ねた場合は画面左の拡張機能アイコンから導入することができます。

Japanese Language Pack for Visual Studio Code

拡張機能アイコンを選択すると、拡張機能を検索するためのテキストボックスが表示されるので「Japanese」と入力します。

表示された拡張機能の中から制作者が「Microsoft」と書かれているものを探し、小さい「Install」のボタンを選択します。

これで次のような画面になるので右下の「Restart」を選択します。

Japanese Language Pack for Visual Studio Code導入後の再起動

これで日本語化されるはずです。

C言語開発のための環境構築

VS Codeが使えるようになったらWSL2上でC言語を開発するための環境を整備していきます。

WSL2のLinuxへ開発環境の導入

WSL2にコンパイラなどの開発環境が入っていなければ何もできませんので導入しておきましょう。

Ubuntu/Mintの場合はbuild-essentialパッケージでコンパイラ等がインストールされます。デバッガ(gdb)も入れておきます。

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

ちゃんとインストールできたかどうかはバージョンを表示させて確認しましょう。

$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gdb --version
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http: gpl.html="" licenses="" gnu.org="">
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

またVS CodeとWSLを連携する際に、データの取得を行うことがあるのでwgetコマンドとca-certificatesをインストールしておきます。

$ sudo apt-get install wget ca-certificates

VS Codeへ拡張機能の導入

次にVS Codeに必要な拡張機能を導入していきます。

まず、C言語の開発を補助する「C/C++」と「C/C++ Extension Pack」を導入します。

VS Code画面の左側で拡張機能アイコンを選び「C++」で検索すると、Microsoftが作成した拡張機能である「C/C++」と「C/C++ Extension Pack」が上位に来るはずです。

「C/C++」と「C/C++ Extension Pack」の導入

これらをインストールしておきます。

同様に「Remote Development」で検索して「Remote Development」拡張機能をインストールします。

Remote Developmentのインストール

これで「Remote – WSL」拡張機能も導入されているはずです。

「Remote – WSL」は「C/C++」と「C/C++ Extension Pack」をインストールした時点で、導入されているようですが、私は念のため「Remote Development」拡張機能を入れておきました。

VS Codeを使ったリモート開発

環境が整ったのでさっそく始めてみましょう。

VS CodeとWSL2の接続

まず、VS CodeがWSL2と接続された状態にします。

左下の歯車アイコンを選択して「コマンドパレット」を選びます。

コマンドパレットの選択

これで画面上部にコマンドを入力するエリアが表示されるので「WSL」と入力すると、「Remote – WSL」拡張機能の提供する機能が表示されます。

Remote-WSLでの接続の設定

デフォルトのLinuxディストリビューションを利用する場合は「Remote-WSL: New WSL Window」を選択します。

デフォルト以外のLinuxディストリビューションを使いたい場合は「Remote-WSL: New WSL Window using Distro…」を選択して、その後に利用するLinuxディストリビューションを選択します。

これで新しいVS Codeの画面が開き、右下に「WSL: ディストリビューション名」と表示されれば、VS CodeとWSL2が連携できている状態となります。

WSLとの接続

なお、初回はWSL2側にファイルを導入する必要があるので、少々待ち時間が必要です。

VS CodeとWSL2を連携させる方法はほかにもあります。

左端のリモートエクスプローラアイコンを選択し、「WSL Target」になっていることを確認して、使用したいLinuxディストリビューションを選ぶ(右クリックして「Connect to WSL」を選択)方法でも同じように連携ができます。

リモートエクスプローラを使った接続

WSL2のLinux側に拡張機能を入れる

VS CodeとWSL2の連携がとれたら、WSL2側に拡張機能を入れていきます。

WSL2のLinuxと連携している状態で、右側の拡張機能を選びます。

WSL2に拡張機能をインストール

そして「LOCAL – インストール済」のところを確認すると「WSL:ディストリビューション名にインストールする」となっている拡張機能があると思います。

このような拡張機能を探し片っ端から「WSL:ディストリビューション名にインストールする」を選択していきましょう。

プログラムを作成する(コーディング)

使い勝手を確認するために、ここではWSL2のLinuxのホームディレクトリに「vscode/c_test」というディレクトリを作成し、その中にフィボナッチ数を計算するプログラムfibonacci.cを作成することにしましょう。

フォルダを作成するにはVS Codeで行うこともできますが、ここではVS Codeのターミナルでコマンドを入力します。

まずVS Codeで「ターミナル」→「新しいターミナル」を選択します。すると画面下部にターミナルが表示されWSL2のLinuxのコマンドが入力できるようになります。

WSL2のLinuxのターミナルを表示

ここで次のコマンドを入力してフォルダを作成します。

$ mkdir –p vscode/c_test

フォルダができたら、VS Codeの「ファイル」→「フォルダーを開く」を選択します。

フォルダを開く

これで画面中央上部に「フォルダーを開く」と表示され、開くフォルダを選べる状態になります。

VS CodeとWSL2が連携できていれば、ここで選択できるフォルダはWSL2のLinux内のフォルダになります。

デフォルトではホームディレクトリが表示されると思うので、先ほど作成したフォルダ(VSCode/c_test)を入力してOKを選択します。

すると次のように「フォルダー内のファイルの作成者を信頼しますか?」と聞かれるので、「はい、作成者を信頼します」を選択します。

フォルダを信用する

これでVS Codeの左側の「エクスプローラ」の領域にWSL2のc_testディレクトリが表示されます。

フォルダを開いた状態

ここで「エクスプローラ」の領域の「C_TEST」部分にマウスを持って行くと「新しいファイル」というアイコンがあるのでこれを選択します。

新しいファイルの作成

これでファイルを作成できますので、ファイル名に「fibonacci.c」を入力します。

これでc_testディレクトリの下にファイルfibonacci.cが作成されます。そして、作成されたfibonacci.cが右側に開かれ編集可能な状態となっています。

新しいファイルが作成された状態

あとはfibonacci.cに下記のコードを入力します。これは10のフィボナッチ数を計算するコードです。

#include <stdio.h>

static int fibonacci(int n) {
    if ( (n== 0) || (n == 1) ) {
        return n;
    }
    return fibonacci(n - 2) + fibonacci(n - 1);
}

int main(int argc, char* argv[]) {
    int n = 10;
    int fibo;

    fibo = fibonacci(n);

    printf("fibonacci(%d) = %d\n", n, fibo);

    return 0;
}

VS Codeの画面ではこんな感じに色分けされて、見やすくなっているはずです。

コーディングした状態

実行する

プログラムを作成したら実行してみましょう。

実行はVS Codeのメニューで「実行」→「デバッグ無しで実行」を選択します。Ctrl+F5でもOKです。

するとVS Codeの画面中央上部に「環境の選択」が表示されるので「C++ (GDB/LLDB)」を選択します。

環境の選択

続いて「構成の選択」と表示されるので「gcc – アクティブファイルのビルドとでバッグ」を選択します。

構成の選択

これで入力したプログラムがコンパイルされ、実行されます。

コンパイルと実行の完了

ただ、右下の方に表示されたのがデバッグコンソールだと、

The program '/home/___/vscode/c_test/fibonacci' has exited with code 0 (0x00000000). 

とだけ表示されて、正常に実行されたことしかわかりません。

その場合は「デバッグコンソール」の隣の「ターミナル」あるいは「・・・」を選択しましょう。これでターミナル画面になり、実行し結果(printfした内容)がわかります。

実行結果の表示

ここでは10のフィボナッチ数が55と計算されています。

デバッグする

せっかくなのでデバッグしてみましょう。

今回は関数fibonacciにブレークポイントを設定して動きを見てみます。

ブレークポイントを設定するにはブレークポイントを設定したい行の行番号の左側をクリックします。

ブレークポイントの設定

ブレークポイントの設定ができたらデバッグを開始してみましょう。デバッグの開始は「実行」→「デバッグの開始」(あるいはF5)です。

ここで「環境の選択」と「構成の選択」が表示された場合は、前のセクションと同様に「C++ (GDB/LLDB)」と「gcc – アクティブファイルのビルドとでバッグ」を選択してください。

するとfibonacci関数が呼ばれたところで、実行が止まる(ブレークする)はずです。

ブレークした状態

ソースコードの3行目がハイライトされ、ここを実行するところでブレークしたことがわかります。

また、画面左側のコールスタックをみると、main関数からfibonacci関数が実行されたことがわかります。

左側の変数の領域でlocalが変な値(32767)になっているのは、まだfibonacci関数の処理に入っておらず、引数の変数が初期化されいないためです。

ここでステップ実行してみましょう。ステップオーバーはF10あるいは下記のボタンです。

デバッグ時の操作用ツールバー

ちなみにこのボタンは、左から続行(F5)、ステップオーバー(F10)、ステップイン(F11)、ステップアウト(Shift+F11)、再起動(Ctrl+Shift+F5)、中止(Shift+F5)となります。

これで次の行(4行目)にハイライトが移動し、変数nの値が10であることがわかります。

ステップ実行した状態

従って引数を10としてfibonacci関数が呼ばれていることがわかります。

ここで続行(F5)をしてみると、次のように再びfibonacci関数(3行目)でブレークします。コールスタックをみるとmain関数→fibonacci関数→fibonacci関数と呼び出されていることがわかります。

2回目にブレークした状態

ちなみにステップ実行するとこのときの引数が「8」で有ることがわかります。

このようにVS Codeを使うとLinuxのコマンドを入力することなく、グラフィカルにコーディング・デバッグを行うことができます。

ビルドとデバッグ設定の確認と変更

さて今回はコンパイラはgccを使うように指定しましたが、コンパイラに渡すオプションについては何も指定しませんでした。

これをカスタマイズしてみましょう。

これ以降の記事は結構試行錯誤したところもあります。

よりよい方法があればコメント欄からご指摘いただけると助かります。

ビルド設定の確認

実際にどのようなコンパイルオプションが使用されているのかは、「ターミナル」→「既定のビルドタスクの構成」で表示させることができます。このメニューを選択すると「既定のビルドタスクとして利用するタスクを選択」としてリストが表示されるので「既に既定のビルドタスクとしてマークされています」というタスクを選択します。

タスクを選択

これでtasks.jsonというファイルが開かれます。

tasks.jsonが開かれた状態

私の場合はこのファイルは次のような内容になっていました。

{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "デバッガーによって生成されたタスク。"
        }
    ],
    "version": "2.0.0"
}

argsの部分がコンパイラ(gcc)に渡されるオプションです。これをみると「-g」でデバッグ情報を付与していますが、最適化オプションなどは指定されていないことがわかります。

ちなみに「既定のビルドタスクとして利用するタスクを選択」のときに表示された「デバッガーによって生成されたタスク」はこのtasks.jsonの”detail”に対応していることがわかります。

ビルド設定の追加

新たにビルド設定(タスク)を追加してみましょう。

作成したソースファイル(fibonacci.c)が表示されている状態で「ターミナル」→「タスクの構成」を選択します。「構成するタスクの選択」が表示されたら「C/C++: gccアクティブファイルのビルド」を選択しましょう。

構成するタスクの選択

すると再びtasks.jsonが表示されますが、tasksリストの中にもう一つタスクが追加されたことがわかります。

{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "デバッガーによって生成されたタスク。"
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build",
            "detail": "コンパイラ: /usr/bin/gcc"
        }
    ],
    "version": "2.0.0"
}

この追加されたタスクをデバッグ用に最適な設定にしてみます。

具体的には、”args”に「最適化を無し(-O0)」、「コンパイルの警告を表示(-Wall)」を追加しましょう。またわかりやすいように”label”と”detail”の記述の修正しておきます。

同様にタスクを追加(コピペでOK)し、こちらはリリース用の設定としてみます。

このようにして修正したtasks.jsonは次のようになります。

{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "デバッガーによって生成されたタスク。"
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド (デバッグ用)",
            "command": "/usr/bin/gcc",
            "args": [
                "-Wall",
                "-O0",
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build",
            "detail": "コンパイラ: /usr/bin/gcc (デバッグ用)"
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc アクティブなファイルのビルド (リリース用)",
            "command": "/usr/bin/gcc",
            "args": [
                "-Wall",
                "-O3",
                "-fdiagnostics-color=always",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build",
            "detail": "コンパイラ: /usr/bin/gcc (リリース用)"
        }
    ],
    "version": "2.0.0"
}

この例はあまり意味のない追加かもしれません。

しかし、より複雑なコンパイルオプションを利用するケースもあると思いますので、tasks.jsonの修正方法は覚えておいた方が良さそうです。

これでタスクが2つ追加されましたので試してみましょう。

再びプログラムのソースファイル(fibonacci.c)を表示された上で、「ターミナル」→「タスクの実行」を選んでみましょう。

画面上部に「実行するタスクの選択」と表示され、先ほど作成したタスク「C/C++: gcc アクティブなファイルのビルド (デバッグ用)」と「C/C++: gcc アクティブなファイルのビルド (リリース用)」が有るはずです。

追加されたタスクが表示されている状態

ここで「C/C++: gcc アクティブなファイルのビルド (リリース用)」を選んでみると、右下のターミナルのエリアに実行されたコマンドが表示されます。

追加したビルド設定(タスク)を利用した状態

tasks.jsonで指定したように「-Wall」と「-O3」のオプションが付いていることがわかります。

同様に「C/C++: gcc アクティブなファイルのビルド (デバッグ用)」を選択すると「-Wall」と「-O0」のオプションでコンパイルされます。

デバッグ構成の変更

さてtasks.jsonを編集してビルド設定(タスク)を追加したら、デバッグ時に利用できるようにしましょう。

利用するのは当然ながら「C/C++: gcc アクティブなファイルのビルド (デバッグ用)」です。

「C/C++: gcc アクティブなファイルのビルド (リリース用)」で作成される実行ファイルは、デバッグに必要な情報がついていないので、デバッグには不適当です。

ソースファイル(fibonacci.c)が表示されている状態で「実行」→「構成の追加」を選択し、続いて表示される「環境の選択」で「C++ (GDB/LLDB)」を選択するとlaunch.jsonというファイルが生成されます。

launch.jsonが開かれた状態

このlaunch.jsonというファイルはデバッグ(実行)時に行われる処理を記述するものです。

最初はlaunch.jsonの内容は実質ないと思いますので、右下の「構成の追加」を選択します。すると追加する構成(テンプレート)が選べますので「C/C++: (gdb)起動)」を選択します。

追加する構成の選択

するとlaunch.jsonにgdbを起動するための設定が挿入され、次のようになります。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) 起動",
            "type": "cppdbg",
            "request": "launch",
            "program": "プログラム名を入力してください (例: ${workspaceFolder}/a.out)",
            "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
                }
            ]
        }
    ]
}

「configuration」の値(リスト)が、デバッグ(実行)時に行われる処理を示しています。

これはあくまでもテンプレートなので、そのままでは動きません。そこで次のように修正します。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "gcc - アクティブファイルのビルドとデバッグ",
            "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++: gcc アクティブなファイルのビルド (デバッグ用)",
        }
    ]
}

修正したのは「name」「program」の値を変更した点と、「preLaunchTask」を追加した点です。

「preLaunchTask」では、デバッグ(実行)の開始前に実行されるビルド設定(タスク)を指定します。ここでは先ほど作成した「C/C++: gcc アクティブなファイルのビルド (デバッグ用)」を指定しました。

このようにすると、ソースファイル(fibonacci.c)が表示されている状態で「実行」→「デバッグの開始」あるいは「実行」→「デバッグ無しで実行」を選ぶと、指定したビルド設定(「-Wall」と「-O0」でビルド)を適用してビルドした後に、デバッグあるいは実行することができます。

まとめ

今回はWSL2でLinuxを導入したWindowsにVS Codeをインストールして、C言語を使って見ました。

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

次回はRemote – SSH拡張機能を使って同様のことをやってみたいと思います。

コメント

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