在 Alpine Linux 上用 bindgen 的踩雷紀錄

最近在弄專題時,想說在一個比較單純的環境裡做測試,就挑了 Alpine Linux 來用。結果在編譯時跑 bindgen 吃了不少苦頭。

最一開始是這樣的,bindgen 會回報說無法動態載入 clang 的 shared library,錯誤訊息是 Dynamic loading not supported

幸好,bindgen 有提供 static 的 feature 可以用

cargo install --no-default-features --features static,logging,clap,which-rustfmt bindgen

但是裝起來之後,一下指令就 Segmentation fault 是怎麼回事??

Debug 了一下就發現,他的 GOT 並沒有 relocate 到正確的地址上,查了很久才發現 rust 在 musl 上會預設編譯一個靜態的 C Runtime,但是執行起來時它並不會去把 shared library load 進來。等於長出了一個不完全是靜態,也不完全是動態連結的程式,所以理所當然的炸了。

解決方式是把 rust 的靜態 C Runtime 關掉,設上環境變數就可以解決

RUSTFLAGS="-C target-feature=-crt-static" cargo install --no-default-features --features static,logging,clap,which-rustfmt bindgen

Source: https://users.rust-lang.org/t/sigsegv-with-program-linked-against-openssl-in-an-alpine-container/52172/4


2021/09/15 更新

後來調查發現,其實這跟 musl 或 Alpine Linux 的關係不大。

Dynamic loading not supported 的主因是:當在 static binary 中呼叫 dlopen() ,musl 的實作會拒絕,所以會回傳以上錯誤訊息。

所以到頭來,根本的解決辦法是把 rustc 預設的 crt-static 關掉就好了。

RUSTFLAGS="-C target-feature=-crt-static" cargo install bindgen

雖然說最後終於解決了,但也折騰了好幾個小時...

musl 的特性跟其他大部分 distro 用的 glibc 差蠻多的,需要特別注意一下這個問題