Integrate Go files in existing C project - c

I have a large project written in C and I wrote a Go script with a function that I would like to call from the C code (C->Go). This same Go function also needs to call some C functions (Go->C).
Here is a simplified look at the project structure:
- src/...
- src/file_c.h
- src/file_c.c
- src/gocode/file_go.go
- src/Makefile
Here is what I would like to do:
file_c.c needs to include file_go.h (C->Go).
file_go.go needs to include file_c.h (Go->C).
The C software has its own large Makefile and I would like to keep using that one to compile it. The final binary to run will also be from the existing C code (and will call a Go function during its execution).
What I tried so far:
In file file_go.go, prior to the import "C" statement, I added these lines:
// #cgo CFLAGS: -I..
// #include "file_c.h"
Then I tried to compile the file_go.go with both commands:
go build -buildmode=c-shared file_go.go
go build -buildmode=c-archive file_go.go
However, in both cases I get error messages of the sort undefined reference to func, where func is the C function (declared in file_c.h and defined in file_c.c) called from the Go code.
If I remove the calls from Go->C in file_go.go, then it compiles correctly and I can include file_go.h in the C Makefile properly. However, I need the Go file to call that C function too.
How can I build the Go file in such a way that the C function is correctly linked?

Related

Combine two C program files in VScode, macOS

I got two C program files, a basic code
main.c and function.c
the function.c file contains the function which I need to call in main.c file
i've tried merging files using -o
the error appears to be : liker not found, although all the libraries and stuff are perfectly present in my system.
I'am facing this problem in vsCode in macOS.
Let's begin with taking an example in the attachment there are two pictures if you see the picture which has code for one.c there I have used a line
#include "two.c"
Just to tell the compiler that I want to see every single definition in two. c
In file one.c I have called a function named print which is defined in two. c
One thing that can be noticed and is a really important observation is that in two.c, the file from where definitions needed to be called doesn't have a main function. Can you guess why? The reason is simply because when you click on one.c your system will call the main function located in one.c. Upon seeing two main functions on the second file it gets confused and throws error, and just think why you even need the main function in two.c. There is no need because we use the main function just to perform certain actions and in two.c you really don't need to perform any action but you only need a function to be exported on another file.
In your case, you need to eliminate the main function from the function .c file and in main .c just include the path of your function .c

How integrate gnatmake/gnatbind/gnatlink in CMake files for C/Ada code?

