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

Why does the order in which libraries are linked sometimes cause errors in GCC?


479
vote

проблема

русский

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

Английский оригинал

Why does the order in which libraries are linked sometimes cause errors in GCC?

</div
     
 
 

Список ответов

584
 
vote

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


Общие файлы, разделяемые всеми следующими командами

 <код> $ 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   

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

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

Если статическая библиотека зависит от другой библиотеки, но другая библиотека снова зависит от прежней библиотеки, существует цикл. Вы можете решить это, включив циклически-зависимые библиотеки по <код> -( и <код> -) , например <код> -( -la -lb -) (вам может потребоваться сбежать в Parens, например <Код> -( и <код> -) ). Затем линкер ищет те прилагаемые Lib несколько раз, чтобы обеспечить разрешение на велосипедные зависимости. В качестве альтернативы, вы можете указать библиотеки несколько раз, поэтому каждый - до другой: <Код> -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 не использует этот флаг по умолчанию, поэтому он не дал ошибку, чтобы не следовать правильному порядку.

Неправильно пропустить зависимость <код> $ 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 0 против <код> $ 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 1 при создании первого. Вам потребуется указать библиотеку при ссылке <код> $ 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 2 тогда, но <код> $ 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 3 не нужен целое число <код> $ 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 4 сам, так что не должно быть сделанным, чтобы заботиться о <Кодекс> $ 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 5 Собственные зависимости.

Вот пример последствий, если вы пропустите указание зависимостей для <код> $ 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 6

 <код> $ 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 7  

