Building Go with C interface to Gtk+ - go

I'm trying to build a Go programm which uses external C code as an interface for Gtk+.
That's the basic Go code I've got (ui.h.go):
package main
//#cgo pkg-config: gtk+-3.0
//#include "ui.h"
import "C"
func CInit() {
C.Init(nil, 0)
}
func CMain() {
C.Main()
}
func CShowWindow() {
C.ShowWindow()
}
func main() {
CInit()
CShowWindow()
CMain()
}
C code is compiled from vala into an object file (ui.o) and a header file (ui.h):
#ifndef __UI_H__
#define __UI_H__
#include <glib.h>
#include <stdlib.h>
#include <string.h>
G_BEGIN_DECLS
void ShowWindow (void);
void Init (gchar** args, int args_length1);
void Main (void);
G_END_DECLS
#endif
When I try go build ui.h.go I get:
# command-line-arguments
/tmp/go-build916459533/command-line-arguments/_obj/ui.h.cgo2.o: In function `_cgo_80fc53cbf347_Cfunc_Init':
./ui.h.go:37: undefined reference to `Init'
/tmp/go-build916459533/command-line-arguments/_obj/ui.h.cgo2.o: In function `_cgo_80fc53cbf347_Cfunc_Main':
./ui.h.go:46: undefined reference to `Main'
/tmp/go-build916459533/command-line-arguments/_obj/ui.h.cgo2.o: In function `_cgo_80fc53cbf347_Cfunc_ShowWindow':
./ui.h.go:55: undefined reference to `ShowWindow'
collect2: error: ld returned 1 exit status
Which is logical, I haven't provided my object file. But if I specify it in cgo header of ui.h.go like that...
//#cgo LDFLAGS: ui.o
//#cgo pkg-config: gtk+-3.0
//#include "ui.h"
import "C"
I get multiple definition error, as if it's being linked twice.
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
ui.o:(.bss+0x0): multiple definition of `window'
/tmp/go-link-461834384/000000.o:/home/oleg/Документы/Projects/rasp/ui.h.go:38: first defined here
ui.o: In function `ShowWindow':
ui.c:(.text+0x0): multiple definition of `ShowWindow'
/tmp/go-link-461834384/000000.o:(.text+0x25): first defined here
ui.o: In function `Init':
ui.c:(.text+0x29): multiple definition of `Init'
/tmp/go-link-461834384/000000.o:(.text+0x4e): first defined here
ui.o: In function `Main':
ui.c:(.text+0x116): multiple definition of `Main'
/tmp/go-link-461834384/000000.o:(.text+0x13b): first defined here
collect2: error: ld returned 1 exit status
How do I link my ui.o file to the Go program correctly?
Thank you.

Well, I figured out that cgo does link well with static libraries. So I decided to archive my ui.o into libui.a and link it using #cgo LDFLAGS: -L. -lui and it worked correctly.

Related

cgo errors with undefined reference to

I have a valid C library, whose header file is located in ./src/include/lib.h.
I am using this code:
package main
/*
#include <stdlib.h>
#include "./src/include/lib.h"
*/
import "C"
import "unsafe"
func main() {
C.my_function()
}
However, when I try running it with go run, it gives an error at compile time:
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
/usr/bin/ld: /tmp/go-link-2251100724/000001.o: in function `_cgo_e59d248326bd_Cfunc_my_function':
/tmp/go-build/cgo-gcc-prolog:62: undefined reference to `my_function'
collect2: error: ld returned 1 exit status
I don't understand what's wrong, as the library is a valid C library (not a CPP library) and the header file is imported with success.

import c-shared library that generated by cython to go with cgo

I wanna import a c-shared-library to go that generated by Cython in python 3.7, try do it by cgo.
in this case:
go version go1.12.7 linux/amd64
Python 3.7.3
Cython version 0.29.12
os: Manjaro 18.0.4
Kernel: x86_64 Linux 5.1.19-1
I will continue:
make a python file vim pylib.pyx:
#!python
cdef public void hello():
print("hello world!")
and run python -m cython pylib.pyx for generate the c-shared-library, I have two files, pylib.c and pylib.h.
now, try import these to golang, so make a go file vim test.go:
package main
/*
#include </usr/include/python3.7m/Python.h>
#include "pylib.h"
*/
import "C"
import "fmt"
func main() {
C.hello()
fmt.Println("done")
}
finaly, I run go run test.go:
I have the following output:
# command-line-arguments
/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_51159acd5c8e_Cfunc_hello':
/tmp/go-build/cgo-gcc-prolog:48: undefined reference to `hello'
collect2: error: ld returned 1 exit status
I try import it to c too but I encountered a similar output like this:
undefined reference to `hello'
ld returned 1 exit status
I don't know what to do, help me, please.
:(
I run go run test.go: I have the following output:
# command-line-arguments
/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_51159acd5c8e_Cfunc_hello':
/tmp/go-build/cgo-gcc-prolog:48: undefined reference to `hello'
collect2: error: ld returned 1 exit status
We can generate an equivalent error message with the following code.
package main
/*
#include <math.h>
*/
import "C"
import "fmt"
func main() {
cube2 := C.pow(2.0, 3.0)
fmt.Println(cube2)
}
Output:
$ go run cube2.go
# command-line-arguments
/usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_f6c6fa139eda_Cfunc_pow':
/tmp/go-build/cgo-gcc-prolog:53: undefined reference to `pow'
collect2: error: ld returned 1 exit status
$
In both cases, ld (the linker) can't find a C function after looking in the usual places: undefined reference to 'pow' or undefined reference to 'hello'.
Let's tell cgo where to find the C pow function in the C math library: m.
For cgo, using ld flags,
#cgo LDFLAGS: -lm
GCC: 3.14 Options for Linking
-llibrary
Search the library named library when linking.
Updating the previous code,
package main
/*
#cgo LDFLAGS: -lm
#include <math.h>
*/
import "C"
import "fmt"
func main() {
cube2 := C.pow(2.0, 3.0)
fmt.Println(cube2)
}
Output:
$ go run cube2.go
8
$
This illustrates a basic cgo principle: include a C header file for your C library and point to the location of the C library.
References:
Cgo and Python : Embedding CPython: a primer

go run throes error " undefined reference to `dlopen'"

