[unix] 시스템에서 어떤 C 라이브러리 버전을 사용합니까?

시스템에서 어떤 유저 랜드 C 라이브러리를 사용하는지 어떻게 알 수 있습니까? 이 정보가 필요한 이유는 다음과 같습니다.

  • 다운로드를 고려하고있는 거대한 소스 패키지가 있습니다. 올바른 확인을 수행하고 최소 라이브러리 버전을 나열 할 것이지만 먼저 작동하는지 먼저 확인하여 잠재적 인 번거 로움을 덜어줍니다.

  • 시스템 패키지 관리 시스템 외부에 설치하려는 일부 타사 바이너리와의 ABI 호환성 에 대해 우려 하고 있습니다.

  • 설명서의 시스템 라이브러리 최소 버전이 필요하다고 언급 한 소스 패키지가 있지만 빌드 프로세스에서 검사를 수행하지 않습니다.

  • 특정 시스템을 대상으로하는 크로스 컴파일러를 작성 중이며 호환성 문제가 발생할 위험이 없습니다 .



답변

GNU / Linux 시스템은 일반적으로 glibc (Fedora / Redhat 제품군, Arch) 또는 가까운 사촌 인 eglibc (Debian / Ubuntu 제품군)를 사용합니다. eglibc는 이제 glibc로 다시 병합 되므로 ( “News”아래에 작성된 EGLIBC 2.19 Branch 참조 ) 조만간 모두 다시 glibc가됩니다.

정확한 버전을 확인하는 가장 쉬운 방법 ldd은 C 라이브러리와 함께 제공되는 ask 입니다.

Fedora 20에서 :

> ldd --version
ldd (GNU libc) 2.18

glibc 2.18입니다.

Raspbian (ARMv6 Broadcom SoC 용 데비안 7 포트) :

> ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2) 2.13

eglibc 2.13입니다.

어떤 이유로 든 어떤 부분을 혼합하여 일치 시키거나 확실하지 않은 ldd경우 C 라이브러리를 직접 쿼리 할 수 ​​있습니다.

> whereis libc.so
libc: /usr/lib64/libc.a /usr/lib64/libc.so /usr/share/man/man7/libc.7.gz

이들 중 어느 것도 실행 가능하지 않지만 어디서 찾을 수 있는지에 대한 단서를 제공합니다.

> $(find /usr/lib64/ -executable -name "*libc.so*") --version
GNU C Library (GNU libc) stable release version 2.18, by Roland McGrath et al.

그러나 C 라이브러리가 whereis찾을 수있는 곳에 상주하지 않아도되므로 반드시 그렇게 쉬운 것은 아닙니다 .

> whereis libc.so
libc: /usr/share/man/man7/libc.7.gz

불행하게도, 매뉴얼 페이지는 버전 번호를 제공하지 않습니다. ldd시스템에서 작동하고 동적으로 링크 된 실행 파일 (예 : 거의 모든 것 /usr/bin)이 C 라이브러리에 링크 되므로 여전히 유용 합니다.

> ldd /usr/bin/touch
    /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so (0xb6eed000)
    librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6ed0000)
    libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6da1000)
    /lib/ld-linux-armhf.so.3 (0xb6efb000)
    libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d82000)

libc.so.6 세 번째 줄에 있습니다.

> /lib/arm-linux-gnueabihf/libc.so.6 --version
GNU C Library (Debian EGLIBC 2.13-38+rpi2) stable release version 2.13, by Roland McGrath et al.


답변

시스템은 실제로 하나의 C 라이브러리로 제한되지 않습니다. 그러나 대부분은 기본적으로 하나만 사용하며 기본 컴파일러도 사용합니다. 그리고 컴파일 할 소스 코드를 다운로드하고 있기 때문에 그것이 관심이있는 것입니다.

사소한 프로그램으로 시작하십시오.

#include <stdio.h>
int main() {
    printf("Hello, world\n");
    return 0;
}

소스 코드에 사용할 컴파일러를 사용하여 컴파일 한 다음 lddC 라이브러리의 위치를 ​​찾는 데 사용 하십시오.

$ ldd ./libc-test
        linux-vdso.so.1 (0x00007fff2e5fe000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c8ad98000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8c8b171000)

