Как вы обнаружили, не доверяйте компоновщику знать лучше, чем вы.Если заказ важен, вам нужно программно указать заказ.Не пытайтесь обмануть компоновщик.
Это то, что вы бы сделали, если бы это не были библиотеки, верно?Конструкторы / функции инициализации, которые вызывали друг друга в правильном порядке?
Мой первый выбор - создать библиотеку так, чтобы не иметь или использовать глобальные переменные.
Если вы не можете этого сделать, мой второй выбор - для каждой библиотеки, которая должна инициализировать глобальные переменные, чтобы иметьметод init.Потребители библиотеки должны вызвать этот метод init, прежде чем они смогут что-либо сделать, и библиотека должна попытаться предотвратить использование / конструирование, пока init не будет правильно выполнен.Возможно, создание статического метода для метода init и установка для них глобальных указателей (K * k) может помочь в этой реализации.Этого должно быть достаточно, чтобы объединить цепочку инициализации в правильном порядке.
Наконец, если есть препятствие для пользователя какой-либо библиотеки (имеется в виду B для A или C для B, приложение для C)вызовите метод init, вы можете использовать такие языковые расширения для gcc:
extern "C" __attribute__ ((constructor)) void A_lib_ctor()
{
// ....
}
extern "C" __attribute__ ((destructor)) void A_lib_dtor()
{
// ....
}
, чтобы автоматически делать то, что вам нужно, при загрузке библиотеки.Это жертвует некоторой переносимостью.Возможно, пожертвовав еще, более новые версии gcc поддерживают синтаксис конструктора (приоритет).
Мой последний выбор - сложные шаги по ручной загрузке библиотек с помощью dlopen.
Дизайн лучше с лучшим выбором, который подходит вам, и хуже с последующими.