【C言語】コンパイル、ビルド時のMakefileについて忘れるからメモ書き

C言語/C++

はじめに

今回の記事は、テーマにもある通りC言語で作成したプログラムをコンパイル、ビルドする時に使用するMakefileについてのメモ書きです。

以下の記事を読むことで下記内容について参考になるかと思いまます。

こんな人は参考になるかも!!!

▶C言語を使い始めてMakefileってなんだろう、、、?って人
▶Makefileが何かは知ってるけど、実際に自身で書いたことはないです。って人
▶Makefileで利用されている変数について曖昧な人
▶中間ファイルの出力先を別ディレクトリにしたい

それじゃさっそく本題に入っていきます。続きが気になる人はぜひ読んでみてください。

そもそもまずMakefileって何???

まずは念のためMakefileとは?というところから、もちろんそんなの知ってるわ!!って人はスクロールしてください。

manコマンドを使用して調べた内容を一部抜粋します。

To prepare to use make,
you must write a file called the makefile that describes the relationships among files in your program,
and the states the commands for updating each file.

man makeコマンドのドキュメントから抜粋

引用した文章によると、Makefileはmakeコマンドを利用する時に使われるファイルとのこと。
そのMakefileの中身に何を記載するのかというと、利用する各ファイルの関係性やファイルを更新するためのルール的なものを記載するものと書かれています。

以上のことからMakefileについて簡単にまとめると

結局Makefileって何?

▶makeコマンドを使う時に呼ばれるファイル
▶Makefileは各ソースファイルの関係性や更新するためのルールを記述するもの
▶結果、gccなどのコンパイルを自動化することが出来るので便利。

Makefileを使ってC言語のプログラムをコンパイル&ビルド

前項でMakefileが何かというのは説明しました。
なので、ここからはより具体的にどうやって使うのかという部分に入っていきます。

ここからはC言語のプログラムをgccを使ってコンパイル&ビルドする時のMakefileについてまとめていきます。
このときにMakefileを書く際、私が毎回あれ?これどうやって書くんだっけ?ってなって調べるのがめんどくさいのが理由です。

想定しているディレクトリ構造

まずは、今回想定しているディレクトリ構造(ツリー構造)から。
中間ファイルや実行ファイルの出力先やソースコードの置き場所などなど以下の画像のようなものを想定しています。

次からいくつかの項目に分けてMakefileの書き方を確認していきます。

まずは簡単にmain.cファイルだけで考える

まずは、何も考えずにmain.cファイルだけをコンパイル&ビルドする方法から。
なるべく不要なものを記述しないようにします。

CC 				= gcc
CFLAGS 			= -g -Wall -O2
INCLUDE			= -I ../include
TARGET			= ../bin/hello
OBJDIR			= ../obj

SOURCE			= main.c

OBJECTS 		= $(addprefix $(OBJDIR)/, $(SOURCE:.c=.o))

$(TARGET)		: $(OBJECTS)
	mkdir -p $(dir $@)
	$(CC) $^ -o $(TARGET)

$(OBJDIR)/%.o	: %.c
	mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $<

all				: $(TARGET)

clean			:
	rm -rf $(OBJECTS) $(TARGET)

基本的な部分については触れませんが、記号であったり関数などについては少しだけ解説を加えておきます。

addprefix関数

addprefix関数・・・頭に文字を追加することが可能です。
$(addprefix {追加文字}, {対象})
9行目では、先頭にオブジェクトファイルを作成するディレクトリを追加しています。

dir関数

dir関数・・・ディレクトリ情報を抽出することが可能です。
12.16行目ではディレクトリ情報をもとにmkdirコマンドでディレクトリを作成します。

【補足】mkdirコマンド

mkdirコマンドを使用してディレクトリを作成した際に
既に作成されている場合エラーが発生するがします。でもpオプションをセットすることによってそのエラーを無視することが出来ます。

自動変数

$@,$<などは自動変数と呼ばれるものです。いくつかの意味は以下で説明します。

$@・・・ターゲット名
$^・・・ターゲットの依存関係の名前
$<・・・ターゲットの依存関係の一番最初の名前

