ライブラリの基礎

このエントリーをはてなブックマークに追加

ライブラリとはどんな言語でも非常に便利な存在です。
ライブラリを一言で説明すれば、何かの共通した目的に対して便利な関数群をまとめた物と言えばよいでしょうか。
ライブラリが無いと開発者はすべての機能を1からの開発が必要となり非常に大きな負担を強いられることとなります。
また開発をそれぞれが分散、集中できるためクオリティやセキュリティの向上等のメリットもあります
いわゆるモジュール・プログラミングを可能とします。

ライブラリディレクトリ

ライブラリはUnix系は歴史的に/usr/lib以下に置かれています。
また、ユーザ用の/usr/local/lib/、64ビット環境への対策として、/usr/lib64、/usr/loca/lib64等があります。
これらのディレクトリ構成はLinux、BSD等のOSの違い、Linuxのディストリビューションやバージョンの違い等により微妙な違いがありますので注意してください。

試しに/usr/libの一部を覗いてみましょう。

$ ls /usr/lib|head
ConsoleKit
NetworkManager
R
VBoxOGL.so
VBoxOGLarrayspu.so
VBoxOGLcrutil.so
VBoxOGLerrorspu.so
VBoxOGLfeedbackspu.so
VBoxOGLpackspu.so
VBoxOGLpassthroughspu.so

この'.so'がライブラリの実態となります。バイナリファイルなので人間が目で見て理解するのは非常に困難ですが...


ライブラリが生まれた過程を追ってみよう

まずは簡単なコードを見てみましょう。

//helloworld.c
#include <stdio.h>

int main(void)
{
	printf("Hello Wold\n");

	return 0;
}

いわゆるHello Worldですね。
$ gcc -o helloworld helloworld.c
$ ./helloworld
Hello World

コンパイルも特に問題ありません。


引き続き、コードを見てみます。
先ほどのコードを複数のファイルに分割します。

//print.c
#include <stdio.h>
void print(void)
{
	printf("Hello Wold\n");
}

//helloworld.c
extern void print(void);

int main(void)
{
	print();

	return 0;
}

printf部分を別ファイルへと分離しています。
$ gcc -o helloworld print.c helloworld.c
$ ./helloworld
Hello World

コンパイルも特に問題ありません。


これはprint.cに必要な機能を別ファイルとして纏めた物です。
これは通常の開発で当たり前に使われている技術ですが、これがSSL、高度な数学の機能、画像ファイルを扱うのように汎用的な機能となるとどのような要望となるでしょう?
こういった汎用的な機能の作成には非常に高いコストや技術力等が必要となります。SSLのような場合ですとセキュリティも大事です。
これらを毎回プロジェクト毎に作るのは非常に無駄と感じ、使い回しをしたいと考えるのは自然な事です。
こうやって出来たのがライブラリです。


静的ライブラリ(static library)

ライブラリの生成を理解するためには、コンパイルについて少し理解が必要です。
ここでは詳しい意味については解説しません。

$ gcc -c print.c
$ gcc -c helloworld.c

$ ls *.o
helloworld.o print.o

$ file *.o
helloworld.o: ELF 64-bit LSB  relocatable, x86-64, version 1 (SYSV), not stripped
print.o:      ELF 64-bit LSB  relocatable, x86-64, version 1 (SYSV), not stripped

$ gcc -o helloworld print.o helloworld.o
$ ./helloworld
Hello World

gccに-cオプションを渡すと.cファイルをオブジェクトファイルと呼びます。
これは.cを機械語に変換したファイルです。ただし実行はできません。
オブジェクトファイルを実行可能な状態にするのがリンクです。
リンクは複数のオブジェクトファイルを結合して実行可能なファイルを生成します。


ここまで見てみると自然に思いつくのが、共通で使いたい機能のオブジェクトファイルだけを共有する方法です。
これは自然な発想ですが共有したいオブジェクトファイルは通常複数となります。これらをそのまま共有するのは現実的ではありません。
この問題にたいして複数のオブジェクトファイルを1つに纏める方法が取られました。これを静的ライブラリ(static library)と言います。
では静的ライブラリの作り方と使い方を見てみましょう。

$ gcc -c print.c
$ gcc -c helloworld.c

$ ar rcs libprint.a print.o

$ gcc -o helloworld helloworld.o -L./ -lprint
$ ./helloworld
Hello World

とくに難しい部分はないと思います。
静的ライブラリの特徴として、リンクはされるのでライブラリ分ファイルサイズが増えます。
つまり通常の場合と代わりはありません。
また、ライブラリを更新する毎に再コンパイルが必要となります。
使い所はクローズドな開発等、状況を選ぶでしょう


動的ライブラリ(dynamic library)

静的という名前が付いているということは、当然これに対する動的ライブラリもあります。
静的ライブラリの欠点はコンパイル時に実行ファイルに結合される事です。
これはHDDの容量が少ない時代には非常に大きな問題でしたし、開発にも手間がかかります。
この欠点に対応したのが動的ライブラリです。

では、早速動的ライブラリを作成してみましょう
コードは静的ライブラリで使用した物と同じ物を使用します。

$ gcc -fPIC -c print.c
$ gcc -shared print.o -o libprint.so

$ gcc -o helloworld helloworld.o -L./ -lprint
$ ./helloworld
Hello World
$ file libprint.so 
libprint.so: ELF 64-bit LSB  shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=a54c2ab879fab6ccef4931821bd1b0b95c4e9f00, not stripped

動的ライブラリを作成するためにはオブジェクトファイル生成時に-fPICオプションが必要となります。
ライブラリ名はlib*.soとなります。静的ライブラリの時はarを使用しましたが、動的ライブラリの場合は'gcc -shared'となります。
fileコマンドの結果をを見ると、shared object、dynamically linkedとあり、動的ライブラリであることがわかります。
動的ライブラリは実行ファイルに直接組み込まれません。実行ファイルの実行時に動的にライブラリを読み込み実行します。
このため、ライブラリにバグがあった場合でもライブラリだけの更新で済むなど非常に便利になっています。


まとめ

ここまで、ライブラリの意味や、簡単な作り方等を紹介してきました。
ライブラリは様々なコストを下げ、開発者を手助けしてくれる非常に便利な存在です
作り方を学び、また公開されているライブラリを使用する事を学べば開発にきっと役に立つことでしょう

Binary Hacks ―ハッカー秘伝のテクニック100選Binary Hacks ―ハッカー秘伝のテクニック100選
高林 哲,鵜飼 文敏,佐藤 祐介,浜地 慎一郎,首藤 一幸

オライリー・ジャパン
売り上げランキング : 80774

Amazonで詳しく見る by AZlink

GNU Make 第3版GNU Make 第3版
Robert Mecklenburg,矢吹 道郎 (監訳),菊池 彰

オライリージャパン
売り上げランキング : 82952

Amazonで詳しく見る by AZlink