Яку версію бібліотеки С використовує моя система?


43

Як я можу точно сказати, яку бібліотеку користувача C використовує моя система? Можливі причини необхідності цієї інформації включають:

  • Є гігантський пакет джерел, який я розглядаю як завантажити, який, напевно, проведу належну перевірку і перелічує мінімальну версію бібліотеки, але я б краще врятувати себе потенційним клопотом, перевіривши спочатку, чи він спрацює.

  • Мене турбує сумісність ABI з деякими сторонніми бінарними файлами, які я хочу спробувати встановити поза системою управління пакетами системи.

  • У мене є вихідний пакет, який у документації згадує про необхідність мінімальної версії бібліотеки моєї системи, але процес збирання не проводить жодних перевірок.

  • Я будую крос-компілятор, орієнтований на конкретну систему, і не хочу ризикувати проблемами сумісності вперед .


Чому б не спробувати і подивитися. Я не знаю, чи все вам розповідає версія; що з патчами? Або дистрибутори обережні щодо зміни ABI? Чи не проблема в тому, чи вирішено експортовані символи, чи щось подібне?
Faheem Mitha

Приємні відповіді, але ніхто не звертається, як це зробити на Mac, де його немає ldd. Я не впевнений, чи otool --versionможна вважати, що вони дають ту саму інформацію.
сумнівним,

@dubiousjim Хтось міг; просто не я, бо я не користувач Mac. Тут, можливо, вам доведеться запитати конкретно про це - частина проблеми, можливо, люди, як правило, зазвичай не використовують звичайний C багато на OSX? Але я впевнений, що знайдеться черговий, хто знає. Ви також можете опублікувати посилання на це в чаті і подивитися, що трапиться, але, напевно, краще буде нове, більш конкретне питання.
goldilocks

Відповіді:


50

Системи GNU / Linux зазвичай використовують або glibc (родина Fedora / Redhat, Arch), або його близького родича, наприклад, eglibc (родина Debian / Ubuntu); Оскільки eglibc тепер об'єднаний назад у glibc ( див. EGLIBC 2.19 Відділення, створене у розділі "Новини" ), найближчим часом вони знову стануть glibc.

Найпростіший спосіб перевірити точну версію - запитати ldd, що постачається з бібліотекою С.

У Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

Це glibc 2.18.

На Raspbian (порт Debian 7 для ARMv6 Broadcom SoC):

> 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.

Однак це не обов'язково так просто, оскільки бібліотека С не повинна десь проживати, whereisможе знайти її.

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

На жаль, сторінка man не містить номера версії. lddвсе ще стане в нагоді, оскільки будь-який працюючий, динамічно пов'язаний виконуваний файл у системі (наприклад, майже все, що знаходиться в ньому /usr/bin) буде посилатися на бібліотеку С.

> 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.

Що робить систему GNU / Linux "нормальною"? А як щодо дистрибуцій за допомогою musl ?
Елліот Фріш

1
@ElliottFrisch Мав бути застосований до GNU / Linux, як у "нормальному GNU / Linux" (прикметник, іменник), оскільки можуть бути (є, я впевнений) системи, які не використовують (e) glibc, але роблять використовувати решту стека GNU (bash, binutils тощо). Я б вважав ці "незвичайні" системи GNU / Linux. Але я видалив "звичайний" і змінив його на "системи GNU / Linux зазвичай використовують ...". Примітка. Навмисно я залишив питання відкритим для WRT OS (немає Linux або GNU або glibc тег), тому, якщо ви хочете додати відповідь стосовно будь-якої системи, відповідної U&L, будь ласка, зробіть це.
золотинок

1
Після того як я знайшов це так, як ви показали, і я запитав версію, він також надрукував доступні розширення! (у моєму випадку заглушки, склеп, libidn, рідні нитки та зв’язування) і посилаються на ABI: libc ABI: UNIQUE IFUNC.

Debian використовує /lib/`uname -m`*шлях. Так стерпний спосіб буде: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Дякую за приємне пояснення.
pevik

@pevik: Неправильно, на руку це /lib/arm-linux-gnueabihf/libc.so.6, а не /lib/armv7l/libc.so.6
скрутне

14

Система насправді не обмежена однією бібліотекою С. Більшість, однак, в основному використовують лише один, який також буде тим, який використовує компілятор за замовчуванням. А оскільки ви завантажуєте вихідний код для компіляції, саме цим ви займаєтесь.

