Programing

libstdc ++를 정적으로 링크 : 문제가 있습니까?

lottogame 2020. 10. 8. 07:39
반응형

libstdc ++를 정적으로 링크 : 문제가 있습니까?


상당히 오래된 libstdc ++ 버전과 함께 제공되는 Ubuntu 10.04를 실행하는 시스템에 GCC 4.7의 libstdc ++와 함께 Ubuntu 12.10에 빌드 된 C ++ 애플리케이션을 배포해야합니다.

현재 저는 -static-libstdc++ -static-libgcc이 블로그 게시물 인 Linking libstdc ++ statically에서 제안한대로를 사용 하여 컴파일하고 있습니다. 저자는 libstdc ++를 정적으로 컴파일 할 때 동적으로로드 된 C ++ 코드를 사용하지 말라고 경고합니다.이 코드는 아직 확인하지 않았습니다. 그래도 지금까지 모든 것이 순조롭게 진행되고있는 것 같습니다. Ubuntu 10.04에서 C ++ 11 기능을 사용할 수 있습니다.

이 기사는 2005 년의 기사이며 그 이후로 많은 것이 변경되었을 것입니다. 그 조언은 여전히 ​​최신입니까? 내가 알아야 할 숨어있는 문제가 있습니까?


그 블로그 게시물은 매우 정확하지 않습니다.

내가 아는 한 C ++ ABI 변경 사항은 GCC의 모든 주요 릴리스 (즉, 다른 첫 번째 또는 두 번째 버전 번호 구성 요소가있는 릴리스)에 도입되었습니다.

사실이 아니다. GCC 3.4 이후 도입 된 유일한 C ++ ABI 변경 사항은 이전 버전과 호환됩니다. 즉, C ++ ABI가 거의 9 년 동안 안정적이었습니다.

설상가상으로, 대부분의 주요 Linux 배포판은 GCC 스냅 샷을 사용하거나 GCC 버전을 패치하므로 바이너리를 배포 할 때 처리 할 GCC 버전을 정확히 알 수 없습니다.

배포판의 패치 된 GCC 버전 간의 차이는 사소하고 ABI가 변경되지 않습니다. 예를 들어 Fedora의 4.6.3 20120306 (Red Hat 4.6.3-2)은 업스트림 FSF 4.6.x 릴리스와 ABI가 호환되며 거의 모든 4.6과 호환됩니다. x 다른 배포판에서.

GNU / Linux에서 GCC의 런타임 라이브러리는 ELF 심볼 버전 관리를 사용하므로 객체와 라이브러리에 필요한 심볼 버전을 쉽게 확인할 수 있습니다. libstdc++.so이러한 심볼을 제공하는를 사용하면 작동합니다. 패치 된 버전이 약간 다른지 여부는 중요하지 않습니다. 배포판의 다른 버전에서.

그러나 이것이 작동한다면 C ++ 코드 (또는 C ++ 런타임 지원을 사용하는 코드)는 동적으로 링크 될 수 없습니다.

이것은 사실이 아닙니다.

즉, 정적으로 연결하는 libstdc++.a것이 하나의 옵션입니다.

라이브러리를 동적으로로드하는 경우 (를 사용하여 dlopen) 작동하지 않을 수있는 이유 는 종속 된 libstdc ++ 기호가 (정적으로) 링크 할 때 애플리케이션에 필요하지 않았기 때문에 해당 기호가 실행 파일에 표시되지 않기 때문입니다. 이는 공유 라이브러리를 동적으로 링크하여 해결할 수 있습니다 libstdc++.so(이에 의존하는 경우 어쨌든 수행하는 것이 옳습니다.) ELF 기호 삽입은 실행 파일에있는 기호를 공유 라이브러리에서 사용하지만 다른 것은 사용하지 않음을 의미합니다. 실행 파일에있는 파일은 libstdc++.so링크 된 모든 위치 에서 찾을 수 있습니다. 애플리케이션이 사용 dlopen하지 않는 경우에는 신경 쓸 필요가 없습니다.

또 다른 옵션 (그리고 내가 선호하는 옵션)은 libstdc++.so애플리케이션과 함께 최신 버전을 배포하고 기본 시스템 앞에 있는지 확인하는 것입니다 libstdc++.so. 이는 $LD_LIBRARY_PATH실행시 환경 변수를 사용하여 동적 링커가 올바른 위치를 찾도록 강제함으로써 수행 할 수 있습니다. 시간 또는 RPATH링크 시간에 실행 파일을 설정하여 . RPATH응용 프로그램이 작동하도록 올바르게 설정된 환경에 의존하지 않기 때문에 사용하는 것을 선호합니다 . 당신이 응용 프로그램을 연결하면 '-Wl,-rpath,$ORIGIN'(확장하려고 쉘을 방지하기 위해 작은 따옴표를 참고 $ORIGIN한 후 실행 파일이 것) RPATH으로 $ORIGIN하는 자체 실행 파일과 같은 디렉토리에 공유 라이브러리를 찾기 위해 동적 링커를 알려줍니다. 새로운 것을 넣으면libstdc++.so실행 파일과 동일한 디렉토리에서 런타임에 발견되고 문제가 해결됩니다. (또 다른 옵션은 실행 파일 /some/path/bin/과 최신 libstdc ++. so 를 넣고 실행 파일 관련된 다른 고정 위치에 /some/path/lib/연결 '-Wl,-rpath,$ORIGIN/../lib'하고 RPATH를에 상대적으로 설정하는 것입니다. $ORIGIN)


