Как создать ada lib.a и связать с C

Я пытаюсь создать библиотеку ada и пробовал несколько разных вещей. Я попытался скомпилировать проект с помощью make-файлов и попытаться создать библиотеку из всех файлов .o. Похоже, это не сработало, как ожидалось. Затем я обратился в службу поддержки adacore, и они указали мне направление использования файлов .gpr как для проектов ada, так и для проектов c, а также в файле ada.gpr, который должен создать библиотеку. Это почти сработало, но когда он пытается скомпилировать ada, я получаю неопределенные ссылки.

Что я пробовал: Командная строка:

ar rc libmy_lib.a *.o

и когда я пытаюсь прочитать то, что находится в библиотеке

ld libmy_lib.a

Я получаю эту ошибку ld: предупреждение: не удается найти символ входа _start; не устанавливает начальный адрес

Файлы проекта: мой файл проекта ada prj.gpr

project Prj is
for Source_Dirs use ("source1/", "source2", ....);
for Object_Dir use ".";

for Languages use ("Ada");
for Library_Name use "test";
for Library_Dir use "lib";
for Library_Interface use (
 --All my ada packages
        );

package Naming is
      for Spec_Suffix ("ada") use ".1.ada";
      for Body_Suffix ("ada") use ".2.ada";
      for Separate_Suffix use ".2.ada";
      for Dot_Replacement use ".";
   end Naming;

   package Compiler is
      for Default_Switches ("ada") use ("-v", "-g", "-gnato", "-gnatwa", "-gnatQ", "-gnat05");
   end Compiler;

   package Builder is
      for Global_Compilation_Switches ("Ada") use ("-gnat95");
   end Builder;

   package Ide is
  end Ide;

end Prj;

Мой файл проекта c c_main.gpr

with "prj.gpr";
project C_Main is
for Source_Dirs use ("source_c_1/", "source_c_2/");
for Languages use ("C");
for Main use ("source_c_1/main.c");
end C_Main;

Когда я запускаю команду gprbuild c_main.gpr

Я получил 2 разные ошибки: во-первых, это неопределенные ссылки на некоторые пакеты, которые являются частью моего кода ada, и пришли к тому, что в файлах gnat .adb я не знал, что они существуют. Итак, сломанная библиотека, я думаю. Во-вторых, поля определенных пакетов не могут быть найдены/не существуют, даже если код компилируется и работает нормально. Это выдает мне ошибки о том, что поля не существуют в коде ada.

TLDR: у меня есть проект ada в 3 разных каталогах, и я хочу создать из них библиотеку. Затем подключитесь к программе тестирования C. В конечном итоге мне просто нужно доставить файл библиотеки. Лучше всего будет командная строка. Я не хочу иметь дело с файлами проекта.


person crychair    schedule 07.11.2014    source источник
comment
Обновил мой вопрос, извините, я не думал, что мои прошлые попытки помогут. Я не думал, что это действительно ошибка. Больше отсутствие направления или что делать в первую очередь с моей стороны.   -  person crychair    schedule 07.11.2014
comment
Вы можете подтвердить, что это библиотечный проект, запустив его library project prj is ...   -  person Simon Wright    schedule 08.11.2014
comment
Я просто удалил свой ответ на это, потому что он полностью провалился, когда библиотека нуждалась в доработке (инициализации). Вернусь, когда/если найду ответ, который действительно работает.   -  person Simon Wright    schedule 09.11.2014
comment
Восстановил ответ. TL;DR: используйте динамические библиотеки, чтобы избежать видимых пользователю проблем с подключением библиотек Ada RTS и с проработкой.   -  person Simon Wright    schedule 10.11.2014


Ответы (1)


Есть большие проблемы с созданием статической библиотеки 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
comment
Большое спасибо, это очень помогло. Также несколько вещей, чтобы добавить. По какой-то причине, когда вы строите это, оно СЧИТАЕТ РЕГИСТР для имен файлов. Для моего проекта у меня был test.1.ada, а затем подпрограмма test.helloWorld.2.ada. Если бы W был заглавным, он не смог бы найти файл. Это просто безумие, что язык ada не чувствителен к регистру, но, по-видимому, gprbuild написан на c, потому что он чувствителен к регистру. - person crychair; 11.11.2014
comment
Я понимаю, что теперь это делает libtest.so. Как бы я связался с этим. Это означает, что если я передам эту библиотеку тому, у кого нет кода ada. Как бы они связались с ним. - person crychair; 11.11.2014
comment
Re: чувствительность к регистру — если вы создаете libtest.so, то вы, вероятно, работаете в системе Linux или BSD, а их файловые системы чувствительны к регистру; так что test.helloWorld.2.ada не увидит test.helloworld.2.ada. Windows и Mac OS X сохраняют регистр, но не чувствительны к нему. - person Simon Wright; 11.11.2014
comment
Re: связывание - добавлен последний раздел. Я не могу легко попробовать это здесь. - person Simon Wright; 11.11.2014
comment
Это работает без ошибок: gcc main.c mainReport.c -o main -Lproject -ltest -lgnat -lgnarl, но я получаю эту ошибку, когда пытаюсь запустить ./main: ./main: ошибка при загрузке общих библиотек: libtest .so: невозможно открыть общий объектный файл: нет такого файла или каталога. и да он находится в папке проекта с libgnarl.so и libgnat.so - person crychair; 12.11.2014
comment
Извиняюсь за то, что не попробовал это перед публикацией. Расширен последний раздел, надеюсь, он поможет вам. - person Simon Wright; 12.11.2014
comment
Вчера вечером я ложился спать и подумал, хм, а для -L нужен полный путь? Не думал о -Wl, это умно. Большое спасибо за помощь. - person crychair; 12.11.2014
comment
Извините, еще одно дополнение к вопросу. Как бы я сделал исполняемый файл C автономным. Это означает, что нужно получить то, что ему нужно, из этих библиотек, а затем иметь возможность переместить только исполняемый файл на другую машину и запустить его там. - person crychair; 12.11.2014
comment
Я думаю, что это должен быть новый вопрос! - person Simon Wright; 13.11.2014