неділю, 20 грудня 2009 р.

Деякі проблеми лінкування динамічних бібліотек на AIX

На жаль, не зміг опублікувати це по свіжих слідах, тому спробую зробити це по пам'яті і старих записках.

Якось я майже два тижні витратив на вирішення проблеми, пов'язаної з лінкуванням динамічних бібліотек на IBM AIX 5.1.

Проблема полягала в тому, що створена динамічна бібліотека викликала падіння аплікації при спробі використати будь-яку функцію з бібліотеки, що означало, що бібліотека зібрана не так, як слід. Дослідження показало, що проблема була в тому, що на AIX слід явно експортувати всі необхідні символи, причому як від бібліотеки до програми, так і в зворотньому напрямку.

Граючись із різними опціями та читаючи документацію, я виявив, що зараз (починаючи з IBM AIX 5.1) замість цілого ряду опцій для включення створення динамічної бібліотеки, дозволу run-time лінкування, та ін., можна використати всього лише опцію -G, яка вкаже лінкеру на необхідність створення shared object з можливістю run-time лінкування. Також слід вказати опцію -bE:exportlist де "exportlist" -- назва файлу зі списком символів (класів та функцій) з бібліотеки, які мають бути викликані з головної аплікації.
Якщо ми використовуємо run-time лінкування, головна аплікація має бути зібрана з опцією -brtl. Для самої аплікації також слід вказати -bE:exportlist_app, де "exportlist_app" -- назва файлу з символами, які експортуються з аплікації, щоб бути видимими у бібліотеці.

У моєму випадку "exportlist" бібліотеки містив її функції та клас "theApplication" з іншої бібліотеки. Файл "exportlist_app" для аплікації містив лише клас "theApplication", інакше у бібліотеці символ "theApplication" з аплікації був недоступний. В результаті це символ у програмі був оголошений двічі -- один раз явно проініціалізований у головній аплікації, а інший -- із конструктором по замовчуванню в моїй бібліотеці, що приводило до падіння аплікації (хоча явного виклику конструктора чи створення об'єкта класу і не було, через недоступність об'єкта класу з аплікації, лінкер створював новий об'єкт у бібліотеці).

Узагальнюючи, ось процес створення динамічної бібліотеки на IBM AIX:
  1. Скомпілювати кожен вихідний файл в об'єктний файл, без лінкування. Наприклад:
    xlc -c foo.c -o foo.o
  2. Створити експортний файл, у якому перераховуються глобальні символи, які мають бути експортовані. Автоматичний спосіб генерує багато зайвого, тому я створював вручну, щось типу такого:
    function_one
    function_two
    ....
    class_one
    ....
  3. Використати опцію -G для створення динамічної бібліотеки зі згенерованих об'єктних файлів, щоб мати символи, які лінкуються до аплікації під час завантаження, і опцію лінкера -bE для вказання імені експортного файлу. (Також можна використати опцію -qmkshrobj для вказання пріоритету для C++ shared object; див. Initializing static objects in libraries (C++).) Наприклад:
    xlc -G -o libfoo.so foo1.o foo2.o -bE:exportlist
  4. Злінкувати бібліотеку з головною аплікацією, якщо бібліотека використовує run-time лінкування, додати опцію -brtl (а також -bE за потребою):
    xlc  -bE:main.exp -brtl -o myprogram main.c -Ldirectory -lfoo