Использует -start-group и -end-группу при связывании быстрее, чем создание статической библиотеки?
Если вы создаете статические библиотеки в одном скрипте сборки и хотите использовать эти статические библиотеки для связывания конечного исполняемого файла, важно, чтобы один из них упоминал файлы .a
:
g++ main.o hw.a gui.a -o executable
Если gui.a
использует что-то определенное в hw.a
, ссылка не будет выполнена, потому что в момент обработки hw.a
компоновщик еще не знает, что определение необходимо позже, и не включает его в исполняемый исполняемый файл. Взаимодействие с линкером вручную нецелесообразно, поэтому решение должно использовать --start-group
и --end-group
, что заставляет компоновщик запускаться дважды через библиотеки, пока не будут найдены символы undefined.
g++ main.o -Wl,--start-group hw.a gui.a -Wl,--end-group -o executable
Однако в руководстве GNU ld говорится
Использование этой опции имеет значительную производительность. Лучше использовать его только тогда, когда есть неизбежные циклические ссылки между двумя или более архивами.
Итак, я подумал, что лучше всего взять все файлы .a
и объединить их в один файл .a
с индексом (-s
) GNU ar), который говорит, в каком порядке файлы должны быть связаны между собой. Затем вы указываете только один файл .a
на g++
.
Но мне интересно, быстрее или медленнее, чем с помощью групповых команд. И есть ли проблемы с этим подходом? Я также задаюсь вопросом, есть ли лучший способ решить эти проблемы взаимозависимости?
EDIT: я написал программу, которая принимает список файлов .a
и создает объединенный файл .a
. Работает с общим форматом ar
GNU. Объединение всех статических библиотек LLVM работает следующим образом
$ ./arcat -o combined.a ~/usr/llvm/lib/libLLVM*.a
Я сравнивал скорость с распаковкой всех файлов .a
вручную, а затем помещал их в новый .a
файл, используя ar
, перекомпонуя индекс. Используя мой инструмент arcat
, я получаю согласованное время работы около 500 мс. Используя ручной способ, время сильно варьируется и занимает около 2 секунд. Поэтому я считаю, что это того стоит.
Код здесь. Я помещаю его в общественное достояние:)
Ответы
Ответ 1
Вы можете определить порядок, используя утилиты lorder
и tsort
, например
libs='/usr/lib/libncurses.a /usr/lib/libedit.a'
libs_ordered=$(lorder $libs | tsort)
приводит к /usr/lib/libedit.a /usr/lib/libncurses.a
, потому что libedit зависит от libncurses.
Это, вероятно, только преимущество выше --start-group
, если вы не запускаете lorder
и tsort
снова для каждой команды связи. Кроме того, он не допускает взаимных/циклических зависимостей, таких как --start-group
.
Ответ 2
Есть ли третий вариант, когда вы просто строите единую библиотеку? У меня была аналогичная проблема, и я в конце концов решил пойти с третьим вариантом.
По моему опыту, группа медленнее, чем просто объединение файлов .a. Вы можете извлечь все файлы из архива, а затем создать новый .a файл из меньших файлов
Однако вы должны быть осторожны с тем обстоятельством, когда оба файла содержат одно и то же определение (вы можете явно проверить это, используя nm
, чтобы узнать, какие определения содержатся в каждой библиотеке)