前言
對(duì)于經(jīng)常在服務(wù)器上跑程序或安裝程序的朋友,不可避免的會(huì)遇到一些問(wèn)題。
其中最常見的問(wèn)題就是,像下面這樣
version `GLIBC_2.23' not found
version `GLIBC_2.15' not found
glibc
庫(kù)找不到的問(wèn)題,當(dāng)然也可能會(huì)有其他庫(kù)找不到的問(wèn)題。
那出現(xiàn)這種問(wèn)題該怎么辦呢?
常用解決方案
針對(duì)這一問(wèn)題,網(wǎng)上搜索的答案大部分都是分為以下幾步
安裝高版本的 glibc
顯然,沒(méi)有這個(gè)庫(kù),當(dāng)然先要在環(huán)境中安裝這個(gè)庫(kù)才行,比如我要安裝 glibc-2.23
- 下載
http://ftp.gnu.org/gnu/libc/
選擇對(duì)應(yīng)的版本并下載,如 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
用戶權(quán)限無(wú)法安裝到默認(rèn)的 /usr/local
目錄下,需要自己手動(dòng)指定
- 安裝
$ make
$ make install
等會(huì)吧,這個(gè)安裝還蠻久的。來(lái)杯咖啡,靜等安裝成功就行。
問(wèn)題:
如果在 ../configure
這一步出現(xiàn)了問(wèn)題,比如我出現(xiàn) ld
版本太低的錯(cuò)誤
*** These critical programs are missing or too old: as ld
也不用著急,再安裝個(gè)較高版本的 binutils
就行。
這個(gè)怎么安裝?類似上面的 1-4
步重新來(lái)一遍就行。一般像這種 C 庫(kù)的安裝過(guò)程都是這樣的,挺簡(jiǎn)單的,只是通常拋出的異常是不簡(jiǎn)單的 (?????_?????)
。
- 配置環(huán)境
安裝完成后,大多數(shù)的答案都是將下面的命令添加到 ~/.bashrc
文件中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path
然后,執(zhí)行
source ~/.bashrc
但是這又會(huì)引入另一個(gè)問(wèn)題更嚴(yán)重的問(wèn)題。
glibc
是 Linux
系統(tǒng)中最底層的 API
,幾乎其他所有的庫(kù)都會(huì)依賴它。
因此當(dāng)你更新了較高版本的 glibc
時(shí),底層的庫(kù)依賴的還是低版本的 glibc
庫(kù),因此可能會(huì)導(dǎo)致系統(tǒng)的嚴(yán)重故障。
我當(dāng)初就是信了這些鬼話,添加到了環(huán)境變量中,導(dǎo)致幾乎所有的命令都無(wú)法使用。運(yùn)行命令或腳本也會(huì)出現(xiàn)
Segmentation fault
最后的解決辦法就是將 ~/.bashrc
文件中的
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your glibc path
刪除之后,才恢復(fù)原狀。
那如何解決呢,一種方法就是每次運(yùn)行之前,在終端臨時(shí)將 glibc
的路徑添加到 LD_LIBRARY_PATH
變量中,但是這非常麻煩。
下面,我們介紹一款神器
PatchELF
PatchELF
是一個(gè)用于修改現(xiàn)有 ELF
可執(zhí)行文件和庫(kù)的簡(jiǎn)單實(shí)用程序
ELF
: 可執(zhí)行與可鏈接格式(Executable and Linkable Format
),常被稱為 ELF
格式。
既然它能夠更改可執(zhí)行文件,那么我們就可以直接將可執(zhí)行文件需要加載的 glibc
庫(kù)的路徑修改為我們剛才安裝的路徑。
這樣就可以在既不需要添加環(huán)境變量,也不需要手動(dòng)加載臨時(shí)變量的情況下使用。
下面,我們先安裝這個(gè)工具
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 | 設(shè)置動(dòng)態(tài)庫(kù)解析器 |
--page-size SIZE | 設(shè)置頁(yè)大小 |
--print-interpreter | 打印解析器 |
--print-soname | 打印 DT_SONAME |
--set-soname SONAME | 設(shè)置 DT_SONAME |
--set-rpath RPATH | 設(shè)置 RPATH |
--remove-rpath | 刪除 RPATH |
--shrink-rpath | 收縮 RPATH |
--allowed-rpath-prefixes PREFIXES | 添加允許的 RPATH 前綴 |
--print-rpath | 打印 RPATH |
--force-rpath | 強(qiáng)制使用 RPATH |
--add-needed LIBRARY | 添加需要的動(dòng)態(tài)庫(kù) |
--remove-needed LIBRARY | 刪除需要的動(dòng)態(tài)庫(kù) |
--replace-needed LIBRARY NEW_LIBRARY | 替換動(dòng)態(tài)庫(kù) |
--print-needed | 打印需要的動(dòng)態(tài)庫(kù) |
--no-default-lib | 不鏈接默認(rèn)的動(dòng)態(tài)庫(kù) |
--output FILE | 輸出文件 |
--debug | 輸出調(diào)試信息 |
--version | 打印版本信息 |
patchelf
的主要功能與動(dòng)態(tài)庫(kù)解析器、RPATH
以及動(dòng)態(tài)庫(kù)有關(guān)。
- 使用方式
- 更改可執(zhí)行文件的動(dòng)態(tài)庫(kù)解析器
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
- 更改可執(zhí)行文件和庫(kù)的RPATH
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
- 收縮可執(zhí)行文件和庫(kù)的RPATH
$ patchelf --shrink-rpath my-program
該命令會(huì)刪除可執(zhí)行文件中所有不包含 DT_NEEDED
字段指定的庫(kù)的路徑。
例如:
一個(gè)可執(zhí)行文件引用一個(gè)庫(kù) libfoo.so
,它的 RPATH
是 /lib:/usr/lib:/foo/lib
,而 libfoo.so
只能在 /foo/lib
中找到,那么新的 RPATH
將是 /foo/lib
其中 RPATH
指定的是可執(zhí)行文件的動(dòng)態(tài)鏈接庫(kù)的搜索路徑
- 刪除動(dòng)態(tài)庫(kù)上聲明的依賴項(xiàng)(
DT_NEEDED
),可多次使用
$ patchelf --remove-needed libfoo.so.1 my-program
- 添加動(dòng)態(tài)庫(kù)上聲明的依賴項(xiàng)(
DT_NEEDED
),可多次使用
$ patchelf --add-needed libfoo.so.1 my-program
- 替換動(dòng)態(tài)庫(kù)聲明的依賴項(xiàng)(
DT_NEEDED
),可多次使用
$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program
- 更改動(dòng)態(tài)庫(kù)的
SONAME
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3
- 示例
我有一個(gè) msi
分析的可執(zhí)行文件 msisensor-blood
在終端執(zhí)行時(shí),出現(xiàn)錯(cuò)誤
$ ./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)
從輸出信息可以看出,需要兩個(gè)庫(kù)
-
glibc-2.15
的libc.so.6
庫(kù) -
glibc-2.23
的libm.so.6
庫(kù)
首先, 我們用 ldd
命令列出其動(dòng)態(tài)庫(kù)依賴關(guān)系
./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
!就是把下面兩個(gè)動(dòng)態(tài)庫(kù)替換掉
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
再看下動(dòng)態(tài)庫(kù)列表
$ 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)替換成功了
接下去看看能不能直接運(yùn)行
$ ./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
沒(méi)問(wèn)題,一切順利。(^?^)??