Если вы сейчас смотрите в какие зависимости двоичные данные, вы отмечаете, что сам двоина зависит также на <код> $ 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 8 , а не только <Код> $ 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 9 , как оно должно. Двоичный файл должен быть снят, если <код> -(0 позже зависит от другой библиотеки, если вы сделаете это таким образом. И если кто-то еще загружает <код> -(1 с использованием <код> -(2 во время выполнения (Думайте о загрузке плагинов динамически), вызов также не удается. Таким образом, <код> -(3 действительно должен быть <код> -(4 .

 

(See the history on this answer to get the more elaborate text, but I now think it's easier for the reader to see real command lines).


Common files shared by all below commands

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

Linking to static libraries

$ 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 

The linker searches from left to right, and notes unresolved symbols as it go. If a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).

Dependencies of static libraries against each other work the same - the library that needs symbols must be first, then the library that resolves the symbol.

If a static library depends on another library, but the other library again depends on the former library, there is a cycle. You can resolve this by enclosing the cyclically dependent libraries by -( and -), such as -( -la -lb -) (you may need to escape the parens, such as -( and -)). The linker then searches those enclosed lib multiple times to ensure cycling dependencies are resolved. Alternatively, you can specify the libraries multiple times, so each is before one another: -la -lb -la.

Linking to dynamic libraries

$ 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 

It's the same here - the libraries must follow the object files of the program. The difference here compared with static libraries is that you need not care about the dependencies of the libraries against each other, because dynamic libraries sort out their dependencies themselves.

Some recent distributions apparently default to using the --as-needed linker flag, which enforces that the program's object files come before the dynamic libraries. If that flag is passed, the linker will not link to libraries that are not actually needed by the executable (and it detects this from left to right). My recent archlinux distribution doesn't use this flag by default, so it didn't give an error for not following the correct order.

It is not correct to omit the dependency of b.so against d.so when creating the former. You will be required to specify the library when linking a then, but a doesn't really need the integer b itself, so it should not be made to care about b's own dependencies.

Here is an example of the implications if you miss specifying the dependencies for 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" 

If you now look into what dependencies the binary has, you note the binary itself depends also on libd, not just libb as it should. The binary will need to be relinked if libb later depends on another library, if you do it this way. And if someone else loads libb using dlopen at runtime (think of loading plugins dynamically), the call will fail as well. So the "right" really should be a wrong as well.

</div
 
 
         
         
110
 
vote

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

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

 

The GNU ld linker is a so-called smart linker. It will keep track of the functions used by preceding static libraries, permanently tossing out those functions that are not used from its lookup tables. The result is that if you link a static library too early, then the functions in that library are no longer available to static libraries later on the link line.

The typical UNIX linker works from left to right, so put all your dependent libraries on the left, and the ones that satisfy those dependencies on the right of the link line. You may find that some libraries depend on others while at the same time other libraries depend on them. This is where it gets complicated. When it comes to circular references, fix your code!

</div
 
 
       
       
57
 
vote

Вот пример, чтобы понять, как все работает с 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   
 

Here's an example to make it clear how things work with GCC when static libraries are involved. So let's assume we have the following scenario:

  • myprog.o - containing main() function, dependent on libmysqlclient
  • libmysqlclient - static, for the sake of the example (you'd prefer the shared library, of course, as the libmysqlclient is huge); in /usr/local/lib; and dependent on stuff from libz
  • libz (dynamic)

How do we link this? (Note: examples from compiling on Cygwin using 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 
</div
 
 
37
 
vote

Если вы добавите <код> -Wl,--start-group на флаги линкера, он не заботится, какой заказ они или если есть круговые зависимости.

на Qt Это означает, что добавление:

 <код> main()0  

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

 

If you add -Wl,--start-group to the linker flags it does not care which order they're in or if there are circular dependencies.

On Qt this means adding:

QMAKE_LFLAGS += -Wl,--start-group 

Saves loads of time messing about and it doesn't seem to slow down linking much (which takes far less time than compilation anyway).

</div
 
 
9
 
vote

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

 <код> main()1  

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

 

Another alternative would be to specify the list of libraries twice:

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

Doing this, you don't have to bother with the right sequence since the reference will be resolved in the second block.

</div
 
 
5
 
vote

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

 <код> main()2  

почти равен

 <код> main()3  

осторожно!

  1. Заказ в группе важен! Вот пример: библиотека отладки имеет рутину отладки, но не отладка Библиотека имеет слабую версию того же. Вы должны поставить библиотеку отладки Сначала в группе или вы будете разрешаться на не отладочную версию.
  2. Вам нужно предшествовать каждой библиотеке в списке групп с -xLinker
 

You may can use -Xlinker option.

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

is ALMOST equal to

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

Careful !

  1. The order within a group is important ! Here's an example: a debug library has a debug routine, but the non-debug library has a weak version of the same. You must put the debug library FIRST in the group or you will resolve to the non-debug version.
  2. You need to precede each library in the group list with -Xlinker
</div
 
 
5
 
vote

Быстрый совет, который покончил мне: если вы вызываете линкер как «GCC» или «G ++», то используя «--start-Group» и «- - DENT-GROUP» не пройдет те параметры через линкер - и не сделает ошибку. Он просто не удастся от ссылки с неопределенными символами, если у вас был ошибочный заказ библиотеки.

Вам нужно написать их как «-WL, - START-GROUP» и т. Д. Для того, чтобы сообщить GCC, чтобы пройти аргумент к линкеру.

 

A quick tip that tripped me up: if you're invoking the linker as "gcc" or "g++", then using "--start-group" and "--end-group" won't pass those options through to the linker -- nor will it flag an error. It will just fail the link with undefined symbols if you had the library order wrong.

You need to write them as "-Wl,--start-group" etc. to tell GCC to pass the argument through to the linker.

</div
 
 
2
 
vote

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

 

Link order certainly does matter, at least on some platforms. I have seen crashes for applications linked with libraries in wrong order (where wrong means A linked before B but B depends on A).

</div
 
 
2
 
vote

Я видел это много, некоторые из наших модулей ссылаются, превышающие 100 библиотек нашего кода Plus System & AMP; 3-я вечеринка Libs.

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

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

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

Мой старый лектор, который говорил, « High Cohenion & AMP; низкое соединение », сегодня все еще верно.

 

I have seen this a lot, some of our modules link in excess of a 100 libraries of our code plus system & 3rd party libs.

Depending on different linkers HP/Intel/GCC/SUN/SGI/IBM/etc you can get unresolved functions/variables etc, on some platforms you have to list libraries twice.

For the most part we use structured hierarchy of libraries, core, platform, different layers of abstraction, but for some systems you still have to play with the order in the link command.

Once you hit upon a solution document it so the next developer does not have to work it out again.

My old lecturer used to say, "high cohesion & low coupling", it’s still true today.

</div
 
 

Связанный проблема

0  Mingw-W64 + CodeBlocks: нет такого файла или каталога  ( Mingw w64 codeblocks no such file or directory ) 
Я установил mingw-w64 , чтобы иметь компилятор 64-бит. Я использовал кодовые блоки как IDE, и у меня до 32 бита mingw , который работает очень хорошо. Моя О...

4  Удалите комментарии, созданные CPP  ( Remove the comments generated by cpp ) 
Я использую <код> <?xml version="1.0" encoding="utf-8" ?> <multistatus xmlns="DAV:"> <response> <href>/caldav.php/user/calendar_path/</href> <propstat> ...

10  Поделинный библиотечный конструктор не работает  ( Shared library constructor not working ) 
В моей общей библиотеке я должен сделать определенную инициализацию при времени загрузки. Если я определим функцию с атрибутом GCC <Код> __attribute__ ((const...

8  Компиляция с GCC (Cygwin на Windows)  ( Compiling with gcc cygwin on windows ) 
У меня есть Cygwin в окнах, через которые я запускаю GCC. Но после создания файлов .exe, если я запускаю их на других компьютерах, которые не имеют Cygwin, он...

0  Minifmod Compilation  ( Minifmod compilation ) 
Я начинаю разработку, и все же имея много проблем, выходящих с момента, когда я пытаюсь немного пойти немного за пределами. Я обычно работаю с CodeBlocks и пр...

25  Если std :: unique_ptr <void> разрешено  ( Should stdunique ptrvoid be permitted ) 
Это очень простой вопрос. Рассмотрим следующий код: <код> #include <iostream> #include <memory> typedef std::unique_ptr<void> UniqueVoidPtr; int main() { ...

1342  Фатальная ошибка: Python.h: нет такого файла или каталога  ( Fatal error python h no such file or directory ) 
Я пытаюсь создать общую библиотеку, используя файл расширения C, но сначала я должен создать выходной файл, используя команду ниже: <Код> gcc -Wall utilsmod...

0  OpenGL: gl_depth_component24 не определен  ( Opengl gl depth component24 not defined ) 
Добрый день, Настройка: . Я никогда не делал никакого программирования GL. Я пытаюсь скомпилировать opengl Код драйвера, который компилирует в других ср...

0  вилка с GCC на окнах  ( Fork with gcc on windows ) 
Я использую вилку в моей программе в Windows, используя GCC (Cygwin). Он работает нормально в моей системе. Но я хочу бежать в других системах, которые не име...

2  Не удается найти `lcrypto` или` lssl`, когда строится с грузом  ( Cannot find lcrypto or lssl when building with cargo ) 
Rust и Cargo от 30/12/2014. GCC 4.8.3. Я получил следующее сообщение на <Код> cargo run внутри каталога проекта. <код> error: linking with `gcc` failed: ...

2  Неявное преобразование оператора скрывает правила  ( Implicit conversion operator hiding rules ) 
Единственный способ, которым я вижу, чтобы представить свой вопрос, предоставляя пример сначала: <код> template<typename T> class foo { public: ...

2  Как вы можете сказать, если ELF Binary был построен с BINDNOW?  ( How can you tell if an elf binary was built with bindnow ) 
<Р> Есть ли простой способ сказать, если бинарный ELF был построен с ленивым связывания инвалидов (-Wl, -z, сейчас)? ...

0  Проблемы с компиляцией OpenMP и Math Library  ( Problems with compiling openmp and math library ) 
Я пытаюсь скомпилировать программу с OpenMP: <код> gcc -c fopenmp -lm prog.c -o prog prog.c включает в себя. Однако при запуске ./prog ошибка: <код> b...

25  Как отключить особое неизвестное предупреждение #Pragma? (GCC и / или Clang)  ( How to disable a particular unknown pragma warning gcc and or clang ) 
Я знаю, как отключить all неизвестных предупреждений #pragma. Ответ был дан, например, здесь: Итак: как отключить #Pragma Предупреждения? Мой вопрос - е...

1  Как избежать принятия персонажей, ввода в задержку в цикле?  ( How to avoid accepting characters inputted during a delay in loop ) 
У меня есть программа здесь, которая читает любой символ, который мы вводим через клавиатуру, распечатайте его, ждет период задержки 1 секунды, а затем повтор...