Есть большие проблемы с созданием статической библиотеки libtest.a
.
Во-первых, код Ады, скорее всего, вызовет систему времени выполнения Ады (RTS). Если вы создаете статическую библиотеку, вам (или вашим пользователям) нужно будет явно вызывать Ada RTS, независимо от того, используете ли вы gprbuild
. Так что ни
gcc main_c.c -ltest
ни
gprbuild -P c_main
будет достаточно; вы получите такие сбои (и хуже):
$ gcc main.c -Lada/lib -ltest
Undefined symbols for architecture x86_64:
"_ada__calendar__delays__delay_for", referenced from:
_Hello in libtest.a(hello.o)
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
Во-вторых, код на Аде может (потребуется!) потребовать доработки, выполняемой при запуске программы. Когда gprbuild
создает библиотеку, он добавляет функции testinit()
, которые ваш код C должен вызывать перед вызовом любого интерфейса библиотеки, и testfinal()
для вызова после всех использований библиотеки (большинство людей не беспокоятся) .
Чтобы обойти первую проблему, нужно создать динамическую библиотеку (.dll
в Windows, .so
в Linux и других системах Unix, .dylib
в Mac OS X). Для этого вы говорите for Library_Kind use "dynamic";
. (Обратите внимание: хотя динамическая библиотека знает, какие другие библиотеки ей нужны, она может не знать, где их найти, поэтому вам придется сделать так, чтобы они находились в пути поиска библиотек загрузчика).
Чтобы обойти вторую проблему, нужно создать то, что AdaCore называет . автономную динамическую библиотеку и заставить ее автоматически инициализироваться.
Для этого вам нужно добавить два атрибута:
for Library_Interface use (...);
задает список имен юнитов, которые вы хотите видеть за пределами библиотеки. В результате в библиотеку будут включены только исходные файлы и .ali
файлов именованных модулей; если единственные вызывающие абоненты должны быть из C, вам, вероятно, нужно назвать только одного.
for Library_Auto_Init use "true";
- Я думаю, что это на самом деле значение по умолчанию.
Я создал небольшой пример (в Mac OS X, GNAT GPL 2014).
Подкаталог ada
Файл проекта,
library project Prj is
for Languages use ("ada");
for Library_Name use "test";
for Library_Kind use "dynamic";
for Library_Interface use ("hello");
for Library_Auto_Init use "true";
for Library_Src_Dir use "include";
for Library_Dir use "lib";
for Source_Dirs use (".");
for Object_Dir use ".build";
end Prj;
привет.объявления,
function Hello return Integer;
pragma Export (C, Hello, "Hello");
привет.adb,
with Number;
function Hello return Integer is
begin
delay 0.001; -- so the tasking runtime gets called in
return Number.Value;
end Hello;
количество.объявлений,
package Number is
pragma Elaborate_Body;
Value : Integer := 0; -- before elaboration
end Number;
и число.adb
package body Number is
begin
Value := 42; -- after elaboration
end Number;
Родительский каталог
Файл проекта,
with "ada/prj";
project C_Main is
for Source_Dirs use (".");
for Languages use ("c");
for Main use ("main.c");
for Exec_Dir use ".";
for Object_Dir use ".build";
end C_Main;
и main.c
#include <stdio.h>
extern int Hello(void);
int main() {
int hello = Hello();
printf("Hello returned %d.\n", hello);
return 0;
}
Сборка
$ gprbuild -p -P c_main
gcc -c main.c
gcc -c -fPIC number.adb
gcc -c -fPIC hello.adb
gprlib test.lexch
gnatbind -n -o b__test.adb -Ltest -a /Users/simon/tmp/crychair/ada/.build/number.ali ...
gcc -c -x ada -gnatA -gnatws b__test.adb -o b__test.o ...
gcc -dynamiclib -shared-libgcc -o /Users/simon/tmp/crychair/ada/lib/libtest.dylib ... /Users/simon/tmp/crychair/ada/.build/number.o ...
ar cr libc_main.a ...
ranlib -c libc_main.a
gcc main.o -o main
и исполнение:
$ ./main
Hello returned 42.
Чтобы распространить вашу библиотеку среди пользователей C на другом компьютере без уже установленной среды выполнения Ada, вам нужно упаковать libtest.so
(или .dylib
, или .dll
) и необходимые общие библиотеки Ada.
В системе Unix это можно узнать, используя ldd libtest.so
. Вы ищете libgnat*.so
и libgnarl*.so
. Вы должны найти их в пути поиска объектов компилятора (обычно это последняя строка раздела «Путь поиска объектов» вывода gnatls -v
). Обычно это будут символические ссылки:
libgnat.so -> libgnat.1.so
libgnat.1.so -> libgnat.1.0.0.so
libgnat.1.0.0.so (the real thing)
Поместите общие библиотеки и символические ссылки в каталог с libtest.so
, скажем, product/
, тогда ваши пользователи смогут связываться с
gcc main.c -o main -Lproduct -ltest
или, может быть
gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl
В зависимости от вашей ОС полученный исполняемый файл может не найти общие библиотеки во время выполнения.
Один из способов обойти это — поместить библиотеки туда, где уже ищет загрузчик, например /usr/local/lib
(в этом случае вам не понадобится -Lproduct
).
Другой способ — указать загрузчику, где искать, установив переменную среды (LD_LIBRARY_PATH
в Linux, DYLD_LIBRARY_PATH
в Mac OS X).
Третий способ — указать компоновщику сохранить путь в исполняемом файле:
gcc main.c -o main -Lproduct -ltest -lgnat -lgnarl -Wl,-rpath,$PWD/product
работает на Mac OS X, возможно, будет и на Linux.
person
Simon Wright
schedule
08.11.2014
library project prj is
... - person Simon Wright   schedule 08.11.2014