CGo doesn't compile C files

2.1k Views Asked by At

I have a really simple setup: A .go file (test.go) and a .c file (PMDK.c). I include the .c file in Go as follows:

test.go:

package main

/*
#include "PMDK.c"
#cgo pkg-config: libpmem
*/
import "C"

func main() {
    C.helloWorld()
}

When I run go run test.go, it builds for exactly one time. Whatever changes I do to PMDK.c, my program has the exact same behavior every time.

I also tried go build test.go, which leads to the same result. Finally , following CGo not compiling C files in same directory, I just did go build. This didn't work, since I had to create a .mod file (go build test.go). Then, the problem was that the three functions in PMDK.c (helloWorld and two others) were supposedly defined multiple times. I can't make it build my changes. By the way, if I copy/move the source files to another directory and build them there, the changes apply (only for once, again).

1

There are 1 best solutions below

0
On BEST ANSWER

The heart of the problem is that your setup is wrong: your Go code should #include, in the Cgo prefix, only the headers for any C code you want compiled separately. For instance:

package main

/*
#include "pmdk.h"
*/
import "C"

func main() {
    C.helloWorld()
}

You can put C code into the prefix:

package main

/*
#include <stdio.h>
void helloWorld() {
        printf("hello world from C\n");
}
*/
import "C"

...

But if you put your C code into a separate file (prog.c, etc.), you should create a small header file that simply declares each function, and #include that header file from both the C code and the Go code.1

Running:

go build

will then compile the C code if it has changed, and build the Go code if it has changed, and link together the two as appropriate. If you #include the C code directly into the Go package, as you did, go build will both build the C code and build the Go code that includes the C code, which is why you get the duplicate definitions.

Whatever C code you embed in the Cgo header should appear nowhere else. This is a good place to put small "plumbing adapters", if you have some existing C code that mostly works with Go, but needs some tweaks.


1This is a general technique in C for making sure that the header file declarations of functions agree with the C source definition of the same functions. That is, the header fifth.h might say:

void func(int arg1, char *arg2);

and, separately, the C code will read:

#include "fifth.h"

void func(int zorg, char *evil) {
    // ...
}

and the C compiler will check that the declaration matches the definition.