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.
Related
I am writing a FindXXX.cmake script for an external C library. I would like my script to provide information about the library version. However, the library only provides this information in the form of a function that returns the version number as a string.
I thought I could extract the version number by having FindXXX.cmake compile the following C program on the fly:
#include <stdio.h>
#include "library.h"
int main() {
char version[256];
get_version(version);
puts(version);
return 0;
}
In order for this to work, CMake should compile and run the program above at configure time, and use the information it prints as the version identifier. I know how to do the latter (execute_process), and I almost know how to do the former: CheckCSourceRuns comes to mind, but I do not know how to capture the stdout of the generated executable.
TL;DR: is there a way to compile a program, run it and capture its stdout from CMake at generation time?
You may use try_run for that purpose (it is assumed that your source file is named as foo_get_version.c):
try_run(foo_run_result foo_compile_result
foo_try_run ${CMAKE_CURRENT_LIST_DIR}/foo_get_version.c
RUN_OUTPUT_VARIABLE foo_run_output)
if(NOT foo_compile_result)
# ... Failed to compile
endif()
if(NOT foo_run_result EQUAL "0")
# ... Failed to run
endif()
# Now 'foo_run_output' variable contains output of your program.
Note, that try_run isn't executed when cross-compiling. Instead, CMake expects that the user will set cache variables foo_run_result and foo_run_result__TRYRUN_OUTPUT.
I'm trying to get started learning basic assembly with Paul A. Carter's book "PC Assembly Language." However I'm unable to run the first example Carter provides, so I'm kind of stuck until I figure this out.
I assembled the example "first.asm" without any problem, but I can't figure out how to link these files: first.obj, driver.c, asm_io.obj into an executable. In the comment section of first.asm Carter gives these instructions for creating an executable (I'm using Windows 10, VS community 2015 developer command prompt):
; Using MS C/C++
; nasm -f win32 first.asm
; cl first.obj driver.c asm_io.obj
I'm doing exactly that but I'm getting a fatal error 2 unresolved externals, _printf and _scanf. I have every necessary file that I can think of in the same directory, and I'm compiling in that directory.
Driver.c calls the function defined in and it uses a header file called "CDECL.h"; I have this file in my directory, but I don't understand much about this header file. I wonder if the problem is here. I haven't altered it or anything. I assembled asm_io.asm according to Dr. Carter's instructions.
Not too far into asm_io.asm is see this:
extern _scanf, _printf, _getchar, _putchar, _fputs
So here are the unresolved externals. Shouldn't they be defined in stdio.h? Driver.c includes stdio.h, shouldn't the linker be able to resolve these symbols be looking at stdio.h? What might I be missing?
ps. I'm new to programming in general, and this is my first stack overflow question. I'm open to any and all criticism/feedback. I'll provide more information if you need it, I just didn't want to post a massive wall of text and code if not necessary.
Welcome to SO. You need to understand:-
The difference between a header file, e.g.
foo.h // C or maybe C++ header file)
and a library, e.g.
foo.lib foo.dll // Windows
libfoo.a, libfoo.so // Unix/Linux
that implements the calling interface that is (merely) described in a header file.
The difference between compiling or assembling a source file, e.g.
bar.c // C source file
bar.asm // Assembly source, Windows
bar.s // Assembly source, Unix/Linux
to make an object file. e.g.
bar.obj // Windows
bar.o // Unix/Linux
and linking object files and libraries together make a complete executable.
Linking can succeed only if the linker is supplied with (or knows by default)
the names and locations of object files and/or libraries that provide
implementations of all the functions that are called in the program - including
functions whose calling interfaces are described in header files. Otherwise
unresolved symbol errors ensue.
Research these points and you'll quickly get yourself unstuck. See this
pretty good introductory tutorial, which although it is about getting
started with the GNU Compiler Collection rather
than with assembly language programming, will clarify the principles
and distinctions you need to grasp.
I am programming stm8s and sht20 from sensirion company with I2C on the IAR. I'm using sht20 sample code: this link
I edited this sample code to my mcu. Then, for example I included i2c_hal.h to my main.c, but functions not working in my main.c file and IAR error is
ERROR LI005 no defition for I2c_Init()
Linking error
For example:
main.c
#include "stm8s.h"
#include "i2c_hal.h"
I2c_Init();
i2c_hal.h
#ifndef I2C_HAL_H
#define I2C_HAL_H
void I2c_Init ();
#endif
i2c_hal.c
#include "I2C_HAL.h"
void I2c_Init ()
{
SDA=LOW;
SCL=LOW;
SDA_CONF=LOW;
SCL_CONF=LOW;
SDA=HIGH;
SCL=HIGH;
}
I copied sht20 files to my project directory. What should I do for this error?
The header file is read by the preprocessor not the linker; if you get as far as linking, it is not a header file issue. The three basic build steps for C code are:
preprocess
compile
link
Your build is failing at the link state. The linker requires all compiled object files and any necessary libraries that constitute your application as input. In your case the most likely issue is that you have not compiled and linked i2c_hal.c (or strictly compiled i2c_hal.c and linked i2c_hal.obj). In the IAR IDE you simply explicitly add i2c_hal.c to your project along with main.c, and all should be good (all other dependencies being satisfied).
I suspect that i2c_hal.c will infact fail compilation since it is missing any declaration of SDA, SCL etc. - you probably need to include stm8s.h there also.
In general the process looks like this (this diagram actually omits pre-processing - i.e. expansion of headers, macros and conditional compilation etc. - but it was the otherwise clearest example I found; the original page does however mention the pre-processor stage, and the preprocessor is normally run automatically when you invoke the compiler in any case):
I have also the same issue with the spi. I got hal_spi_init() linking problem. To resolve the issue you need to enable the I2C in your stm32 hal drivers. In stm32xx_hal_conf.h file we have different #define modules. There you can enable the I2C module or just include the defined symbol in your IAR tool. Then Issue resolved
You need to add the C source files to the project. Header files shall not have any code or data, only the declarations of types , extern variables, macros, static inline functions and function prototypes.
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.
I have a C project I'm importing to eclipse to work with. It was prewritten but not a C program, so I imported it as a C Makefile program. Actually for some reason the program was written with shell scripts which called the make in the appropriate directories, I added a Makefile that called the shell script, though I'll probably change it to use only make files.
Anyways the unusual thing is that I get exceptions on all the #define variables used in my C code. The variables are defined in a .h file which is included on the top of the C code, and the #include doesn't haev a warning. I can compile the code and run it without exception. Yet I still get dozens of errors where the #define values are used in the editor. The .h which defines the variables is in a different folder then the C code that throws the excception, but adding the folder with the .h into the C include path didn't do any good. Anyone know how I can get the editor to play nice with my #define variables?
Are you actually typing #DEFINE? It's supposed to be #define. C is case sensitive.
Here are some options to investigate the issue further:
Right-click your project in Eclipse, go to Properties -> C/C++ General -> Paths and Symbols -> Symbols. You can check the symbols defined there, maybe something is messing up the preprocessor there.
Add to your g++ command line the following option: -save-temps. This will output some intermediate compilation files. Check the .i or .ii files - these contain the preprocessed output. More information on this g++ option is here.
Also, it would be nice if you could give some more information about the actual errors/warnings.
How is the .h file included in the .c file?
#include <file.h>
or
#include "file.h"
These have different meanings in the preprocessor.
What is the error that you are getting? Is the .h file not found, causing the other errors?