macOS sonomaのSIPのバグとgolang test実行トラブル - foolmacky/DevelopDocs GitHub Wiki

■ macOSをsonomaにアップしたところ、go testでloaderがエラーをリターンするようになった

dyld[6098]: Library not loaded: @rpath/libclntsh.dylib.19.1

 Reason: no LC_RPATH's found
  • Oracleのクライアントライブラリをロードするときに失敗しているが、ライブラリ自体はlinkとして/usr/local/lib以下に配置されている
  • dyldはデフォルトで特に指定無くても、この場所を参照するはずで、わざわざバイナリにLC_RPATHを設定したりはしていない
  • go testでコンパイルされる実行ファイルは/private/var/folders/zs/*/T/go-build*/b001/<package名>.test として一時的に生成されるので、無理やりコピーして中を見てみる
otool -l hogehoge | less
Load command 12
          cmd LC_LOAD_DYLIB
      cmdsize 56
         name @rpath/libclntsh.dylib.19.1 (offset24)
   time stamp 2 Thu Jan 1 09:00:02 1970
      current version 0.0.0
compatibility version 0.0.0
//当然ながらLC_PATHは設定されていない
       DYLD_FALLBACK_LIBRARY_PATH
              This is a colon separated list of directories that contain libraries.  If a dylib is not found at its install  path, dyld
              uses this as a list of directories to search for the dylib.  By default, it is set to /usr/local/lib:/usr/lib.
  • このテスト用バイナリを直接実行すると、やはりgo testで実行したときと同じエラーが出てしまうが、環境変数としてDYLD_LIBRARY_PATHを設定すると実行できる
export DYLD_LIBRARY_PATH=/Library/Oracle/instantclient_19_8
//envコマンドではこのexportは表示されない
  • go testで実行する場合は、あくまでgoの環境で実行されているので、あらかじめこの環境変数を設定していても、効果はない

■ 回避方法

  • go testのオプションでバイナリの実行環境にDYLD_LIBRARY_PATHを設定する
  • 設定するパスはもちろん/usr/local/libでもOK(変だけど)
go test -v -race -failfast -count=1 -exec "env DYLD_LIBRARY_PATH=/Library/Oracle/instantclient_19_8" .
  • またはgo testのCGOコンパイル環境に環境変数をセットして、バイナリにLC_RPATHエントリを埋め込む
CGO_LDFLAGS='-Wl,-rpath,/Library/Oracle/instantclient_19_8' go test -v -race -failfast -count=1 .
  • もしくはgoの環境変数としして、この値を設定してしまう
//go envで環境設定を参照、変更できる
go env
CGO_LDFLAGS='-02 -g -Wl,-rpath,/usr/local/lib'
  • でも、この実行方法だと、cgoが呼ばれるたび(LC_LOAD_DYLIBがcallされるたび?)にエントリが追加されて、LC_RPATHがダブって設定されるので、実行時にそのwarnが出る
ld: warning: duplicate -rpath '/Library/Oracle/instantclient_19_8' ignored
  • バイナリを覗いてみるとたしかに同じエントリが複数設定されている。なんだかなー
Load command 17
          cmd LC_RPATH
      cmdsize 48
         path /Library/Oracle/instantclient_19_8 (offset 12)
Load command 18
          cmd LC_RPATH
      cmdsize 48
         path /Library/Oracle/instantclient_19_8 (offset 12)

■ 原因は何だ?

NAME
       dyld - the dynamic linker

SYNOPSIS
       DYLD_FRAMEWORK_PATH
       DYLD_FALLBACK_FRAMEWORK_PATH
       DYLD_VERSIONED_FRAMEWORK_PATH
       DYLD_LIBRARY_PATH
       DYLD_FALLBACK_LIBRARY_PATH
         (省略)

DESCRIPTION
       The dynamic linker (dyld) checks the following environment variables during the launch of each process.
       Note: If System Integrity Protection is enabled, these environment variables are ignored when executing binaries protected by
       System Integrity Protection.
  • golangを最新にしても状況は変わらない。またLinuxではこの現象は起きていない。macOS固有の問題なのでは?
⚠️ **GitHub.com Fallback** ⚠️