I am trying to integrate Golang script with existing C shared library.
The C shared library in turn loads other shared libraries at run time.
While I am trying to run
go run gotest.go
it throws error
./libtest.so: undefined reference to `dlopen'
./libtest.so: undefined reference to `dlclose'
./libtest.so: undefined reference to `dlerror'
./libtest.so: undefined reference to `dlsym'
collect2: error: ld returned 1 exit status
I have created separate C executable to load this libtest.so at run time and that is working properly.
Any idea what should be done to fix the issue?
I have tried following commands
sudo go build -compiler=gccgo -gccgoflags="-ltest" gotest.go
also tried the command
sudo go build -compiler=gccgo -gccgoflags="-ltest -ldl" gotest.go
Also tried the command
go run gotest.go
===============================================
Here is the code I am using
testapi.h
typedef Students{
char name[40];
int id;
} Student;
Student* getStudent();
test.c
#include <stdlib.h>
#include <stdio.h>
#include "mylib.h"
#include "testapi.h"
int rc = 0;
Student *s = 0;
Student* getStudent(){
rc = loadmylib(); //This function loads another shared library
if (!rc)
{
rc = initlib(); //This calls dlsym to get the necessary function from opened shared library
if (!rc)
{
s= (student *)malloc(sizeof(Student));
//use the function pointer received from dlsym to populate the Student struct 's'
}
}
return s;
}
I have following entries in my gotest.go file
package main
/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -ltest -ldl
#include "testapi.h"
*/
import "C"
import (
"fmt"
)
type Student struct{
name string
id int
}
func main() {
st := C.getStudent()
fmt.Println("Name: ", string(st.name))
}
I have copied testapi.h, gotest.go, mylib.h, libmylib.so, libtest.so in the same directory.
Then run the command
go run gotest.go
It has thrown the error " error: undefined reference to 'getStudent' "
What am I doing wrong here?
Am I supposed to run command
sudo go build -compiler=gccgo -gccgoflags="-ltest" gotest.go

cgo : Undefined symbols for architecture x86_64

