Вопрос:

Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?

c++ gcc linker

153766 просмотра

11 ответа

7248 Репутация автора

Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?

Автор: Landon Источник Размещён: 05.09.2008 02:24

Ответы (11)


-1 плюса

5330 Репутация автора

Я полагаю, это потому, что некоторые из этих библиотек имеют зависимости от других библиотек, и если они еще не были связаны, вы получите ошибки компоновщика.

Автор: roo Размещён: 05.09.2008 02:33

3 плюса

1718 Репутация автора

Я видел это много, некоторые из наших модулей связывают более 100 библиотек нашего кода плюс системные и сторонние библиотеки.

В зависимости от разных компоновщиков HP / Intel / GCC / SUN / SGI / IBM / и т. Д. Вы можете получить неразрешенные функции / переменные и т. Д., На некоторых платформах вам придется дважды перечислять библиотеки.

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

Как только вы натолкнетесь на документ решения, чтобы следующему разработчику не пришлось снова его разрабатывать.

Мой старый лектор говорил: « высокая сплоченность и низкая связь », это все еще верно сегодня.

Автор: titanae Размещён: 05.09.2008 03:56

92 плюса

2603 Репутация автора

GNU ld linker - это так называемый умный линкер. Он будет отслеживать функции, используемые предыдущими статическими библиотеками, постоянно отбрасывая те функции, которые не используются из его справочных таблиц. В результате, если вы связываете статическую библиотеку слишком рано, то функции в этой библиотеке больше не будут доступны статическим библиотекам позже в строке ссылки.

Типичный компоновщик UNIX работает слева направо, поэтому разместите все зависимые библиотеки слева, а те, которые удовлетворяют этим зависимостям, справа от строки ссылки. Вы можете обнаружить, что некоторые библиотеки зависят от других, в то же время другие библиотеки зависят от них. Это где это становится сложным. Когда дело доходит до циклических ссылок, исправьте свой код!

Автор: casualcoder Размещён: 03.01.2009 05:21

510 плюса

409255 Репутация автора

(Посмотрите историю этого ответа, чтобы получить более сложный текст, но теперь я думаю, что читателю легче увидеть реальные командные строки).


Общие файлы, используемые всеми командами ниже

$ cat a.cpp
extern int a;
int main() {
  return a;
}

$ cat b.cpp
extern int b;
int a = b;

$ cat d.cpp
int b;

Ссылки на статические библиотеки

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o

$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

Компоновщик выполняет поиск слева направо и отмечает неразрешенные символы. Если библиотека разрешает символ, она принимает объектные файлы этой библиотеки для разрешения символа (в данном случае bo из libb.a).

Зависимости статических библиотек друг от друга работают одинаково - сначала должна быть библиотека, которая нуждается в символах, а затем библиотека, которая разрешает символ.

Если статическая библиотека зависит от другой библиотеки, но другая библиотека снова зависит от предыдущей библиотеки, существует цикл. Вы можете решить эту проблему, заключив циклически зависимые библиотеки в -(и -), например, -( -la -lb -)(вам может понадобиться экранировать символы, такие как -\(и -\)). Затем компоновщик несколько раз просматривает эти вложенные библиотеки, чтобы убедиться, что циклические зависимости разрешены. Кроме того , вы можете указать в библиотеках несколько раз, так что каждый друг перед другом: -la -lb -la.

Ссылки на динамические библиотеки

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!

$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

Здесь то же самое - библиотеки должны следовать объектным файлам программы. Разница здесь со статическими библиотеками заключается в том, что вам не нужно заботиться о зависимости библиотек друг от друга, потому что динамические библиотеки сами разбирают свои зависимости .

Некоторые недавние дистрибутивы, по-видимому, по умолчанию используют --as-neededфлаг компоновщика, который обеспечивает, чтобы объектные файлы программы предшествовали динамическим библиотекам. Если этот флаг передан, компоновщик не будет ссылаться на библиотеки, которые на самом деле не нужны исполняемому файлу (и он обнаруживает это слева направо). Мой недавний дистрибутив archlinux по умолчанию не использует этот флаг, поэтому он не выдает ошибку за несоблюдение правильного порядка.

Это не правильно опускать зависимость b.soот d.soпри создании первого. aТогда вам потребуется указать библиотеку при компоновке , но на aсамом деле само целое число не нужно b, поэтому ее не следует заботиться о bсобственных зависимостях.

