💥

/usr/bin/ld: cannot find -lpython3.9: No such file or directory の対処法メモ

2023/11/05に公開

自分用のメモです。間違えたこと言ってたら教えてください。

経緯

rye で用意した python 環境で、pola-rs/pyo3-polars の example を build しようとしたら、

> make install
...
  = note: /usr/bin/ld: cannot find -lpython3.9: No such file or directory
          collect2: error: ld returned 1 exit status


error: could not compile `expression_lib` (lib) due to previous error
💥 maturin failed
  Caused by: Failed to build a native library through cargo
...

と怒られれ、build できなかった。

環境
❯ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.3 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.3 LTS (Jammy Jellyfish)"
...
❯ python --version
Python 3.9.16
❯ venv/bin/pip list
Package        Version
-------------- -------
expression_lib 0.1.0
maturin        1.3.1
pip            22.0.4
polars         0.19.12
setuptools     58.1.0
tomli          2.0.1

解決法

以下のコマンドで build する。

> RUSTFLAGS='-L <PATH_TO>/.rye/py/cpython@3.9.16/install/lib' make run

原因

maturin(というか Rust)は、使用している python を dynamic リンクする際に(linux 環境だと)、 /usr/lib/ を見にいく。しかし、rye を使って環境を管理していると、そこにライブラリは存在せず、(自分でカスタマイズしない限りは)~/.rye の中に持っている。そのため、maturin がライブラリを見つけることができずに上記のエラーになっていたと考えられる。

その場所を maturin に明示的に教えてあげればよい。Rust では RUSTFLAGS='-L <PATH_TO_LD_LIBRARY_PATH> とすることで、それが可能。もちろん、LD_LIBRARY_PATH を設定してあげることでも可能である。

ちなみに、static リンクしてる場合は、LIBRARY_PATH を設定する必要がある(気がする)。どちらが必要かは、build してみて必要だと言われている file が dynamic なのか static なのかを判断した上で決める感じで現状は対処している。

補足

polars を test する際に、RUSTFLAGS='-L ... を設定するだけでは fail し、LIBRARY_PATH も設定しないといけない場面があった。つまり、

RUSTFLAGS='-L <PATH_TO>/.rye/py/cpython@3.9.16/install/lib' make test

ではエラーになるが、

LIBRARY_PATH=<PATH_TO>/.rye/py/cpython@3.9.16/install/lib/ RUSTFLAGS='-L  <PATH_TO>/.rye/py/cpython@3.9.16/install/lib' make test

だと問題ないということがあった。詳しい理由はまだ追えてないので、ご存じの方いたら教えてください。

memo

内容とは全く関係ないですが、LD_PRELOAD という環境変数を使ってコンパイルなしに動的ライブラリを書き換えることができるようです
https://qiita.com/developer-kikikaikai/items/f6f87b2d1d7c3e14fb52

参考

Discussion