이제 C 라이브러리에 대한 경로가 있습니다. 패키지 관리자에서이 패키지를 찾아 패키지를 찾을 수 있습니다 (예 : dpkg -S /lib/x86_64-linux-gnu/libc.so.6또는 rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

최소한 eglibc / glibc의 경우 다음을 실행할 수 있습니다.

$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.

당신의 단서를 얻을 수 있다면 마지막으로, 당신은 볼 수 objdump -p /lib/x86_64-linux-gnu/libc.so.6에서 보면, 버전 정의 섹션 :

Version definitions:
1 0x01 0x0865f4e6 libc.so.6
2 0x00 0x09691a75 GLIBC_2.2.5
3 0x00 0x09691a76 GLIBC_2.2.6
⋮
21 0x00 0x06969197 GLIBC_2.17
        GLIBC_2.16
22 0x00 0x06969198 GLIBC_2.18
        GLIBC_2.17
23 0x00 0x0963cf85 GLIBC_PRIVATE
        GLIBC_2.18 

GLIBC_2.18 심볼이 나열된 심볼 중에서 가장 최신 버전 번호를 가지며 라이브러리 버전은 실제로 2.18입니다. 그래도 eglibc입니다 (glibc 2.18과 바이너리 호환을 목표로하므로 동일한 심볼 버전을 사용합니다).

당신은 strings그것에 대해 뭔가를 찾기 위해 사용하려고 할 수도 있습니다. 더 긴 최소 길이 ( -n) 를 지정 하거나 grep을 사용하여 무언가를 검색하려고합니다.

$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep 'version [0-9]'
$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep -iC1 'copyright'

둘 다이 eglibc에서 작동합니다.

참고 : 데비안 패키지 유틸리티 dpkg-shlibdepsobjdump빌드시에 바이너리 데비안 패키지에 필요한 최소 버전의 종속성을 결정하기 위해 데비안 라이브러리 패키지에 저장된 심볼 정보와 함께 후드 아래를 사용합니다. 기본적으로 바이너리 Debian 패키지에서 내 보낸 심볼을보고 해당 심볼이 포함 된 라이브러리의 최소 버전을 찾습니다.


답변

가장 포괄적 인 것은 아니지만 명백한 대답은 패키지 관리자를 확인하는 것입니다.

rpm -qi glibc
dpkg -l libc6

(슬프게도 glibc에는 pkconfig .pc파일이 없으므로 pkgconfig --modversion glibc러너가 아닙니다.) @Gnouc의 훌륭한 getconf제안을 참조하십시오 .

gcc + glibc를 사용하는 가장 간단한 경우와 가장 많이 사용하는 것은 libc.so여기에있는 다른 답변 중 일부에서 설명한 것처럼 그냥 실행 하는 것입니다. 인수를 전달할 필요가 없으며 기본적으로 버전을 출력합니다. 이것은 glibc-2.1 (glibc-2.0 seg-faults glibcbug)까지 작동합니다. 이 방법은 musl-libc 의 최신 (> 0.9.15) 버전 (3 월 20 일 오늘 1.0으로 방금 )에서도 작동합니다 . uClibc에서는 작동하지 않으며 segfaults입니다.

정확히 무엇을할지 알 수있는 간단한 방법 중 하나 gcc는 컴파일입니다.

#include <gnu/libc-version.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("%s %s\n",gnu_get_libc_version(),gnu_get_libc_release());
    printf("glibc v%i %i.%i\n",__GNU_LIBRARY__,__GLIBC__,__GLIBC_MINOR__);
    return 0;
}

(glibc, 관련 GLIBC 매크로를 정의하는 <stdio.h>include 를 사용하면 함수 선언 <features.h>이 필요 <gnu/libc-version.h>합니다.)

물론 올바른 컴파일러 (및 플래그)를 사용한다고 가정하면 더 복잡한 경우 (여러 libc 및 / 또는 여러 컴파일러)를 잡을 수 있습니다. (나는 그것이 eglibc와 glibc를 제대로 구별하지 못할 것이라고 생각합니다.)

glibc (또는 eglibc)를 사용하고 있다고 확신하면 ld버전도 확인합니다 (죄송합니다, 올바르지 않습니다).

__GNU_LIBRARY__이 정의되지 않은 경우 오류가 발생하며 계획 B의 시간입니다.

gcc -dumpmachine예를 들어 uclibc의 경우 -uclibc접미사를 사용할 수 있습니다 gcc -dumpspecs | grep dynamic-linker. 이것은 또한 ABI를 암시 할 수 있습니다.

