Calling Ada from C++ in Eclipse - c++

I am trying to create a program that is completely hosted in Eclipse, starts in C++, and calls Ada. I have GNATBench loaded, and can run Ada programs without a problem. What I cannot do is have a C++ project call an Ada project.
After hunting around, I found and executed the code shown below using a make file.
http://www.pegasoft.ca/resources/boblap/book.html
I also found a post stating that my goal has been done.
http://blogs.windriver.com/parkinson/2009/10/yesterday-adacore-announced-the-release-of-gnatbench-231-its-ada-integrated-development-environment-eclipse-plugin-which.html
What else do I need to include to have C++ in Eclipse call Ada in Eclipse?
USING MAKE FILE:
$ c++ -c test.cc
$ gnatgcc -c test_subr
$ gnatbind -n test_subr
$ gnatgcc -c b~test_subr
$ gnatlink -o main test.o test_subr.ali --link=c++
$ ./main
 
CPP Code:
//main.cc
#include extern "C" void adainit(void);
#include extern "C" void adafinal(void);
#include extern "C" void ada_subroutine(void);
int main(int argc, char **argv)
{
puts("C++ main");
adainit();
ada_subroutine();
adafinal();
puts("C++ done");
return 0;
}
Ada Code:
package Test_Subr is
procedure Ada_Subroutine;
pragma export(CPP, Ada_Subroutine);
end Test_Subr;
with Ada.Text_IO;
use Ada.Text_IO;
package body Test_Subr is
procedure Ada_Subroutine is
begin
put("IN ADA");
end Ada_Subroutine;
end Test_Subr;

Have you tried using the External_Name parameter of the Export pragma? (IIRC, C++ linkages can get quite mangled.)
pragma Export
( Convention => CPP,
Entity => Ada_Subroutine,
External_Name => "Ada_Subroutine "
);

I don’t know Eclipse; but, how would you get a C++ project in Eclipse to call up another C++ project? or one written in C?
You might be able to get Eclipse to build the Ada as a library and invoke that from the C++?

