読者です 読者をやめる 読者になる 読者になる

tak0kadaの何でもノート

発声練習、生存確認用。

医学関連は 医学ノート

ライブラリのビルド時の依存関係の解決

拾い物のアプリケーションをコンパイルしようとして依存関係を解決できない時のメモ。

1. 依存しているライブラリを列挙する

  • ドキュメントにある場合はそれを見る
  • include宣言だけ見ておけば良いのではないかと思ったので、拾ってきたファイルの一番上の階層でgrep -r "#include <" | cat > dependencies.txtする。
  • できたファイルから重複を除く
#python
include_libs = []

with open( "./dependencies.txt", "r" ) as f:
    for line in f:
        lib = line.split(' ')[1].rstrip('\n')[1:-1]
        include_libs.append(lib)

include_libs = list(set(include_libs))
include_libs.sort()

with open("./dependencies2.txt", "w") as f:
    for i in include_libs:
        f.write(i + "\n")
  • 上の手順は多分コマンド一発でできるはずだが...
  • 標準ライブラリ以外はインストールが必要なライブラリ由来のヘッダファイル

2. 必要なパッケージのインストール

  • apt-file search hoge.hして必要なものを探す。hoge-devみたいなものが使えることが多い
    • ある場合: aptを使ってレポジトリからインストールする
    • ない場合: ソースコードからインストールする。インストールする依存ライブラリの依存関係を調べるため1に戻る
  • 参考サイト

3. コンパイル

  • パスの指定

    • ヘッダは普通/usr/include/usr/local/includeにある → -Iオプションに渡す
    • ライブラリは普通/usr/lib/usr/local/libにある → -Lオプションに渡す
    • .soファイルはapt-file list LIBRARY_NAMEを実行して探す。それでダメなら諦めて元のレポジトリMakefileを読む(.hと.a、.soは同名とは限らない)
  • 参考

    • 静的ライブラリはlibxxxx.a
    • 動的ライブラリはlibxxxx.so
      • API design for C++によれば、動的ライブラリは依存関係の依存関係も含めて配布する必要がある
        • /usr/libの.soファイルにlddコマンドを使えばたくさん見つかる
      • 実際にはOSが管理してくれる便利な方法がある(参考サイト1参考サイト2(1を眺めてから読むと分かりやすい)、参考サイト3)
        • linuxではld.soリンカ、ローダというものが/lib、/usr/libを検索する
          • ldconfigを使って登録する方法(-nでカレントディレクトリを登録)
            • ubuntuでは/etc/ld.so.conf.d/libc.confに/usr/local/libを登録してあるが、ディストリビューションによっては/usr/local/libは検索されないので先にld.so.confを編集する
          • 環境変数LD_LIBRARY_PATHを用いて、export LD_LIBRARY_PATH=/home/..とする方法(デバッグ向け)
          • -rpath(実行時に検索するディレクトリを指定)、-rpath-link(ビルド時に検索するディレクトリを指定)を用いる方法
    • libhoge.hppなら-lhogeとする
  • pkg-config、.acファイルがあるならpkg-configメモ - tak0kadaの何でもノートを利用することもできる

  • libtoolを使えば簡単になりそう
# 静的ライブラリのコンパイル
g++ -c hoge.cpp
ar -crs libhoge.a hoge.o

# 動的ライブラリのコンパイル(.oファイルを残す)
g++ -c -fPIC hoge.cpp
g++ -shared -o libhoge.so -fPIC hoge.o
# .oファイルを残さない
g++ -shared -fPIC -o libhoge.so hoge.cpp

# 複数ファイルのコンパイル(main -> foo -> bar)
g++ -Wl,-no-as-needed -L. -lfoo -lbar main.cpp
g++ -L. main.cpp -lfoo -lbar

# 依存関係を考慮してコンパイル(mainのコンパイルの時にfooしかリンクしなくていい)
# -Wl,optionでオプションをリンカに渡す
g++ -shared -fPIC -o libbar.so bar.cpp
g++ -shared -fPIC -Wl,-no-as-needed -L. -lbar -o libfoo.so foo.cpp
g++ -Wl,-no-as-needed -Wl,-rpath,$PWD -Wl,-rpath-link,$PWD -L. -lfoo main.cpp

# 動的ライブラリのバージョンも管理したい場合
# sonameが実際のリンクに使われる
g++ -shared -fPIC -Wl,-soname=libbar.so bar.cpp -o libbar.so.1.0
  • 上のコマンド例はコンパイル時に依存ファイルを参照する様子を表している。-rpath-link以外は実行時のためにldconfigなどを実行しておく必要がある。
  • 参考サイト
  • これ以上ややこしくなったら間違いを防ぐために項目4に進む

4. ビルドの自動化

  • TODO

4.1 make

hoge: hoge.o
  g++

4.2 cmake

  • その他automake、autoconfというものがあるらしい
  • ビルドを自動化するツールは山ほどあるらしい