I wrote a code in a few languages (C, C++, Fortran77, Fortran90) and I can compile it without any sort of problem by using CMake. It works out perfectly.
Now, I would like to add in the main(), which is written in C, some Ada function and I want to compile it by CMake. Given that I am not able to link my Ada function to the main one by using CMake, I get
main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal
I did another simplified test by using the main function (written in C) calling the only Ada function, which I coded, and I compiled it by using
gcc -c main.c
gnatmake -c lib_ada.ali
gnatbind -n lib_ada.ali
gnatlink lib_ada.ali main.o -o exe
and it works out. Do you know how I can integrate this approach in a CMakeList.txt?
Note: I think (maybe I mistake) I cannot use the only gnatlink because I need to link all other functions I already have.
Here is reported a minimal reproducible example.
--- main.c ---
#include <stdio.h>
extern int adainit();
extern int adafinal();
extern int Add(int,int);
int main()
{
adainit();
printf ("Sum of 3 and 4 is: %d\n", Add (3,4));
adafinal();
return 0;
}
--- lib_test.adb ---
package body Lib_Test is
function Ada_Add (A, B : Integer) return Integer is
begin
return A + B;
end Ada_Add;
end Lib_Test;
--- lib_test.ads ---
package Lib_Test is
function Ada_Add (A, B : Integer) return Integer;
pragma Export (C, Ada_Add, "Add");
end Lib_Test;
1° test: if you compile by using the following commands:
gcc -c main.c
gnatmake -c lib_test.adb
gnatbind -n lib_test.ali
gnatlink lib_test.ali main.o -o exe
and run ./exe you get Sum of 3 and 4 is: 7.
2° test: I tried to use the following CMake file (CMakeLists.txt) linking the *.a
cmake_minimum_required(VERSION 2.6)
project(Ada2C)
enable_language(C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -m64")
find_library(TEST_lib lib_test.a PATHS ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "Finding library: ${TEST_lib}")
add_executable(TEST_release ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
target_link_libraries(TEST_release ${TEST_lib})
I generate library lib_test.a for the Ada function
gnatmake lib_test.adb
ar rc lib_test.a
I run the cmake and make and I get
main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal
More of a comment than an answer, but too long for a comment, so here goes:
Compiling Ada code into your binary means that your binary needs access to the GNAT runtime. This is one thing gnatlink does when you use it to link the final executable. The other thing is the b~<something>.ad{s,b} source gnatbind generates which you need to compile and link against as others mentioned.
The cleanest way to embed Ada in C I've seen so far is to create an encapsulated library. This probably does not make sense if your actual problem is with only one Ada function, but it does with larger chunks of Ada. The encapsulated library will be a shared library that has GNAT's runtime baked in. Being a shared library enables it to implicitly handle initialization during library loading so you don't need adainit() / adafinal() anymore.
The easiest way to create an encapsulated library is to use a ada_code.gpr file:
project ada_code is
for Library_Name use "mylib";
for Library_Dir use "lib";
for Library_Kind use "relocatable";
for Library_Standalone use "encapsulated";
for Library_Auto_Init use "true";
for Library_Interface use ("All", "Packages", "In.Your", "Ada.Code");
for Source_Dirs use ("adasrc");
end ada_code;
In CMake, you can then do:
# tell CMake how to call `gprbuild` on the `.gpr` file.
# you may need to replace `gprbuild` with the absolute path to it
# or write code that finds it on your system.
add_custom_target(compile_mylib
COMMAND gprbuild -P ada_code.gpr)
# copy the library file generated by gprbuild to CMake's build tree
# (you may skip this and just link against the file in the source tree)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mylib.so
DEPENDS compile_mylib
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/lib/mylib.so
${CMAKE_CURRENT_BINARY_DIR}/mylib.so)
# ... snip ...
# link to the copied library
# I am not 100% sure this adds the correct dependency to the custom command.
# You may need to experiment a bit yourself
target_link_libraries(TEST_release ${CMAKE_CURRENT_BINARY_DIR}/mylib.so)
In your C file, you can then delete everything related to adainit() and adafinal().

Using Go code in an existing C project

Ever since Go 1.5 came out, I started taking another look at how I could integrate it into an existing project of mine.
The project's codebase is written entirely in C for low level access to to hardware and other fun stuff. However, some of the higher level things are tedious, and I would like to start writing them in a higher level language (Go)
Is there any way I can call Go code from a C program? I installed Go 1.5, which added -buildmode=c-archive (https://golang.org/s/execmodes) which I am trying to get working.
However, I can't seem to get Go to generate the appropriate header files to allow my project to actually compile. When I generate the archive, I see the function in the exported symbols (using objdump), but without the header files to include gcc complains about the function not existing (as expected)
I'm quite new to Go - however, I love the language and would like to make use of it. Is there any idiomatic way ("idiomatic" gets used a lot in the world of Go I see...) to get this to play nicely with each other?
The reason I asked this question and specifically mentioned Go 1.5 is that according to this document, https://docs.google.com/document/d/1nr-TQHw_er6GOQRsF6T43GGhFDelrAP0NqSS_00RgZQ/edit?pli=1#heading=h.1gw5ytjfcoke
Go 1.5 added support for non-Go programs to call Go code. Specifically, mentioned under the section "Go code linked into, and called from, a non-Go program"
To build an archive callable from C, you will need to mark them as exported CGo symbols.
For example, if I create a file foo.go with the following contents:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
func main() {}
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
The results will be an archive foo.a and a header foo.h. In the header, we get the following (eliding irrelevant parts):
...
typedef long long GoInt64;
...
typedef GoInt64 GoInt;
...
extern void PrintInt(GoInt p0);
...
So that's enough to call the exported function. We can write a simple C program that calls it like so:
#include "foo.h"
int main(int argc, char **argv) {
PrintInt(42);
return 0;
}
We can compile it with a command like:
gcc -pthread foo.c foo.a -o foo
The -pthread option is needed because the Go runtime makes use of threads. When I run the resulting executable it prints 42.
The code above work just fine, but gcc will complain about functions and headers.
The includes should be:
#define _GNU_SOURCE
#include <stdio.h>
#include "mygopkg.h"
If you forget the #define _GNU_SOURCE, the gcc will complain:
warning: implicit declaration of function 'asprintf'; did you mean 'vsprintf'? [-Wimplicit-function-declaration]
If you forget the #include "mygopkg.h", the gcc will complain:
warning: implicit declaration of function 'PrintString' [-Wimplicit-function-declaration]
The last but not less important. The build command line I recommend for production code is:
go build -ldflags "-s -w" -buildmode c-archive -o mygopkg.a
It'll save you 53% size of final mygopkg.a.

Linking to MATLAB generated code

I'm using embedded MATLAB to generate C code from an .m script. However, after the generation I'm left with about 15 files (most of them are source). If I want to write a standalone main in C how do I link to the MATLAB generated code? Is there a way to do this without writing my own Makefile?
So I figured out how to generate static libraries (.a) with the matlab generated code... can I build dynamically loaded libraries (.so)?
I don't know if this is particular to my project, but I find that I can include Matlab generated files the same way as you would normally include anything else.
I copy my generated matlab source files (.c and .h) into my project directly, and then I have to specifically add them to my project. ( I wonder if that has more to do with the IDE I use though).
Then, in main.c that you create, just add the line #include "yourGeneratedFile.h". Within main.c now, you should be able to use whatever functions were created by Matlab.
For instance, in an example:
within main.c, include the header file and use the function you need
#include "SPIUARTDemo30f.h"
//further down in the file
SPIUARTDemo30f_step(); //using the function I asked Matlab to generate
SPIUARTDemo30f.h and SPIUARTDemo30f.c are the generated files from Matlab:
within the .h you'll see
extern void SPIUARTDemo30f_step(void);
and, if you look at the .c you'll find:
void SPIUARTDemo30f_step(void)
{
/* lots of code */
}

Interface Go with C libraries

How does one interface a Go program with a C library?
I've been browsing Go's source code but I still didn't figured it out. If someone has already done so, could you share, please?
UPDATED: Thanks to #fserb, I am posting some documentation from the Go sources:
Cgo enables the creation of Go
packages that call C code.
Usage: cgo [compiler options] file.go
The compiler options are passed
through uninterpreted when invoking
gcc to compile the C parts of the
package.
The input file.go is a syntactically
valid Go source file that imports the
pseudo-package "C" and then refers to
types such as C.size_t, variables such
as C.stdout, or functions such as
C.putchar.
If the import of "C" is immediately
preceded by a comment, that comment is
used as a header when compiling the C
parts of the package. For example:
// #include <stdio.h>
// #include <errno.h>
import "C"
Cgo transforms the input file into
four output files: two Go source
files, a C file for 6c (or 8c or 5c),
and a C file for gcc.
The standard package makefile rules in
Make.pkg automate the process of using
cgo. See $GOROOT/misc/cgo/stdio and
$GOROOT/misc/cgo/gmp for examples.
Cgo does not yet work with gccgo.
Check cgo. Also, take a look at misc/cgo/gmp on the Go source code for an example code on how to wrap a C library in Go.

Resources