Linuxで、lddとかldconfigとか.soファイルまわりのトピックが苦手です。


オープンソースのソフトウェアをコンパイルとかインストールしようとしたときに、この辺でエラーが出ると途方にくれてしまいます。
(ググれば解決することもありますが、解決までにすごく時間かかります)

この苦手分野を克服したいのですが、何をどう勉強したらいいでしょうか?
お勧めのサイトや書籍などがあれば教えてください。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/10/16 21:19:35
  • 終了:2012/10/23 21:20:08

ベストアンサー

id:a-kuma3 No.4

a-kuma3回答回数4545ベストアンサー獲得回数18952012/10/17 23:21:30

ポイント50pt

ldd や ldconfig コマンドが出てきている時点で、ほぼ理解できてるんじゃないかと思います。
DQNEO さんは、開発者目線というか、プログラムをいじれる側の立場ですよね。
共有オブジェクト (Shared Object) とか、動的リンケージ (Dynamic Linkage) という概念については、問題無いのだと思います。
その上で、ポイントになるとしたら、以下の二つ。

  • 動的リンケージと言いながら、実行形式を作る際にも .so を解決できてないと、リンクに失敗する(不思議に思うのは、ぼくだけ?)
  • .so を探す順番があり、リンカのオプションによって、微妙に違ってくる

これが分かっていれば、「○○って、シンボルが見つからねーじゃん」って、(コンパイルではなく)リンクの時点でエラーが出たときに、○○というシンボル(関数、もしくは変数)が含まれているライブラリは何だろう、って調べるだけです。

まずは、導入したいプログラムのドキュメントをあたって、依存しているライブラリは何だろう、ってことを調べるのが第一だとは思いますが、ドキュメントをあさるのが面倒なら、configure で生成された Makefile を見て、-l を探すのがてっとり早いかも。
-l○○○ というオプションがあれば、lib○○○.a か lib○○○.so がリンカが解釈できるところにあるはずで、ライブラリのバージョンを吸収する意味で、lib○○○.so が lib○○○.so.××× へのシンボリックリンクになっている、というだけです。
実際には、ライブラリのバージョンとかもあるでしょうから、ドキュメントに戻る、ということになるのかもしれませんが。


知っていることかもしれませんが、ローダーの動作については、以下の man だけで、用をなすと思います。
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man8/ld.so.8.html

ぼくみたいな、古い人間だと LD_LIBRARY_PATH 辺りまでの理解で止まっちゃうところですが、linux だと、それに加えて ld.so.conf が入ってくるだけで、大筋は変わりません。


妙にマイナー(世の移り変わりを含む)なライブラリを使われているときに、どのライブラリに含まれてるんだっけか、ということで苦労することがある、ということには、激しく同意します。

他1件のコメントを見る
id:a-kuma3

ldd や ldconfig コマンドをよくわからずに「おそるおそる」叩いてる感じなので、この「おそるおそる感」を克服したいのです。

少なくとも、ldd コマンドは、情報を表示しているだけなので、バンバン叩いちゃってください。

2012/10/20 02:14:32
id:DQNEO

はい!

2012/10/24 23:14:35

その他の回答(3件)

id:oil999 No.1

oil999回答回数1728ベストアンサー獲得回数3202012/10/16 21:55:09

ポイント50pt

この記事が参考になるでしょう。

プログラマーでない人のための「共有ライブラリ」講座

http://www.glamenv-septzen.net/nifty/others/computer/linux_ldd01.html

id:DQNEO

ありがとうございます!
そのものずばりですね。読んでみます。

2012/10/20 01:27:03
id:pigmon88 No.2

pigmon88回答回数501ベストアンサー獲得回数252012/10/16 23:58:36

ポイント50pt

