* on calling Ada from C/C++ @ 1996-06-12 0:00 Nasser Abbasi 1996-06-13 0:00 ` Nasser Abbasi 0 siblings, 1 reply; 4+ messages in thread From: Nasser Abbasi @ 1996-06-12 0:00 UTC (permalink / raw) this is fyi: This is a little note about calling Ada subprogram from C++ . I started 2-3 hours ago to learn how to call Ada from C++, I still need to learn more about this. But it turned out much easier than I as I thought it would be. The main issues are on how to declare the Ada subprograms in C++, and how to make sure the way the Ada subprogram is called matches the way it expects to be called. A C++ main calls an Ada procedure to update an integer. (I also use C in this example just for testing.) I also show the steps used to build the program, and few points at the end about few things. This was done on solaris 2.5, using gnat 3.04. file main.cc ------------- #include <iostream.h> #include <stdio.h> extern "C" { void Ada_Function(int*); void adainit(); // this and adafinal are calls to ada void adafinal(); // rtl to insure things are initialized } // and finailized ok... main() { int i=0; adainit(); // call befor any other ada call printf("This is a C printf ... \n"); cout<<"this is C++ cout..."<<endl; cout<<" before calling Ada, i="<<i<<endl; Ada_Function(&i); cout<<" after calling Ada, i="<<i<<endl; adafinal(); // call before program terminates return 0; } file: ada_function.adb ---------------------- with Text_Io; use Text_Io; procedure Ada_Function(I:in out integer) is begin Put_Line("This is Ada Put_Line ..."); Put_Line("Number passed in is" & Integer'Image(I)); I := I+1; end; pragma Export(C,Ada_Function,"Ada_Function"); Steps used to build main* are : (note: gcc here is the gcc that comes with gnat 3.04. for the g++ include files, and libg++.a and libstdc++.a libraries, those were obtained seperatly and build in different directory. I found out for example that cc1plus* was needed to be under 2.7.2/ directory in the gnat 2.4 solaris installtion tree, but it was not, so I copied that file from the 2.7.2/ directory under the tree that was build seperatly for the 2.5 solaris. This way I was able to use gnat gcc to build C++, without cc1plus* one can not build C++ files using the gcc that comes with gnat 3.04-solaris 2.4.) gcc -c main.cc -I/usr/local/netshare/lib/g++-include gnatbind -n ada_function.ali gnatlink -L/usr/local/netshare/lib ada_function.ali main.o \ -lg++ -lstdc++ -o main ...now run the program... {95} main This is a C printf ... this is C++ cout... before calling Ada, i=0 This is Ada Put_Line ... Number passed in is 0 after calling Ada, i=1 few points I noticed: 1) In C++, one must declare the Ada procedure and functions as C functions, else C++ will mangle the ada function names, and the gnatlink step will fail as poor linker will not be able to resolve the name. for example, if one do not use extern "C" {..}, and then look at the object file generated, one sees : $ nm -x main.o main.o: [Index] Value Size Type Bind Other Shndx Name [5] |0x00000000|0x00000000|NOTY |GLOB |0x0 |UNDEF |Ada_Function__Fi But after using the extern "C" {...} to declare the Ada procedure, the function name is not changed by C++ : $nm -x main.o main.o: [Index] Value Size Type Bind Other Shndx Name [14] |0x00000000|0x00000000|NOTY |GLOB |0x0 |UNDEF |Ada_Function Now, the function name matches that in the ada object file, and the linker is a happy camper. 2) In the Ada procedure, defining Ada_function as procedure Ada_Function(I:in out integer) ^^^^^ or procedure Ada_Function(I:out integer) ^^^^ resulted in no difference in build or run results. 3) more about point 2: How to make sure that the way the Ada subprogram is called from the C++ module matches that the way Ada subprogram is defined in the Ada module? For example, in the above example, in main.cc, one can change the argument being passed to the Ada procedure from int* to char*, and rebuild the C++ main.cc, link to the ada procedure, and no errors are detected, untill the program is run. So, it is important to "manually" make sure the way the Ada program is called matches the way it is defined. Is there better way? .. When calling C++ from C++, one uses common function prototypes (in common headers) to make sure all modules agree on the function signature, so that the way a function is called matches the way the is defined. Similar idea is used when calling Ada from Ada. The Ada compiler makes sure the formal and actual parameters agree. But how to insure this when calling Ada from C++ ? Nasser ========================================================== Nasser Abbasi. Senior software engineer. C/C++/Solaris. GeneAssist- a client/server application for Nucleic acid and protein sequence search and analysis. PE-Applied BioSystem division. nasser@apldbio.com -- Nasser Abbasi. Senior software engineer. C/C++/Solaris. GeneAssist- a client/server application for Nucleic acid and protein sequence search and analysis. PE-Applied BioSystem division. nasser@apldbio.com ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: on calling Ada from C/C++ 1996-06-12 0:00 on calling Ada from C/C++ Nasser Abbasi @ 1996-06-13 0:00 ` Nasser Abbasi 1996-06-13 0:00 ` Robert Dewar 1996-06-13 0:00 ` Robert Dewar 0 siblings, 2 replies; 4+ messages in thread From: Nasser Abbasi @ 1996-06-13 0:00 UTC (permalink / raw) To: Nasser Abbasi little more on this subject.. If you want to call more than one ada subprogram from C++, I found that gnatlink (the gnat ada linker) does not take more than .ALI file, this means that you can not have separate ada functions/procedure in separate files and have C++ call them (unless I missed something), the easy solution is to put them in one ada package, this way you can have one .ALI file , and the gnatlink is happy. Below is little larger example of a C++ main calling a number of Ada subprograms, also using arrays. the Interfaces.C package has usefull stuff for interfacing to C/C++, but it does not have converter functions to convert C arrays to Ada and visversa arrays where the array compononet is other than char,char_array,wchar_t, wchar_array, but it is easy to write these. So if you pass an array of int (say) to Ada, and you want Ada to process the array as starting from 1 not from 0, then you need to convert/"slide" over the array inside the Ada function before processing it, also to convert the array component types from the C++ int type to the Ada Integer type. Or you can just leave it the way it is starting from zero, and cast the array compononet to Integer from int. A simple function will do the conversion. Is there is way to slide the array over on the fly ? (since the array compononets are different types, one in standard.integer and one is Interfaces.C.int I could not do it on the fly, so I wrote a function, probably there is a more elegent way that this... Need to look more into this..) I happend to dislike arrays that start from 0, I think arrays that start from 1, as in Fortran say , are more natural to use, and also easier to process. The following are the steps used to build main, and the source code example. This example is just for testing/learning how to call Ada from C++, so please dont scream at me if you think it is not the most efficient. steps: 1. first I compile the C++ main gcc -c main.cc -I/usr/local/netshare/lib/g++-include 2. compile the ada package that contains all the ada functions/procedures that will be called from C++ gcc -c my_pkg.adb 3. bind my_pkg.ali (the .ali file is generated from step 2) : gnatbind -n my_pkg.ali 4. link everything togother (with the C++ libraries also offcourse) gnatlink -L/usr/local/netshare/lib my_pkg.ali main.o -lg++ -lstdc++ -o main main.cc ------ #include <iostream.h> #include <stdio.h> extern "C" { void Increment( int* ); int Sum( int[] , int ); int Sum_Version2( int[] , int ); void Modify( int[] , int ); void adainit(); void adafinal(); } main() { int i=0; int a[5]= {0,1,2,3,4}; adainit(); Increment(&i); // we pass address since it is declared IN OUT in ada cout<<" after calling Ada, i="<<i<<endl; i = Sum(a,sizeof(a)/sizeof(int)); cout<<" in C++, first sum is "<<i<<endl; // Now call ada to modify elements of array Modify(a,sizeof(a)/sizeof(int)); i = Sum(a,sizeof(a)/sizeof(int)); cout<<" In C++, Ada did another sum, and the result is "<<i<<endl; i = Sum_Version2(a,sizeof(a)/sizeof(int)); cout<<" In C++, Ada did Sum_Version2, and the result is "<<i<<endl; adafinal(); return 0; } my_pkg.ads --------- with Interfaces.C; package My_Pkg is package C renames Interfaces.C; type Ada_Int_Array_type is array(Integer range <>) of Integer; type C_Int_Array_type is array(integer range <>) of C.int; procedure Modify(A: in out C_Int_Array_type ; Len: in C.Size_t ); function Sum(A: in C_Int_Array_type ; Len: in C.Size_t ) return C.int; function Sum_version2(A: in C_Int_Array_type ; Len: in C.Size_t ) return C.int; procedure Increment(I:in out C.int); function To_Ada(A: in C_Int_Array_Type; Len: in C.Size_t) return Ada_Int_Array_type; end My_Pkg; my_pkg.adb ========== with Ada.Text_Io; use Ada.Text_Io; package body My_Pkg is -- -- -- function Sum(A: in C_Int_Array_type; Len : in C.Size_t ) return C.Int is The_Sum: Integer; Length: Integer := Integer(Len); begin The_Sum := 0; Put_Line("array from C++ has length " & integer'Image(Length)); for I in 0 .. Length-1 loop Put_line("array from C++ at index " & integer'Image(I) & " is " & C.int'Image(A(I))); The_Sum := The_Sum + Integer(A(I)); end loop; return C.Int(The_Sum); end Sum; pragma Export(C,Sum,"Sum"); -- -- -- function Sum_version2(A: in C_Int_Array_type; Len : in C.Size_t ) return C.Int is The_Sum: Integer; Length: Integer := Integer(Len); Ada_Int_Array: Ada_Int_Array_Type(1..Integer(Len)); begin Ada_Int_Array := To_Ada(A,len); The_Sum := 0; Put_Line("array from C++ has length " & integer'Image(Length)); for I in 1 .. Length loop The_Sum := The_Sum + Ada_Int_array(I); end loop; return C.Int(The_Sum); end Sum_version2; pragma Export(C,Sum_Version2,"Sum_Version2"); -- -- -- procedure Modify(A: in out C_Int_Array_type; Len: in C.Size_t ) is Length: Integer := Integer(Len); use Interfaces.C; begin for I in 1 .. Length loop A(I) := A(I) * 2; end loop; end Modify; pragma Export(C,MOdify,"Modify"); -- -- -- procedure Increment(I:in out C.int) is use Interfaces.C; begin Put_Line("Number passed in is" & C.int'Image(I)); I := I+1; end Increment; pragma Export(C,Increment,"Increment"); -- -- --- function To_Ada(A: in C_Int_Array_Type;Len: C.Size_t) return Ada_Int_Array_Type is Back : Ada_Int_Array_Type(1..Integer(Len)); begin for I in Back'Range loop Back(I) := Integer(A(I-1)); end loop; return Back; end To_Ada; begin null; end My_Pkg; Nasser -- Nasser Abbasi. C/C++/Ada Solaris. GeneAssist - A client/server application for Nucleic acid and protein sequence search and analysis. PE-Applied BioSystem division. email: nasser@apldbio.com MSEE, MSCS, MSCE, FM (and Karpov is my chess hero! ..). ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: on calling Ada from C/C++ 1996-06-13 0:00 ` Nasser Abbasi @ 1996-06-13 0:00 ` Robert Dewar 1996-06-13 0:00 ` Robert Dewar 1 sibling, 0 replies; 4+ messages in thread From: Robert Dewar @ 1996-06-13 0:00 UTC (permalink / raw) Nasser said "If you want to call more than one ada subprogram from C++, I found that gnatlink (the gnat ada linker) does not take more than .ALI file, this means that you can not have separate ada functions/procedure in separate files and have C++ call them (unless I missed something), the easy solution is to put them in one ada package, this way you can have one .ALI file , and the gnatlink is happy. " That's wrong, use the -n switch for gnatbind, that's what it is for! ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: on calling Ada from C/C++ 1996-06-13 0:00 ` Nasser Abbasi 1996-06-13 0:00 ` Robert Dewar @ 1996-06-13 0:00 ` Robert Dewar 1 sibling, 0 replies; 4+ messages in thread From: Robert Dewar @ 1996-06-13 0:00 UTC (permalink / raw) Nasser said "gnatbind -n my_pkg.ali" odd, so you do know about -n, so how come the fiddling around? Just put a list of ali files after the -n switch! ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~1996-06-13 0:00 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1996-06-12 0:00 on calling Ada from C/C++ Nasser Abbasi 1996-06-13 0:00 ` Nasser Abbasi 1996-06-13 0:00 ` Robert Dewar 1996-06-13 0:00 ` Robert Dewar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox