VSCodeでMakefileを作成・実行する方法

採用はこちら

VSCodeでは、プロジェクトのルートフォルダにMakefileを作成し、統合ターミナルからmakeコマンドを実行することで、ビルドやテスト、ファイル削除などの処理を自動化できます。

MakefileはCやC++のコンパイルでよく使われますが、C/C++専用の仕組みではありません。
Pythonのテスト実行、JavaScriptのビルド、Dockerイメージの作成、デプロイスクリプトの実行など、コマンドラインで処理できる内容であれば幅広く利用できます。

VSCodeとMakefileを組み合わせることで、複数のコマンドを毎回手入力する必要がなくなり、開発作業を効率化できます。

目次

VSCodeでMakefileを使うために必要なもの

VSCodeでMakefileを利用するには、VSCodeだけでなく、makeコマンドを実行できる環境が必要です。

VSCode自体にGNU Makeが内蔵されているわけではありません。
VSCodeはMakefileを編集したり、統合ターミナルから外部コマンドを実行したりするための開発環境です。

主に必要になるものは次のとおりです。

  • Visual Studio Code
  • GNU Makeなどのmakeコマンド
  • 必要に応じてGCCやClangなどのコンパイラ

たとえばC言語のプログラムをMakefileからビルドする場合、makeだけでなくgccなどのコンパイラも必要です。

makeがインストールされているか確認する

まずは、現在の環境でmakeを利用できるか確認しましょう。

VSCodeの統合ターミナルを開く

VSCodeの上部メニューから、次の順番で開きます。

ターミナル
↓
新しいターミナル

WindowsやLinuxでは、一般的に次のショートカットでもターミナルを開けます。