Почніть з тривіальної програми:

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

компілюйте його за допомогою компілятора, який ви збираєтеся використовувати для вихідного коду, а потім використовуйте, lddщоб дізнатися, де знаходиться бібліотека C:

$ 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)

Тепер у вас є шлях до бібліотеки С. Ви можете знайти це у своєму менеджері пакунків, щоб знайти пакунок (наприклад, 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.

ПРИМІТКА: Утиліта пакунків Debian dpkg-shlibdepsвикористовує objdumpпід кришкою разом із збереженою інформацією символів у пакунках бібліотеки Debian для визначення мінімальних версій залежностей, необхідних для двійкових пакунків Debian під час збирання. В основному, він переглядає символи, експортовані двійковим пакетом Debian, а потім знаходить мінімальні версії бібліотек, які містять ці символи.


9

Очевидною відповіддю, хоча і не найбільш вичерпною, є перевірка менеджера пакунків, наприклад

rpm -qi glibc
dpkg -l libc6

(На жаль, у glibc немає .pcфайлу pkconfig , тому pkgconfig --modversion glibcце не є учасником.) Дивіться також чудову getconfпропозицію @ Gnouc .

Найпростіший випадок, що стосується gcc + glibc, і той, який я в основному використовую перший, - це просто виконати libc.so, як викладено в деяких інших відповідях тут. Не потрібно передавати жодних аргументів, вона виводить свою версію за замовчуванням. Це спрацьовує, наскільки glibc-2.1 (glibc-2.0 seg-несправності, хоча назад, тоді ви можете перевірити glibcbugсценарій (зараз у відставці) для підтвердження версії). Цей метод також працює з останніми (> 0,9.15) версіями musl-libc (що минуло 1,0 сьогодні, 20 березня). Він не працює з 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, <stdio.h>включає, <features.h>що визначає відповідні макроси GLIBC, вам потрібні <gnu/libc-version.h>декларації функції.)

Це фіксує більш складні випадки (декілька libc та / або декілька компіляторів), припускаючи, що ви, звичайно, використовуєте правильний компілятор (і прапори). (Я підозрюю, що він не дозволить розрізнити власне eglibc та glibc.)

Якщо ви впевнені, що використовуєте glibc (або eglibc), ldви також підтвердите версію (вибачте, це невірно).

Якщо __GNU_LIBRARY__не визначено, ви отримаєте помилки, тоді настає час для плану Б.

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мій білд окр дметься сьогодні , тому я не можу підтвердити.)

У тому випадку, коли ви використовуєте dietlibc , запущена diet -vверсія відобразить версію.

(FWIW, протягом декількох років із програмним забезпеченням, що використовує autoconf, у мене було більше проблем із неперевіреною системою gccта g++вимогами, ніж із перевіреними функціями glibc.)


5

GNU libc (те, що більшість дистрибутивів Linux використовує в тій чи іншій формі) має великі зусилля, щоб зберігати сувору зворотну сумісність. Тож у вас виникають проблеми, лише якщо ви спробуєте запустити занадто новий бінарний файл на старій версії (або "корпоративний" дистрибутив, вони зазвичай заморожують версії, особливо основні, такі як бібліотека C, підтримуючи виправлення, зберігаючи сувору бінарну сумісність) . Я вважаю, що ви набагато більш схильні до виникнення проблем з іншими бібліотеками (у C ++ було кілька змін API / ABI в останній пам'яті; деякі інші бібліотеки просто не переймаються зворотною сумісністю).

На жаль, єдиний спосіб дізнатися напевно - спробувати.


+1 Насправді у них є діаграма щодо зворотної сумісності, і я вважаю, що єдина причина, що це не все на 100% - це код, який використовує езотеричні розширення GNU. Однак немає такої діаграми, про яку я знаю щодо сумісності вперед , що, як ви зазначаєте, викликає більшу стурбованість.
золотинок

5

(Це по суті те саме, що відповідь золотокрилих, але ще з деяким поясненням того, що відбувається під капотом.)

Основна спільна бібліотека для 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 або чимось більш екзотичним.


2
Ну, вам не потрібно знати повний шлях до / bin / sh чи будь-який інший. Ви завжди можете $ ldd $(which sh) | grep libc. : D
Метт Нордхофф

5

Ще один спосіб отримати це:

getconf GNU_LIBC_VERSION

Приємно, що це має надійно працювати, оскільки glibc-2.3.3.
mr.spuratic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.