gocgogo-build

CGo doesn't compile C files


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).


Solution

  • 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.