そういうコンパイルでエラーがでたときの対処法は、ネットでくぐるしかないですね。
Linuxなんかだと大抵同じエラーで苦しんでいる人がいるし、詳しい人が教えています。ただ、それらは大概掲示板の類いで、無償なので教え方がいいかげんだったり、
尻切れとんぼだったりします。相手のスキルがあまりに低いと放置されますし。
そういうものを体系的に学ぶというのは不可能で、というか文化がちがいます。
体系的に学びたいのだったら、高価なOSを買えばいいわけです。
ジャンク的なものを使って、体系的なドキュメントがないと文句言ってるのがおかしいわけで。中国のコピー商品にサポートがないと文句言ってるようなものです。
要はあなたの発想はLinux的でないということですね。

id:DQNEO

>要はあなたの発想はLinux的でないということですね。

これは手厳しいお言葉。(笑)

いちおうググればたいてい解決できますし、そうやってきました。

別に無償でサポートしろといってるわけはなく、お金を払って書籍を買ってもよいと言っています。実際にこうして有償ポイントをつけて質問を投稿しています。

ドキュメントがないことに文句を言ってるわけではないです。あればいいなあと考えてるだけです。
ApacheもEmacsもGitも、体系的ドキュメントがありますよね?

コンパイルエラーについて体系的に学ぶ筋道があってもよいと思います。

2012/10/20 01:38:42
id:sanada33 No.3

みかん回答回数293ベストアンサー獲得回数32012/10/17 19:04:43

ポイント50pt

まずは Windows に戻りましょう。
「本題」に戻る

 生粋の Linux/UNIX ユーザーはこの文章は読んでいない、と仮定して大胆にも一旦話を Windows に引き戻します。
 というのは、最近になってLinux/UNIXをいじり始めた人たちは大半が Windows も使っている人たちであろうからです。

 んで。Windows でもやっぱり「共有ライブラリ」や「ライブラリ」といった言葉が頻発するわけです。が、何故かLinux/UNIX 程には恐怖感がありません。
 まずはそこから入っていきましょうか。

 単刀直入に切り出します。「共有ライブラリ」や「ライブラリ」と言われているシロモノの実体は単なるファイルです。
 で、Windows では「****.dll」、Linux/UNIX では「lib****.so.****」というファイル名(*の部分はライブラリの名前何かが入ります。つまり何でも良い)が「共有ライブラリ」や「ライブラリ」といわれているシロモノの本体です。

 ほら、Windows で言うところの悪名高いVBランタイムライブラリ何かがまさにそれですよ。
 すこし Windows に詳しくなれば誰もが口にする「DLL」というのが、Windows 版の「共有ライブラリ」です(後述しますがDLLファイルは「ライブラリ」とはちょっと違う場合もあります)。

 Windows を始めた頃を思い出して下さい。うっかり「****.dll」を削除してしまったばっかりに重要なアプリケーションが起動しなくなったりしたこと、ありませんか?あれと同様の事が Linux/UNIX でも起こりうるのです。
 もっともLinux/UNIXシステムの場合、システム中枢に関わるライブラリは root 権限がないと消去できないパーミッションが与えられていますのでおいそれとは(サーバーマシンなどでは)上記のような現象は起こらないでしょうが・・・。
 Linux/UNIX ではむしろ、「ライブラリのバージョンが違うために動作しない」現象の方が圧倒的に多いと思われます。

 そういえば、VBランタイムライブラリにも「VB5」とか「VB6」みたくバージョンがありました ねえ。フリーソフトなどを利用するときはVBランタイムライブラリのバージョンが違って動かなかった、みたいなこと。経験しませんでした?

 話がまとまりませんが、「あ、共有ライブラリとかって Windows で言うところの DLL か!」と頭の上にろうそくが灯って頂ければ十分かな、と。