I would like to call the go func from the C function space, but the program throws the build error.
example.go
package main
/*
#include "test.c"
*/
import "C"
import "fmt"
func Example() {
fmt.Println("this is go")
fmt.Println(C.GoString(C.myprint(C.CString("go!!"))))
}
// export receiveC (remove the extra space between // and export)
func receiveC(msg *C.char) {
fmt.Println(C.GoString(msg))
}
func main() {
Example()
}
test.c
#include <stdio.h>
extern void receiveC(char *msg);
char* myprint(char *msg) {
receiveC(msg); // calling the exported go function
return msg;
}
When I execute the command to run/build (go build or go run example.go or go build example.go) the program, it throws the error:
# github.com/subh007/goodl/cgo
Undefined symbols for architecture x86_64:
"_receiveC", referenced from:
_myprint in example.cgo2.o
__cgo_6037ec60b2ba_Cfunc_myprint in example.cgo2.o
_myprint in test.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I am following the cgo slides to writing the program. Please let me know for any mistakes here.
Edit1: I am using OS-X 10.9 OS.
Edit2:
I have one extra space between // export, there should be no space between // and export. But now I am getting the following error while building :
# github.com/subh007/goodl/cgo
duplicate symbol _myprint in:
$WORK/github.com/subh007/goodl/cgo/_obj/_cgo_export.o
$WORK/github.com/subh007/goodl/cgo/_obj/example.cgo2.o
duplicate symbol _receiver_go in:
$WORK/github.com/subh007/goodl/cgo/_obj/_cgo_export.o
$WORK/github.com/subh007/goodl/cgo/_obj/example.cgo2.o
duplicate symbol _myprint in:
$WORK/github.com/subh007/goodl/cgo/_obj/_cgo_export.o
$WORK/github.com/subh007/goodl/cgo/_obj/test.o
duplicate symbol _receiver_go in:
$WORK/github.com/subh007/goodl/cgo/_obj/_cgo_export.o
$WORK/github.com/subh007/goodl/cgo/_obj/test.o
ld: 4 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Duplicate symbols are generated because I have included the test.c directly to the go file. So the symbols are included twice.
I think, the correct way of writing this code is (please comment if I am wrong) to:
Define the header file (test.h):
#ifndef TEST_H_
#define TEST_H_
char* myprint(char *msg);
#endif
Define the implementation file (test.c):
#include <stdio.h>
#include "test.h"
extern void receiveC(char *msg);
char* myprint(char *msg) {
receiveC(msg);
return msg;
}
Include the .h file to the go file (example.go) :
package main
/*
#include "test.h"
*/
import "C"
import "fmt"
func Example() {
fmt.Println("this is go")
fmt.Println(C.GoString(C.myprint(C.CString("go!!"))))
}
// make sure that there should be no space between the `//` and `export`
//export receiveC
func receiveC(msg *C.char) {
fmt.Println(C.GoString(msg))
}
func main() {
Example()
}
Build the program :
go build
run the generated executable (the executable file generate with the cgo name, need some investigation to find the reason).
$./cgo

Trouble using scriptedmain in MinGW

I want to reproduce this Perl code in C, bundling API and CLI in the same C source code file (scriptedmain). This is done in Python with if __name__=="__main__": main() and in gcc/Unix, this looks like:
$ gcc -o scriptedmain scriptedmain.c scriptedmain.h
$ ./scriptedmain
Main: The meaning of life is 42
$ gcc -o test test.c scriptedmain.c scriptedmain.h
$ ./test
Test: The meaning of life is 42
scriptedmain.h
int meaning_of_life();
scriptedmain.c
#include <stdio.h>
int meaning_of_life() {
return 42;
}
int __attribute__((weak)) main() {
printf("Main: The meaning of life is %d\n", meaning_of_life());
return 0;
}
test.c
#include "scriptedmain.h"
#include <stdio.h>
extern int meaning_of_life();
int main() {
printf("Test: The meaning of life is %d\n", meaning_of_life());
return 0;
}
However, when I try to compile with gcc/Strawberry, I get:
C:\>gcc -o scriptedmain scriptedmain.c scriptedmain.h
c:/strawberry/c/bin/../lib/gcc/i686-w64-mingw32/4.4.3/../../../../i686-w64-mingw32/lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o): In function `main':
/opt/W64_156151-src.32/build-crt/../mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain#16'
collect2: ld returned 1 exit status
And when I try to compile with gcc/MinGW, I get:
$ gcc -o scriptedmain -mwindows scriptedmain.c scriptedmain.h
c:/mingw/bin/../lib/gcc/mingw32/4.5.2/../../../libmingw32.a(main.o):main.c:(.text+0x104): undefined reference to `WinMain#16'
collect2: ld returned 1 exit status
How can I get GCC in Windows to recognize the __attribute__((weak)) syntax?
Also, G++ shows the same error.
I found a solution that works in Windows and in Unix: Simply wrap main() in preprocessor instructions that omits it unless explicit compiler flags are set.
scriptedmain.c:
#include <stdio.h>
int meaning_of_life() {
return 42;
}
#ifdef SCRIPTEDMAIN
int main() {
printf("Main: The meaning of life is %d\n", meaning_of_life());
return 0;
}
#endif
Now main() will be entirely omitted unless you compile with
gcc -o scriptedmain -DSCRIPTEDMAIN scriptedmain.c scriptedmain.h
This code is safe to import into other C code, because the preprocessor will strip out main(), leaving you to code your own main. The best part is that this solution no longer depends on obscure compiler macros, only simple preprocessor instructions. This solution works for C++ as well.
This isn't good practice in C regardless of operating system. Best practice in C for anything complicated enough to be worth separating into library and driver is to put main in a file all by itself.

Resources