Jonathan Wakely의 탁월한 답변에 추가 된 사항 중 하나는 dlopen ()이 문제가되는 이유입니다.

GCC 5의 새로운 예외 처리 풀 ( PR 64535PR 65434 참조)로 인해 libstdc ++에 정적으로 링크 된 라이브러리를 dlopen 및 dlclose하면 매번 풀 객체의 메모리 누수가 발생합니다. 따라서 dlopen을 사용할 가능성이 있다면 libstdc ++를 정적으로 링크하는 것은 정말 나쁜 생각처럼 보입니다. 이것은 PR 65434에 언급 된 양성 누출과는 대조적으로 실제 누출 입니다.


동적 glibc에 의존하지 않는지 확인해야 할 수도 있습니다. 실행 ldd하여 결과 실행과 동적 종속성을주의 (libc의 / libm의 / libpthread의 USAL 용의자).

추가 연습은이 방법론을 사용하여 관련 C ++ 11 예제를 빌드하고 실제 10.04 시스템에서 결과 바이너리를 실제로 시도하는 것입니다. 대부분의 경우 동적 로딩으로 이상한 작업을 수행하지 않는 한 프로그램이 작동하는지 또는 충돌하는지 즉시 알 수 있습니다.


Jonathan Wakely의 답변에 다음을 추가하고 싶습니다.

주위 재생 -static-libstdc++리눅스에, 나는의 문제에 직면했습니다 dlclose(). 정적으로 연결된 애플리케이션 'A'가 libstdc++있고 libstdc++런타임에 플러그인 'P'에 동적으로 연결된로드 한다고 가정 합니다. 괜찮아. 그러나 'A'가 'P'를 언로드하면 분할 오류가 발생합니다. 내 가정은 언로드 후 libstdc++.so'A'가 더 이상 관련 기호를 사용할 수 없다는 것 libstdc++입니다. 'A'와 'P'가 모두에 정적으로 연결되어 libstdc++있거나 'A'가 동적 으로 연결되고 'P'가 정적으로 연결되어 있으면 문제가 발생하지 않습니다.

요약 : 애플리케이션이에 동적으로 링크 될 수있는 플러그인을로드 / 언로드하는 경우 libstdc++앱도 동적으로 링크 되어야합니다. 이것은 단지 내 관찰이며 귀하의 의견을 듣고 싶습니다.


RPATH에 관한 Jonathan Wakely의 답변에 대한 추가 기능 :

RPATH는 문제의 RPATH가 실행중인 응용 프로그램 의 RPATH 인 경우에만 작동합니다 . 자체 RPATH를 통해 라이브러리에 동적으로 연결되는 라이브러리가있는 경우 라이브러리의 RPATH를로드하는 응용 프로그램의 RPATH가 덮어 씁니다. 이는 애플리케이션의 RPATH가 라이브러리의 RPATH와 동일하다는 것을 보장 할 수없는 경우에 발생하는 문제입니다. 예를 들어 종속성이 특정 디렉토리에있을 것으로 예상하지만 해당 디렉토리가 애플리케이션의 RPATH의 일부가 아닌 경우입니다.

예를 들어 GCC 4.9의 libstdc ++. so.x에 동적으로 연결된 종속성이있는 App.exe 응용 프로그램이 있다고 가정 해 보겠습니다. App.exe는 RPATH를 통해이 종속성을 해결합니다.

App.exe (RPATH=.:./gcc4_9/libstdc++.so.x)

이제 GCC 5.5의 libstdc ++. so.y에 동적으로 연결된 종속성이있는 다른 라이브러리 Dependency.so가 있다고 가정 해 보겠습니다. 여기서 종속성은 라이브러리의 RPATH를 통해 해결됩니다.

Dependency.so (RPATH=.:./gcc5_5/libstdc++.so.y)

App.exe가 Dependency.so를로드 할 때 라이브러리의 RPATH를 추가하거나 앞에 추가하지 않습니다 . 전혀 상담하지 않습니다. 고려되는 유일한 RPATH는 실행중인 응용 프로그램의 RPATH이거나이 예에서 App.exe입니다. 즉, 라이브러리가 gcc5_5 / libstdc ++. so.y에 있지만 gcc4_9 / libstdc ++. so.x에는없는 기호에 의존하는 경우 라이브러리가로드되지 않습니다.

나는 과거에 이러한 문제를 직접 겪었으므로 이것은 경고의 한마디입니다. RPATH는 매우 유용한 도구이지만 구현에는 여전히 몇 가지 문제가 있습니다.

참고 URL : https://stackoverflow.com/questions/13636513/linking-libstdc-statically-any-gotchas

반응형