gccを用いたCの共有ライブラリの作り方

ゆとりなもので,ついこないだまで動的リンクと静的リンクの違いがわかっていなかった.動的リンクというのが理解できた頃,そっかユーティリティライブラリは自分で共有ライブラリ作ってしまえばいいんだ,というごく当たり前のことが理解できた.

UNIXをさわりはじめていた初期の頃,mecab.soのシンボリックが〜〜という用なハマりがあったのだけれど,あれは要するに実行時に共有ファイルへのパスを指定してあげればよかっただけのこと.
わかると当たり前だけれど,わからないと「何がわからないのかわからない」状態に落ち込むなぁ,と改めて思いました.
(幸いなことに,僕の周りには「ゆとり乙ww」と指導してくれる方々がいるので認識できるようになるのですが,少なくとも大学(院)時代はそうでなかったわけで,ゆとりスパイラルの恐ろしさを体感した気がしています.)

というわけで自分用共有ライブラリの作り方をきちんと理解できているか,自分用メモ.
ちなみに今回はarコマンドによって生成されるライブラリアーカイブ(*.a)は扱わない.(そもそもこちらはよくわかっていない)


こんなソースファイルのライブラリをつくってみる.

  • ソースファイル
// test.c
#include <stdio.h>
#include "test.h"

void
print_hoge (int num)
{
  int i;
  for (i = 0; i < num; i++) {
    printf("hoge\n");
  }
}
  • ヘッダファイル
// test.h
#ifndef TEST_H
#define TEST_H

void print_hoge (int num);

#endif

共有ライブラリを作成する.名前の先頭にlibをつける必要がある.

% gcc -shared test.c -o libtest.so

これで共有ライブラリが生成された.この共有ライブラリを使用するためには,
コンパイルをする際にヘッダファイルとライブラリファイルの位置を知らせる必要がある.

// main.c
#include "test.h"

int
main (void)
{
  print_hoge(5);
  return 0;
}

コンパイルを行う際に,

  • ヘッダファイルの場所
  • 共有ライブラリの場所
  • 共有ライブラリの名前

を指定する必要がある.標準ライブラリと同じパスに置く場合は不要.

% gcc -I./ -L./ main.c -o main -ltest

できあがった実行ファイルをこのまま実行すると怒られる.共有ライブラリの場所がわからないとさ.

% ./main
./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

「使用する共有ライブラリ名」という情報はコンパイル時にわかっているものの,実際に使用する共有ライブラリのある場所(ライブラリパス)がどこにあるかわからない.
lddで実行ファイルが使用する共有ライブラリを調べることができる.

% ldd main
main:
        libtest.so => not found (0x0)
        libc.so.6 => /lib/libc.so.6 (0x2807b000)

libtest.soが見つかりません.というエラーが出ていることがわかる.共有ライブラリパスの指定は,環境変数LD_LIBRARY_PATHで行う.

% LD_LIBRARY_PATH=./ ./main

自分でつくった共有ライブラリを置く場所が決まっていれば,

% export LD_LIBRARY_PATH=~/lib/

ただ,LD_LIBRARY_PATHの指定はあまりよろしくないらしい.

環境変数を使った指定

gccのIオプションやLオプションなどで与えていた情報は,環境変数で指定することもできる.

C_INCLUDE_PATH       # C ヘッダファイルの検索パス
CPLUS_INCLUDE_PATH   # C++ ヘッダファイルの検索パス
LIBRARY_PATH         # コンパイル時のライブラリの検索パス
LD_LIBRARY_PATH      # 動的ライブラリの検索パス

so? so.1? so.2?

今まで疑問に思っていた,so.1とかso.2(例:libtest.so.1, libtest.so.2)という後ろの数字はライブラリのバージョン番号を表しているらしい.
.soを置き換えるのではなく,libtest.soを最新バージョンへのシンボリックリンクにすることで適切なバージョンを使うようにしているらしい.