How to build a static library from Ada source that's callable from C++ code?

心不动则不痛 提交于 2019-12-23 09:22:11

问题


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.


回答1:


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



回答2:


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.



来源:https://stackoverflow.com/questions/40870366/how-to-build-a-static-library-from-ada-source-thats-callable-from-c-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!