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