This is an old revision of the document!
Table of Contents
The Problem
How to use C++ functions from Ada. Please consider the following C++ code:
header file random_number.h
#ifndef GUARD_random_number_h #define GUARD_random_number_h #include <unistd.h> #include <ctime> #include <cstdlib> void getNewSeed(); double getRandom(int a, int b); int getRandomInt(int a, int b); int getRounded(double res); #endif
source file random_number.cpp
#include <unistd.h> #include <ctime> #include <cstdlib> #include "random_number.h" #include <math.h> using std::srand; using std::rand; void getNewSeed() { srand(time(NULL)); } double getRandom(int a, int b) { return (b-a) * ( (double) rand()/RAND_MAX) + a; } int getRounded(double res) { return (res > 0.0) ? floor(res + 0.5) : ceil(res - 0.5); } int getRandomInt(int a, int b) { res = getRandom(a, b); return getRounded(res); }
How can we call the C++ function getRandomInt(0,10) from an Ada program?
The solution
Start by creating an Ada specification based on the C++ header file (assuming a suitably recent GCC):
gcc -c -fdump-ada-spec random_number.h
Or read this for examples on auto-generating Ada bindings from C and C++ headers.
Comment out the #includes in random_number.h. They are unused and they are repeated in random_number.cpp anyway. Save it as random_number.hpp. (This forces C++ style Ada specs rather than C style, which is essential to link to the C++ code). Generate the Ada specification automatically:
/usr/gnat/bin/gcc -fdump-ada-spec random_number.hpp
This produces the file random_number_hpp.ads.
random_number_hpp.ads
with Interfaces.C; use Interfaces.C; package random_number_hpp is procedure getNewSeed; -- random_number.hpp:8:21 pragma Import (CPP, getNewSeed, "_Z14getNewSeedv"); function getRandom (a : int; b : int) return double; -- random_number.hpp:9:35 pragma Import (CPP, getRandom, "_Z14getRandomii"); function getRandomInt (a : int; b : int) return int; -- random_number.hpp:10:39 pragma Import (CPP, getRandomInt, "_Z21getRandomIntii"); function getRounded (res : double) return int; -- random_number.hpp:11:26 pragma Import (CPP, getRounded, "_Z10getRoundedd"); end random_number_hpp;
While not essential, it is recommended to write a wrapper package to hide the C interface and C types, and to make the interface look like Ada: random_wrapper.ads and random_wrapper.adb. (This constitutes a “thick binding”, while package random_number_h is a thin binding). At this point you can choose what to expose to the Ada code; I have been selective (or lazy!).
random_wrapper.ads
package random_wrapper is procedure initialise_seed; function random_between(a,b : in Integer) return Integer; end random_wrapper;
random_wrapper.adb
with random_number_hpp; use random_number_hpp; with Interfaces.C; use Interfaces.C; package body random_wrapper is procedure initialise_seed is begin getNewSeed; end initialise_seed; function random_between(a,b : in Integer) return Integer is begin return Integer(getRandomInt (int(a), int(b))); end random_between; end random_wrapper;
Now write your main Ada program:
andom.adb
-- Random number tester with Ada.Text_Io; use Ada.Text_Io; with Ada.Integer_Text_Io; use Ada.Integer_Text_Io; with random_wrapper; use random_wrapper; procedure random is begin initialise_seed; Put("Five random numbers"); New_Line; for i in 1 .. 5 loop Put(random_between(1,100)); New_Line; end loop; end random;
Compile the C++ portion (more complex examples may need a Makefile):
g++ -g -m64 -c -o random_number.o random_number.cpp
Build the Ada portion:
gnatmake -m64 -gnat05 -gnato -gnatwa -fstack-check -o random random.adb -largs ./random_number.o -lstdc++
Note additional arguments -largs ./random_number.o -lstdc++ to gnatlink; extend these if you add more C++ objects and libraries.
Run it.
./random Five random numbers 9 40 2 77 66
Credits
This page was adapted from a post under the subject Need some light on using Ada or not in comp.lang.ada. The question was put forward by Luis P. Mendes and kindly answered by Brian Drummond.