Вопрос линкера ld: опция --whole-archive - PullRequest
36 голосов
/ 30 апреля 2009

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

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

Спасибо

Ответы [ 5 ]

59 голосов
/ 09 мая 2009

Существуют допустимые варианты использования --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, например с расширением __attribute__((constructor)) GNU.

9 голосов
/ 07 февраля 2011

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

4 голосов
/ 04 мая 2009

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

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

3 голосов
/ 27 октября 2015

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

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

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

0 голосов
/ 10 января 2017

Еще один хороший сценарий, в котором --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

Если не вставить --whole-archive, будет отключена функция c(), которая в любом случае используется program, что помешает правильному процессу компиляции.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...