Ctrl + `

統合ターミナルを開いたら、次のコマンドを入力します。

make --version

GNU Makeが正常にインストールされていれば、次のようなバージョン情報が表示されます。

GNU Make 4.x
Copyright (C) Free Software Foundation, Inc.
...

このように表示されれば、Makefileを実行する準備はできています。

makeが見つからない場合

次のようなエラーが表示される場合があります。

make: command not found

Windowsでは、次のようなメッセージが表示されることもあります。

'make' is not recognized as an internal or external command

この場合は、GNU Makeがインストールされていないか、PATHが正しく設定されていない可能性があります。

Windowsでmakeをインストールする方法

Windowsには、GNU Makeが標準では含まれていない環境が多いため、別途導入する必要があります。

代表的な方法としては、次のようなものがあります。

  • MSYS2
  • WSL
  • MinGW系の開発環境
  • Chocolateyなどのパッケージマネージャー

MSYS2を利用する場合

Windows上でUnix系の開発ツールを利用したい場合は、MSYS2が便利です。

MSYS2をインストールしたあと、MSYS2のターミナルから次のように実行できます。

pacman -S make

インストール後は、次のコマンドで確認します。

make --version

MSYS2では通常のGNU Makeであるmakeを利用できます。

環境によってはmingw32-makeというコマンドも存在しますが、一般的なMakefileでは通常のmakeを利用する方が扱いやすい場合があります。

WSLを利用する場合

Linuxに近い開発環境をWindows上で利用したい場合は、WSLも便利です。

Ubuntuを使用している場合は、次のように実行できます。

sudo apt update
sudo apt install build-essential

build-essentialには、GNU MakeやGCCなど、C/C++開発でよく利用するツールが含まれています。

Makeだけが必要な場合は、次のようにインストールすることもできます。

sudo apt install make

macOSでmakeを利用する方法

macOSでは、Xcode Command Line Toolsをインストールすることで、makeなどの開発ツールを利用できます。

ターミナルから次のコマンドを実行します。

xcode-select --install

インストール後、次のコマンドで確認できます。

make --version

なお、macOSに標準で用意されるmakeと、Homebrewなどから導入するGNU Makeでは、バージョンや細かな挙動が異なる場合があります。

Linuxでmakeをインストールする方法

UbuntuやDebian系Linuxでは、次のようにインストールできます。

sudo apt update
sudo apt install make

CやC++の開発環境もまとめて導入したい場合は、次の方法があります。

sudo apt install build-essential

Fedora系Linuxでは、次のようにインストールできます。

sudo dnf install make

VSCodeでMakefileを作成する

makeが利用できるようになったら、VSCodeでMakefileを作成します。

プロジェクトフォルダを作成する

たとえば、次のような構成を考えます。

sample/
├── main.c
└── Makefile

VSCodeでsampleフォルダを開き、エクスプローラーから新しいファイルを作成します。

ファイル名は、一般的に次のようにします。

Makefile

通常は拡張子を付けません。

Makefile.txt

ではなく、次のようにします。

Makefile

GNU MakeはGNUmakefile、makefile、Makefileなどを自動的に探しますが、一般的にはMakefileという名前を使用すると分かりやすいでしょう。

Makefileの基本的な書き方

Makefileは、基本的に次のような構造で記述します。

ターゲット: 依存ファイル
	実行するコマンド

このとき、実行するコマンドの部分を「レシピ」と呼びます。

最も簡単なMakefile

たとえば、次のように書きます。

hello:
	echo "Hello Make!"

echoの前には、通常タブ文字を使用します。

保存したあと、VSCodeの統合ターミナルで次のように実行します。

make

すると、次のような結果が表示されます。

echo "Hello Make!"
Hello Make!

ここでは、helloがターゲットです。

その下にある、

echo "Hello Make!"

が実行されるレシピです。

Makefileではタブとスペースに注意する

Makefile初心者が特につまずきやすいのが、レシピ部分のインデントです。

通常のMakefileでは、レシピ行の先頭にタブ文字を使用します。

たとえば、次のように書きます。

hello:
	echo "Hello"

一方、スペースでインデントすると、次のようなエラーになる場合があります。

*** missing separator. Stop.

VSCodeではタブとスペースの見た目が分かりにくいことがあります。

Makefileでmissing separatorが表示された場合は、まずレシピ部分のインデントを確認するとよいでしょう。

GNU Makeにはタブ以外の接頭辞を設定する方法もありますが、一般的なMakefileではタブを使用するのが基本です。

C言語をMakefileでコンパイルする

Makefileの代表的な用途が、CやC++のコンパイルです。

main.cを作成する

たとえば、main.cを次のように作成します。

#include <stdio.h>

int main(void)
{
    printf("Hello, Make!\n");
    return 0;
}

続いてMakefileを作成します。

main: main.c
	gcc main.c -o main

makeを実行する

VSCodeの統合ターミナルで、次のように実行します。

make

MakeはMakefileを読み込み、実質的に次のコマンドを実行します。

gcc main.c -o main

コンパイルに成功すると、実行ファイルが作成されます。

LinuxやmacOSでは、一般的に次のように実行できます。

./main

Windowsでは、環境やシェルによって次のように実行します。

.\main.exe

WSLやMSYS2などのUnix系シェルを利用している場合は、Windows上でも./mainのような書き方が利用できる場合があります。

makeでターゲットを指定する

Makefileには、複数のターゲットを定義できます。

たとえば、次のように記述します。

build:
	gcc main.c -o main

run:
	./main

clean:
	rm -f main

それぞれ、次のように実行できます。

make build
make run
make clean

基本的な形式は次のとおりです。

make ターゲット名

ターゲットを指定しない場合

単純に、

make

と実行した場合、通常はMakefile内で最初に定義された通常のターゲットがデフォルトゴールとして使用されます。

たとえば、

build:
	gcc main.c -o main

run:
	./main

なら、makeだけを実行するとbuildが対象になります。

allターゲットを利用する

Makefileでは、プロジェクト全体をビルドするターゲットとしてallという名前がよく使われます。

たとえば、次のように書きます。

all: main

main: main.c
	gcc main.c -o main

この場合、

make

を実行すると、最初のターゲットであるallが対象になります。

allはmainに依存しているため、最終的にmainがビルドされます。

なお、allはGNU Makeの予約語ではありません。
プロジェクト全体をビルドするターゲット名として広く使われている慣習です。

Makefileの依存関係を理解する

Makeの大きな特徴は、ターゲットと依存ファイルの関係を管理できることです。

たとえば、次のMakefileを考えます。

main: main.c
	gcc main.c -o main

この場合、

main

がターゲットで、

main.c

が依存ファイルです。

Makeは、ターゲットと依存ファイルの更新日時などを確認し、再ビルドが必要かどうかを判断します。

一度、

make

を実行したあと、main.cを変更せずにもう一度、

make

を実行すると、次のようなメッセージが表示される場合があります。

make: 'main' is up to date.

つまり、変更されていないファイルを毎回ビルドする必要がありません。

ソースファイルを変更すると、必要なターゲットだけが再ビルドされます。

複数のソースファイルをコンパイルする

実際のCやC++プロジェクトでは、複数のソースファイルを利用することがあります。

たとえば、次のような構成です。

sample/
├── main.c
├── calculator.c
├── calculator.h
└── Makefile

Makefileは次のように書けます。

main: main.o calculator.o
	gcc main.o calculator.o -o main

main.o: main.c calculator.h
	gcc -c main.c

calculator.o: calculator.c calculator.h
	gcc -c calculator.c

このように依存関係を記述すると、変更されたソースファイルに関係する部分だけを再コンパイルできます。

Makefileで変数を使う

同じコンパイラ名やオプションを何度も記述する場合は、変数を使うと管理しやすくなります。

たとえば、次のように書きます。

CC = gcc
CFLAGS = -Wall -Wextra

main: main.c
	$(CC) $(CFLAGS) -o main main.c

ここでは、

CC = gcc

で使用するコンパイラを指定しています。

また、

CFLAGS = -Wall -Wextra

でコンパイルオプションを設定しています。

実際には、次のようなコマンドが実行されます。

gcc -Wall -Wextra -o main main.c

コンパイラを変更したい場合も、CCの値を変更するだけで済みます。

.PHONYを使う

cleanやrunなど、実際のファイルを作成することを目的としないターゲットには、.PHONYを指定する方法があります。

たとえば、次のように書きます。

.PHONY: all run clean

all: main

main: main.c
	gcc main.c -o main

run: main
	./main

clean:
	rm -f main

.PHONYを指定することで、all、run、cleanが実ファイルではなく、処理を実行するためのターゲットであることをMakeに伝えられます。

たとえば、プロジェクト内に偶然cleanという名前のファイルが存在していたとしても、

make clean

を実行すれば、cleanのレシピが実行されます。

パターンルールを利用する

ソースファイルが増えてくると、ファイルごとにコンパイルルールを書くのが大変になります。

その場合は、パターンルールを利用できます。

たとえば、次のように書きます。

CC = gcc
CFLAGS = -Wall -Wextra

TARGET = app
SRCS = main.c calculator.c
OBJS = $(SRCS:.c=.o)

.PHONY: all run clean

all: $(TARGET)

$(TARGET): $(OBJS)
	$(CC) $(OBJS) -o $(TARGET)

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

run: $(TARGET)
	./$(TARGET)

clean:
	rm -f $(TARGET) $(OBJS)

ここで、

%.o: %.c

は、「.cファイルから対応する.oファイルを作成する」というパターンルールです。

また、

$<

は最初の依存ファイルを表します。

$@

は現在のターゲットを表します。

たとえば、main.cからmain.oを作る場合、

$(CC) $(CFLAGS) -c $< -o $@

は実質的に、

gcc -Wall -Wextra -c main.c -o main.o

のように展開されます。

VSCodeのTasksからmakeを実行する

毎回ターミナルからmakeを入力しても問題ありませんが、VSCodeのTasks機能と組み合わせることもできます。

tasks.jsonを作成する

プロジェクト内に次のファイルを作成します。

.vscode/tasks.json

たとえば、次のように設定します。

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Make Build",
            "type": "shell",
            "command": "make",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": []
        }
    ]
}

この設定をすると、VSCodeからビルドタスクとしてmakeを実行できます。

make cleanやmake runをTaskに登録する

複数のMakeターゲットをVSCode Tasksとして登録することもできます。

たとえば、次のように設定します。

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Make",
            "type": "shell",
            "command": "make",
            "problemMatcher": []
        },
        {
            "label": "Make Clean",
            "type": "shell",
            "command": "make",
            "args": [
                "clean"
            ],
            "problemMatcher": []
        },
        {
            "label": "Make Run",
            "type": "shell",
            "command": "make",
            "args": [
                "run"
            ],
            "problemMatcher": []
        }
    ]
}

make cleanと1つの文字列で記述する方法もありますが、commandとargsを分ける方が設定内容を理解しやすくなります。

Taskを実行する

VSCodeのコマンドパレットを開き、

Tasks: Run Task

を選択します。

登録した、

Make
Make Clean
Make Run

などのタスクから、実行したい処理を選べます。

WindowsでMakefileを使うときの注意点

Windowsでは、Makefile自体は正しくても、レシピ内のコマンドが実行できない場合があります。

rmコマンドに注意する

たとえば、次のMakefileです。

clean:
	rm -f main

rmはUnix系のコマンドです。

Linux、macOS、WSL、MSYS2、Git Bashなどでは利用できますが、Windowsの環境によっては利用できません。

Makefile内で利用できるコマンドは、OSだけでなく、Makeが使用しているシェルやPATHの設定にも影響されます。

./mainにも注意する

次のような記述もUnix系の環境では一般的です。

run:
	./main

LinuxやmacOS、WSLなどでは問題ありません。

一方、Windows PowerShellでは、手動で実行する場合、

.\main.exe

のように記述することがあります。

WindowsとLinux・macOSの両方で同じMakefileを利用したい場合は、OSやシェルの違いを考慮する必要があります。

Makefileが実行できない場合の対処法

Makefileが正常に動かない場合は、エラーメッセージを確認すると原因を特定しやすくなります。

make: command not foundと表示される

次のようなエラーです。

make: command not found

GNU Makeがインストールされていないか、PATHが正しく設定されていない可能性があります。

まず、次のコマンドを実行します。

make --version

バージョン情報が表示されなければ、Makeのインストール環境を確認しましょう。

missing separatorと表示される

次のようなエラーが表示されることがあります。

*** missing separator. Stop.

代表的な原因は、レシピ行のインデントです。

次のようにスペースを使用している場合、

hello:
    echo "Hello"

通常はタブに変更します。

hello:
	echo "Hello"

VSCodeの設定によっては、Tabキーを押してもスペースに変換される場合があります。

Makefileを編集するときは、実際にタブ文字が入力されているか確認するとよいでしょう。

No rule to make targetと表示される

次のようなエラーです。

No rule to make target ...

これは、必要なターゲットや依存ファイルを作成する方法をMakeが見つけられない場合に発生します。

たとえば、

main: mian.c
	gcc mian.c -o main

のようにファイル名を間違えていると、エラーになる可能性があります。

確認するポイントは次のとおりです。

  • ファイル名にスペルミスがないか
  • 依存ファイルが実際に存在するか
  • 必要なビルドルールが定義されているか
  • ディレクトリの指定が正しいか

No targets specified and no makefile foundと表示される

次のようなエラーです。

No targets specified and no makefile found

現在のディレクトリにMakefileが存在しない場合などに表示されます。

LinuxやmacOS、WSLなどでは、

pwd

で現在のディレクトリを確認できます。

PowerShellでは、

Get-Location

でも確認できます。

Makefileが別のフォルダにある場合は、

cd フォルダ名

で移動してから、

make

を実行します。

MakefileはC/C++以外でも使える

MakefileはCやC++専用ではありません。

コマンドラインから実行できる処理であれば、さまざまな作業を登録できます。

Pythonで利用する例

test:
	pytest

実行すると、

make test

でPythonのテストを実行できます。

JavaScriptで利用する例

lint:
	npm run lint

次のコマンドで実行できます。

make lint

Dockerで利用する例

docker-build:
	docker build -t myapp .

次のように実行できます。

make docker-build

複雑なコマンドを覚えておかなくても、短いターゲット名で実行できるのがMakefileのメリットです。

VSCodeとMakefileの役割を理解する

VSCodeとMakefileの関係を整理すると、次のようになります。

VSCode
↓
統合ターミナル
↓
make
↓
Makefileを読み込む
↓
必要なターゲットを判断する
↓
gccなどの外部コマンドを実行する
↓
実行ファイルなどを生成する

VSCodeは、Makefileを編集したり、ターミナルからコマンドを実行したりするためのエディタです。

Makefileは、「何をどのように作るか」を定義する設定ファイルです。

makeはMakefileを読み込み、どの処理が必要なのかを判断するプログラムです。

gccなどのコンパイラは、実際にソースコードをコンパイルします。

それぞれの役割を分けて理解すると、Makefileの仕組みが分かりやすくなります。

VSCodeでMakefileを使う基本的な流れ

VSCodeでMakefileを利用する流れをまとめると、次のようになります。

  1. GNU Makeをインストールする
  2. 必要に応じてGCCやClangなどをインストールする
  3. VSCodeでプロジェクトフォルダを開く
  4. プロジェクト内にMakefileを作成する
  5. ターゲット、依存関係、レシピを書く
  6. VSCodeの統合ターミナルを開く
  7. makeを実行する
  8. 必要に応じてmake runやmake cleanを実行する

たとえば、最初は次のようなシンプルなMakefileから始めるとよいでしょう。

.PHONY: all run clean

all: main

main: main.c
	gcc -Wall -Wextra main.c -o main

run: main
	./main

clean:
	rm -f main

ビルドするときは、

make

実行するときは、

make run

生成ファイルを削除するときは、

make clean

とします。

まとめ

VSCodeでMakefileを利用するには、まずGNU Makeを利用できる環境を用意し、プロジェクト内にMakefileを作成します。

Makefileでは、基本的に次の形式で処理を定義します。

ターゲット: 依存ファイル
	実行するコマンド

VSCodeの統合ターミナルから、

make

を実行すると、Makefileが読み込まれ、必要な処理だけが実行されます。

また、

make run
make clean

のように複数のターゲットを用意しておけば、ビルド、実行、削除などの処理を簡単なコマンドで呼び出せます。

さらにVSCodeのtasks.jsonと組み合わせれば、MakeをVSCodeのビルドタスクとして登録することも可能です。

Makefileを初めて使う場合は、最初から複雑な記述を覚える必要はありません。

まずは、

1つのターゲットを作る
↓
makeで実行する
↓
依存関係を追加する
↓
変数を使う
↓
.PHONYを使う
↓
複数ファイルのビルドに発展させる

という順番で覚えると理解しやすいでしょう。

Makefileの基本を身につけると、VSCodeでのビルドやテスト、実行といった定型作業を効率よく自動化できるようになります。

以上、VSCodeでMakefileを作成・実行する方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次