C LANGUAGE TECHNOLOGY

【C言語】Makeの使い方

悩んでいる人

C言語のMakeの使い方を教えて!

こういった悩みにお答えします.

本記事の信頼性

  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校コンピュータサイエンス学部2020年の世界大学学術ランキング17位)で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
  • プログラミング歴15年以上,習得している言語: C/C++Solidity/Vyper,Java,Python,Ruby,HTML/CSS/JS/PHP,MATLAB,Assembler (x64,ARM).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開
  • 2020年1月~現在はアメリカのスタートアップ「Guarantee Happiness LLC」CTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
  • 2020年からC言語で業務委託のエンジニアとして3件,コンサル(技術顧問,アドバイザー)として3件,講師として1件の案件を請け負った実績.

こういった私が解説していきます.

C言語はPython,Ruby,HTML/CSS/JS/PHPのようなアプリケーション系の言語と比較して難易度が高いですよね.

私がC言語を習い始めた時は,デバッグがうまくいかなくて何度も挫折しそうになり,その度に開発ツールに助けられました.

そんなあなたに元東大教員がおすすめするC言語の開発ツールとしてMakeを紹介します.

Make

MakeはGNUが開発した代表的なビルド自動化ツールで,C言語だけでなくプログラミング言語全般で利用できます.

Makeの目的は,もともと複数のファイルが複雑な依存関係をしている際のコンパイル作業を軽減することです.

つまり,Makeを効果的に利用するとソフトウェアの開発時間を大幅に削減できます.

ファイルの依存関係をMakefileと呼ばれるファイルに記述すれば,Makeは依存関係をたどって必要最低限の作業で分割コンパイル等を行うことが可能になります.

そのために,Makeは依存関係のあるファイルの更新日時をチェックします.

あるファイルを修正したとき,コンパイル回数を必要最小限に抑えるように制御(コンパイル)しようとします.

Makeは,Linuxカーネルを含む多くのC言語で開発されたソフトウェアで利用されています.

LinuxカーネルはGitでバージョン管理されていますが,GitもC言語で開発されたソフトウェアでMakeでビルドできます.

このようにMakeはC言語の開発ツールでよく使われていますので,使いこなせるようにしましょう.

LInuxカーネルを学びたいあなたはこちらからどうぞ.

Linuxカーネル
元東大教員から学ぶLinuxカーネル

こういった私から学べます. Linuxカーネルとは,C言語で開発されたオープンソースのOSです. Linuxカーネルは主に以下のコンピュータで広く利用されています. スーパーコンピュータ サーバ An ...

続きを見る

Makeの実行

Makeを実行するためには,カレントディレクトリにMakefileという名前のファイルを用意し,Makefileに依存関係を記述します.

Makefileのファイル名は,先頭の文字が小文字のmakefileでも構いませんが,通常はMakefileという先頭の文字が大文字のファイル名にします.

この理由は,Linux上で開発するC言語のファイル名は通常は先頭が小文字なので,大文字から始まるMakefileのファイル名にすると見つけやすくするためだと思われます.

※lsコマンドを実行する場合,先頭が大文字のファイル名が先に表示されます.

そして,以下のコマンドでMakeを実行できます.

Makefileという名前以外のファイルをMakefileとして指定する際には-fオプションを利用して任意のファイル名のMakefileを指定できます.

また,大規模な開発でMakeを複数のジョブで並列コンパイルして高速に処理(並列Make)したい場合,-jオプションを利用します.

-jオプションの直後に並列処理したいジョブ数(以下の例では4)を指定します.

Makefileの記述

Makefileの基本フォーマットは,以下のようになります.

コマンドの前は必ずタブでなければならないことに注意して下さい.

もしXX行目のコマンドの前にタブではなくスペースを入れた場合,以下のエラーが発生します.

Makeは,ターゲットファイルと依存ファイルの日時を比較し,依存ファイルの日時の方がターゲットファイルの日時よりも新しければコマンドを実行します.

コマンドには,ターゲットファイルを生成するための実行コマンドを記述します.

以下のファイル一式は,こちらからダウンロードできます.

ここで重要なのは,m1-1.hはm1-1.cとm1-2.cの両方でインクルードされていることです.

つまり,m1-1.cとm1-2.cはm1-1.hの依存しています.

これらのファイルを分割コンパイルするシンプルなMakefileは以下のM1-1a.makになります.

M1-1a.makでMakeを実行すると以下になります.

実行ファイルm1-1は,m1-1.oとm1-2.oに依存しています.

つまり,どちらかのファイルが変更されたら,再コンパイル(この場合はリンク)する必要があります.

具体的には,m1-1.o,m1-2.oとm1-1の日時を比較し,m1-1.oかm1-2.oの日時がm1-1よりも新しければMakeは以下を実行します.

さらに,m1-1.oはm1-1.cに依存し,m1-2.oはm1-2.cに依存します.

m1-1.oの日時とm1-1.cの日時を比較し,m1-1.cの日時が新しければMakeは以下を実行します.

m1-2.oとm1-2.cの関係も同様です.

m1-1.cとm1-2.cはともにm1-1.hに依存しています.

この場合,m1-1.hはコンパイル時にインクルードされるので,コマンドには何も書かなくてもよいです.

Makeは,m1-1.hが変更されると(日時が新しくなると),m1-1.cやm1-2.cが変更されたとみなします.

したがって,m1-1.oとm1-2.oがそれぞれコンパイルされ,次に依存関係からm1-1がリンクされます.

また,このMakefileはM1-1b.makのように書くこともできます.

この例では,m1-1.oはm1-1.cとm1-1.hの両方に依存しているというように記述しているので,m1-1.cかm1-1.hが変更される(日時が新しくなる)と,コンパイルします.m1-2.oも同様です.

M1-1b.makでMakeを実行すると以下になります.

※m1-1,m1-1.o,m1-2.oを手動で削除してから実行して下さい.

Makefileのサフィックスルール

先述したMakefile(M1-1a.makやM1-1b.mak)の記述には似たような記述が多くあり,ファイルが多くなると記述が大変になります.

実際にMakeは,このような場合(ファイル数が数百以上)にとても役に立ちます.

Makeにはサフィックスルール(拡張子.cや.o)により簡単に記述できます.

サフィックスルールを利用して書き直したMakefileは,以下のM1-1c.makのようになります.

ここでは,以下のようなサフィックスルールが利用されています.

この意味は,サフィックス.cのファイルからサフィックス.oのファイルを作成するためには以下を実行するということです.

また,$<はMakeのマクロ(自動変数)であり,具体的にはターゲットが依存ファイルの最初の1つに展開されます.

したがって,上記のように記述したサフィックスルールによりMakeは*.oというファイルが必要であり,そのファイルを作成するためには*.cというファイルが必要です.

そして,Makeは*.cから*.oを作成するためには上記のコマンド(gcc -c $<)を利用します.

M1-1c.makでMakeを実行すると以下になります.

※m1-1,m1-1.o,m1-2.oを手動で削除してから実行して下さい.

その他のマクロ(自動変数)には,主に下表のものがあります.

マクロ意味
$@ターゲットファイル名
$<最初の依存ファイル名
$~全ての依存ファイル名
$*サフィックスを除いたターゲットファイル名
$?ターゲットファイルより新しい全ての依存ファイル名

Makefileのマクロ

Makefileは,ユーザ定義のマクロを利用して記述できます.

先述したMakefileをユーザ定義マクロで書き直したものがM1-1d.makです.

ユーザ定義マクロは以下のように記述できます.

M1-1d.makの場合は,以下のように,CCとOBJSというマクロを定義しています.

定義したマクロを利用するためには,$マークを付けてカッコ()で囲めば参照できます.

例えば,上記のマクロは以下のように展開されます.

M1-1d.makでMakeを実行すると以下になります.

※m1-1,m1-1.o,m1-2.oを手動で削除してから実行して下さい.

Makefileでサフィックスルールとマクロの利用

Makefileをサフィックスルールとマクロを利用したものが,M1-1e.makになります.

OBJSマクロで以下のように書くと,オブジェクトのファイル名はSRCSマクロの.cを.oに変換したものになります.

SRCSがm1-1.cとm1-2.cなので,OBJSはm1-1.oとm1-2.oになります.

M1-1e.mak内では,以下のようにコンパイルオプションを指定するCFLAGSマクロを定義しています.

同時にリンクオプションのLDFLAGSマクロも定義していますが,この例では何も指定していません.

例えば,数学ライブラリ(libm.so)をリンクしたい場合は以下のように指定します.

Makeは,ターゲット名を指定すると,そのターゲットを実行します.

