前言
對于經(jīng)常在服務器上跑程序或安裝程序的朋友,不可避免的會遇到一些問題。
其中最常見的問題就是,像下面這樣
version `GLIBC_2.23' not found
version `GLIBC_2.15' not found
glibc 庫找不到的問題,當然也可能會有其他庫找不到的問題。
那出現(xiàn)這種問題該怎么辦呢?
常用解決方案
針對這一問題,網(wǎng)上搜索的答案大部分都是分為以下幾步
安裝高版本的 glibc
顯然,沒有這個庫,當然先要在環(huán)境中安裝這個庫才行,比如我要安裝 glibc-2.23
- 下載
http://ftp.gnu.org/gnu/libc/
選擇對應的版本并下載,如 libc-2.23.tar.gz
- 解壓
$ tar -zxf glibc-2.23.tar.gz
- 生成配置文件
$ cd glibc-2.23
$ mkdir build && cd build
$ ../configure --prefix=LIB_DIR
可以用 --prefix=LIB_DIR,LIB_DIR 為你要將 glib 安裝到的路徑
通常非 root 用戶權限無法安裝到默認的 /usr/local 目錄下,需要自己手動指定
- 安裝
$ make
$ make install
等會吧,這個安裝還蠻久的。來杯咖啡,靜等安裝成功就行。
問題:
如果在 ../configure 這一步出現(xiàn)了問題,比如我出現(xiàn) ld 版本太低的錯誤
*** These critical programs are missing or too old: as ld
也不用著急,再安裝個較高版本的 binutils 就行。
這個怎么安裝?類似上面的 1-4 步重新來一遍就行。一般像這種 C 庫的安裝過程都是這樣的,挺簡單的,只是通常拋出的異常是不簡單的 (?????_?????)。
- 配置環(huán)境
安裝完成后,大多數(shù)的答案都是將下面的命令添加到 ~/.bashrc 文件中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path
然后,執(zhí)行
source ~/.bashrc
但是這又會引入另一個問題更嚴重的問題。
glibc 是 Linux 系統(tǒng)中最底層的 API,幾乎其他所有的庫都會依賴它。
因此當你更新了較高版本的 glibc 時,底層的庫依賴的還是低版本的 glibc 庫,因此可能會導致系統(tǒng)的嚴重故障。
我當初就是信了這些鬼話,添加到了環(huán)境變量中,導致幾乎所有的命令都無法使用。運行命令或腳本也會出現(xiàn)
Segmentation fault
最后的解決辦法就是將 ~/.bashrc 文件中的
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path
刪除之后,才恢復原狀。
那如何解決呢,一種方法就是每次運行之前,在終端臨時將 glibc 的路徑添加到 LD_LIBRARY_PATH 變量中,但是這非常麻煩。
下面,我們介紹一款神器
PatchELF
PatchELF 是一個用于修改現(xiàn)有 ELF 可執(zhí)行文件和庫的簡單實用程序
ELF: 可執(zhí)行與可鏈接格式(Executable and Linkable Format),常被稱為 ELF 格式。
既然它能夠更改可執(zhí)行文件,那么我們就可以直接將可執(zhí)行文件需要加載的 glibc 庫的路徑修改為我們剛才安裝的路徑。
這樣就可以在既不需要添加環(huán)境變量,也不需要手動加載臨時變量的情況下使用。
下面,我們先安裝這個工具
1. 安裝
- 下載
https://github.com/dxsbiocc/patchelf
先從 GitHub 上下載源碼
- 配置環(huán)境
./bootstrap.sh
./configure
- 安裝
make
make check
make install
2. 使用
- 查看參數(shù)
$ patchelf
syntax: patchelf
[--set-interpreter FILENAME]
[--page-size SIZE]
[--print-interpreter]
[--print-soname] Prints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist
[--set-soname SONAME] Sets 'DT_SONAME' entry to SONAME.
[--set-rpath RPATH]
[--remove-rpath]
[--shrink-rpath]
[--allowed-rpath-prefixes PREFIXES] With '--shrink-rpath', reject rpath entries not starting with the allowed prefix
[--print-rpath]
[--force-rpath]
[--add-needed LIBRARY]
[--remove-needed LIBRARY]
[--replace-needed LIBRARY NEW_LIBRARY]
[--print-needed]
[--no-default-lib]
[--output FILE]
[--debug]
[--version]
FILENAME...
- 參數(shù)描述
| 參數(shù) | 描述 |
|---|---|
| --set-interpreter FILENAME | 設置動態(tài)庫解析器 |
| --page-size SIZE | 設置頁大小 |
| --print-interpreter | 打印解析器 |
| --print-soname | 打印 DT_SONAME |
| --set-soname SONAME | 設置 DT_SONAME |
| --set-rpath RPATH | 設置 RPATH |
| --remove-rpath | 刪除 RPATH |
| --shrink-rpath | 收縮 RPATH |
| --allowed-rpath-prefixes PREFIXES | 添加允許的 RPATH 前綴 |
| --print-rpath | 打印 RPATH |
| --force-rpath | 強制使用 RPATH |
| --add-needed LIBRARY | 添加需要的動態(tài)庫 |
| --remove-needed LIBRARY | 刪除需要的動態(tài)庫 |
| --replace-needed LIBRARY NEW_LIBRARY | 替換動態(tài)庫 |
| --print-needed | 打印需要的動態(tài)庫 |
| --no-default-lib | 不鏈接默認的動態(tài)庫 |
| --output FILE | 輸出文件 |
| --debug | 輸出調(diào)試信息 |
| --version | 打印版本信息 |
patchelf 的主要功能與動態(tài)庫解析器、RPATH 以及動態(tài)庫有關。
- 使用方式
- 更改可執(zhí)行文件的動態(tài)庫解析器
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
- 更改可執(zhí)行文件和庫的RPATH
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
- 收縮可執(zhí)行文件和庫的RPATH
$ patchelf --shrink-rpath my-program
該命令會刪除可執(zhí)行文件中所有不包含 DT_NEEDED 字段指定的庫的路徑。
例如:
一個可執(zhí)行文件引用一個庫 libfoo.so,它的 RPATH 是 /lib:/usr/lib:/foo/lib,而 libfoo.so 只能在 /foo/lib 中找到,那么新的 RPATH 將是 /foo/lib
其中 RPATH 指定的是可執(zhí)行文件的動態(tài)鏈接庫的搜索路徑
- 刪除動態(tài)庫上聲明的依賴項(
DT_NEEDED),可多次使用
$ patchelf --remove-needed libfoo.so.1 my-program
- 添加動態(tài)庫上聲明的依賴項(
DT_NEEDED),可多次使用
$ patchelf --add-needed libfoo.so.1 my-program
- 替換動態(tài)庫聲明的依賴項(
DT_NEEDED),可多次使用
$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program
- 更改動態(tài)庫的
SONAME
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3
- 示例
我有一個 msi 分析的可執(zhí)行文件 msisensor-blood
在終端執(zhí)行時,出現(xiàn)錯誤
$ ./msisensor-blood
./msisensor-blood: /lib64/libm.so.6: version `GLIBC_2.23' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./msisensor-blood)
從輸出信息可以看出,需要兩個庫
-
glibc-2.15的libc.so.6庫 -
glibc-2.23的libm.so.6庫
首先, 我們用 ldd 命令列出其動態(tài)庫依賴關系
./msisensor-blood: /lib64/libm.so.6: version `GLIBC_2.23' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ./msisensor-blood)
./msisensor-blood: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./msisensor-blood)
linux-vdso.so.1 => (0x00007ffc75beb000)
libz.so.1 => /home/dengxs/software/zlib-1.2.11/lib/libz.so.1 (0x00007f7594351000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033dee00000)
libstdc++.so.6 => /home/dengxs/software/anaconda3/lib/libstdc++.so.6 (0x00007f75941c4000)
libm.so.6 => /lib64/libm.so.6 (0x00000033de600000)
libgomp.so.1 => /home/dengxs/software/anaconda3/lib/libgomp.so.1 (0x00007f7594196000)
libgcc_s.so.1 => /home/dengxs/software/anaconda3/lib/libgcc_s.so.1 (0x00007f7594182000)
libc.so.6 => /lib64/libc.so.6 (0x00000033de200000)
/lib64/ld-linux-x86-64.so.2 (0x00000033dde00000)
librt.so.1 => /lib64/librt.so.1 (0x00000033df200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000033dea00000)
OK!就是把下面兩個動態(tài)庫替換掉
libm.so.6 => /lib64/libm.so.6
...
libc.so.6 => /lib64/libc.so.6
更換 libm.so.6 的路徑
patchelf --replace-needed libm.so.6 /home/dengxs/software/glibc-2.23/lib/libm.so.6 msisensor-blood
更換 libc.so.6 的路徑
patchelf --replace-needed libc.so.6 /share/software/glibc/2.15/lib/libc.so.6 msisensor-blood
再看下動態(tài)庫列表
$ ldd msisensor-blood
linux-vdso.so.1 => (0x00007ffde0199000)
libz.so.1 => /home/dengxs/software/zlib-1.2.11/lib/libz.so.1 (0x00007f6a786df000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00000033dee00000)
libstdc++.so.6 => /home/dengxs/software/anaconda3/lib/libstdc++.so.6 (0x00007f6a78552000)
/home/dengxs/software/glibc-2.23/lib/libm.so.6 (0x00007f6a7844b000)
libgomp.so.1 => /home/dengxs/software/anaconda3/lib/libgomp.so.1 (0x00007f6a7841d000)
libgcc_s.so.1 => /home/dengxs/software/anaconda3/lib/libgcc_s.so.1 (0x00007f6a78409000)
/share/software/glibc/2.15/lib/libc.so.6 (0x00007f6a78062000)
/lib64/ld-linux-x86-64.so.2 (0x00000033dde00000)
librt.so.1 => /lib64/librt.so.1 (0x00000033df200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00000033dea00000)
OK,已經(jīng)替換成功了
接下去看看能不能直接運行
$ ./msisensor-blood
Program: msisensor-blood (homopolymer and miscrosatelite analysis using cfDNA bam files)
Version: v0.1
Author: Beifang Niu && Kai Ye
Usage: msisensor-blood <command> [options]
Key commands:
scan scan homopolymers and miscrosatelites
msi msi scoring
沒問題,一切順利。(^?^)??