ラベル make の投稿を表示しています。 すべての投稿を表示
ラベル make の投稿を表示しています。 すべての投稿を表示

make入門 #4 組み込みルール

組み込みルールの概要

前回(make入門 #3 自動変数とパターンルール)は以下のようなパターンルールについて説明しました。
prog2: main.o sub.o
        gcc -o $@ $^

%.o: %.c
        gcc -c -o $@ $<

main.o: main.c sub.h
sub.o: sub.c sub.h
ここで青字で示されるパターンルールをMakefileから削除してみます。
prog2: main.o sub.o
        gcc -o $@ $^

main.o: main.c sub.h
sub.o: sub.c sub.h
このMakefileをカレントディレクトリに配置してmakeを実行します。
$ make
cc    -c -o main.o main.c
cc    -c -o sub.o sub.c
gcc -o prog2 main.o sub.o
なんと、このMakefileでもビルドが成功します。 とくに驚くべきことは、*.cから*.oを作成する方法を指定しなていにもかかわらず、コンパイルが実行されています。 実は、makeはデフォルトのパータンルールを持っており、パターンルールが明示されていない場合、そのデフォルトのルールが使用されます。 このパターンルールを組み込みルールと呼びます。

C言語用の組み込みルール

以下のGNU Makeの公式マニュアルに組み込みルールが列挙されています。 この中で*.cから*.oを作成する組み込みルールは以下のように記載されています。
$(CC) $(CPPFLAGS) $(CFLAGS) -c
さらに、上記の変数の$(CC)なども組み込みのデフォルト値があります。以下に記載されています。 上記のサイトに記載されている、それぞれの変数のデフォルト値を以下に示します。
変数デフォルト値
CC cc
CPPFLAGS (なし)
CFLAGS (なし)
これらの変数をMakefile内で以下のように上書きできます。
CFLAGS = -g3 -O2

prog2: main.o sub.o
        gcc -o $@ $^

main.o: main.c sub.h
sub.o: sub.c sub.h
このMakefileを使ってmakeを実行すると以下のようにCFLAGSに設定したオプションが付与されています。
cc -g3 -O2   -c -o main.o main.c
cc -g3 -O2   -c -o sub.o sub.c
gcc -o prog2 main.o sub.o

まとめ

本記事では、組み込みルールについて説明しました。

以下には、make入門の全記事がリストアップされています。

make入門 #3 自動変数とパターンルール

前回(make入門 #2 複数のルール)は、複数のルールからなるMakefileについて説明しました。 その際に気づいた方もいるかもしれませんが、ファイル名などが反復して使用されています。 今回は、反復した記述を少なくし、よりシンプルにMakefileを記述するための機能である自動変数とパターンルールを説明します。

自動変数を使って記述

以下は前回のMakefileです。
prog2: main.o sub.o
        gcc -o prog2 main.o sub.o

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

sub.o: sub.c sub.h
        gcc -c -o sub.o sub.c
これを自動変数を使うと次のように記述することができます。$@$^のように$から始まる単語が自動変数です。 それぞれの意味を下の表に示します。
prog2: main.o sub.o
        gcc -o $@ $^

main.o: main.c sub.h
        gcc -c -o $@ $<

sub.o: sub.c sub.h
        gcc -c -o $@ $<
自動変数 説明
$@ ターゲット(入力)ファイル(コロンの左側)
$^ すべての依存(出力)ファイル(コロンの右側のファイル全て)
$< 最初の依存ファイル(コロンの右側の最初のファイル)
このMakefileをカレントディレクトリに配置してmakeを実行すると以下のように自動変数が、具体的なファイル名に置換されて実行されていることが分かります。
$ make
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o prog2 main.o sub.o

パターンルール

上記の自動変数を使ったMakefileでmain.oとsub.oを作成するコマンドが同じになっています。ソースコードが増えていっても、同様の記述になるでしょう。 Makefileは、*.cから*.oを作成するような同じコマンドになるルールを共通化する仕組みを持っています。この仕組みをパターンルールと呼びます。 パターンルールを使って、記載したMakefileの例を以下に記載します。
prog2: main.o sub.o
        gcc -o $@ $^

%.o: %.c
        gcc -c -o $@ $<

main.o: main.c sub.h
sub.o: sub.c sub.h

青字で示した%.o: %.cという行があります。これは、*.cから*.oを作るルールという意味です。 そのコマンドとして、gccを使ったコンパイル処理が記述されています。ここでの$@$<は 実際のファイルに置換されるため、自動変数を使うとファイル名だけ異なる類似の処理をひとつのコマンドとして記載できます。

また、main.oとsub.oのルールにはコマンドがありません。具体的なコマンドはパターンルールで定義してあるため、 ここでは入出力(依存)関係のみを記述すればよくなります。

まとめ

本記事では、自動変数とパターンルールについて説明しました。

以下には、make入門の全記事がリストアップされています。

make入門 #1 makeとは

概要

Linuxにはmakeというコマンドがあります。もともとはC言語などで作られたプログラムをコンパイルやリンクするために開発されました。そして、今もその用途が中心です。 大規模なプログラムでは、ソースコードファイルが数千や数万以上になります。いくつかのソースコードファイルを変更するたびに、全てをコンパイルしなおすと膨大な時間がかかります。そのため、makeは、変更があったソースコードのみを抽出してコンパイルする手段を提供します。

では、どうやって変更があったソースコードを検出しているのでしょうか?実は、その仕組みはとても単純です。ソースコードのタイムスタンプ(変更日時)とそれをコンパイルして生成されるバイナリファイルのタイムスタンプを比較するだけです。このため、何かのファイルから別のファイルを生成するような用途には、プログラムに限らずに利用できます。例えば、数値データのCSVファイルからグラフファイルを作成するような場合です。

Makefileの書式

makeを使用するには、makeに以下の3つの情報を与える必要があります。
  • 入力ファイル (Input File)
  • 出力ファイル (Output File)
  • 処理方法 (Command)
これを図示すると次のようなイメージです。
この情報を記載したファイルをMakefileといいます。ファイル名はMakefile以外を使用することもできますが、makeコマンドはカレントディレクトリにMakefileがあると、明示的に指定しなくともそれを使用します。 Makefileの書式は次のとおりです。 赤字で[TAB]と記載してしているように、処理方法の前はスペースでなくタブ1つでなければなりません。
出力ファイル: 入力ファイル
[TAB]処理方法
また、出力ファイルと入力ファイルは、より抽象的に、それぞれ、ターゲットと依存ファイルと呼ばれることもあります。

C言語のプログラムをコンパイルする例

以下のソースコードprog.cをコンパイルして、実行ファイルprogを作成してみます。
#include <stdio.h>

int main() {
    printf("Happiness depends upon ourselves.\n");
    return 0;
}
コマンドラインからビルドするには以下のように入力します。
gcc -o prog prog.c
つまり、先に述べた3つの情報は次のようになります。
  • 入力ファイル: prog.c
  • 出力ファイル: prog
  • 処理方法: 上記のgccのコマンドライン
つまりMakfileとしては次のようになります。再度の注意ですが、2行目gccの前はTABが1つです。
prog: prog.c
        gcc -o prog prog.c
Makefileがあるディレクトリでmakeと入力すると以下のようにコンパイルが実行され、progが作成されていることが分かります。 また、makeの副次的な利点として、gccのコマンドラインオプションすべてを入力しなくても良い点があります。
$ make
gcc -o prog prog.c
$ ls -l
total 28
-rw-r--r-- 1 foo foo    33 Mar 21 09:01 Makefile
-rwxr-xr-x 1 foo foo 16608 Mar 21 10:44 prog
-rw-r--r-- 1 foo foo   100 Mar 21 09:01 prog.c

入力ファイルと出力ファイルのタイムスタンプによるmakeの振る舞い

一度コンパイルした状態で、再度makeを実行しても、make: 'prog' is up to date(progは最新です)と表示され、コンパイルは行われません。
$ make
make: 'prog' is up to date.
冒頭で説明したように、出力ファイルのタイムスタンプが、入力ファイルのタイムスタンプより新しいため、makeは何も処理を実行しなかったのです。ここで、以下のようにtouchコマンドを実行して、入力ファイルのタイムスタンプを更新します。
$ touch prog.c 
$ ls -l
total 28
-rw-r--r-- 1 kyamato kyamato    33 Mar 21 09:01 Makefile
-rwxr-xr-x 1 kyamato kyamato 16608 Mar 21 10:44 prog
-rw-r--r-- 1 kyamato kyamato   100 Mar 21 11:01 prog.c
この状態でmakeを実行すると、コンパイルが行われます。
$ make
gcc -o prog prog.c

まとめ

本記事では、make概要とMakefileの基本的な記述方法について説明しました。次回は、Makefileに複数のルールを記載する方法を説明します。

以下には、make入門の全記事がリストアップされています。