makefileおさらい

概要

linuxシステムのカーネル触る機会があるんだかないんだかで、改めてmakefileについておさらい。
今回はほとんど自分のメモみたいなものです。

makefileファイル

今回取り上げるのは

PREFIX = /usr/local
DEST_HEADER = $(PREFIX)/include/

TARGET = librpi_gpio.a
SRCS = rpi_gpiolib.c
OBJS = $(subst .c,.o,$(SRCS))
HEADERS = rpi_gpiolib.h rpi_gpio.h

RM := rm
CC := gcc
AR := ar

CPPFLAGS = -g -fPIC -O2 -l./
LDFLAGS = -g -fPIC
ARFLAGS = cr

$(TARGET): $(OBJS)
	$(AR) $(ARFLAGS) $@ $^ $(LOADLIBES)

install: $(TARGET) $(HEADERS)
	mkdir -p $(PREFIX)/lib/
	install -m644 $(TARGET) $(PREFIX)/lib/$(TARGET)
	mkdir -p $(DEST_HEADER)
	install -m644 $(HEADERS) $(DEST_HEADER)

.PHONY: clean

clean:
	$(RM) $(OBJS) $(TARGET)

出典は下記の書籍を読み進めていて出てきました。話はそれますが低レイヤの知識を得る際にオススメです。興味のある方は是非どうぞ。

さて私はそんなにmakefileをガッツリ触ったことがあるわけではないので、分からない点をひとつひとつ掘り下げていきます。

subst関数

まずここsubst関数について

SRCS = rpi_gpiolib.c
OBJS = $(subst .c,.o,$(SRCS))

Makefileで使えるユーザ関数であり、substは3つの引数を受け取ります。
c言語ライクにかくならば subst(from, to, text); のようなイメージになります。

この関数は text 文字列を対象として from を to に置換します。
したがって上記のMakefileの中で言うと “.c” という文字列を “.o” という文字列に置換することになります。
最終的に OBJS変数には rpi_gpiolib.o という文字列が格納されることになります。
文字通りコンパイル時のオブジェクトファイルの文字列を格納しているようです。

ビルド

AR := ar
ARFLAGS = cr

$(TARGET): $(OBJS)
	$(AR) $(ARFLAGS) $@ $^ $(LOADLIBES)

まずは細かいメタ変数の部分から確認すると
$@ はターゲット名なので librpi_gpio.a
$^ は全依存関係のリストなので rpi_gpiolib.c
を指すことになります。

その後いきなり arコマンドが展開されているので、.oを生成するルールが無いように見えるのですが
makefileにはデフォルトルールがありそこに .oターゲットが定義されており .cを依存ファイルとしてコンパイルするルールが存在します。
このあたりは make -p で確認できるようです。

下記のようなルールを確認しました。

make -p
...
%.o: %.c
#  commands to execute (built-in):
        $(COMPILE.c) $(OUTPUT_OPTION) $<
...

$(LOADLIBES)に関しては定義されていないようなので、この場合は特に意味を成さないですが、通常はリンクするライブラリのパスを入れます。

さて最後に ar コマンドに関してですが、アーカイブを作成します。
現在ではもっぱらライブラリの作成時にのみ使用されるコマンドで、複数オブジェクトをまとめてライブラリを作成する際の典型的なパターンです。
これによって複数の .oファイル(この例に関しては1角ファイルですが)から .aファイルを作成します。

インストール

install: $(TARGET) $(HEADERS)
	mkdir -p $(PREFIX)/lib/
	install -m644 $(TARGET) $(PREFIX)/lib/$(TARGET)
	mkdir -p $(DEST_HEADER)
	install -m644 $(HEADERS) $(DEST_HEADER)

installコマンドにより作成したライブラリファイルを適切な場所にコピーします。
cpコマンドと何が違うのかというと、コピーと同時に属性を指定することができます。
こちらは特に難しいことはないですね。

以上となります。
はじめはよくわからなかったですが分解して見たらかなりしっかりした構造であることがわかりました。
また調べていてこちらのページを見つけたのですが、リンカ/ローダの仕組みを歴史的な側面からも見つつ体系的に非常によくまとめられていたのでオススメです。

参考ページ

http://qiita.com/chibi929/items/b8c5f36434d5d3fbfa4a
http://0xcc.net/blog/archives/000107.html
http://linuxjf.osdn.jp/JFdocs/Program-Library-HOWTO/shared-libraries.html

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください