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

ビルド職人になるために覚えたコマンドメモ

ここ2年ぐらいffmpegとかopencvとかRuby + CUDAみたいなやつとか たまーにビルド職人になることがあって上手くコンパイルするために各種コマンドを使うことがあるのだけど、 使い方はおろか、普段あんまり使わないのでコマンド名すら忘れることが多々あるためコマンド名とか使い時を覚えている限りざっくりメモしとく。 あとはmanを読めば良い。

pkg-config

インストール済みのライブラリをコンパイルに利用するときに必要なコンパイルオプションを返してくれるやつ .pcファイルを元に返してくれる。 PKG_CONFIG_PATHを指定して利用したりする。

ldd

.so(Shared Object)ファイルが動的リンクで依存しているライブラリへの依存関係を表示してくれる。 何かをコンパイルした結果、共有ライブラリがリンクできているかを調べるのに使える。

$ ldd `which ffmpeg`
        linux-vdso.so.1 =>  (0x00007ffeaa3c0000)
        libavdevice.so.56 => /usr/local/lib/libavdevice.so.56 (0x00007fda9b4f4000)
        libavfilter.so.5 => /usr/local/lib/libavfilter.so.5 (0x00007fda9b1c5000)
        libavformat.so.56 => /usr/local/lib/libavformat.so.56 (0x00007fda9ae0a000)
        libavcodec.so.56 => /usr/local/lib/libavcodec.so.56 (0x00007fda996e2000)
        libpostproc.so.53 => /usr/local/lib/libpostproc.so.53 (0x00007fda994c4000)
        libswresample.so.1 => /usr/local/lib/libswresample.so.1 (0x00007fda992ac000)
        libswscale.so.3 => /usr/local/lib/libswscale.so.3 (0x00007fda99037000)
        libavutil.so.54 => /usr/local/lib/libavutil.so.54 (0x00007fda98ddc000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fda98bbf000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fda988bd000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fda984fb000)
        libz.so.1 => /lib64/libz.so.1 (0x00007fda982e4000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fda980e0000)
        liblzma.so.5 => /usr/lib64/liblzma.so.5 (0x00007fda97ebc000)
        /lib64/ld-linux-x86-64.so.2 (0x0000557f457af000)

ldconfig

ldがリンクするときに共有ライブラリ探すための情報をキャッシュするために使用する。 共有ライブラリをインストールした直後に期待通りに動かなかったら叩いてみたりする。 -pでキャッシュ済みのライブラリのリストを見られるのでリンク失敗するときにみる。

nm

.soとか.oとか実行バイナリとかのシンボル一覧を見るのに使う。 シンボル一覧見つつリンクがうまくいっているかどうか見る。 リンクが失敗してundefined symbolみたいなエラー出たときに何が足りないのか見極めるときに使う。

適当な間違ったコードを書いたときにprtfなんていう存在しない関数でオブジェクトファイルを作ったときに、 nmコマンドの表示結果がprtfに対してUとなっているときはこの時点ではprtfが実際には未定義状態であることを表す。 こういう情報を元にソースコード上にタイポがあってビルドうまくいかないとかそういうのを探した記憶がある。

$ cat a.c
int main () {
  prtf("aaaaaaaaa");
}
$ gcc -c a.c
$ nm a.o
0000000000000000 T main
                 U prtf

nm自体は多分もっといろいろ使えると思う。
nmコマンドでC/C++のシンボルテーブルを見る、C++の名前マングリング、"C"リンケージ、あるいはリンカに関するメモ - 百日半狂乱

objdump

Macでlddしたいときに最初から入ってた気がしたので代わりに利用できる。 実際にはotoolが良いらしい。

rpmbuild

名前の通り、RPMパッケージを作るときに使う。 オプションがややこしいので毎回ググりながら使っていたがモダンな日本語情報を見つけるのが難しいので、 自分が参考にしたページリストを貼る。

cmake

cmakeはmakeで使うMakefileの生成するためのメタなやつで、CMakeLists.txtに生成ロジックが書いてある。 make単体で使うときは再ビルドするときにmake cleanしてたけど、cmake使うときはビルド中のファイルが吐き出されるのは 自分が指定したディレクトリになるのでビルド結果を入れるディレクトリに移動してからコマンドを叩いてディレクトリごと消せば良い。

$ cd /path/to/src_root
$ mkdir build
$ cd build
$ cmake ..
$ make

tar

xxx.tar.gzじゃなくて xxx.tar.bz2 を解凍するときは tar -xvfz みたいな4つ入りオプションじゃなくて、 tar -xf のみで良いとのこと。-zgzip解凍用のオプションとのこと。よく忘れて困るのでメモ。

CUDA, cuDNN, nvcc

NVidiaGPUを使うためのSDK。そこそこ特殊環境なので油断するとハマる。 CUDAを使うときは、とにかく公式の手順通りにインストールすると入る。 各OSごとにインストール用のパッケージが用意されている。(ディープラーニング用のcuDNNは、NVidiaのサイトにアカウント登録しないとダウンロードできないので注意。) docs.nvidia.com

/usr/local/cuda-8.0/lib64以下に共有ライブラリが配置されたりして標準のパスだけではビルド通らないので注意。 -I-Lでパスを追加してコンパイルする。.cuファイルをビルドするときはg++とかの代わりにnvccを利用する。

mkmf

library mkmf (Ruby 2.4.0)

コマンドではないけどRubyのC拡張作る時に使う標準ライブラリ。 いわゆるextconf.rb。ext/以下にdependファイルをおくとextconf.rbで生成するMakefileの末尾にそのdependファイルが追記されるのでそこを駆使すると便利。 ruby ext/hoge/extconf.rbで実際にMakefileを生成してみてデバッグもできる。

他に便利なのあれば教えてください。