2009-04-30 4 views
25

Единственное реальное использование опции компоновщика --whole-archive, которую я видел, заключается в создании разделяемых библиотек из статических. Недавно я наткнулся на Makefile (ы), которые всегда используют этот параметр при связывании с внутренними статическими библиотеками. Это, конечно, заставляет исполняемые файлы излишне тянуть за код объекта без ссылок. Моя реакция на это заключалась в том, что это просто неправильно, я что-то упустил?Вопрос ld linker: опция -whole-archive

Второй вопрос, который у меня есть, связан с чем-то, что я прочитал относительно опции «весь архив», но не смог разобрать. Что-то в том, что опция --whole-archive должна использоваться при связывании со статической библиотекой, если исполняемый файл также связывается с общей библиотекой, которая, в свою очередь, имеет (частично) тот же объектный код, что и статическая библиотека. Это общая библиотека, а статическая библиотека перекрывается с точки зрения объектного кода. Использование этой опции приведет к тому, что все символы (независимо от использования) будут разрешены в исполняемом файле. Это должно избегать дублирования объектного кода. Это сбивает с толку, если символ реферируется в программе, он должен быть однозначно разрешен во время соединения, что это за дело о дублировании? (Простите, если этот пункт не совсем воплощение ясности)

Благодаря

ответ

3

Я согласен, что с помощью -whole-архива строить исполняемые файлы, вероятно, не то, что вы хотите (из-за связывания в ненужную коде и создание раздутого программного обеспечения). Если у них есть все основания для этого, они должны были задокументировать его в системе сборки, так как теперь вам остается угадать.

Что касается вашей второй части вопроса. Если исполняемый файл связывает как статическую библиотеку, так и динамическую библиотеку с (частично) тем же объектным кодом, что и статическая библиотека, тогда -все-архив гарантирует, что во время соединения предпочтительнее код из статической библиотеки , Обычно это то, что вы хотите, когда статичное связывание.

50

При связывании исполняемого файла со статическими библиотеками существует законное использование --whole-archive. Одним из примеров является строительство C++ код, в котором глобальные экземпляры "зарегистрировать" себя в своих конструкторах (предупреждение: непроверенный код):

main.cc

typedef void (*handler)(const char *protocol); 
typedef map<const char *, handler> M; 
M m; 

void register_handler(const char *protocol, handler) { 
    m[protocol] = handler; 
} 
int main(int argc, char *argv[]) 
{ 
    for (int i = 1; i < argc-1; i+= 2) { 
     M::iterator it = m.find(argv[i]); 
     if (it != m.end()) it.second(argv[i+1]); 
    } 
} 

http.cc (часть libhttp.a)

class HttpHandler { 
    HttpHandler() { register_handler("http", &handle_http); } 
    static void handle_http(const char *) { /* whatever */ } 
}; 
HttpHandler h; // registers itself with main! 

Обратите внимание, что в http.cc символов не указано, что main.cc нуждается. Если связать это как

g++ main.cc -lhttp 

вы не получить обработчик HTTP, связанный в основной исполняемый файл, и не будет в состоянии назвать handle_http(). Сравните это с тем, что происходит, когда вы связываете как:

g++ main.cc -Wl,--whole-archive -lhttp -Wl,--no-whole-archive 

Тот же «саморегистрации» стиль также можно в простом-C, например, с расширением GNU __attribute__((constructor)).

+1

Russion Если libhttp.a может быть построено, то это доказывает, что функция register_handler существует в этом libhttp.a. Итак, как эта функция может ссылаться на register_handler в main.cc? Поэтому в этом случае мы должны использовать другой способ реализации вашей идеи. – longbkit

9

Еще одно законное использование для --whole-archive - это для разработчиков инструментальных средств для распространения библиотек, содержащих несколько функций в одной статической библиотеке. В этом случае провайдер понятия не имеет, какие части библиотеки будут использоваться потребителем и поэтому должны включать все.

+4

s/shared/static / – Igor

1

Старый запрос, но по вашему первому вопросу («Почему»), я видел - весь архив, используемый для внутренних библиотек, в первую очередь, чтобы обойти круговые ссылки между этими библиотеками. Он, как правило, скрывает плохую архитектуру библиотек, поэтому я бы не рекомендовал его. Однако это быстрый способ получить быстрое испытание.

Для вашего второго запроса, если один и тот же символ присутствовал в общем объекте и в статической библиотеке, компоновщик будет удовлетворять ссылке с той библиотекой, с которой она встречается в первую очередь.
Если общая библиотека и статическая библиотека имеют точный код обмена, все это может работать. Но там, где общая библиотека и статическая библиотека имеют разные реализации одних и тех же символов, ваша программа все равно будет компилироваться, но будет вести себя по-разному в зависимости от порядка библиотек.

Форсирование всех символов, загружаемых из статической библиотеки, является одним из способов устранения путаницы в отношении того, что загружено с того места. Но в целом это звучит как решение неправильной проблемы; вам в основном не нужны одинаковые символы в разных библиотеках.

0

Дополнительный хороший сценарий, в котором --whole-archive хорошо используется при работе со статическими библиотеками и инкрементной привязкой.

Предположим, что:

  1. libA реализует a() и b() функции.
  2. Некоторая часть программы должна быть связана только с libA, например. из-за некоторую функцию упаковки с использованием --wrap (классический пример malloc)
  3. libC реализует c() функции и использует a()
  4. окончательная программа использует a() и c()

Добавочных соединительные шагов может быть:

ld -r -o step1.o module1.o --wrap malloc --whole-archive -lA 
ld -r -o step2.o step1.o module2.o --whole-archive -lC 
cc step3.o module3.o -o program 

Неспособность вставить - wholes-архив будет использовать функцию c() который в любом случае используется program, что предотвращает правильный процесс компиляции.

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

Смежные вопросы