Вот пример последствий, если вы пропустите указание зависимостей для libb.so

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)

$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"

Если вы теперь посмотрите на зависимости, которые есть у бинарного файла, вы заметите, что сам бинарный файл также зависит libd, а не так, libbкак должен. Бинарный файл необходимо будет повторно связать, если libbвпоследствии он зависит от другой библиотеки, если вы сделаете это таким образом. И если кто-то еще загружает libbиспользование dlopenво время выполнения (подумайте о динамической загрузке плагинов), вызов также не удастся. Так что "right"действительно должно быть wrong.

Автор: Johannes Schaub - litb Размещён: 03.01.2009 05:53

2 плюса

56676 Репутация автора

Порядок ссылок, безусловно, имеет значение, по крайней мере, на некоторых платформах. Я видел сбои для приложений, связанных с библиотеками в неправильном порядке (где неправильный означает A, связанный перед B, но B зависит от A).

Автор: David Cournapeau Размещён: 28.04.2009 01:57

49 плюса

10155 Репутация автора

Вот пример, чтобы прояснить, как работают GCC, когда задействованы статические библиотеки. Итак, давайте предположим, что у нас есть следующий сценарий:

  • myprog.o- содержащая main()функция, зависящая отlibmysqlclient
  • libmysqlclient- статический, для примера (вы бы предпочли разделяемую библиотеку, конечно, так как libmysqlclientона огромна); в /usr/local/lib; и зависит от вещей изlibz
  • libz (Динамическая)

Как мы связываем это? (Примечание: примеры компиляции на Cygwin с использованием gcc 4.3.4)

gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too

gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line

gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works
Автор: Lumi Размещён: 16.07.2011 12:32

5 плюса

51 Репутация автора

Вы можете использовать опцию -Xlinker.

g++ -o foobar  -Xlinker -start-group  -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a  -Xlinker -end-group 

ПОЧТИ равен

g++ -o foobar  -Xlinker -start-group  -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a  -Xlinker -end-group 

Осторожный !

  1. Порядок в группе важен! Вот пример: у библиотеки отладки есть подпрограмма отладки, но у библиотеки без отладки есть слабая версия той же самой. Вы должны поместить отладочную библиотеку FIRST в группу, иначе вы перейдете к неотладочной версии.
  2. Вам необходимо предшествовать каждой библиотеке в списке групп с -Xlinker
Автор: yundorri Размещён: 09.08.2011 08:06

4 плюса

106093 Репутация автора

Подсказка, которая меня смутила: если вы вызываете компоновщик как «gcc» или «g ++», то использование «--start-group» и «--end-group» не передаст эти параметры компоновщик - и при этом он не будет отмечать ошибку. Он просто потеряет связь с неопределенными символами, если вы неправильно указали порядок в библиотеке.

Вам нужно написать их как "-Wl, - start-group" и т. Д., Чтобы GCC передал аргумент компоновщику.

Автор: M.M Размещён: 11.08.2013 02:07

8 плюса

42852 Репутация автора

Другой альтернативой было бы указать список библиотек дважды:

gcc prog.o libA.a libB.a libA.a libB.a -o prog.x

При этом вам не нужно беспокоиться о правильной последовательности, поскольку ссылка будет разрешена во втором блоке.

Автор: eckes Размещён: 21.03.2014 10:07

24 плюса

468 Репутация автора

Если вы добавляете -Wl,--start-groupк флагам компоновщика, то не имеет значения, в каком порядке они находятся или существуют ли циклические зависимости.

На Qt это означает добавление:

QMAKE_LFLAGS += -Wl,--start-group

Экономит кучу времени, тратя время на компоновку, и, похоже, не сильно замедляет линковку (что в любом случае занимает гораздо меньше времени, чем компиляция).

Автор: SvaLopLop Размещён: 05.04.2015 12:24

0 плюса

1 Репутация автора

Я хочу istall Spro в alize baut, когда я запускаю make, у меня есть эта проблема:

make 2: * spro.info ошибка 127 make-файл: 639 repicepe для цели «все-рекурсивный» не выполнен make 1: все-рекурсивная ошибка 1 make-файл: 413: рецепт для цели «all» не выполнен make: * все ошибки

Автор: Hanane AMESSAFI Размещён: 12.03.2019 03:32
Вопросы из категории :
32x32