Homebrew 2.0.0でLinuxbrewが統合され、Homebrew-fileもLinuxに対応させたので Linuxでの環境作りにもHomebrewを使い始めましたが、 エラーが出てしまっていてなんとなく無理やり対処していた部分がありました。 ライブラリ関連のエラーですが、 悪さをしていたのはglibcパッケージでした。
起こっていた問題
適当に必要なパッケージをインストール後、LD_LIBRARY_PATHに
$HOME/.linuxbrew/libを加えると
$ ls
ls: 0s": ELF: x: Error 1325453653
といた様に、基本的なコマンド(ls、grep、catなど)
がエラーを起こしてまともに作業できない状態になってしまいました。
また、goをインストールしたところ、
$ go
go: relocation error: /usr/lib64/libc.so.6: symbol _dl_starting_up, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference
と言ったエラーが起こりました。
ここで
$ export LD_LIBRARY_PATH=$HOME/.linuxbrew/lib:$LD_LIBRARY_PATH
とするとgoは使えるようになるのですが上のエラーが出るのでどうしようもなくなった、という問題。
その後、いろいろパッケージのインストールやアンインストールや
Homebrewの再インストールなどをしてなんとなく使えるような状態に出来てしまったのですが、
brew upgradeしたところまたrelocation errorがgo関連で出るようになってしまったので
再度調べてみました。
原因
原因はglibcパッケージがインストールされていることでした。
このパッケージはgccの依存パッケージとしてインストールされていました。
gcc自体はbrew deps --tree --installedとかで確認すると
どれにも依存されてないように見えたのですが、
どうやらインストール先を/home/linuxbrew/.linuxbrewではなく、$HOME/.linuxbrewにしているため、
いくつかのパッケージがbottleからではなくソースからコンパイルしてインストールされるようになっていて、
これをインストールする際にgccがインストールされるようです。
今回のupgradeに関してもアップグレードされたのはtmuxでtmuxはgccに依存していませんが
ソースからびるどされるため、この際にgccをインストール、そしてその依存先のglibcもインストールしていました。
上でいろいろやったら使えるようになったと書いてますが、
gccやglibcに関して問題があるのはなんとなくわかっていて
これらをアンインストールしたら使えるようになっていた、という状態だったようで、
再度アップグレードに際してglibcがインストールされ問題が再発するようになってしまったようです。
もうちょっと詳しく見てみると、
$HOME/.linuxbrew/lib/ld.so
のリンクがが問題のもとになっています。
このld.soはglibcをインストールすると、その中の
$HOME/.linuxbrew/Cellar/glibc/2.23/lib/ld-linux-x86-64.so.2へのリンクになります。
一方、glibcが入っていない状態でld.soを必要するパッケージ(tmuxなどソースからコンパイルするもの)をインストールしたり、
gccを--without-glibcでインストールすると
/usr/lib64/ld-linux-x86-64.so.2など、システムのldライブラリに対するリンクとして生成されます。
これ以上詳しくは省きますが
そもそもglibcを複数システムに入れるといろいろ面倒な問題が起こってしまうようで、
この辺の違いが起因で
上のエラーが起こったりします。
linux - Multiple glibc libraries on a single host - Stack Overflow
ちなみに現在、Homebrewでインストールされるglibcは2.23
でテストした環境(CentOS 7.5)では2.17がインストールされていました。
glibcに依存しているgccなどのFormulaでは
depends_on "glibc" => (Formula["glibc"].installed? || OS::Linux::Glibc.system_version < Formula["glibc"].version) ? :recommended : :optional
のような書き方になっていて、システムのglibcがFormulaの定義より新しければ:optionalとなって--with-glibcと
明示しなければglibcはインストールしないようになっています。
逆にシステムのglibcが古い場合は:recommendedになって--without-glibcとしない限りインストールするようになっています。
glibcに依存しているパッケージ
現在のLinux用のFormulaのcore(Homebrew/linuxbrew-core)
の中でglibcに依存しているものは
- clang-format
- gcc
- gcc@5
- gcc@6
- gcc@7
- gcc@8
- llvm
- llvm@4
- llvm@5
- llvm@7
- libgweather
だけで、libgweatherだけが
depends_on "glibc"
と単純なglibc依存をしていて後はすべて上のようなオプションで設定できる仕様になっていました。
(多分libgweatherもそう出来るけど忘れられているだけだと思いますが。)
なのでこれらのパッケージを使うときは以下の解決法などを行うときもちょっと注意が必要です。
特にlibgweatherはこのままではどうしようもないので
別に自分でFormulaを用意するかCoreのものを変更してもらうしか無いです。
(再々libgweatherに依存しているパッケージはCore内にはありません。)
ちなみにLinuxでは
Homebrew/homebrew-core
の代わりに
Homebrew/linuxbrew-core
が使われるのですが、
brew tapしてみるとhomebrew/coreが見えて、実際
$HOME/.linuxbrew/Homebrew/Library/Taps/homebrew/homebrew-core
にlinuxbrew-coreがインストールされている状態でした。
coreはHomebrewが直接Tapするものなので中で名前を合わせるような変換を入れているようです。
(Tapする際にレポジトリ名にhomebrew-という接頭詞がないとTap出来ない仕様ですが、linuxbrew-coreは中で直接特別扱いしているようです。)
解決法
gcc自体は/usr/bin/gccとしてシステム自体にインストールされている環境だったので
gccすらインストールする必要がない状態なのですが、
これに関してはHomebrewの中身に入っていて簡単にオプションで外れるかどうかはわかりませんでした。
(オプションとしてありそうだとは思うのですが調べきれてません。)
一方、gcc自体のオプションを見てみると上にも書いたようにオプションで設定できるようになっていてinfoを見てみると
$ brew info gcc
gcc: stable 5.5.0 (bottled)
GNU compiler collection
https://gcc.gnu.org/
/home/user/.linuxbrew/Cellar/gcc/5.5.0_4 (2 files, 8.1KB)
Built from source
From: https://github.com/Homebrew/linuxbrew-core/blob/master/Formula/gcc.rb
==> Dependencies
Required: zlib (installed), gmp (installed), libmpc (installed), mpfr (installed), [email protected] (installed)
Recommended: glibc (installed)
==> Options
--without-glibc
Build without glibc support
と最後の--without-glibcを使うとglibcなしでインストール出来ます。
ちなみにMac版だと
$ brew info gcc
gcc: stable 8.3.0 (bottled), HEAD
GNU compiler collection
https://gcc.gnu.org/
/usr/local/Cellar/gcc/8.3.0_2 (1,414 files, 288.5MB) *
Poured from bottle on 2019-XX-XX at XX:XX:XX
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/gcc.rb
==> Dependencies
Required: gmp ✔, isl ✔, libmpc ✔, mpfr ✔
==> Options
--HEAD
Install HEAD version
==> Analytics
install: 111,890 (30 days), 290,273 (90 days), 818,489 (365 days)
install_on_request: 52,849 (30 days), 137,514 (90 days), 395,719 (365 days)
build_error: 0 (30 days)
となっていてそもそもいろいろ状態が違います。 そもそもHomebrewではMac用のhomebrew-coreい入っているパッケージのFormualからはオプションが 2.0.0になるにあたりすべて削除されましたが、 linuxbrew-coreにはまだオプションありのものが残っているようです。
ともかく、gccがglibcなしでインストールできるようなので
そうすればよいのですが、これらは
$HOME/.linuxbrewにインストールしようとすると
最初に
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
をした段階でインストールされてしまいます。
(初期インストールでgitなどビルドを必要とするパッケージがあるため。)
なのでこの後にgoなどをインストールすると問題が起こります。
そこで、まず初期インストールを行ったらgcc、glibcを削除してgccを--without-glibcで入れ直します。
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
$ brew uninstall gcc glibc
$ brew cleanup
$ brew install gcc --without-glibc
途中でbrew cleanupをしているのは
glibcをアンインストールした段階で$HOME/.linuxbrew/lib/ld.so
がリンク切れのシンボリックリンクとして残ってしまい、これが原因でbrewコマンドなどで、
/home/user/.linuxbrew/Homebrew/Library/Homebrew/brew.sh: /home/user/.linuxbrew/opt/curl/bin/curl: /home/user/.linuxbrew/lib/ld.so: bad ELF interpreter: No such file or directory
といったようなWarningが出てしまうためです。(これは無視して無理やりgccの再インストールをしても出来ないことはないのですが。)
これでgccの再インストールが出来たら、
$ brew info gcc
gcc: stable 5.5.0 (bottled)
GNU compiler collection
https://gcc.gnu.org/
/home/user/.linuxbrew/Cellar/gcc/5.5.0_4 (1,335 files, 143.4MB) *
Built from source on 2019-XX-XX at XX:XX:XX with: --without-glibc
From: https://github.com/Homebrew/linuxbrew-core/blob/master/Formula/gcc.rb
==> Dependencies
Required: zlib (installed), gmp (installed), libmpc (installed), mpfr (installed), [email protected] (installed)
Recommended: glibc (uninstalled)
==> Options
--without-glibc
Build without glibc support
のようにwith: --without-glibcでビルドされた、となっているはずです。
また、brew lsしてもglibcが無いことを確認してください。
これでglibcなしでgccがインストールできたので
goとかtmuxとか好きなパッケージをインストールしていきます。
この状態だとrelocation errorは起こりません。
また、
export LD_LIBRARY_PATH=$HOME/.linuxbrew/lib:$LD_LIBRARY_PATH
の設定をしても
$ ls
ls: 0s": ELF: x: Error 1325453653
のようなエラーは起きなくなるのでライブラリを常時使うこともできます。
もしすでにいろいろパッケージをインストールしてしまっていて、それらが問題を起こすようであれば
殆どの場合はbrew reinstall <package>をすれば解決できるはずです。
(gitなどは最初にglibcを入れた後にコンパイルしていますがglibcを削除した後でも問題なく動きました。)
まとめ
問題が起こるのは
- /home/linuxbrew/.linuxbrewではなく$HOME/.linuxbrewを使う
- システムのglibcがFormulaの指定より古い
の場合にglibcがインストールされてしまう場合です。
glibcをインストールしても上手いことやる方法もあるかもしれませんが、
glibcを意図的にインストールしたい場合を除き
この対処法で大概の問題は解決出来るはずです。