ビルドに必要なファイルの種類を整理する

最近、mrubyを触ってるんだけど、ビルド周りの知識があいまいで自分が何をしているのかよくわからないときがあったので、Head First Cを読み直した。あらためて基本的なことを確認できたので、メモに残しておく。

*.c

  • C言語のソースコード

*.h

  • ヘッダーファイル。ソースコードで実装されている関数や構造体の宣言が書いてある。
  • 宣言をソースコードと分けることで、ソースコード内で関数や構造体を実装する順番を気にしなくてよくなる。
  • #include <stdio.h>#include "myheader.h"でヘッダーファイル内の宣言をソースコードに展開する。前者は/usr/include/usr/local/include以下にあるヘッダーファイルを検索し、後者はソースコードからの相対パスで検索する。

*.o

  • オブジェクトコード。CPUが実際に実行できるバイナリ形式のコード。
  • 以下のようにgcc -cでソースコードから生成できる。-cオプションはコンパイルするけどリンクしない。
    # foo.oを生成する
    $ gcc -c foo.c
    

lib*.a

  • スタティックリンクライブラリ。オブジェクトファイルを含んだzipファイルのようなアーカイブファイル。/usr/lib/usr/local/libのようなライブラリディレクトリに置かれている。
  • arコマンドを使ってスタティックリンクライブラリを生成できる。
    # foo1.oとfoo2.oを含むlibfoo.aを生成する
    $ ar -rcs libfoo.a foo1.o foo2.o
    
  • スタティックリンクライブラリを使ったコンパイルは以下のようになる。
    # libfoo.aを使ってbazを生成する
    $ gcc bar.c -lfoo -o baz
    

lib*.so

  • ダイナミックリンクライブラリ。複数のオブジェクトファイルを含むが、スタティックリンクライブラリとは異なり、オブジェクトファイルが適切にリンクされた1つのオブジェクトコードを持つ。/usr/lib/usr/local/libに置かれる。

  • gcc -sharedでオブジェクトファイルからダイナミックリンクライブラリを生成する

    # foo1.oを含むlibfoo.soを生成する
    $ gcc -shared foo1.o -o libfoo.so
    
  • ダイナミックリンクライブラリを使ったコンパイルは以下のようにスタティックリンクライブラリのときと同じ。

    $ gcc bar.c -lfoo -o baz
    

    ただし、コンパイラはライブラリを実行可能ファイルに含めない。代わりに、実行時にライブラリを見つけ出してリンクするプレースホルダーを挿入する。

    このように生成された実行可能ファイルはダイナミックリンクライブラリを変更しても再コンパイルする必要はなく、ダイナミックリンクライブラリをコンパイルするだけでいい。

実行可能ファイル

  • 複数のオブジェクトファイルをリンクして実行可能な形式に変換される。
  • 以下のようにgcc -oでオブジェクトファイルから生成できる。
    # すべてのオブジェクトファイルからfooを生成する
    $ gcc *.o -o foo
    

まとめ

以上のような種類のファイルから最終的に実行可能ファイルができるまでの図を書いてみた。

foo.c  -> foo.o  ----------------+-> qux
                                 |
bar1.c -> bar1.o -+-> libbar.a --+
                  |              |
bar2.c -> bar2.o -+              |
                                 |
baz1.c -> baz1.o -+-> libbaz.so -+
                  |
baz2.c -> baz2.o -+