例えば,以下のように実行すると,allというターゲットが実行されます.

Makeのデフォルトのターゲット名はallなので,allは省略でき,上記は以下と同じ実行になります.

また,以下のように実行するとターゲットファイル(m1-1)とオブジェクトファイル(*.o)とを削除します.

オブジェクトファイルのみ削除したい場合は以下のように実行します.

ターゲットファイルのみ削除したい場合は以下のように実行します.

このようにMakefileを適切に記述しておくと,複雑な依存関係があるような大規模プログラムの開発が楽になります.

M1-1e.makでMakeを実行すると以下になります.

1行目の「make -f M1-1e.mak clean」でターゲットファイルとオブジェクトファイルを削除します.

3行目の「make -f M1-1e.mak」でビルドします.

Makeの疑似ターゲット「PHONY」と依存ファイル「DEPS」

先述したM1-1e.makで以下のように疑似ターゲット「PHONY」 と依存ファイル「DEPS」を設定したM1-1f.makは以下になります.

PHONYを設定すると同じファイルがある場合でも適切に動作します.

また,DEPSマクロで依存ファイルを以下のように定義します.

コンパイルオプションは以下のように追加します.

また,ファイルの最後に以下のように記述します.

M1-1f.makでMakeを実行すると以下になります.

DEPSマクロにより作成されたm1-1.dとm1-2.dファイルの中身は以下になります.

オブジェクトファイルとヘッダファイル毎にそれぞれに依存する.c/.hファイルが設定されていることがわかります.

依存しているファイルが更新された場合にのみ再コンパイルする設定になるため,開発効率を向上させることが可能になります.

Makeの実例

Makeの実例を学びたいあなたはこちらからどうぞ.

C言語 リングバッファ
【C言語】おすすめのリングバッファのライブラリ

こういった悩みにお答えします. こういった私から学べます. 目次1 embedded-resources:おすすめのリングバッファのライブラリ2 embedded-resourcesのC言語のリングバ ...

続きを見る

C言語 乱数生成
【C言語】rand関数と自作関数で乱数の生成【モンテカルロ法で円周率の計算】

こういった悩みにお答えします. こういった私から学べます. 目次1 乱数2 一様乱数と一様分布3 rand関数による乱数の生成3.1 rand関数による乱数の生成コード3.2 rand/srand関数 ...

続きを見る

C言語 ソケット通信
【C言語】INETドメイン/UNIXドメインソケット通信によるネットワークプログラミング【TCP,UDP】

こういった悩みにお答えします. こういった私から学べます. 目次1 C言語のINETドメイン/UNIXドメインソケット通信によるネットワークプログラミング2 INETドメインソケット通信2.1 INE ...

続きを見る

C言語 ラズパイ3
【C言語】Raspberry Pi 3のユーザモードとカーネルモードでプログラムの実行

こういった悩みにお答えします. こういった私から学べます. 目次1 Raspberry Pi 32 Raspberry Pi 3のエミュレータ「QEMU」3 Raspberry Pi 3でC言語のプロ ...

続きを見る

CMake

CMakeは,コンパイラに依存しないビルド自動化のためのツールで,LinuxやWindowsを含む様々なOSで動作させることができます.

実際のビルドでは,makeやVisual StudioのようなOSネイティブのビルド環境が利用されます.

CMakeの使い方は以下の記事がわかりやすいです.

まとめ

C言語でMakeの使い方を紹介しました.

Makeを使いこなすことで,Linuxカーネルのビルドがどのように実行されるのかが理解できます.

Makeを深く理解したいあなたは,オライリー・ジャパン発行の書籍「GNU Make 第3版」を読みましょう.

この本は有料ですが,各章のPDFは無料で読めますので是非読みましょう.

各章のPDFだと目次の各章へのリンクがなくて読みにくいと思いますので,こちらから一つのPDFになったものをダウンロードして読むことをおすすめします.

英語ができる方は「Makeの公式マニュアル」を読むことをおすすめします.

All-in-Oneのビルドツール「SCons」を知りたいあなたはこちらからどうぞ.

C言語 SCons
【C言語】SCons:All-in-Oneのビルドツール

こういった悩みにお答えします. こういった私から学べます. 目次1 SCons2 SConsの使い方3 まとめ SCons SConsは,ソフトウェアプロジェクトの記述からソースコードファイルの依存性 ...

続きを見る

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , ,