Как работать с рекурсивными зависимостями между статическими библиотеками с помощью компоновщика binutils?

Я переношу существующую систему из Windows в Linux. Конструкция построена с несколькими статическими библиотеками. Я столкнулся с ошибкой связывания, когда символ (определенный в libA) не найден в объекте из libB. Линия компоновщика выглядела как

g++ test_obj.o -lA -lB -o test

Проблема, конечно, в том, что к тому моменту, когда компоновщик находит, что ему нужен символ из libA, он уже передал его и не выполняет повторное сканирование, поэтому он просто выдает ошибки, даже несмотря на то, что символ существует для принятия.

Моя первоначальная идея состояла в том, чтобы просто поменять ссылку (на -lB -lA), чтобы впоследствии была проверена libA, и все символы, отсутствующие в libB, которые находятся в libA, были подобраны. Но потом я нахожу, что на самом деле существует рекурсивная зависимость между libA и libB! Я предполагаю, что компоновщик Visual С++ обрабатывает это каким-то образом (он выполняет повторное сканирование по умолчанию?).

Способы решения этой проблемы, которую я рассмотрел:

  • Использование общих объектов. К сожалению, это нежелательно с точки зрения требования к PIC-усложнению (это код с высокой чувствительностью к производительности и потерять% ebx, чтобы удерживать GOT, действительно больно), а общие объекты не нужны.

  • Создайте одну мегавалюту всех объектов, избегая проблемы.

  • Реструктурируйте код, чтобы избежать рекурсивной зависимости (что, очевидно, делает Right Thing, но я пытаюсь сделать этот порт с минимальными изменениями).

Есть ли у вас другие идеи, чтобы справиться с этим? Можно ли каким-то образом убедить компоновщик binutils выполнить rescans библиотек, на которые он уже посмотрел, когда ему не хватает символа?

Ответы

Ответ 1

Просто сделайте следующее:

g++ test_obj.o -lA -lB -lA       -o test

Когда компоновщик читает первый libA в командной строке, он отбрасывает в нем объект/символы, от которых никто не зависел, например. все символы libB нужны, но не test_obj.o. Таким образом, вы просто заставляете его снова читать libA, и он также подберет эти символы.

Ответ 2

В то время как @nos предоставляет простое решение, оно не масштабируется, если задействовано несколько библиотек, а взаимные зависимости более сложны. Чтобы решить проблемы, ld предоставляет --start-group archives --end-group.

В вашем конкретном случае:

g++ test_obj.o --start-group -lA -lB --end-group -o test