共有ライブラリの作成と利用方法
Unix/Linuxにおける共有ライブラリの作成と利用方法を解説します。この記事は、分割コンパイル手法を理解していることが前提です。
共有ライブラリとは
共有ライブラリとは、実行ファイル生成時に、静的にリンクせず、実行時に、リンク可能なオブジェクトファイルのことです。共有ライブラリは、リンク時にリンクすることが可能で、かつ、実行時に読み込むこともできます。拡張子は「.so」です。
ここで解説する、共有ライブラリは、UNIX/Linuxの仕組みであって、MacやWindowsの仕組みではないことに注意してください。Macの場合は、拡張子が異なります。Windowsには、DLL(ダイナミックリンクライブラリ)という似た仕組みがありますが、UNIX/Linuxの共有ライブラリとは異なります。
共有ライブラリの作成方法
共有ライブラリを作成するには「-shared」オプションを指定します。一般的には、「-fPIC」を指定して位置独立コードとして作成します。
オブジェクトファイル生成する手順に、「-shared」と「-fPIC」オプションを追加して、以下のようにします。
# 通常のコンパイル - オブジェクトファイルの作成 gcc -Iinclude -c -o mylib1.o src/mylib1.c # 共有ライブラリの作成 gcc -Iinclude -c -shared -fPIC -o mylib1.so src/mylib1.c
共有ライブラリを作成してリンクする
この手順は分割コンパイル手法で使った手順を流用できます。ライブラリを共有ライブラリとして作成します。
アプリケーションのソースファイル
アプリケーションのソースファイル「myapp.c」です。
myapp.c
#include <stdio.h> #include "mylib1.h" #include "mylib2.h" int main(void) { mylib1_print(); mylib2_print(); }
ライブラリのヘッダファイル
ライブラリのヘッダファイル「mylib1.h」と「mylib2.h」です。
mylib1.h
#ifndef MYLIB1_H #define MYLIB1_H void mylib1_print (void); #endif
mylib2.h
#ifndef MYLIB2_H #define MYLIB2_H void mylib2_print (void); #endif
ライブラリのソースファイル
ライブラリのソースファイル「mylib1.c」と「mylib2.c」です。
mylib1.c
#include <stdio.h> #include "mylib1.h" void mylib1_print (void) { printf("mylib1_print\n"); }
mylib2.c
#include <stdio.h> #include "mylib2.h" void mylib2_print (void) { printf("mylib2_print\n"); }
コンパイル
アプリケーションのソースファイルと、共有ライブラリのソースファイルを、それぞれコンパイルします。ヘッダファイルの場所をオプション「-I」で指定します。「-shared」と「-fPIC」オプションを使って、共有ライブラリを作成します。
gcc -Iinclude -c -o myapp.o src/myapp.c gcc -Iinclude -c -shared -fPIC -o mylib1.so src/mylib1.c gcc -Iinclude -c -shared -fPIC -o mylib2.so src/mylib2.c
リンク - 実行ファイルの作成
リンクして実行ファイルを作成します。関数名などのシンボルが、実体に結びつけられます。
gcc -o myapp myapp.o mylib1.so mylib2.so
実行
実行ファイルを実行してみましょう。
./myapp
出力結果です。
mylib1_print mylib2_print
共有ライブラリを作成して、実行ファイルを作成するときに、リンクする方法をマスターしました。
実行時に共有ライブラリを読み込んで、関数を実行するには?
実行時に共有ライブラリを読み込んで、関数を実行する手順だけを公開します。
1. dlopen関数で、共有ライブラリをオープンします。
2. dlsymで関数名を指定して、関数ポインタを取得します。
3. 関数ポインタから関数を実行します。
共有ライブラリに含まれている関数名などのシンボルを知るには?
共有ライブラリに含まれている関数名などのシンボルを知るには「nm」コマンドを使用します。「name」の略のようです。
nm mylib1.so
出力結果です。
U _GLOBAL_OFFSET_TABLE_ 0000000000000000 T mylib1_print U puts
nmコマンドは、共有ライブラリだけでなく、実行ファイルやオブジェクトファイルにも使えます。
共有ライブラリの検索
共有ライブラリは、衝突を回避する仕組みを持っています。共有ライブラリは、ファイル名を直接してししなくても「-L」オプションで、共有ライブラリの検索ディレクトリを指定できます。ライブラリ名は「lib」で始まっている必要があります。
共有ライブラリの検索ディレクトリに、共有ライブラリを配置すれば、「-l」オプションで指定された、最初に見つかった共有ライブラリを利用します。「-l」オプションでは、先頭の「lib」と「.so」を省略します。
共有ライブラリ
/foo/lib/libmylib1.so
共有ライブラリのリンク
gcc -o myapp myapp.o -L /foo/lib -l mylib1