Какую версию библиотеки C использует моя система?

43

Как я могу точно сказать, какую пользовательскую библиотеку C использует моя система? Возможные причины, по которым эта информация нужна:

  • Есть гигантский пакет с исходным кодом, который я собираюсь загрузить, и я уверен, что он сделает правильные проверки и перечислит версию библиотеки mininum, но я бы предпочел избавить себя от потенциальных хлопот, проверив сначала, будет ли он работать.

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

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

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

лютик золотистый
источник
Почему бы не попробовать и посмотреть. Я не знаю, если версия говорит вам все; как насчет патчей? Или диструбуции осторожны при изменении ABI? Разве проблема не в том, разрешены ли экспортируемые символы или что-то в этом роде?
Фахим Митха
Хорошие ответы, но никто не рассматривает, как это сделать на Mac, где его нет ldd. Я не уверен, что otool --versionможно рассматривать как предоставление той же информации.
Dubiousjim
@dubiousjim Кто-то мог; только не я, потому что я не пользователь Mac. Здесь вам, возможно, придется спросить конкретно об этом - отчасти проблема в том, что, возможно, люди обычно не используют обычный C на OSX? Но я уверен, что будет постоянный, кто знает. Вы также можете опубликовать ссылку на это в чате и посмотреть, что произойдет, но, возможно, будет лучше новый, более конкретный вопрос.
Златовласка

Ответы:

50

Системы GNU / Linux обычно используют либо glibc (семейство Fedora / Redhat, Arch), либо его близкий родственник, eglibc (семейство Debian / Ubuntu); поскольку eglibc теперь объединяется с glibc ( см. ветку EGLIBC 2.19, созданную в разделе «Новости» ), в ближайшем будущем все они снова будут glibc.

Самый простой способ проверить точную версию - спросить ldd, которая поставляется с библиотекой C.

На 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

Это, например, 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.
лютик золотистый
источник
Что делает систему GNU / Linux "нормальной"? А как насчет дистрибутивов, использующих musl ?
Эллиотт Фриш
1
@ElliottFrisch Он был предназначен для применения к GNU / Linux, как в «нормальном GNU / Linux» (прилагательное, существительное), поскольку могут существовать (я уверен) системы, которые не используют (e) glibc, но делают используйте остальную часть стека GNU (bash, binutils и т. д.). Я бы рассмотрел эти "необычные" системы GNU / Linux. Но я удалил «нормальный» и изменил на «GNU / Linux системы обычно используют ...». Примечание. Я намеренно оставил вопрос открытым в отношении особенностей ОС WRT (нет тегов linux, GNU или glibc), поэтому, если вы хотите добавить ответ относительно любой системы, подходящей для U & L, сделайте это.
Златовласка
1
После того, как я нашел его, как вы показали, и запросил версию, он также распечатал доступные расширения! (в моем случае заглушки, crypt, libidn, нативные потоки и связывание) и ссылаются на ABI: libc ABI: UNIQUE IFUNC.
Debian использует /lib/`uname -m`*путь. Так переносимый способ будет: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Спасибо за приятное объяснение.
Певик
@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)

Теперь у вас есть путь к библиотеке 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.

ПРИМЕЧАНИЕ. Утилита пакетов Debian dpkg-shlibdepsиспользует objdumpскрытую информацию вместе с хранимой информацией о символах в пакетах библиотек Debian для определения минимальных версий зависимостей, требуемых бинарными пакетами Debian во время сборки. По сути, он просматривает символы, экспортируемые двоичным пакетом Debian, а затем находит минимальные версии библиотек, которые содержат эти символы.

derobert
источник
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, хотя еще тогда вы могли проверить (теперь уже удаленный) 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__не определено, вы получите ошибки, то пришло время для плана 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мой билд окр дуется сегодня , поэтому я не могу подтвердить.)

В маловероятном случае, если вы используете dietlibc , при запуске diet -vбудет отображаться версия.

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

mr.spuratic
источник
5

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

К сожалению, единственный способ узнать наверняка - попробовать.

vonbrand
источник
+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 или что-то более экзотическое.

zwol
источник
2
Ну, вам не нужно знать полный путь к / bin / sh или что-то еще. Вы можете всегда $ ldd $(which sh) | grep libc. : D
Мэтт Нордхофф
5

Еще один способ получить это:

getconf GNU_LIBC_VERSION
cuonglm
источник
Хороший, это должно работать надежно, так как glibc-2.3.3.
mr.spuratic