Почему GNU ld разрешает символы по-разному при связывании исполняемых файлов и общих объектов?

У меня есть тривиальный кусок кода C ++, который выглядит примерно так:

#include <boost/timer/timer.hpp>

int main(void) {
boost::timer::auto_cpu_timer t;
return 0;
}

Я попытался скомпилировать и связать его (с gcc 4.8.1 и GNU ld 2.23.52.20130828) следующим образом:

$ g++ -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc2jP1jv.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

Одним из решений является явное упоминание -lboost_system в командной строке, и это работает. Тем не менее, я также могу сделать:

$ g++ -Wl,--copy-dt-needed-entries -o test test.cc -lboost_timer

В соответствии с документацией ld «с —copy-dt-required-entry динамические библиотеки, упомянутые в командной строке, будут рекурсивно обыскиваться, следуя их тегам DT_NEEDED для других библиотек, для разрешения символов, требуемых выходным двоичным файлом», так что это все имеет смысл: ld вычисляет из boost_timer, что ему также необходимо связать систему с boost_system для разрешения всех символов.

Тем не менее, я понял, что это также работает:

$ g++ -fPIC -shared -o test test.cc -lboost_timer

Очевидно, что теперь я сгенерировал общий объект, а не исполняемый файл. Очевидно, что ld смог выяснить, что ему нужно связать общий объект с boost_system:

$ ldd test | grep boost_system
libboost_system.so.1.54.0 => /usr/lib/libboost_system.so.1.54.0 (0x00007f385246e000)

Поэтому мой вопрос заключается в следующем: почему разрешение символов отличается при построении общего объекта от исполняемого файла? Как я могу выяснить, что мой общий объект должен быть связан с boost_system без моего указания --copy-dt-needed-entries?

7

Решение

Прямой ответ на мой вопрос в --[no-]allow-shlib-undefined вариант к лд, я думаю. Со страницы руководства:

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

Поэтому, когда я строю с -sharedсимволы в boost_system не определены, но поведение ld по умолчанию не имеет значения. Можно сказать, чтобы заботиться:

$ g++ -fPIC -shared -Wl,--no-allow-shlib-undefined -o test test.cc -lboost_timer
/usr/bin/ld: /tmp/cc6j1de3.o: undefined reference to symbol '_ZN5boost6system15system_categoryEv'
/usr/lib/libboost_system.so.1.54.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

Точно так же мы можем сказать, что это не важно при сборке исполняемого файла:

$ g++ -Wl,--allow-shlib-undefined -o test test.cc -lboost_timer
/tmp/ccUHoCIU.o: In function `__static_initialization_and_destruction_0(int, int)':
test.cc:(.text+0x7a): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x86): undefined reference to `boost::system::generic_category()'
test.cc:(.text+0x92): undefined reference to `boost::system::system_category()'
collect2: error: ld returned 1 exit status

Но создать двоичный файл не удается без определения этих символов.

Спасибо @CharlesBailey за указание мне в правильном направлении!

5

Другие решения

Существуют различия в команде collect2, которые могут иметь значение. Различные команды сравниваются в http://imgur.com/eMr2tY2 . Правая часть создает разделяемую библиотеку (-fPic -shared), левая — обычная компиляция.

0