gcc -print-file-name=libc.so컴파일러가 ” -lc“에 사용할 파일을 알려줄 것입니다 . 이것은 gcc 설치에서 링커 스크립트입니다. 일반 텍스트로 읽을 수 있습니다. 정확한 경로를 보여줍니다 libc.so. -m32또는 같은 플래그를 전달하는 경우에도 작동합니다 -m64.

경우에 당신은 사용하고 uClibc가 (OpenWRT에서 더 사용)는 정의 __UCLIBC_MAJOR__, __UCLIBC_MINOR__그리고 __UCLIBC_SUBLEVEL__뿐만 아니라 __UCLIBC__에서 <features.h>그것을 쉽게 C 위의 코드에 약간의 변화를 이용하여 검출 그래서. 호환성을 위해 uClibc는 위에서 사용 된 GNU / GLIBC 매크로를 정의 할 수도 있으며 현재는 glibc-2.2 인 것처럼 가장합니다. 그것은 현재 구현되어 있지 않은 gnu_get_libc_X()기능을하지만, 않습니다 구현 getconf(나는 그것을위한 빈 대답을 반환 의심도 오해 할 수있는 getconf GNU_LIBC_VERSION그래서 난 확신 할 수 없습니다 내 빌드 ENV 오늘을 찡됩니다.)

드물게 dietlibc를 사용 하는 경우 running diet -v은 버전을 표시합니다.

(FWIW, autoconf를 사용하는 소프트웨어를 사용하여 수년에 걸쳐 확인 된 glibc 기능보다 확인 되지 않은 요구 사항 gccg++요구 사항에 더 많은 문제가있었습니다 .)


답변

GNU libc (대부분의 Linux 배포판이 한 형태 또는 다른 형태로 사용하는 것)는 이전 버전과의 호환성을 엄격하게 유지하기 위해 많은 노력을 기울입니다. 따라서 이전 버전 (또는 “엔터프라이즈”배포판에서 너무 새로운 바이너리를 실행하려고 시도하는 경우에만 문제가 발생합니다. 일반적으로 버전은 특히 C 라이브러리와 같은 기본 버전, 고정 바이너리 바이너리 호환성을 유지하면서 수정을 백 포트합니다) . 다른 라이브러리에서 문제가 발생하기 훨씬 쉽다고 생각합니다 (C ++은 최근 메모리에서 API / ABI가 약간 변경되었지만 일부 라이브러리 는 이전 버전과의 호환성을 신경 쓰지 않습니다 ).

안타깝게도 확실히 알아내는 유일한 방법은 시도하는 것입니다.


답변

(이것은 본질적으로 goldilocks의 답변과 동일하지만 후드 아래에서 일어나는 일에 대한 자세한 설명이 있습니다.)

GNU libc의 핵심 공유 라이브러리 libc.so.6(Linux의 경우 Hurd에는 다른 SONAME이 있음)에는 실행 파일로 호출 할 수있는 특별한 속성 (공유 라이브러리의 경우)이 있습니다. 그렇게하면 GNU 유틸리티가 다음과 --version같이 실행될 때 일반적으로 인쇄하는 것과 같은 종류를 출력 합니다.

$ /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.12.6 system on 2014-03-02.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

그러나 물론 libc.so.6삶이 어디에 있지 않은 디렉토리 는 $PATH어디를 찾아야하는지 알아야합니다. 그것은에있을 수 있습니다 /lib, /lib64, /usr/lib, 또는 (이 경우에서와 같이)도 wackier 뭔가. 편리하게, ldd당신에게 말할 것입니다 :

$ ldd /bin/sh | grep libc
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5660b93000)

물론 작동하려면 동적으로 연결된 이진 실행 파일의 전체 경로 이름을 알아야합니다. sh실행 파일에 보장되어있다 /bin(많은 때문에 #!스크립트가 될 것으로 기대), 그 자체는 될 수 없습니다 #!스크립트를 실행합니다. 그것은 정적으로 링크 할 수 있지만, 나는 많은 년간 그랬 시스템을 발생하지 않았습니다.

uClibc이나 musl 또는 더 이국적인 것을 사용하면 어떻게 해야할지 모르겠습니다.


답변

그것을 얻는 또 다른 방법 :

getconf GNU_LIBC_VERSION


답변