undefined reference to error only for certain functions - go

I have a library and a C interface built for it.
My program compiles just fine with versionString() but not with loadConfig(). How is that possible?
walker.h :
#ifndef WFE_C_H
#define WFE_C_H
#ifdef __cplusplus
extern "C" {
#endif
const char* versionString();
void* loadConfig(const char *filePath, char* errorMessageBuffer, int bufferLen);
#ifdef __cplusplus
}
#endif
#endif
Working version:
package main
/*
#cgo CFLAGS: -Isrc/walker
#cgo LDFLAGS: -L${SRCDIR}/lib -lwalker
#include "walker.h"
*/
import (
"C"
)
func main() {
p := C.versionString()
version := C.GoString(p)
fmt.Println(version)
}
// output: v1.94
Not working version:
package main
/*
#cgo CFLAGS: -Isrc/walker
#cgo LDFLAGS: -L${SRCDIR}/lib -lwalker
#include "walker.h"
*/
import (
"C"
)
func main() {
errorMessageBuffer := C.CString("")
pathPtr := C.CString("/src/vali/config")
bufferLen := C.int(len(4000))
C.loadConfig(pathPtr, errorMessageBuffer, bufferLen)
}
Traceback:
/tmp/go-build056292810/github.com/testong/vali/_obj/main.cgo2.o: In
function `_cgo_b2bd1c9e3dda_Cfunc_loadConfig':
/tmp/go-build/github.com/testong/vali/_obj/cgo-gcc-prolog:43: undefined
reference to `loadConfig'
collect2: error: ld returned 1 exit status

In walker.h , the export function is
void* loadConfig(const char *filePath, char* errorMessageBuffer, int bufferLen);
And you used C.loadConfigDirectory(pathPtr, errorMessageBuffer, bufferLen).
The function loadConfigDirectory is not defined.
Maybe it is a typo?
Working version works because versionString is already defined.

Related

Cgo pass a string to C file

I am using cgo and saw this post about running c++ from go:
I want to use [this function] in Go. I'll use the C interface
// foo.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void* Foo;
Foo FooInit(void);
void FooFree(Foo);
void FooBar(Foo);
#ifdef __cplusplus
}
#endif
I did this, but how can I pass a string as an argument to the C++ function? I tried to pass a rune[] but it did not work.
This is the Go code:
// GetFileSizeC wrapper method for retrieve byte lenght of a file
func GetFileSizeC(filename string) int64 {
// Cast a string to a 'C string'
fname := C.CString(filename)
defer C.free(unsafe.Pointer(fname))
// get the file size of the file
size := C.get_file_size(fname)
return int64(size)
}
From C
long get_file_size(char *filename) {
long fsize = 0;
FILE *fp;
fp = fopen(filename, "r");
if (fp) {
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
fclose(fp);
}
return fsize;
}
Remember that you need to add the headers library that you need before the import in the Go file:
package utils
// #cgo CFLAGS: -g -Wall
// #include <stdio.h> |
// #include <stdlib.h> | -> these are the necessary system header
// #include <string.h> |
// #include "cutils.h" <-- this is a custom header file
import "C"
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
....
)
This is an old project that you can use for future working example:
https://github.com/alessiosavi/GoUtils

warning: unused variable ‘_cgo_a’

What is the '_cgo_a' variable?
I'm trying to link a c++ static lib.
greeter.cpp
#include "greeter.h"
#include <iostream>
void
greet()
{
std::cout << "Greetings\n";
}
greeter.h
#ifndef GREETER_H_
#define GREETER_H_
#ifdef __cplusplus
extern "C" {
#endif
void
greet();
#ifdef __cplusplus
}
#endif
#endif
I compiled the above into a static library like so:
$ g++ -c greeter.cpp
$ ar vfx greeter.o -o libgreeter.a
and here's my main.go
package main
// #cgo CFLAGS: -g -Wall
// #cgo LDFLAGS: -L. -lgreeter
// #include "greeter.h"
import "C"
func main() {
C.greet()
}
Then when I do go build that's what I get:
# error
cgo-gcc-prolog: In function ‘_cgo_261f55e693f4_Cfunc_greet’:
cgo-gcc-prolog:46:49: warning: unused variable ‘_cgo_a’ [-Wunused-variable]
My go version: go version go1.12.5 linux/amd64
EDIT:
If I remove the -Wall from the CFLAGS it compiles fine. Still what is the _cgo_a variable and why is it give me an error?
Do not use -Wall in cgo CFLAGS. This is a general issue in Go. Read more in the github thread: https://github.com/golang/go/issues/6883#issuecomment-383800123

Shared library undefined reference for CUDA Kernel wrapper

