I need to build a static library with a bunch of code written in Ada that can be called from code written in C/C++.
I've searched through internet and got some knowledge about gnatmake
, gnatbind
and gnatlink
, but still can't get the job done correctly.
Also, I've read there are tools that relies upon some kind of project file.
I'm not interested in those, I just need a bunch of commands to write in a Makefile
.
ar is used to create static libraries. These are used in software development. And ar is also be used to create package files such as the “.
This answer assumes you’re using the GCC toolchain.
The big hurdle is that Ada code needs elaboration (roughly, the equivalent of calling file-level constructors in C++). gnatbind is the tool that does this, and you use the flag -L
:
-Lxyz Library build: adainit/final renamed to xyzinit/final, implies -n
[...]
-n No Ada main program (foreign main routine)
As an example, consider Ada source foo.ads
,
package Foo is
procedure Impl
with
Convention => C,
Export,
External_Name => "foo";
end Foo;
or, if using Ada prior to Ada2012,
package Foo is
procedure Impl;
pragma Export (Convention => C, Entity => Impl, External_Name => "foo");
end Foo;
and foo.adb
,
with Ada.Text_IO;
package body Foo is
procedure Impl is
begin
Ada.Text_IO.Put_Line ("I am foo");
end Impl;
begin
Ada.Text_IO.Put_Line ("foo is elaborated");
end Foo;
and a similar pair of files bar.ads
, bar.adb
(s/foo/bar/g
throughout).
Compile these:
gnatmake foo bar
Bind:
gnatbind -Lck -o ck.adb foo.ali bar.ali
(this will actually generate ck.ads
as well as the named ck.adb
; these are the code that does the elaboration).
Compile the elaboration code:
gnatmake ck.adb
Generate the library:
ar cr libck.a ck.o foo.o bar.o
and you’re nearly ready to roll.
The C main program might look like
#include <stdio.h>
void ckinit(void);
void ckfinal(void);
void foo(void);
void bar(void);
int main()
{
ckinit();
printf("calling foo:\n");
foo();
printf("calling bar:\n");
bar();
ckfinal();
return 0;
}
(your main is in C++, so you’ll need extern "C" {
..., of course).
You’d think that
gcc main.c libck.a
would do the trick. However, libck
calls in the Ada runtime. Here (macOS), that means I say
gcc main.c libck.a /opt/gnat-gpl-2016/lib/gcc/x86_64-apple-darwin14.5.0/4.9.4/adalib/libgnat.a
(you can find that path using gcc --print-libgcc-file-name
)
The resulting executable runs:
$ ./a.out
bar is elaborated
foo is elaborated
calling foo:
I am foo
calling bar:
I am bar
Thank you for you great help! Actually, it worked with the following Makefile:
ada_libs := -lgnat -lgnarl
cpp_src := ...
ada_src := ...
library.so : $(cpp_src:.cc=.o) adalib.a
g++ -o $@ $^ $(ada_libs)
$(cpp_src:.cc=.o) : %.o : %.cc
g++ -c -o $@ $<
$(cpp_src:.cc=.d) : %.d : %.cc
g++ -MM -MF $@ $^
$(addprefix objects/,$(ada_src:.adb=.o)) : objects/%.o : %.adb
gnatmake -c -D objects $^
adabind.adb : $(addprefix objects/,$(ada_src:.adb=.o))
gnatbind -n -o $@ $(^:.o=.ali)
adabind.ali : adabind.adb
gnatmake -c -D objects $^
adalib.a : adabind.ali
ar cur $@ $(^:.ali=.o) objects/*.o
include $(cpp_src:.cc=.d)
Besides this, I had to declare my function as extern "C" in my C++ file.
Thank you a lot, I was almost there but missed to include the ada runtime libraries (-lgnat -lgnarl) while linking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With