mattintosh note

どこかのエンジニアモドキの備忘録

MacPorts の GCC にはバグがある(気がする)

最近の MacPortsGCC はなんだか怪しく感じる。最近のバージョンでは /opt/local/lib/libstdc++.6.dylib が依存関係に追加されるようになったらしい。チケットを見てみるとなんだかごたごたしているような雰囲気ではあるが英語なのでよくわからない。

Mac OS X 10.6 で g++-mp-4.7 -arch x86_64 なんてやるとコンパイルは通るものの、実行時に /usr/lib/libSystem.B.dylib/usr/lib/libstdc++.6.dylib を呼び出すためクラッシュしてしまう。これを回避するために色々試行錯誤しているんだけどなかなかうまくいかない。

一番簡単なのは DYLD_LIBRARY_PATH=/opt/local/lib/gcc47 と指定すること。こうすればとりあえず /usr/lib/libstdc++.6.dylib を読まなくなる。ただし実行ファイルから直接起動ができないので事前に DYLD_LIBRARY_PATH を設定しなくてはいけない。

$ DYLD_LIBRARY_PATH=/opt/local/lib/gcc47 ./application

次に簡単なのはコンパイル時に /usr/lib/libstdc++.6.dylib を最優先でリンクしてしまうこと。これは LDFLAGS=/usr/lib/libstdc++.6.dylib のようにフルパスで直接指定すればいい(-L とか lstdc++ とかは要らない)。こうすれば /opt/local/lib/libstdc++.6.dylib が後から読み込まれて上書きしてくれる。otool で見た時に一番上に出てるのがなんだか微妙だけど。

$ cmake -DCMAKE_EXE_LINKER_FLAGS="/usr/lib/libstdc++.6.dylib" ..

最後に DYLD_INSERT_LIBRARIES を使う方法。これは LD_PRELOAD の Mac 版かな?実行ファイルを起動するときに最初に読み込むライブラリを指定できる。ただし、普通にコンパイルした場合は DYLD_FORCE_FLAT_NAMESPACE=1 も一緒に指定する必要がある。これがちょっと面倒だけど、コンパイラフラグに -flat_namespace をつけてコンパイルしてあげると設定しなくてもいい。DYLD_LIBRARY_PATH だとディレクトリまるごとになってしまうけどこれは単体で指定できるので使い易い。

ビルド時

$ cmake -DCMAKE_EXE_LINKER_FLAGS="-Wl,-flat_namespace" ..

起動時

$ DYLD_INSERT_LIBRARIES=/usr/lib/libstdc++.6.dylib ./application

自分が使っているのが MacBook Air3,1 Snow Leopard なので CPU は x86_64 なのに uname とかが i386 だったり困惑する。arch とかの結果を永続的に書き換える方法ってないんだろうか?

自分でビルドした LLVM/CLANG-3.3 は /usr/lib/libstdc++.6.dylib を使っているのでこの作業は必要ないけど、まだ対応していないものが多いので GCC を使うしかない。時間があるときに自分でビルドしよう。依存関係多くて面倒だけど。


man ld を色々読んで見て、オプションに -weak-library なんてのがあったので設定してみたらライブラリをフルパスで指定したときと同じように一番最初に読み込むようにリンクしてくれるようになった。

(最近 tcsh にしました)

setenv CC       "/opt/local/bin/gcc-mp-4.7"
setenv CXX      "/opt/local/bin/g++-mp-4.7"
setenv LDFLAGS  "-flat_namespace -pie -Wl,-lazy_library,/usr/lib/libstdc++.6.dylib"

/usr/lib/libstdc++.6.dylib は後から /opt/local/lib/libstdc++.6.dylib で上書きされる。

/usr/local/src/rawtherapee/RELWITHDEBINFO/rawtherapee:
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)

	(中略)

	/opt/local/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.17.0)
	/opt/local/lib/gcc47/libgomp.1.dylib (compatibility version 2.0.0, current version 2.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)
	/opt/local/lib/gcc47/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)

otool -l -v で確認してみると -weak-library で指定すると LC_LOAD_DYLIB ではなく LC_LOAD_WEAK_DYLIB として設定されている。

Load command 11
          cmd LC_LOAD_WEAK_DYLIB
      cmdsize 56
         name /usr/lib/libstdc++.6.dylib (offset 24)
   time stamp 2 Thu Jan  1 09:00:02 1970
      current version 7.9.0
compatibility version 7.0.0

(中略)

Load command 54
          cmd LC_LOAD_DYLIB
      cmdsize 64
         name /opt/local/lib/libstdc++.6.dylib (offset 24)
   time stamp 2 Thu Jan  1 09:00:02 1970
      current version 7.17.0
compatibility version 7.0.0

ウィークリンクについてまだ勉強不足でどのような結果になるかはわからないけどとりあえず今回はここまで。