So I am attempting to use the CUDA Runtime API with Go's cgo on Windows. I've been at this for a few days now and am stuck: I am getting an undefined reference to my kernel wrapper.
I have separated out my kernel and it's wrapper into the following
FILE: cGo.cuh
typedef unsigned long int ktype;
typedef unsigned char glob;
/*
function Prototypes
*/
extern "C" void kernel_kValid(int, int, ktype *, glob *);
__global__ void kValid(ktype *, glob *);
FILE: cGo.cu
#include "cGo.cuh"
#include "device_launch_parameters.h"
#include "cuda.h"
#include "cuda_runtime.h"
//function Definitions
/*
kernel_kValid is a wrapper function for the CUDA Kernel to be called from Go
*/
extern "C" void kernel_kValid(int blocks, int threads, ktype *kInfo, glob *values) {
kValid<<<blocks, threads>>>(kInfo, values);//execute the kernel
}
/*
kValid is the CUDA Kernel which is to be executed
*/
__global__ void kValid(ktype *kInfo, glob *values) {
//lots of code
}
I compile my CUDA source code into a shared library as such:
nvcc -shared -o myLib.so cGo.cu
then I have created a header file to include in my cgo
FILE: cGo.h
typedef unsigned long int ktype;
typedef unsigned char glob;
/*
function Declarations
*/
void kernel_kValid(int , int , ktype *, glob *);
Then from the go package I utilize cgo to call my kernel wrapper I have
package cuda
/*
#cgo LDFLAGS: -LC:/Storage/Cuda/lib/x64 -lcudart //this is the Cuda library
#cgo LDFLAGS: -L${SRCDIR}/lib -lmyLib //this is my shared library
#cgo CPPFLAGS: -IC:/Storage/Cuda/include //this contains cuda headers
#cgo CPPFLAGS: -I${SRCDIR}/include //this contains cGo.h
#include <cuda_runtime.h>
#include <stdlib.h>
#include "cGo.h"
*/
import "C"
func useKernel(){
//other code
C.kernel_kValid(C.int(B), C.int(T), unsafe.Pointer(storageDevice), unsafe.Pointer(globDevice))
cudaErr, err = C.cudaDeviceSynchronize()
//rest of the code
}
So all of the calls to the CUDA runtime API don't throw errors, it's only my kernel wrapper. This is the output when I build the cuda package with go.
C:\Users\user\Documents\Repos\go\cuda_wrapper>go build cuda_wrapper\cuda
# cuda_wrapper/cuda
In file included from C:/Storage/Cuda/include/host_defines.h:50:0,
from C:/Storage/Cuda/include/device_types.h:53,
from C:/Storage/Cuda/include/builtin_types.h:56,
from C:/Storage/Cuda/include/cuda_runtime.h:86,
from C:\Go\workspace\src\cuda_wrapper\cuda\cuda.go:12:
C:/Storage/Cuda/include/crt/host_defines.h:84:0: warning: "__cdecl" redefined
#define __cdecl
<built-in>: note: this is the location of the previous definition
# cuda_wrapper/cuda
C:\Users\user\AppData\Local\Temp\go-build038297194\cuda_wrapper\cuda\_obj\cuda.cgo2.o: In function `_cgo_440ebb0a3e25_Cfunc_kernel_kValid':
/tmp/go-build\cuda_wrapper\cuda\_obj/cgo-gcc-prolog:306: undefined reference to `kernel_kValid'
collect2.exe: error: ld returned 1 exit status
It's here I'm not really sure what's wrong. I have been looking at questions asked about undefined references with cgo but nothing I have found has solved my issue. I have also been looking at the fact that the CUDA runtime API is written in C++ and if that would affect how cgo will compile this but again I haven't found anything conclusive. At this point I think I have confused myself more than anything else so I'm hoping someone more knowledgeable can point me in the right direction.
Good catch on the name manlging.
Here's a solution we used for gorgonia:
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
__global__ void sigmoid32(float* A, int size)
{
int blockId = blockIdx.x + blockIdx.y * gridDim.x + gridDim.x * gridDim.y * blockIdx.z;
int idx = blockId * (blockDim.x * blockDim.y * blockDim.z) + (threadIdx.z * (blockDim.x * blockDim.y)) + (threadIdx.y * blockDim.x) + threadIdx.x;
if (idx >= size) {
return;
}
A[idx] = 1 / (1 + powf((float)(M_E), (-1 * A[idx])));
}
#ifdef __cplusplus
}
#endif
So... just wrap your kernel wrapper function in extern "C"

How to Link Golang package to an existing C project (Using Go from C) on windows x86-64

