I am trying to get Ada code to compile to a DLL to be callable in C. So far I have managed to get this to work for simple types such as integers but i'm having difficulty with more complex types such as array's or records/structs.
Below is my Ada code for an record/struct. It is a dynamic library which i compile to a dll using the command "gprbuild -P ./math.gpr -p":
person.adb
with Interfaces.C; use Interfaces.C;
package body Person is
function Set_Age_To_Five(P : Person_Record) return Person_Record is
Result : Person_Record;
begin
Result := P;
Result.Age := 5;
return Result;
end Set_Age_To_Five;
end Person;
person.ads
with Interfaces.C; use Interfaces.C;
package Person is
type Person_Record is record
Name : String(1 .. 100);
Age : Interfaces.C.int;
Address : String(1 .. 100);
end record with Convention => C_Pass_By_Copy;
function Set_Age_To_Five(P : Person_Record) return Person_Record;
pragma Export (C, Set_Age_To_Five, "Set_Age_To_Five");
end Person;
math.gpr
library project Math is
for Languages use ("Ada");
for Library_Name use "Person";
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Library_Dir use "lib";
for Library_Kind use "Dynamic";
end Math;
I then have a C header file math.h:
#ifndef MATH_H
#define MATH_H
#ifdef __cplusplus
extern "C"
#endif
typedef struct {
char Name[101];
int Age;
char Address[101];
} Person_Record;
Person_Record Set_Age_To_Five(Person_Record P);
#ifdef __cplusplus
#endif
#endif /* MATH_H */
and finally my C code:
#include <stdio.h>
#include "math.h"
int main() {
Person_Record p, q, r;
// Initialize the person record
snprintf(p.Name, sizeof(p.Name), "John");
p.Age = 25;
snprintf(p.Address, sizeof(p.Address), "123 Main St");
// Call the Set_Age_To_Five function from the DLL
q = Set_Age_To_Five(p);
// Print the modified person record
printf("Name: %s\n", q.Name);
printf("Age: %d\n", q.Age);
printf("Address: %s\n", q.Address);
return 0;
}
This should when executed return
Name: John
Age: 5
Address: 123 Main St
Instead its returning:
Name: John
Age: 25
Address: 123 Main St
I've tried passing by variable, passing by reference. using convention C and convention pass by c in ada.
ADA to C interop of data structures is typically done using pointers, and is likely to be more reliable.
ADA:
procedure Set_Age_To_Five (P : in out Person_Record);
pragma Export (C, Set_Age_To_Five, "Set_Age_To_Five");
procedure Set_Age_To_Five (P : in out Person_Record) is
begin
P.Age := 5;
end Set_Age_To_Five;
C:
void Set_Age_To_Five(Person_Record *P);
Set_Age_To_Five(&p);
I do understand that this is rather less convenient than returning the new struct from ADA, but there seems to be a problem with the way ADA returns the value. It might have something to do with the fact that ADA uses a different model for "Pass By Value" than C does.