DLLについて。
「本題」に戻る

 何だかとりとめない話になってしまいし、「何でLinux/UNIXでは共有ライブラリに対する恐怖感を覚えるのか」が終わっていません。

 これは人によりけりですので、どうせ(私個人が)汎用的(だと思っている)な理由を挙げても大した足しにはなりません。
 ここでは私自身がなぜ恐怖感を覚えたのか語らせていただきます。

 私が「共有ライブラリ」に出会ったのはやっぱりWindowsで、DLLファイルを削除してしまった事件でした。
 エラーメッセージが表示されたんですよね。「****.dllが見つかりません」みたいな。
 んで、(幸いにも)ゴミ箱に入れてた ****.dll を元に戻したら動くようになりました。

 私自身はプログラミングを勉強中でした。特にC言語を学んでいたせいもあってか、「DLL」の意味するところが朧気ながら(当然誤解も含めて)直感的に察しがついていました。何となく、複数のアプリケーションから使用される機能の固まりではないかな、と。まあ、パソコン雑誌を拾い読みしていたせいもありましたが。

 そう言うわけで、Windowsでは大規模なアプリケーションにはDLLが使われているんだな、ということ。そして、「DLLファイルは大概、C:\WINDOWSディレクトリの中か、個別のアプリケーションのフォルダの中にあるんだな。」ということをフリーソフトのインストール作業から学びました。
 現実問題として DLL 絡みの問題があまり起こらなかったということもあるのかもしれません。

 で、Linux/UNIXです。
 やっぱり最初、「ライブラリって何だっぺ」状態でした。
 C言語の知識から、「やっぱりコンパイル時に使うものだろうか」とか、「それとも Windows のDLLみたいなものじゃろか」とか。

 実は Windows において(特にプログラミングに於いて)「ライブラリ」と「共有ライブラリ」は相当意味が違うシロモノなのです(詳細は後述)。
 それが、Linux/UNIXではずいぶんとごちゃ混ぜに使われています。その時点ですでに若干の混乱を引き起こしていました。

 極めつけは /lib ディレクトリ内にある大量の「lib****.so.****」ファイルとそれへのリンク。
 実例を下に示します。ls -l から適当に引っ張ってきた部分です。


lrwxrwxrwx 1 root root 11 9月 10日 07:25 libpam.so -> libpam.so.0*
lrwxrwxrwx 1 root root 14 9月 10日 07:25 libpam.so.0 -> libpam.so.0.75*

  • rwxr-xr-x 1 root root 38656 4月 28日 2002 libpam.so.0.75*


 どれがどうリンクしてるのかさっぱり分からん!!というか、なんでわざわざこんなにリンク張る必要があるわけ!?
 リンクはWindowsで言うところのショートカットにあたります。
 ですが・・・なんでこんなにリンクを張ってるのか、全く謎でした。今まで。

 しかもですね。/lib, /usr/lib, /usr/local/lib と分散してしまっている・・・。
 Windows と共有ライブラリの配置に対する哲学がまるで異なっています。

 Windows ではDLLは大抵 C:\WINDOWS(NT/2000では C:\WINNT)か、アプリケーション固有のディレクトリにまとめられます。
 ところが Linux/UNIX ではアプリ固有だろうと何だろうと見境なしに /lib, /usr/lib ディレクトリにつっこまれてる ので、分散してしまって分かりづらかったんです。

 いえ、分かりづらかったわけではありません。選択肢は /lib, /usr/lib, /usr/local/lib の三つしか無いわけですから。
 どちらかというと

居こごちが悪かった。
 というわけです。全てが「何となく想像はつくんだけど・・・でも何でこうなってんの?」という疑問で埋め尽くされているわけです。
 そんなわけで、JFのドキュメントに出会った今日までずっともやもやした不安というか気持ち悪さが Linux/UNIX の共有ライブラリにはあったわけです。

つまり Linux/UNIX の哲学に慣れていなかった。
 慣れた者がちです、この世界。一旦慣れれば(自転車を初めて一人で乗れるようになった子供のように)応用や新しい方向へのチャレンジへの道が開けますし、少なくとも目の前の靄の一つくらいは吹き飛ばせるはずです。

 というわけで、そろそろ「だーかーら、ライブラリってなんなんだよ!!!」と喚きたくなった頃合いでしょうか。では。例え話を用いてライブラリの本質を語らせていただきます。