How to use Golang Generated libgolang.a from C code to build C executable: test.exe:
these commands makes executable binary 'test' in Ubuntu x86-64 and works fine (but not in Windows x86-64):
go build -buildmode c-archive -o libgolang.a
gcc -o test _main.c libgolang.a -lpthread
with:
this is main.go file:
package main
import "C"
import "fmt"
//export Add
func Add(a, b uint64) uint64 {
return a + b
}
func main() {
fmt.Println("Hi")
}
and this is _main.c file:
#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"
int main()
{
uint64_t a=10;
uint64_t b=20;
uint64_t c=Add(a,b);
printf("%ld\n",c);
return 0;
}
in Windows this command:
go build -buildmode c-archive -o libgolang.a
works fine and generates libgolang.a and libgolang.h files. libgolang.h:
/* Created by "go tool cgo" - DO NOT EDIT. */
/* package github.com/ARamazani/go/DLL */
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
/* Start of boilerplate cgo prologue. */
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef __SIZE_TYPE__ GoUintptr;
typedef float GoFloat32;
typedef double GoFloat64;
typedef float _Complex GoComplex64;
typedef double _Complex GoComplex128;
/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
typedef struct { const char *p; GoInt n; } GoString;
typedef void *GoMap;
typedef void *GoChan;
typedef struct { void *t; void *v; } GoInterface;
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
#endif
/* End of boilerplate cgo prologue. */
#ifdef __cplusplus
extern "C" {
#endif
extern GoUint64 Add(GoUint64 p0, GoUint64 p1);
#ifdef __cplusplus
}
#endif
but this command:
gcc -o test _main.c libgolang.a -lpthread
output:
libgolang.a(go.o):(.data+0x2150): undefined reference to `NtWaitForSingleObject'
libgolang.a(go.o):(.data+0x21b8): undefined reference to `WSAGetOverlappedResult'
libgolang.a(go.o):(.data+0x21d8): undefined reference to `timeBeginPeriod'
collect2.exe: error: ld returned 1 exit status
go version go1.7rc3 windows/amd64
I want to use this libgolang.a from C code to build C executable: test.exe
any workaround?
some useful links:
http://blog.ralch.com/tutorial/golang-sharing-libraries/
Using Go code in an existing C project
Using Go on existing C project
Finally found at least one way:
using this file main.go:
package main
import "C"
import "fmt"
//export Add
func Add(a, b uint64) uint64 {
return a + b
}
func main() {
fmt.Println("Hi")
}
run this command:
go build -buildmode c-archive -o libgolang.a
to generate libgolang.a and libgolang.h
then using _main.c:
#include <stdio.h>
#include <stdint.h>
#include "libgolang.h"
int main()
{
uint64_t a=10;
uint64_t b=20;
uint64_t c=Add(a,b);
printf("%ld\n",c);
return 0;
}
this is the answer (this works for me):
gcc -o test _main.c libgolang.a -lWinMM -lntdll -lWS2_32
that test.exe created.
run:
test.exe
output:
30
The Microsoft Windows always trick us!
But for production code my suggestion is use the optimization compile commands below:
go build -ldflags "-s -w" -buildmode c-archive -o libgolang.a
The parameter -ldflags "-s -w", will reduze the final file size.
The "libgolang.a" shrink from 4.295.562 to 1.994.554.
And the "test.exe" shrink from 3.430.485 to 1.715.561.
I guess this is a desired behavior!

how to compile Cuda source with Go language's cgo?

I wrote a simple program in cuda-c and it works on eclipse nsight. This is source code:
#include <iostream>
#include <stdio.h>
__global__ void add( int a,int b, int *c){
*c = a + b;
}
int main(void){
int c;
int *dev_c;
cudaMalloc((void**)&dev_c, sizeof(int));
add <<<1,1>>>(2,7,dev_c);
cudaMemcpy(&c, dev_c, sizeof(int),cudaMemcpyDeviceToHost);
printf("\n2+7= %d\n",c);
cudaFree(dev_c);
return 0;
}
Now I'm trying to use this code with Go language with cgo!!!
So I wrote this new code:
package main
//#include "/usr/local/cuda-7.0/include/cuda.h"
//#include "/usr/local/cuda-7.0/include/cuda_runtime.h"
//#cgo LDFLAGS: -lcuda
//#cgo LDFLAGS: -lcurand
////default location:
//#cgo LDFLAGS: -L/usr/local/cuda-7.0/lib64 -L/usr/local/cuda-7.0/lib
//#cgo CFLAGS: -I/usr/local/cuda-7.0/include/
//
//
//
//
//
//
//
//
//
//
/*
#include <stdio.h>
__global__ void add( int a,int b, int *c){
*c = a + b;
}
int esegui_somma(void){
int c;
int *dev_c;
cudaMalloc((void**)&dev_c, sizeof(int));
add <<<1,1>>> (2,7,dev_c);
cudaMemcpy(&c, dev_c, sizeof(int),cudaMemcpyDeviceToHost);
cudaFree(dev_c);
return c;
}
*/
import "C"
import "fmt"
func main(){
fmt.Printf("il risultato è %d",C.esegui_somma)
}
But it doesn't work!!
I read this error message:
cgo_cudabyexample_1/main.go:34:8: error: expected expression before '<' token
add <<<1,1>>> (2,7,dev_c);
^
I think that I must to set nvcc cuda compiler for cgo instead of gcc.
How can I do it? Can I change CC environment variable?
best regards
I finally figured out how to do this. Thing biggest problem is that nvccdoes not follow gcc standard flags and unlike clang it won't silently ignore them. cgo triggers the problem by adding a bunch of flags not explicitly specified by the user.
To make it all work, you'll need to separate out your device code and the functions that directly call it into separate files and compile/package them directly using nvcc into a shared library (.so). Then you'll use cgo to link this shared library using whatever default linker you have on your system. The only thing you'll have to add is -lcudart to your LDFLAGS (linker flags) to link the CUDA runtime.

Resources