複数ファイルやヘッダーファイルを含めるパターン

開発の規模が大きくなるにつれてソースファイルもmain.cだけとはいかなくなりますね。
処理毎にファイルを生成したりヘッダーファイルを用意したりライブラリを使ったりもしますよね。

次は、それらを考慮したMakefileです。
以下では、main.cの他に四則演算関数を記載したarithmeticOperations.cを用意しました。
それと追加でincludeディレクトリにarithmeticOperations.hを追加しました。
それでも追記は1箇所です。ファイルを追加したのでその追加したファイルを記載するだけです。

CC 				= gcc
CFLAGS 			= -g -Wall -O2
INCLUDE			= -I ../include
TARGET			= ../bin/hello
OBJDIR			= ../obj


#変更点
# - SOURCE		= main.c
# + SOURCE		= main.c arithmeticOperations.c
SOURCE			= main.c arithmeticOperations.c

OBJECTS 		= $(addprefix $(OBJDIR)/, $(SOURCE:.c=.o))

$(TARGET)		: $(OBJECTS)
	mkdir -p $(dir $@)
	$(CC) $^ -o $(TARGET)

$(OBJDIR)/%.o	: %.c
	mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $<

all				: $(TARGET)

clean			:
	rm -rf $(OBJECTS) $(TARGET)

ライブラリをリンクする方法

開発を行っていれば、ライブラリを使用することがあるはずです。
例えば、数値演算を使用したいのであればmathライブラリがありますね。

mathライブラリを使用するためには、
・ソースコード内に include <math.h> を追加
・コンパイルする時に -lm をリンクする必要があります。
1番目はソースコードに記載しますが、2番目はMakefileに記述する必要があります。
その場合の変更点は以下です。

CC 				= gcc
CFLAGS 			= -g -Wall -O2
INCLUDE			= -I ../include
TARGET			= ../bin/hello
OBJDIR			= ../obj
#追加
# + LIBS		= -lm
LIBS			= -lm



SOURCE			= main.c arithmeticOperations.c

OBJECTS 		= $(addprefix $(OBJDIR)/, $(SOURCE:.c=.o))

#変更点 リンクオプションを追加
# - $(CC) $^ -o $(TARGET)
# + $(CC) $^ -o $(TARGET) $(LIBS)
$(TARGET)		: $(OBJECTS)
	mkdir -p $(dir $@)
	$(CC) $^ -o $(TARGET) $(LIBS)

$(OBJDIR)/%.o	: %.c
	mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $<

all				: $(TARGET)

clean			:
	rm -rf $(OBJECTS) $(TARGET)

もちろんリンクするライブライが変わるときにはそれに置換した対応が必要になります。

Makefileでマクロを定義する方法

次は、マクロをMakefile内で定義することも可能ですのでそれについてもメモしておきます。

gccコンパイラではDオプションを利用することでマクロ定義を行うことができます。
オブジェクトファイル生成時にDオプションを利用してください。

CC 				= gcc
CFLAGS 			= -g -Wall -O2
INCLUDE			= -I ../include
TARGET			= ../bin/hello
OBJDIR			= ../obj
LIBS			= -lm

#追加 -Dオプションでマクロ定義
# + MACRO		= -DDEV
MACRO			= -DDEV

SOURCE			= main.c arithmeticOperations.c

OBJECTS 		= $(addprefix $(OBJDIR)/, $(SOURCE:.c=.o))

$(TARGET)		: $(OBJECTS)
	mkdir -p $(dir $@)
	$(CC) $^ -o $(TARGET) $(LIBS) 

#変更点
# - $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $<
# + $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< $(MACRO)
$(OBJDIR)/%.o	: %.c
	mkdir -p $(dir $@)
	$(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< $(MACRO)

all				: $(TARGET)

clean			:
	rm -rf $(OBJECTS) $(TARGET)

まとめ

これで自分でMakefileを記述するときに毎度これどうやって書くんだっけな~で迷わなくて済みます。
めでたしめでたし。

参考

ここまでの内容を調べるときに参考にしたものです。

GNU make
GNU make

コメント

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