In the general case, you need to use extern C on the C++ side and pragma exprort (C, .. on the Ada side to get both linkages (parameter passing schemes) the same. However, if you are using gcc for both Ada and C++ then you could use pragma export (CPP instead.
There is one more nit you have to be aware of. If your "main" (the program's entry point) is not written in Ada, then you will need to manually invoke Ada's elaboration process (via the routine adainit()) once before calling anything. Likewise you should in most cases call adafinal() before exiting your program.

Related

Problem with ADA file executed by a c++(UsrAppInit) in VXWorks 6.7(workspace-4)?

I have a file build and compiled correctly in ADA (a simple Hello world). I want to execute the file .o from a c++ using taskspawn. To do that I have read that you must declare in the c++ something like that:
...
#include <taskLib.h>
/* Ada binder-generated main - ADA_MAIN is passed as a macro from the makefile */
extern void ADA_MAIN(void);
void UsrAppInit()
{
int stackSize = 0x80000;
int spawnFlags = VX_FP_TASK;
/* MAIN_TASK_NAME is passed as a macro from the makefile */
char * mainTaskName = (char *) MAIN_TASK_NAME;
int priority = 100;
/* Spawn Ada environment task */
taskSpawn(mainTaskName, priority, spawnFlags, stackSize,
(FUNCPTR) ADA_MAIN, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
}
to complete the process I have declared the ADA_MAIN as a MACRO in makefile (in my case the makefile is makefile.mk)
(MAIN_ADA pathOfmyADAexe and MAIN_TASK_NAME "the procedure of the helloworld")
but the MACRO are not recognized in the process so I have error in compilation for MAIN_TASK_NAME and ADA_MAIN. Any suggestion about how am I missing? I could also do in different way but how?
I don’t know about your ADA_MAIN, and you don't tell us what your MACRO is, so it's a little hard to talk about them. Also, it's a while since I used VxWorks (and, then, we were supported, so had access to a cross-compiler that did the build for us: and our main program was in Ada).
That said, your problem comes down to building a program with Ada components where the main program isn't in Ada.
Ada programs need elaboration. This is the process that calls in all the components of the runtime library and arranges for them to be initialized in the right order. What components, you ask? well, for instance, there's the obvious Ada.Text_IO; and there's the less-obvious things, such as exception handling.
The elaboration code is generated using gnatbind.
Given this hello.adb
with Ada.Text_IO;
procedure Hello is
begin
Ada.Text_IO.Put_Line ("hello!");
end Hello;
you really need to supply a specification, as otherwise the compiler will generate a linker name such as __ada_hello; take control by hello.ads,
procedure Hello with
Export,
Convention => C,
External_Name => "hello";
You'll be using a cross-compilation suite. The components are prefixed by the target name, e.g. powerpc-wrs-vxworks-gnatmake, arm-eabi-gnatbind, but I'll just use the bare component name below.
$ gnatmake -c hello.adb
which generates hello.o, hello.ali (if the program was more complicated, it'd compile the closure too).
Now bind:
$ gnatbind -n -Lhello -static hello.ali
where
-n : main program not in Ada
-Lhello: adainit, adafinal renamed helloinit, hellofinal
-static: pretty sure VxWorks doesn't support shared libraries?
generating b~hello.ads, b~hello.adb (depending on the compiler release, the ~ may be replaced by e.g. double underscore). Compile:
$ gnatmake -c b~hello.adb
Now, to call from C++. you need to tell the compiler about the symbols in the Ada code, in e.g. hello.h:
extern "C" {
void helloinit();
void hellofinal();
void hello();
}
and then the main program in main.cc:
#include "hello.h"
int main() {
helloinit();
hello();
hellofinal();
}
which leaves you with the C++ compile and link, which needs the Ada runtime in libgnat.a and (for tasking) libgnarl.a, and is of course very compiler- and installation-specific: here, on the macOS host, I used
$ g++ main.cc b~hello.o hello.o /opt/gcc-8.1.0/lib/gcc/x86_64-apple-darwin15/8.1.0/adalib/libgnat.a
$ ./a.out
hello!
Translating this to the VxWorks context, I'd say that you'd call helloinit() from your main program (you probably won't need hellofinal()), and pass hello to taskSpawn() in place of your ADA_MAIN.

"no main" function for linking or execution in C++ [duplicate]

This question already has answers here:
How to change entry point of C program with gcc?
(4 answers)
Closed 5 years ago.
I am trying to compile a function (not called main) that can be integrated in another code or directly executed (after linking).
I try it one my mac, and work well.
I finally test it on Linux (CentOS and ubuntu). However, the task looks harder as expected on Linux.
The source code is the following one (just to explain the problem)
test.cpp:
#include <cstdio>
#ifdef __cplusplus
extern "C" {
#endif
int test(int argc, char const *argv[]);
#ifdef __cplusplus
}
#endif
int test(int argc, char const *argv[]) {
fprintf(stderr, "%s\n", "test");
return 0;
}
Compilation line on MacOS
g++ -c test.cpp -o test.o && g++ test.o -o test -e _test
and on Linux
g++ -c test.cpp -o test.o && g++ test.o -o test -e test
I try on my MacOS with clang, g++ and Intel compiler, all 3 works fine.
And I try with g++ and the Intel compiler on Linux, always, the same error.
usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Any advice, explanation or solution, on what I am doing wrong or missing would be very helpful.
Thanks
Edit:
Currently, I have a "define" to create a main, but if we have lots of function we are obligated to do two compilations each time (one for the function version and one for the execution) and make finally the code heavier.
Like discussed in this topic is there a GCC compiler/linker option to change the name of main?
To don't do a XY I inherited from a bunch of small programs that I want to put to gather, that it is easier to use (for remote execution ...). However, each one need to be able to be executed independently if needed, for debugging,... I hesitate, between using "execv" and just convert each main as a function. I probably take the bad chose.
Edit:
The final goal is to be able to have independent programs. But that we can call from an external software too.
Solution:
The solution looks to be, to a call to the main through a dlopen
You cannot do that (and even if it appears to work on MacOSX it is implementation specific and undefined behavior).
Linux crt0 is doing more complex stuff that what you think.
The C standard (e.g. n1570 for C11) requires a main function for hosted implementations (§5.1.2.2.1) :
The function called at program startup is named main. The implementation declares no prototype for this function.
And the C++ standard also requires a main and strongly requires some processing (e.g. construction of static data) to be done before main is running and after it has returned (and various crt0 tricks are implementing that feature on Linux).
If you want to understand gory details (and they are not easy!), study the ABI and the (free software) source code of the implementation of the crt0.
I am trying to compile a function (not called main) that can be integrated in another code
BTW, to use dynamically some code (e.g. plug-ins) from another program, consider using the dynamic linker. I recommend using the POSIX compliant dlopen(3) with dlsym(3) on position-independent code shared libraries. It works on most Unix flavors (including MacOSX & Linux & Solaris & AIX). For C++ code beware of name mangling so read at least the C++ dlopen mini howto.
Read also the Program Library HowTo.
Problems with libraries, they cannot be executed, no ?
I don't understand what that means. You certainly can load a plugin then run code inside it from the main program dlopen-ing it.
(and on Linux, some libraries like libc.so are even specially built to also work as an executable; I don't recommend this practice for your own code)
You might take several days to read Drepper's How To Write Shared Libraries (but it is advanced stuff).
If you want to add some code at runtime, read also this answer and that one.
The final goal is to be able to have independent program. But that we can call from an external software too
You can't do that (and it would make no sense). However, you could have conventions for communicating with other running programs (i.e. processes), using inter-process communication such as pipe(7)-s and many others. Read Advanced Linux Programming first and before coding. Read also Operating Systems : Three Easy Pieces
The solution looks to be, to a call to the main through a dlopen
Calling the main function via dlopen & dlsym is forbidden by the C++ standard (which disallows using a pointer to main). The main function has a very specific status and role (and is compiled specially; the compiler knows about main).
(perhaps calling main obtained by dlsym would appear to work on some Linux systems, but it certainly is undefined behavior so you should not do that)

Vala GUI and logic in C++

I have a drawing program that uses SDL, written in C++. I would like to create a graphical interface only in Vala and use it to call functions from a program (functions are ready to use and I only want to call them from the GUI). I was looking for solutions as VAPI, and I was thinking of using GObject, but I can not embrace both. Has anyone done similar things and can you suggest me a solution to my problem?
If you want to use the C++ code in Vala we prepare them properly. Here's an example.
First you have to tell the valac compiler that the function is defined somewhere else. Let's use the extern directive.
// ccodetest.vala
extern void cpp_test_function ();
void main () {
stdout.printf ("This is Vala code\n");
cpp_test_function ();
}
Then the functions in C++ are properly linked with the object files derived from C, we declare them as extern "C".
// cpplibrary.cpp
# include
using namespace std;
extern "C" void cpp_test_function () {
cout << "This is a C + + code\n";
}
When we are so ready, we can compile Vala code to C. We get ccodetest.c.
valac -C ccodetest.vala
Now we can use gcc to compile the object file. We get ccodetest.o.
gcc-o ccodetest.o ccodetest.c-c-I /usr/include/glib-2.0/ -I /usr/include/glib-2.0/glib/ -I /usr/lib/glib-2.0/include/
File C++ compile as follows.
g++ -o cpplibrary.cpp.o cpplibrary.cpp -c
At the end we linking both files.
g++ -o ccode_test ccodetest.o cpplibrary.cpp.o -L /usr/lib/ -lglib-2.0 -lgobject-2.0
The program works as follows:
$ ./ccode_test
This is Vala code
This is a C++ code

Go shared library as C++ plugin

I have a project where I would like to load Go plugins inside a C++ application.
After a lot of research, it is not clear for me whether or not Go supports this.
I encountered a lot of discussions pointing out the bad habit of dynamic linking, proning IPC instead. Moreover it is not clear for me if dynamic linking is intended by the language or not (new Go philosophy ?).
cgo provides the ability to call C from Go or Go from C (inside Go), but not from plain old C. Or does it ?
gc doesn't seem to support shared library (even if https://code.google.com/p/go/issues/detail?id=256 mentions it does)
gccgo support Go shared libraries but I couldn't make it work (probably because the main entry point is not in Go ...)
SWIG doesn't seem to help either :(
Apparently something is going on upstream as well (https://codereview.appspot.com/7304104/)
main.c
extern void Print(void) __asm__ ("example.main.Print");
int main() {
Print();
}
print.go
package main
import "fmt"
func Print() {
fmt.Printf("hello, world\n")
}
Makefile :
all: print.o main.c
gcc main.c -L. -lprint -o main
print.o: print.go
gccgo -fno-split-stack -fgo-prefix=example -fPIC -c print.go -o print.o
gccgo -shared print.o -o libprint.so
Output :
/usr/lib/libgo.so.3: undefined reference to `main.main'
/usr/lib/libgo.so.3: undefined reference to `__go_init_main'
Is there a solution for that ? What is the best approach ? forking + IPC ?
References :
cgo - go wiki
callback in cgo
c callbacks and non go threads
cgo - golang
call go function from c
link c code with go code
I don't think you can embed Go into C. However you can embed C into Go and with a little stub C program you can call into C first thing which is the next best thing! Cgo definitely supports linking with shared libraries so maybe this approach will work for you.
Like this
main.go
// Stub go program to call cmain() in C
package main
// extern int cmain(void);
import "C"
func main() {
C.cmain()
}
main.c
#include <stdio.h>
// Defined in Go
extern void Print(void);
// C Main program
int cmain() {
printf("Hello from C\n");
Print();
}
print.go
package main
import "fmt"
import "C"
//export Print
func Print() {
fmt.Printf("Hello from Go\n")
}
Compile with go build, and produces this output when you run it
Hello from C
Hello from Go
AFAIK, you cannot compile a Go package to a shared library witg 'gc' ATM, it may change in the future. There might be some chance with 'gccgo' as 'libgo' (Go runtime, I suppose) is a shared library already. I guess the missing piece is then only to properly initialize the runtime, which normally a Go command handles automatically.
The gccgo expert is I.L. Taylor, he is reachable at the golang-nuts mailing list almost daily. I suggest to ask him directly.
PS: Other problems possibly include the interaction of the Go garbage collector and the (C++) process memory etc. Maybe I'm too optimistic and it is not at all feasible.

error occured when fortran code called c code

I have used a method in a reference book about fortran codes calling c codes. The method is that if your function name in the c codes are capitalized, you may not make additional changes in your fortran code. The following is my code.
Source1.f90:
program main
implicit none
call c_subprint()
endprogram
ccode.c:
#include <stdio.h>
#include <string.h>
#ifdef _cplusplus
extern "C" {
#endif
void _stdcall C_SUBPRINT()
{
int a;
printf("%s\n","kk");
scanf("%d",&a);
}
#ifdef _cplusplus
}
#endif
The error message is that the main function cannot find out _C_SUBPRINT(LNK2019). But I have already added the .lib generated by the c code to the fortran code. And my code is almost the same as that in the reference book. what is wrong?
Different Fortran compilers generate calls differently. Many add underscores to routine names to avoid name conflicts with C-code. Its very hard to say whether or not you should exactly follow the example of an unnamed reference book. In the past, to mix Fortran and C, you have to understand some of the compiler internals. Here the Fortran compiler appears to have added an underscore to the start of the name. You could probably fix the problem by adding that in your C++ code. But that won't be portable and in principle could change with compiler versions. There is a better way: the Fortran ISO_C_Binding. This is part of the Fortran language standard and therefore standard and portable. Examples are given in the gfortran manual in the Chapter "Mixed-Language Programming" and in other questions on Stackoverflow.
From the inclusion of _stdcall I deduce you are probably using a Windows platform. Unfortunately I'm working on a Mac, so things may not be exactly the same. However, the following works for me (small changes from your code) to get a mix of Fortran and C code working together. Note - on my Mac, the gcc compiler does not include Fortran, so I used a separate Fortran compiler gfortran which I downloaded from a link at http://hpc.sourceforge.net - where instructions for installation could also be found.
program src1.f90:
program main
implicit none
call C_SUBPRINT()
endprogram
program ccode.c:
#include <stdio.h>
#include <string.h>
void c_subprint_()
{
printf("hello world!\n");
}
Note I took out the #ifdef sections - I was using pure C, so it was not needed; more importantly, note the underscore after the function name
I compiled these two modules as follows:
gcc -c ccode.c -o ccode.o
gfortran src1.f90 ccode.o -o hello
After which I can run
./hello
And get the expected output:
hello world!
Without the underscore, the linker complains about unknown symbols. There is an option in the compiler to turn off "name mangling" with the underscore. You can check your specific compiler to see how that would be done - but that's almost certainly the problem you are having.