例え話も程々に。
「本題」に戻る

 私は今大変狂喜しています。というのは、私自身今まであやふやだった「ライブラリ」「共有ライブラリ」を相当日常生活に例えた形で解説できる機会に出会えたからです。多くのユーザーが心の隅で抱いて居るであろう、この謎についてなぜ今までこれほどわかりやすい例えが用いられなかったのか不思議に思う(以下めんどいので削除)

 ライブラリを語る前に、まずそもそもみなさんが日常使っている「アプリケーションソフト」とは何なのかの説明から始めましょう。

 アプリケーションソフト、サーバー、デーモン・・・。色々呼び名はありますが、一般にソフトウェア本体とされているファイルが Windowsにも、Linux/UNIX にも存在します。
 よーするにWindowsではアイコンをダブルクリックするとアプリケーションが起動するファイルで拡張子が「EXE」のやつ。
 Linux/UNIXの場合はシェルから直接打ち込むことにより何らかのソフトが起動するファイルです。

 これらは「実行形式のファイル」とも呼ばれています。
 ぶっちゃけた話、パソコンのCPUが理解できる言語で書かれた処理手順書です。
 そのアプリケーションが何をどうするか。それを記述した手順書が実行形式ファイルです。
 CPUつまり中央処理装置は全てを数値で処理します。それを直接人間が書こうとするにはとてつもない知識と技量が必要になります(まれにそれをやってのけてしまう人種も居ます。OSの開発者達です)。

 とにかく、CPUにだけ分かる言語で「最初にあーしろ、次どーしろ、もしユーザーがこのボタンクリックしたらこーしろ・・・」といった処理手順が書き連なったファイルが「実行形式のファイル」と呼ばれるものです。

 これは料理で言えば一種のレシビ、職人さんなら一種の設計図にあたります。

 で、こっからが話の本題です。
 もっともわかりやすいレシピ(または設計図)は一つのレシピ(または設計図)に、必要な処理手順が逐一書かれている 状態でしょう。そのレシピさえ見れば、包丁の使い方からジャガイモの皮の向き方、おまけに食器の後かたづけ方法まで全て載っているわけです。
 ところが、全てのレシピに対していちいちそこまで記述するのは(もしそのレシピが紙で出来ているなら)紙の無駄遣いですし、何よりも慣れてくると鬱陶しくなります。
 そこで、包丁の握り方やキャベツの千切り方法など、殆どのレシピでおよそ共通している部分を抜き出します。

 この抜き取った共通部分のレシピこそが、ライブラリにあたります。

 ただし・・・もとのレシピに、「ここは他のレシピでも共通に使われてる部分だから切り抜いたよ。」という印が無かったらどうなるでしょうか。たとえば「三枚おろし」に関する部分が切り抜かれている状態で、「ここで三枚おろしにします。」などという記述がレシピに出てきたらどうなるでしょう。

 人間なら「どっかに書かれてなかったかな」と他のレシピをめくりますが、CPUはそう言った自分で何か考える能力は文句無くゼロです(仮にあるように見えても、それはレシピにそう振る舞うように指示が書かれていたからです)。
 というわけで、もし切り抜かれた共通部分(ライブラリ)が見つからないとCPUは「そんなこと知りませんよ。」とエラーを発生してくれます。
 今回の例なら「三枚おろし?どうやるの、それ。」と自分で調べもせずに聞いてくる、あまつさえ多くの場合、そのままやる気を無くしてレシピの料理を作ろうとするのを止めてしまいます。

 このようなとき、正しく「三枚おろしってのはこうするんだよ。」と教える方法はざっと3通りあります。

1.人間側で予め、レシピに「三枚おろし」の部分を糊とかで貼り付けて剥がれないように一体化してから CPUにレシピを渡す。

2.レシピに、「三枚おろしについて知りたければどこそこの本棚のこういうファイルに載っている」と、本体のレシピの冒頭部分に付け足してからCPUに渡す。

3.「三枚おろし」の記述が現れる時点でようやく「ここの本棚のこういうファイルに載っている」という記述を付け足してからCPUに渡す。


 特に2.と3.の違いについて注意して下さい。2.では予め共通部分のレシピの存在箇所を冒頭で、まとめて書き付けておきます。3.では、共通部分を使う段になって初めてその共通部分の存在箇所を教えています。

 実際にはこんな風なレシピを渡すことになります。
1. 2. 3.
材料:サンマ一匹
手順1:包丁を握ります。
・・・
手順2:サンマを三枚おろしにします。
魚をのせ、包丁を尻尾の方から...
...
...
手順3:...
・包丁の握り方についてはこういう名前のファイルに書き付けときました。
・三枚おろしの方法についてはこんな名前のファイルに書き付けときました。
材料:サンマ一匹
手順1:包丁を握ります。
手順2:サンマを三枚おろしにします。
手順3:...
材料:サンマ一匹
手順1:包丁を握ります。 ・包丁の握り方についてはこの名前のファイル名に。
・また、包丁が果物包丁しか無い場合はこちらの名前のファイルに書き付けてあります。
手順2:サンマを三枚おろしにします。
・三枚おろしの方法についてはこんな名前のファイルを参照。
手順3:...



 まあ、こんな感じです。特に3.で、そのときの条件によって参照先を変えている事に注目して下さい。

Linux/UNIX へ。
「本題」に戻る

 まず、1.のレシピについて考えてみましょう。
 一番これが「手抜き」なレシピでもあります。単に共通部分をぺたりと貼り付けただけですから。
 ただ、もしも他のレシピにもこういったことをするとどうなるでしょう。レシピを作る度に共通部分をいちいち貼り付けていく訳ですから、一つ二つのレシピしかCPUに渡さないのであればそうでもないでしょうが、数百のレシピをCPUに渡す事になると、重複部分の無駄は無視できなくなってきます。
 他にもその三枚おろしの方法は自分の家では出来るやり方であっても(包丁の種類や職人の腕前など)、別の家に持っていっても出来るとは限りません。

 そこで2.の出番です。共通部分を書き付けたファイル名を予め冒頭でリストしておきます。CPUは三枚おろしと出てきたら冒頭のリストを参照し、どのファイルに書かれているか(ようやく自分で)調べに行きます(実はこれとて、とある共通部分にそうしなさいと書かれているから)。
 こうすれば1.で起こり得た重複部分の無駄は激減します。また、共通部分を書き付けたファイル名は一般にどの家でも一緒(大抵の料理集にはそのままの名前で目次に載っている)です。そして、家毎に共通部分はカスタマイズしてある(はず)ので2.のレシピを違う家のCPUに頼んでも、CPUはその家に応じた共通部分をとってきてくれるのでエラーになりません。
 デメリットとしては、共通部分に依存するレシピが多くなってしまい逆に共通部分を管理する負担が増えてくることです。
 またレシピの共通部分に依存する率が高くなるので、ちょっとした家の違いでも「この共通部分が無い」といった現象が発生しやすくなります。
 それでも、家を管理している人たちがよく使われる共通部分をそれぞれしっかり管理していれば、よほどカスタマイズされたレシピを渡さない限り、大抵は問題なく料理してくれます。

 3.は、その場その場の条件によって、共通部分の参照先を変更できるメリットがあります。
 たとえば、包丁の握り方一つとっても和包丁、ナイフ、果物包丁、中華包丁・・・とあるわけです。
 そのときそのときの条件によって、「今日は和包丁」「昨日はナイフ」と柔軟に切り替えられます。つまり、問題へのアプローチ方法がリアルタイムで複数存在するときに威力を発揮します。これこそがブラウザなどでお世話になるプラグイン の正体です。
 今回の例ではちょっと分かりづらいかもしれません。というのも、包丁の種類は家の違いと考えてしまえば別段、2.の方式をとっても問題ないからです。
 非現実的ですが、マグロが材料に渡されてきたとしましょう。そうなってくると2.では対処が難しくなります。

 本マグロを捌くのは並大抵の技量では出来ません。とにかく、包丁からして普通のものでは無理です。
 しかし、家と家の間で互換性を維持するためには、「包丁が無い」からといって終わりにするのはよくありません。
 むしろこの場合、「包丁はどうでも良い。むしろ、その場にある包丁でどう捌くか」という捌く手順を複数用意します。

 ・・・よくよく考えるとこれは2.でも出来てしまいます。つまり、今回は「材料として渡された魚に応じて捌き方を変える」 必要があるのです。これは2.では不可能です。2.では予め渡される材料が分かっているか、予測できる場合は有効です。しかし全く未知の場合はいったいいくつの「**魚の捌き方」共通部分を冒頭に書き付けておく必要があるのでしょうか。
 こういうときこそ、3.の出番になります。こうすれば万事解決です。

・包丁の握り方は「houtyou_nigirikata.dll」ファイルに書き付けてあります。
材料:とりあえず魚一匹。
手順1:包丁を握ります。
手順2:魚を三枚おろしにします。
    もしも魚がサンマだった場合は「sabakikata_sannma.dll」ファイルに捌き方が載っています。
    もしも魚が本マグロだった場合は「sabakikata_honnmaguro.dll」ファイルに・・・
    もしも・・・
    というわけでとにかく魚を三枚おろしにします。
手順3:...

 もうちょっと改良を加えましょう。魚の種類と、捌き方を載せた共通部分(dllファイル)を対にした内容のファイルを作っておきます。

ファイル名:「tui_sakana_sabakikata.txt」
サンマ:sabakikata_sannma.dll
本マグロ:sabakikata_honnmaguro.dll
イワシ:sabakikata_iwasi.dll
...

 そして、いざ三枚に下ろすときにこのファイルを参照して、対応するDLLをロードするようにすればいいのです。

(省略)手順2:魚を三枚に下ろします。
    魚の種類と捌き方を載せたファイルの対応表は「tui_sakana_sabakikata.txt」にあります。
    それみて適切な捌き方を調べて下さい。
    というわけでとにかく魚を三枚おろしにします。
手順3:...

 こうすれば新しい魚が入ってきたときでも対応表に、対応するDLLを書き付けるだけで対処できるようになります。
 まさしく「魚の三枚おろし」に関するプラグインシステムを作ってきたわけです。


 以上、1.、2.、3.と全く同じ仕組みが Windows, Linux/UNIX 両OSに備わっています。
 各レシピの共通部分が Windows で言うところの DLLファイル であり、Linux/UNIXでの 共有ライブラリ になることが実感して頂けたでしょうか。

 ・・・Windowsの場合はDLLファイルであるのは周知の通りです。では、肝心のLinux/UNIXではどんなファイル名の命名規則が使われているのか。そして、なぜlib****.so****はあんなにリンクが張ってあり、しかも分散しているのか。
 引き続きこの謎に迫っていきたいと思います。

Linux/UNIX 特有のお約束。
「本題」に戻る

 ここでは、主に「命名規則」と「配置場所」に絞ってお話しします。
 まずは命名規則からです。

 共有ライブラリのファイル名は次の形式に従ってリンクファイルを含めて作成する必要があります。
 下に示す例の「****」の部分はそのライブラリを表す文字列が入ります。たとえばlibpam.soはPAMを実装するためのライブラリです。

ファイル名の形式自体の名前 ファイル名の形式 例 リンク先
real name lib****.so.(メジャー番号).(マイナー番号群) libhogehoge.so.2.0.1.2 (共有ライブラリ本体なのでリンク先は無し)
soname lib****.so.(メジャー番号) libhogehoge.so.2 libhogehoge.so.2.0.1.2
linker name lib****.so libhogehoge.so libhogehoge.so.2


 ・・・何でこんな事になっちゃったんでしょう。その原因は、Linux/UNIXの実行ファイル形式にあります。

 先ほどの例えで、「(ようやく自分で)調べに行きます(実はこれとて、とある共通部分にそうしなさいと書かれているから)」とあった部分を思い出して下さい。この「とある共通部分」が「プログラムローダー」や「リンカローダー」と呼ばれる部分です。
 このプログラムローダー(ld-linux.so)は前述の命名規則に従っていない、超特別な共通部分です。

 先ほどの例えで言うと、まさに「人間の読めるレシピからCPUの読めるレシピに変換する」ときデフォルトで冒頭に宣言される共通部分です。これがないと、他の共通部分をCPUが読み込めないほどの重要な部分です。

 で、上に挙げた命名規則やリンク生成はこのプログラムローダーの仕様に基づきます。

 さて。人間の読めるレシピからCPUの読めるレシピに変換する(以降、この動作を「コンパイルする」と言います)時、使用する共有ライブラリ名を「-l****」(上の例なら -lhogehoge)とする事がプログラムローダーの仕様になっています。
 ****はすなわち、linker nameのlib****.soに該当します(メジャー番号を無視してますし)。するとリンク先のsonameがプログラムの内部で使われるようにな(るらしい)ります。

 んで。この段階ではライブラリの「ファイル名」は判明しても「ディレクトリ」が分かりません。実はLinux/UNIXには「/sbin/ ldconfig」というコマンドがあります。このコマンドが(設定ファイルに登録済みの)ディレクトリを検索し、ライブラリの「ファイル名」とそのディレクトリ位置を目録化してくれます。この目録は/etc/ld.so.cacheファイルに格納されます。
 で、この目録の作成に使われる「ファイル名」が soname なわけです。んで、プログラムからプログラムローダ、そしてファイルシステム上のリンクをたどってようやく realname に至るわけです。

 とにかく、プログラムローダーとldconfigの仕様によって2種類のリンクを作成する必要があったわけです。

 次に配置場所について解説します。今までの説明ですと、プログラム内部で共有ライブラリを指定するときはsonameを使います。が、これだけですと「どのディレクトリにあるのか」が分かりません。そのために、sonameを検索するときのインデックスとして/etc/ld.so.cacheがあり、そのインデックスを更新するのが/sbin/ldconfigでした。
 で。実際にldconfigはどのディレクトリを検索してインデックスを作成しているのか。検索するディレクトリをリストしたのが 「/etc/ld.so.conf」ファイルです。これは単純なテキストファイルです。私の(TLXW8)を載っけます。

[fenjin@seisyuu fenjin]$ cat /etc/ld.so.conf
/usr/X11R6/lib
/usr/lib/gconv
/usr/lib/qt/lib
/usr/local/lib
/usr/i386-linuxaout/lib
/usr/lib/libc5-compat
/usr/lib/sane
/usr/lib/Omni
[fenjin@seisyuu fenjin]$


 ・・・「/lib」や「/usr/lib」はどこ行ったのでしょう。実はこの二つのディレクトリはldconfigがデフォルトで必ずチェックするディレクトリです。そのため、わざわざ/etc/ld.so.confに記述する必要がない訳です。
 /usr/local/libもしっかり指定されています。実は、/usr/local/libはldconfigのデフォルトではありません(RHL6.2以降)。そのためわざわざld.so.confに記述する必要があったわけです。

 結局、パターンさえ掴めてしまえばWindowsと同じか、それ以上にきめ細かくライブラリを管理できるというへんてこな具合になってしまいます。
 なぜならライブラリの指定に用いているのはsonameですが、これはrealnameへのシンボリックリンクです。
 ということは、もしライブラリがバージョンアップされたときなどは、古いライブラリを上書きせずにリンクだけ変更することによって、万が一に備えたライブラリのバージョンアップが出来るわけです。

 そして、ライブラリのインストール先は「/lib」「/usr/lib」、そして/etc/ld.so.confに記述されているディレクトリ内であることも確実です(本当はLD_LIBRARY_PATH環境変数でローカルに変更もできるのですが)。

 まあこんな感じで、Linux/UNIXの共有ライブラリの仕組みは成り立っています。

目次に戻る

