6. さらに多くの例

下記に、全三つのアプローチ (静的、共有、および動的にロードされるライブラリ) の例をさらに挙げます。ファイル libhello.c は平凡なライブラリで、 ヘッダファイルとして libhello.h を持ちます。ファイル demo_use.c は、 そのライブラリの平凡な呼出しです。 静的ライブラリや動的ライブラリとして当該ライブラリを使う方法を示すため、 コメント付きのスクリプト (script_static と script_dynamic) があとに続きます。 さらに demo_dynamic.c と script_dynamic があとに続きます。 これらは共有ライブラリを動的にロードされるライブラリとして使う方法を示します。

6.1. ファイル libhello.c

/* libhello.c - ライブラリ使用の実例 */

#include <stdio.h>

void hello(void) {
  printf("Hello, library world.\n");
}

6.2. ファイル libhello.h

/* libhello.h - ライブラリ使用の実例 */


void hello(void);

6.3. ファイル demo_use.c

/* demo_use.c -- "hello" ルーチンを直接使用する実例 */

#include "libhello.h"

int main(void) {
 hello();
 return 0;
}

6.4. ファイル script_static

#!/bin/sh
# 静的ライブラリの実例

# 静的ライブラリのオブジェクト libhello-static.o を作成します。
# 静的ライブラリと動的ライブラリの例を明確に区別するため、
# libhello-static という名前を使用しています。しかし、あなたの
# オブジェクトファイルや静的ライブラリの名前に "-static" を使う
# 必要はありません。

gcc -Wall -g -c -o libhello-static.o libhello.c

# 静的ライブラリを作成します。

ar rcs libhello-static.a libhello-static.o

# ここで、libhello-static.a を使うためにそれをどこか他の場所へ
# 単にコピーすることもできます。デモが目的なので、ライブラリは
# カレントディレクトリ内にとどめておきます。

# demo_use プログラムをコンパイルします。

gcc -Wall -g -c demo_use.c -o demo_use.o

# demo_use プログラムを作成します。-L. により、プログラム作成中に
# "." が検索されることになります。このコマンドは、libhello-static.a
# 内の関係するオブジェクトを demo_use_static に組み込むということ
# に注意してください。

gcc -g -o demo_use_static demo_use.o -L. -lhello-static

# プログラムを実行します。

./demo_use_static

6.5. ファイル script_shared

#!/bin/sh
# 共有ライブラリの実例

# 共有ライブラリのオブジェクトファイル libhello.o を作成します。

gcc -fPIC -Wall -g -c libhello.c

# 共有ライブラリを作成します。
# libhello は C ライブラリに依存しているので、C ライブラリと
# リンクさせるために -lc オプションを使います。

gcc -g -shared -Wl,-soname,libhello.so.0 \
    -o libhello.so.0.0 libhello.o -lc

# ここで、libhello.so.0.0 をどこかのディレクトリ、/usr/local/lib
# など、に単にコピーできます。

# シンボリックリンクを修正するため、ldconfig を呼び出す必要があります。
 
# soname を設定します。単に、
#
#   ln -sf libhello.so.0.0 libhello.so.0
#
# を実行するだけでもよいですが、ldconfig にやってもらいましょう。

/sbin/ldconfig -n .

# linker name を設定します。
# より洗練された設定をおこなうなら、既に linker name が存在するかを
# 確認し、もし存在すれば、それを残しておくべきか否かを調べます。

ln -sf libhello.so.0 libhello.so

# demo_use プログラムをコンパイルします。

gcc -Wall -g -c demo_use.c -o demo_use.o

# demo_use プログラムを作成します。-L. により、プログラム作成中に
# "." が検索されることになります。これは、プログラム実行時に "."
# が検索されることを意味 'しない' ということに注意してください。

gcc -g -o demo_use demo_use.o -L. -lhello

# プログラムを実行します。LD_LIBRARY_PATH を使って、どこに共有
# ライブラリが存在するかをプログラムに教える必要があることに注
# 意してください。

LD_LIBRARY_PATH="." ./demo_use

6.6. ファイル demo_dynamic.c

/* demo_dynamic.c -- 動的ローディングと "hello" ルーチン使用の実例 */


/* 動的にライブラリをロードするルーチン用に dlfcn.h が必要 */
#include <dlfcn.h>

#include <stdio.h>

/* "libhello.h" をインクルードする必要がないことに
   注意してください。しかしながら、関連するものを
   指定する必要はあります。dlsym() から得ようとして
   いる値を保持するタイプを指定する必要があります。*/

/* "simple_demo_function" タイプは、引数をとらず、
   何も値を返さない関数を示しています。 */

typedef void (*simple_demo_function)(void);


int main(void) {
 const char *error;
 void *module;
 simple_demo_function demo_function;

 /* 動的にロードされるライブラリをロードする */
 module = dlopen("libhello.so", RTLD_LAZY);
 if (!module) {
   fprintf(stderr, "Couldn't open libhello.so: %s\n",
           dlerror());
   exit(1);
 }

 /* シンボルを得る */
 dlerror();
 demo_function = dlsym(module, "hello");
 if ((error = dlerror())) {
   fprintf(stderr, "Couldn't find hello: %s\n", error);
   exit(1);
 }

 /* DL ライブラリ内の関数を呼び出す */
 (*demo_function)();

 /* 全てが終了したので、物事をきれいに片付ける */
 dlclose(module);
 return 0;
}

6.7. ファイル script_dynamic

#!/bin/sh
# 動的にロードされるライブラリの実例

# libhello.so とその仲間が既に作成されているものとします
# (共有ライブラリの例を見てください)。

# demo_dynamic プログラムファイルをオブジェクトファイルへ
# コンパイルします。

gcc -Wall -g -c demo_dynamic.c

# demo_use プログラムを作成します。
# このプログラムが使用する唯一の特別なライブラリは、プログラム
# 起動後までロードされないので、DL ライブラリをどこに探しにい
# けばよいかを教える必要がないことに注目してください。しかしな
# がら、DL ライブラリをロードするライブラリを含めるため、-ldl
# オプションは '必要' となります。

gcc -g -o demo_dynamic demo_dynamic.o -ldl

# プログラムを実行します。LD_LIBRARY_PATH を使い、動的にロード
# されるライブラリをどこで得られるかを教える必要があります。

LD_LIBRARY_PATH="." ./demo_dynamic