RPATH가 설정되어 있는데도 이 실행 파일이 상대 경로 모듈 라이브러리를 로드하지 않는 이유는 무엇입니까?

RPATH가 설정되어 있는데도 이 실행 파일이 상대 경로 모듈 라이브러리를 로드하지 않는 이유는 무엇입니까?

이 질문은 프로그래밍 측면과 관련되어 있지만 무슨 일이 일어나고 있는지 이해하려고 노력할수록 Unix/Linux RPATH와 관련이 있을 수 있다고 생각됩니다. Unix/Linux와 관련이 있다고 가정합니다. $ORIGIN(내 질문은 스택 오버플로에서도 큰 관심을 끌지 못합니다.) 질문의 프로그래밍 관련 측면을 최대한 많이 제거하겠습니다(예: CMakeLists.txt). 그러나 응답자가 관련성이 있다고 말하면.

실행 파일이 있는 하위 디렉터리에서 모듈 라이브러리(또는 다르게 호출되는 "공유 라이브러리" 또는 "플러그인 라이브러리")를 로드하는 실행 파일을 만들었습니다. 디렉토리 구조는 다음과 같습니다.

build/
├── main  # the executable
└── plugins
    └── libmy-plugin.so

이 질문의 프로그래밍 측면에서 어느 정도 거리를 두기 위해 전체 C 코드를 표시하지 않겠습니다(누군가가 이 사이트의 주제에서 질문을 빼내지 않는다고 말하는 경우 제외). 그러나 실제로는 모듈 라이브러리를 로드하는 "hello-world"와 동일하지만 한 가지 차이점이 있습니다. 상대 경로에서 플러그인 라이브러리를 로드한다는 것입니다. 구체적으로 로드되는 plugins/libmy-plugin.so최소 코드 조각은 다음과 같습니다.

const char* plugin = "plugins/libmy-plugin.so";
void* handle = dlopen(plugin, RTLD_NOW);

매뉴얼 페이지에는 다음과 dlopen같이 나와 있습니다.

dlopen() 함수는 null로 끝나는 문자열 파일 이름으로 명명된 동적 공유 객체(공유 라이브러리) 파일을 로드하고 로드된 객체의 불투명 "핸들"을 반환합니다. 파일 이름이 NULL이면 반환된 핸들은 다음 작업에 사용됩니다. 메인 파일 프로그램. 파일 이름에 슬래시("/")가 포함되어 있으면 (상대 또는 절대) 경로 이름으로 해석됩니다.

매뉴얼 페이지에는 다음과 ld-linux.so같이 나와 있습니다.

$ORIGIN (또는 이에 상응하는 ${ORIGIN})
이는 프로그램이나 공유 객체가 포함된 디렉터리로 확장됩니다. 따라서 somedir/app에 위치한 애플리케이션은
gcc -Wl,-rpath,'$ORIGIN/../lib'
somedir이 디렉토리 계층 구조의 어디에 위치하든 상관없이 somedir/lib에서 연관된 공유 객체를 찾도록 컴파일될 수 있습니다. 이는 특별한 디렉터리에 설치할 필요가 없지만 어떤 디렉터리에든 압축을 풀고 여전히 자체 공유 개체를 찾을 수 있는 "턴키" 응용 프로그램을 만드는 데 도움이 됩니다.

확인 방법을 알 수 있는 한, 내가 컴파일한 바이너리는 다음과 같이 RPATH설정 되어 있습니다 $ORIGIN.

$ objdump -x ./build/main | grep PATH
  RUNPATH              $ORIGIN
$
$ readelf -d ./build/main

Dynamic section at offset 0x2d98 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [$ORIGIN]
...

내가 읽은 바에 따르면 $ORIGIN"프로그램이 포함된 디렉터리로 확장"되고 "파일 이름에 슬래시("/")가 포함되어 있으면 (상대 또는 절대) 경로 이름으로 해석됩니다." 이는 다음을 의미해야 합니다. 프로그램 RPATH슬래시(및 상대 경로)가 포함된 파일 이름으로 $ORIGIN호출되도록 설정된 경우 dlopen()해당 모듈 라이브러리의 검색 경로는 프로그램이 포함된 디렉터리에 상대적이어야 합니다.

그러나 그것은 내가 관찰한 것이 아니다. 내가 실제로 관찰한 것은 내 CWD가 실행 파일을 포함하는 디렉터리일 때 실행 파일은 모듈 라이브러리만 찾는다는 것입니다. 다른 디렉터리에 있고 실행 파일에 대한 전체 상대/절대 경로를 지정하면 모듈 라이브러리를 찾을 수 없습니다(그리고 설정의 영향을 받지 않는 것 같습니다 LD_LIBRARY_PATH).

$ ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ LD_LIBRARY_PATH=./build ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ LD_LIBRARY_PATH=/home/user/dev/cmake-learn/rpath/build/ ./build/main
failed loading plugins/libmy-plugin.so: plugins/libmy-plugin.so: cannot open shared object file: No such file or directory
$
$ cd build/
$ ./main
all good
$

나는 이것이 프로그래밍 문제인지 아니면 Unix/Linux 문제인지 머리 속으로 왔다 갔다 하고 있습니다. 앞서 언급했듯이 이것이 Unix/Linux 모듈 검색 경로와 관련이 있다는 불특정한 느낌이 들었습니다. 커뮤니티에서는 이것이 실제로 프로그래밍 질문이라고 생각합니다. 스택 오버플로에 대해 다시 한번 시험해 보겠습니다.
(Stack Overflow에 대한 내 원래 질문에 대한 댓글 작성자는 검색 경로가 항상 CWD에 상대적이라고 말했지만 이는 완전히 설명적인 답변이 아니므로 댓글이 달린 매뉴얼 페이지 섹션을 읽은 것과 해당 진술을 일치시킬 수 없습니다.)

답변1

나에게 이것은 파일 이름이 거기 에 있어서 검색되지 않거나("."에 상대적이거나 "/"에서 옴), 거기에 없고 모든 경로 메커니즘에서 검색된다는 man dlopen의미입니다 ./

아마도 사용 dlopen("libmy-plugin.so",)하고 제공 해야 할 것으로 예상해야 합니다.-Wl,-rpath,'$ORIGIN/plugins'

관련 정보