eX0r
eX0r

Reputation: 53

Create a static Ada-Library which can be linked without gnat-tools

I want to Create a Static-Library from Ada-Code and deploy it to Developers without the GNAT-Toolchain (for C/C++ Code).

I will get following Linker-Errors when I try to Link Ada-Library ('.a') with a C-Program:

undefined reference to `__gnat_rcheck_CE_Overflow_Check'
undefined reference to `ada__text_io__put_line__2'

How can I achieve this ? It seams that I should link against the Runtime-library, but how ?


Test-Code:

main.c:

#include <stdio.h>

extern void adaTest();
extern int add5(int);

int main(){
  adaTest();
  int b = add5(2);
  printf("--> %d \ndone.\n", b);
  return 0;
}

ada_lib_project.gpr:

library project ada_lib_project is
    for Languages use ("Ada");
    for Library_Name use "My_Ada_Lib";
    for Library_Dir use "my_generated_lib";
    for Library_Kind use "Static";
end ada_lib_project;

adatestpacket.ads:

with Interfaces.C; use Interfaces.C;
package adatestpacket is
  procedure adatest with
    Export, Convention => C, External_Name => "adaTest";

  function add5(x: in int) return int with
    Export, Convention => C, External_Name => "add5";
end adatestpacket;

adatestpacket.adb:

with Ada.Text_IO; use Ada.Text_IO;
with Interfaces.C; use Interfaces.C;
package body adatestpacket is
  procedure adatest is
  begin
    Put_Line("This is executed ADA/SPARK-Code...");
    null;
  end adatest;

  function add5(x: in int) return int is
  begin
    return x + 5;
  end add5;
end adatestpacket;

Compiling:

gcc -c main.c -o main.o           # .c -> .o
gprbuild -P ada_lib_project.gpr   # .ad[sb] -> .a
gcc main.o -L my_generated_lib -l My_Ada_Lib -o a.out # Linking -- with undefined References

Upvotes: 3

Views: 1074

Answers (3)

eX0r
eX0r

Reputation: 53

For anyone whose interested in a Working-Implementation, these are the Changes from my Question:

main.c:

#include <stdio.h>

extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);

int main(){
  adainit();
  adaTest();
  int b = add5(2);
  printf("--> %d \ndone.\n", b);
  adafinal();
  return 0;
}

ada_lib_project.gpr:

library project ada_lib_project is
    for Languages use ("Ada");
    for Library_Name use "My_Ada_Lib";
    for Library_Dir use "my_generated_lib";
    for Library_Kind use "static-pic";
    for Library_Interface use ("adatestpacket");

    package Binder is
      -- "-Lada" set "ada" as Prefix for "init" and "final" Function
      for Default_Switches ("Ada") use ("-n","-Lada");
    end Binder;

end ada_lib_project;

Compiling:

gprbuild -P ada_lib_project.gpr # .adb -> .a
gcc main.c -L my_generated_lib -l My_Ada_Lib -l gnat_pic -ldl

For the last Command, I just need to Transfer the Library (My_Ada_Lib) and the Runtime (libgnat_pic.a) from GNAT/2021/lib/gcc/x86_64-pc-linux-gnu/10.3.1/rts-native/adalib to the remote Machine.

Upvotes: 2

&#193;lex
&#193;lex

Reputation: 1703

I have generated static binaries with -static. I don't know if something similar can work while generating your library or you will also need to have the GNAT runtime for linking with the C/C++ tools.

Upvotes: 0

flyx
flyx

Reputation: 39688

Probably the easiest way to do this is to simply also compile the C source with gprbuild (even if you can't do that in your target scenario, you can do it for testing and see with -v what GPRbuild does to get it to work):

with "ada_lib_project";

project My_Executable is
   for Languages use ("C");
   for Main use ("main.c");
end My_Executable;

You will also need to call adainit and adafinal to initialize / finalizate Ada packages:

#include <stdio.h>

extern void adainit();
extern void adafinal();
extern void adaTest();
extern int add5(int);

int main(){
  adainit();
  adaTest();
  int b = add5(2);
  printf("--> %d \ndone.\n", b);
  adafinal();
  return 0;
}

adainit and adafinal are generated by gnatbind for standalone libraries. I am not entirely sure whether GPRBuild takes care of this when seeing that you use an Ada library from a C executable; if not you'll need

package Binder is
   for Default_Switches ("Ada") use ("-n");
end Binder;

in your library. After doing this, you should be able to do

gprbuild my_executable.gpr

If you want to do it without GPRbuild, the -n/adainit/adafinal part still applies and you need to link your executable with

-l<your-gnat-lib>

where <your-gnat-lib> is the Ada standard library of your GNAT version; last time I did this, it was something like gnat-2021. You may need to add a -L<directory-containing-that-lib> depending on where it's located.

(there may be mistakes in this answer since I cannot currently test it due to being on an M1)

Edit: If you really want to supply developers without any access to GNAT, you need to build an encapsulated, i.e. dynamic, library. This answer covers that process. If providing a static library is a requirement, you have to at least supply the GNAT standard library file.

Upvotes: 4

Related Questions