LoginSignup
8
2

More than 5 years have passed since last update.

Linuxbrew環境でRust1.32.0以降コンパイルに失敗するとき

Posted at

はじめに

Linuxbrewを入れた環境でRust1.32.0以降の場合、proc_macroを使ったクレートのコンパイルに失敗することがあります。
(正確にはPATHが通ったところにシステムのglibcより新しいバージョンのglibcを参照するccコマンドが存在する場合、です。Linuxbrew環境はシステムのglibcバージョンによってはこれに該当します。もしかしたらMac OSのHomebrew環境でも起きるのかもしれません)
この問題が発生した場合の解決策と、詳細な原因を(分かる範囲で)まとめておきます。

解決策

以下のようにデフォルトのリンカをシステムのリンカに設定すれば、コンパイルできるようになります。
(同様のファイルは各プロジェクトのルートにも置けますが、ホームに置いておくとデフォルトでこれが適用されます。)

~/.cargo/config
[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::dlopenlibserde_derive.soをロード

通常このフローでロードに失敗することは多分ありません。

一方、Linuxbrewを入れた環境では(Linuxbrewのコマンドを優先したいので当然ですが)コマンド探索はLinuxbrewを優先するようPATH設定します。
そのためRustがコンパイル時に使用するリンカもLinuxbrewのものになります。
しかし(rustupが配布する公式の)rustcが参照するlibcはシステムのglibcなので

  • serde_deriveをrustcがコンパイル。Linuxbrewリンカlibserde_derive.soを作成
  • serdeをrustcがコンパイル。この時にシステムglibclibc::dlopenlibserde_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が使えないので実用的には厳しい感じがします。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2