Динамическая линковка C++ на AIX

AIX мне всегда нравился своим особо изощренным отношением к линковке.

Итак, рассмотрим пример (система AIX 5.3).

Файл alib.cpp компилируем как динамическую библиотеку.

struct A {
  A() {
    value_ = 123;
  }
  int value_;
};

A a = A();

extern "C"
int value() {
  return a.value_;
}

В этой библиотеке создается статический объект класса А, и значение его поля возвращается функцией value().

Компилируем:

xlC -o alib.so -qrtti=all -qmkshrobj=-100 -G -brtl -bnolibpath alib.cpp

xlC - это компилятор С++ на AIX.

Далее, файл main.c. Это головной модуль на С, который вызывает функцию value().

extern int value();

int main() {
  return value();
}

Этот модуль вызывает value(), и значение становится кодом возврата процесса.

Компилируем:

xlc -c -o main.o main.c

xlc (маленькая “с” на конце) - это компилятор С на AIX.

Линкуем, используя компилятор С, запускаем и печатаем код возврата ($?)

xlc -o main main.o alib.so && LIBPATH=.:$LIBPATH ./main ; echo $?

Результат на экране:

0

Интересно?! Почему не ожидаемое 123?

Теперь линкуем, используя компилятор “С++”, запускаем и печатаем код возврата:

xlC -o main main.o alib.so && LIBPATH=.:$LIBPATH ./main ; echo $?

Результат на экране:

123

Мораль: на AIX, при динамической линковке библиотек, чтобы правильно работала статическая инициализация на С++, надо принудительно линковать конечный бинарь в режиме С++ (как бы это странно не звучало). Иначе конструкторы статических объектов вызваны не будут, и их инициализация будет произведена не ДО функции main(), а непонятно когда.

Можно принудительно заставить таки систему вызвать конструкторы статических объектов, написав что-то вроде:

#include <dlfcn.h>

static int module_initialised = 0;
static void ManualInitilizationForStatics() {
  if (module_initialised) return;
  dlopen("blah.so", RTLD_NOW);
  module_initialised = 1;
}

Но это не программирование, а ерзанье.


Оригинальный пост | Disclaimer

Комментарии