I lack a deep understanding of how C works, but I wanted to call some of the functions within the pdh.dll Windows library from my Go code. I explored a few rabbit holes, so I figured I would post how I got this working. If you want to skip to running my examples on your own, you can download them here.
First off, if you don’t know anything about cgo (like myself) then I recommend learning the basics by reading C? Go? Cgo!
Before running any code using cgo or gcc you have to have gcc installed on your machine. I found the easiest install method to be tdm-gcc. Simply download the file corresponding to the architecture of your machine then run it.
Including a Windows Library
In my example code, pdh.go demonstrates what I set out to do. Here is the code:
package pdh // #cgo LDFLAGS: -L./lib -lpdh // #include <pdh.h> import "C" func PdhValidatePath(path string) uint32 { ret := C.PdhValidatePath(C.CString(path)) return uint32(ret) }
// #cgo LDFLAGS: -L./lib -lpdh
tells the gcc compiler to look for the pdh library within the standard lib directory (note that this directory is not within the Go project directory).
// #include <pdh.h>
tells the gcc compiler to include pdh.h. This means that all of the functions within pdh.h can be called using C.<function name>. An example of this is shown by the line ret := C.PdhValidatePath(C.CString(path))
Including Your Own C
If you want to write your own C class, then I recommend taking a look at the package named increment
within my example. In the package directory you can see increment.c and increment.h. These files were translated into increment.lib by running the following commands:
gcc -O2 -c increment.c ar q increment.lib increment.o
Since increment.lib and increment.h exist within the package directory, they can be referenced with just a simple #include statement as shown here:
package increment // #include <increment.h> import "C" func Increment(i int) int{ return int(C.x(C.int(i))) }
Including a Standard Library With Custom C Code
My package titled stdlib demonstrates how to include a standard library with custom C code that references that standard library.
package stdlib /* #include #include void myprint(char* s) { printf("%s\n", s); } */ import "C" import "unsafe" func PrintText() { cs := C.CString("Hello from stdio\n") C.myprint(cs) C.free(unsafe.Pointer(cs)) } func Random() int { return int(C.rand()) } func Seed(i int) { C.srand(C.uint(i)) }
In this code, you can see that there is a C function called myprint that is defined in the cgo preample. The myprint function can be used to print text using the stdio printf function. This is a pretty simple example, but it is a good starting point for anyone that has a reason to write code in C rather than Go.