상대 경로를 사용하여 공유 라이브러리에 연결하는 방법은 무엇입니까?

상대 경로를 사용하여 공유 라이브러리에 연결하는 방법은 무엇입니까?

내부에ld.so(8) 매뉴얼 페이지,그것은 말한다

라이브러리 종속성을 해결할 때 동적 링커는 먼저 각 종속성 문자열에 슬래시가 포함되어 있는지 확인합니다. 이는 슬래시가 포함된 라이브러리 경로 이름이 링크 타임에 지정된 경우에 발생합니다. 슬래시가 발견되면 종속성 문자열은 (상대 또는 절대) 경로 이름으로 해석되고 해당 경로 이름을 사용하여 라이브러리가 로드됩니다.

gcc슬래시 경로로 라이브러리를 연결하는 방법은 무엇입니까 ? 나는 그것을 시도했지만 -l경로 매개변수 자체가 아닌 다양한 경로를 검색하는 데 사용하는 라이브러리 이름에서만 작동하는 것 같습니다.

후속 질문: 이런 방식으로 상대 경로에 연결할 때 상대 경로는 무엇입니까(예: 바이너리가 포함된 디렉터리 또는 런타임 시 작업 디렉터리)?

검색하는 동안 찾은 모든 링크된 가이드는 RPATH, LD_LIBRARY_PATH및 를 사용하여 논의되었습니다 RUNPATH. .로 시작하는 경로는 RPATH더 이상 사용되지 않으며 대부분의 논의에서는 상대 경로에 대한 연결을 허용하지만 재정의될 수 있다는 점에서 약간 취약합니다 LD_LIBRARY_PATH. 상대 경로가 더 강력한지 궁금합니다(이에 대해 논의하는 내용을 찾을 수 없기 때문에 아마도 경로가 런타임 디렉터리에 상대적이기 때문일 것입니다).RUNPATH$ORIGINLD_LIBRARY_PATH

답변1

(지금은) gcc질문의 또는 링크 부분을 무시하고 대신 다음을 사용하여 바이너리를 수정 하면patchelf리눅스 시스템에서

$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffd35584000)
        libhello.so.1 => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f02e4f6f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f02e533c000)
$ patchelf --remove-needed libhello.so.1 hello
$ patchelf --add-needed ./libhello.so.1 hello
$ ldd hello
        linux-vdso.so.1 =>  (0x00007ffdb74fc000)
        ./libhello.so.1 => not found
        libc.so.6 => /lib64/libc.so.6 (0x00007f2ad5c28000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2ad5ff5000)

libhello.so.1파일이 포함된 적절한 디렉터리가 존재 하는 경우 이제 라이브러리에 대한 상대 경로가 있는 바이너리가 생겼습니다.

$ cd english/
$ ../hello
hello, world
$ cd ../lojban/
$ ../hello
coi rodo

경로가 프로세스의 작업 디렉터리에 상대적이라는 것을 알았습니다., 이는 특히 다양한 문제를 야기할 것입니다.안전 질문. 이는 아마도 다른 버전의 라이브러리를 테스트하는 등 생산적인 용도로 사용될 수 있습니다. patchelf상대적인 작업 디렉터리의 복잡함 없이 두 개의 서로 다른 바이너리를 컴파일하거나 필요한 라이브러리에서 컴파일하는 것이 더 간단할 수 있습니다 .

컴파일 단계

libhello단 한 통 helloworld의 전화

$ cat libhello.c
#include <stdio.h>
void helloworld(void)
{
    printf("coi rodo\n");
}

그리고 컴파일

CFLAGS="-fPIC" make libhello.o
gcc -shared -fPIC -Wl,-soname,libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
ln -s libhello.so.1.0.0 libhello.so.1
ln -s libhello.so.1.0.0 libhello.so

hello호출을 수행하는 메소드는 helloworld다음과 같이 컴파일 됩니다.

$ cat hello.c
int main(void)
{
    helloworld();
    return 0;
}
$ CFLAGS="-lhello -L`pwd`/english" make hello

패치 없음

돌이켜보면 gcc상대 디렉터리 경로를 사용하도록 명령을 수정합니다.

$ gcc -shared -fPIC -Wl,-soname,./libhello.so.1 -o libhello.so.1.0.0 libhello.o -lc
$ cd ..
$ rm hello
$ CFLAGS="-lhello -L`pwd`/lojban" make hello
$ ldd hello | grep hello
        ./libhello.so.1 => not found
$ english
$ ../hello
hello, world

일반적인 방법으로 라이브러리를 컴파일하고 필요에 따라 사용하십시오 patchelf.

답변2

링커에 옵션을 전달하면 됩니다. 예를 들어 ncurses 빌드 디렉터리(제거된 라이브러리에 의존)에서 테스트 프로그램을 실행하려면 다음 옵션을 사용합니다(gcc 명령줄에서):

-Wl,-rpath,../lib

상대 경로 이름이 포함되어 있습니다. 동일한 옵션으로 절대 경로 이름을 포함할 수 있습니다.

-Wl,-rpath,../lib:/usr/local/ncurses6/lib

이렇게 하면 로컬 테스트에는 유용하지만 여러 가지 이유로 시스템에 설치하는 데는 적합하지 않습니다. 데비안은 1990년대부터 이에 반대하는 정책을 갖고 있지만 일관된 논의는 거의 없습니다(예:RPATH 문제일부 정보를 수집합니다.)

답변3

gcc를 사용하여 간단히 컴파일하는 경우 다음만 수행하면 됩니다.

gcc -o prog main.c ./liblib.so

컴파일 후 프로그램은 thrig의 답변과 동일하게 작동합니다. 이 명령은 테스트 환경에서만 사용해야 한다고 생각합니다.

관련 정보