Linux RPATH & $ORIGIN
許多現(xiàn)代C / C ++項(xiàng)目都利用Autotools創(chuàng)建GNU構(gòu)建系統(tǒng),例如 根據(jù)平臺(tái)生成make文件。 可執(zhí)行文件(二進(jìn)制文件)在生成/編譯過程中生成,并且可以在執(zhí)行編譯的計(jì)算機(jī)上本地執(zhí)行。 但是,如果將同一可執(zhí)行文件移動(dòng)到另一臺(tái)計(jì)算機(jī)上,或者只是移到同一臺(tái)計(jì)算機(jī)上的其他文件夾,則在運(yùn)行該可執(zhí)行文件時(shí)可能會(huì)遇到“找不到庫”錯(cuò)誤。什么是RPATH和$ORIGIN?
RPATH代表運(yùn)行時(shí)搜索路徑。 根據(jù)Wikipedia的說法,“rpath指定在可執(zhí)行文件或庫中硬編碼的運(yùn)行時(shí)搜索路徑。 動(dòng)態(tài)鏈接加載程序使用rpath查找所需的庫” 動(dòng)態(tài)鏈接是所需共享庫的一種“惰性”鏈接,不是在編譯階段,而是在運(yùn)行一個(gè)可執(zhí)行文件的后期。 如果設(shè)置了rpath,覆蓋或補(bǔ)充系統(tǒng)默認(rèn)的共享庫搜索路徑,則共享庫的路徑將被編碼到可執(zhí)行文件的頭中,就像擴(kuò)展PATH系統(tǒng)變量鏈一樣。
$ORIGIN是一個(gè)特殊的變量,指示實(shí)際的可執(zhí)行文件名。它在運(yùn)行時(shí)解析到可執(zhí)行文件的位置,在設(shè)置RPATH時(shí)非常有用。
- 示例
3.1 編寫libhello.so動(dòng)態(tài)庫文件
// hello.h
#pragma once
void HelloFunc();
// hello.cpp
#include <iostream>
void HelloFunc()
{
std::cout << "hello function \n";
}
3.2 編譯
g++ -fPIC -shared -o libhello.so hello.c
3.3 編寫主文件
// main.c
#include <iostream>
#include "hello.h"
int main()
{
HelloFunc();
std::cout << "hello world \n";
return 0;
}
正常編譯
g++ main.c -o main -L. -lhello
3.4 運(yùn)行結(jié)果
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
我們需要解決找到libhello.so的問題才可以使main運(yùn)行起來,可以通過以下兩種方式:
3.4.1 export LD_LIBRARY_PATH=yourpath/lib
將libhello.so拷貝到/usr/local/lib,然后運(yùn)行l(wèi)dconfig
使用RPATH
編譯期 編譯命令改為
g++ main.c -o main -L. -lhello -Wl,-rpath='$ORIGIN/'
運(yùn)行
./main
hello function
hello world
程序正常運(yùn)行
在編譯之后,執(zhí)行之前
使用 chrpath
chrpath -r "\$\ORIGIN/path/to/library" <executable>
—如果之前沒有為可執(zhí)行文件設(shè)置rpath,上述命令可能會(huì)失敗。使用patchelf實(shí)用程序嘗試下面的命令,它不會(huì)抱怨沒有設(shè)置rpath,并且會(huì)設(shè)置RUNPATH來實(shí)現(xiàn)類似的目標(biāo):
使用 patchelf
patchelf --set-rpath '$ORIGIN/path/to/library' <executable>
如何檢查RPATH的值?
有多種方法可以檢查可執(zhí)行文件或庫的RPATH值。objdump、readelf和chrpath是3個(gè)常用的實(shí)用程序"
objdump -x path/to/executable | grep RPATH
readelf -d path/to/executable | head -20
chrpath -l path/to/executable
使用readelf結(jié)果:
