Если вы создаете статические библиотеки в одном скрипте сборки и хотите использовать эти статические библиотеки для связывания конечного исполняемого файла, важно, чтобы один из них упоминал файлы .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 секунд. Поэтому я считаю, что это того стоит.
Код здесь. Я помещаю его в общественное достояние:)