はじめに
Linuxbrewを入れた環境でRust1.32.0以降の場合、proc_macroを使ったクレートのコンパイルに失敗することがあります。
(正確にはPATHが通ったところにシステムのglibcより新しいバージョンのglibcを参照するcc
コマンドが存在する場合、です。Linuxbrew環境はシステムのglibcバージョンによってはこれに該当します。もしかしたらMac OSのHomebrew環境でも起きるのかもしれません)
この問題が発生した場合の解決策と、詳細な原因を(分かる範囲で)まとめておきます。
解決策
以下のようにデフォルトのリンカをシステムのリンカに設定すれば、コンパイルできるようになります。
(同様のファイルは各プロジェクトのルートにも置けますが、ホームに置いておくとデフォルトでこれが適用されます。)
[target.x86_64-unknown-linux-gnu]
linker = "/usr/bin/cc"
経緯
Linuxbrewが2.0になったので手元のLinuxbrew環境を再構築したところ、いくつかのRustプロジェクトがコンパイル不能になっていることに気づきました。
当初はLinuxbrewのインストールの仕方が悪かったかと思っていましたが、検索すると以下のIssueがヒットしました。
wrong libc linked during build
これによると1.32.0にアップデートしたらコンパイルが通らなくなったとのことで、手元の環境でも確かに1.31.1に戻すと通ります。
そこで、git bisect
で問題が発生したリビジョンを確定させて、Issueを立てました。
(元のIssueはcargoの問題として立ててられていたのですが、リビジョン的にrustcだったので立て直しました)
Wrong glibc linked in building crates using proc_macro with linuxbrew
ここのコメントのやり取りで、なんとなく発生している現象は分かった気がするので以下にまとめておきます。
詳細
Rustにおいてproc_macroを使ったクレート(serde_deriveとか)をコンパイルする手順は以下のようになります。
(この辺り詳しくないので間違っていたら教えて下さい。)
- serde_deriveをrustcがコンパイル。リンカが
libserde_derive.so
を作成 - serdeをrustcがコンパイル。この時に
libc::dlopen
でlibserde_derive.so
をロード
通常このフローでロードに失敗することは多分ありません。
一方、Linuxbrewを入れた環境では(Linuxbrewのコマンドを優先したいので当然ですが)コマンド探索はLinuxbrewを優先するようPATH設定します。
そのためRustがコンパイル時に使用するリンカもLinuxbrewのものになります。
しかし(rustupが配布する公式の)rustcが参照するlibcはシステムのglibcなので
- serde_deriveをrustcがコンパイル。Linuxbrewリンカが
libserde_derive.so
を作成 - serdeをrustcがコンパイル。この時にシステムglibcの
libc::dlopen
でlibserde_derive.so
をロード
この時、Linuxbrewのglibcがシステムのものより新しいと、libserde_derive.so
が新しいglibcを参照しているのに、システムglibcのlibc::dlopen
は古いglibcしか見つけられずに以下のようにロードに失敗します。
error: /usr/lib64/libc.so.6: version `GLIBC_2.18' not found (required by /tmp/cargo-installkV0c2k/release/deps/libserde_derive-615594b83ebc865a.so)
--> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/grep-printer-0.1.1/src/lib.rs:81:1
|
81 | extern crate serde_derive;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
Rust1.32.0以降というのは、1.31.1-1.32.0の間にproc_macroのリンクをstaticからdynamicに変える変更が入ったためです。
実際git bisect
して見つかったリビジョンはこれです。
188d2dafcdd4d0dbd54315412503fb8011d716b6 is the first bad commit
commit 188d2dafcdd4d0dbd54315412503fb8011d716b6
Author: Eduard-Mihai Burtescu <edy.burt@gmail.com>
Date: Thu Apr 26 14:11:08 2018 +0300
Statically link proc_macro into proc macros.
:040000 040000 a218f2092aad86632374db4fc3ba0effe6705d7f b8357a8a11394a8ab0f6e20875802930dd0ecc9f M src
bisect run success
リンカとローダの環境が異なる(Linuxbrewリンカ+システムローダ)ことが原因なので、どちらかに揃えてやれば解決するはずです。冒頭の解決策はシステムリンカ+システムローダにする方です。
逆にLinuxbrew側に揃えることも可能なはずですがこちらは未確認です(brew install rust
でよい?)。
ただこちらはrustupが使えないので実用的には厳しい感じがします。