後書き或いは感想
 最後に、C言語における厳密な意味でのライブラリと共有ライブラリの違いについて言及しておきます。
 C言語ではコンパイルするときに一緒に抱き合わせるのがライブラリです。つまり、魚の三枚おろしで言う1.のパターンの時用いている共通部分を「ライブラリ」といいます。拡張子が「.a」になっていることが大きな特徴です(Windowsでは「.lib」になっている場合が多い)。
 Linux/UNIX, Windowsで「共有ライブラリ」と言う場合、それは「.a」ファイルではありません。
 というのは、.aファイルはその他のメインプログラムに抱き合わされる事が予想されているため、.a自身が使用している共通部分(printfとか)は.aには含めないようになっています。抱き合わせ先のメインプログラム側で一緒にしてくれる事を予想されているからです。
 ところが共有ライブラリは、それ自体で完結するようになっています。共通部分としてのライブラリも(あたかもメインプログラムと同等の存在であるかのように)きちんとリンクされて、lib****.so****が生成されるわけです(Windowsなら*.dll)。
 厳密な定義を追いかけるとこういった違いも出てきます。まあ、非プログラマの人たちにはおよそ関係ない話です。


 もしあなたがC/C++のプログラマ(学習者)で、共有ライブラリの実際のソースコードで実験したければ、本ページの前書きで載せてあるJFドキュメントを参照すると良いでしょう。ここではプログラミングには一切立ち入らず話をしたため、物足りない向きは当然あったと思われます。
 どちらにせよ、このページがあなたのLinux/UNIXのライブラリに対する漠とした不安感を幾分でも軽減できれば大変うれしいです。

id:DQNEO

すいませんコピペしなくてもURLだけはっていただければ大丈夫です。

2012/10/20 01:39:34
id:a-kuma3 No.4

a-kuma3回答回数4545ベストアンサー獲得回数18952012/10/17 23:21:30ここでベストアンサー

ポイント50pt

ldd や ldconfig コマンドが出てきている時点で、ほぼ理解できてるんじゃないかと思います。
DQNEO さんは、開発者目線というか、プログラムをいじれる側の立場ですよね。
共有オブジェクト (Shared Object) とか、動的リンケージ (Dynamic Linkage) という概念については、問題無いのだと思います。
その上で、ポイントになるとしたら、以下の二つ。

  • 動的リンケージと言いながら、実行形式を作る際にも .so を解決できてないと、リンクに失敗する(不思議に思うのは、ぼくだけ?)
  • .so を探す順番があり、リンカのオプションによって、微妙に違ってくる

これが分かっていれば、「○○って、シンボルが見つからねーじゃん」って、(コンパイルではなく)リンクの時点でエラーが出たときに、○○というシンボル(関数、もしくは変数)が含まれているライブラリは何だろう、って調べるだけです。

まずは、導入したいプログラムのドキュメントをあたって、依存しているライブラリは何だろう、ってことを調べるのが第一だとは思いますが、ドキュメントをあさるのが面倒なら、configure で生成された Makefile を見て、-l を探すのがてっとり早いかも。
-l○○○ というオプションがあれば、lib○○○.a か lib○○○.so がリンカが解釈できるところにあるはずで、ライブラリのバージョンを吸収する意味で、lib○○○.so が lib○○○.so.××× へのシンボリックリンクになっている、というだけです。
実際には、ライブラリのバージョンとかもあるでしょうから、ドキュメントに戻る、ということになるのかもしれませんが。


知っていることかもしれませんが、ローダーの動作については、以下の man だけで、用をなすと思います。
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man8/ld.so.8.html

ぼくみたいな、古い人間だと LD_LIBRARY_PATH 辺りまでの理解で止まっちゃうところですが、linux だと、それに加えて ld.so.conf が入ってくるだけで、大筋は変わりません。


妙にマイナー(世の移り変わりを含む)なライブラリを使われているときに、どのライブラリに含まれてるんだっけか、ということで苦労することがある、ということには、激しく同意します。

他1件のコメントを見る
id:a-kuma3

ldd や ldconfig コマンドをよくわからずに「おそるおそる」叩いてる感じなので、この「おそるおそる感」を克服したいのです。

少なくとも、ldd コマンドは、情報を表示しているだけなので、バンバン叩いちゃってください。

2012/10/20 02:14:32
id:DQNEO

はい!

2012/10/24 23:14:35

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません