We'll name our package main, even though we are not creating a command module it's important the package name is main, otherwise when we build a c-shared library it will build an ar archive, and not a dynamic library.

package main

And in the comments section we include emacs-module.h . We also declare int plugin_is_GPL_compatible .

We need to provision our feature within emacs. To do this we need to call the Emacs (provide) function just like we did with the C module. Unfortunately we can not call C pointer functions directly from Go. But we can call them from C. So we'll create a helper C function that can access the struct function pointer we need. We'll do this in the special comment section just before import "C" .

static void provide ( struct emacs_runtime *ert, const char *feature ) { emacs_env *env = ert-> get_environment ( ert ) ; emacs_value Qfeat = env-> intern ( env, feature ) ; emacs_value Qprovide = env-> intern ( env, "provide" ) ; emacs_value args [] = { Qfeat } ; env-> funcall ( env, Qprovide, 1 , args ) ; }

We declare our function in C even though cgo will generate a gmodule.h file. If we don't declare it now we won't be able to reference it from this file.

extern emacs_value Fgo_version ( emacs_env* p0 ) ;

We create a helper function to fset our function within emacs, this function assumes our Emacs function will not be taking any arguements it's not ideal but it will work for the function we want to create. We also hardcode our doc

static void fset ( struct emacs_runtime *ert, const char *name, void *fn ) { emacs_env *env = ert-> get_environment ( ert ) ; emacs_value Qfn = env-> make_function ( env, 0 , 0 , fn, "Return string describing the go runtime version." , NULL ) ; emacs_value Qfset = env-> intern ( env, "fset" ) ; emacs_value Qsym = env-> intern ( env, name ) ; emacs_value fargs [] = { Qsym, Qfn } ; env-> funcall ( env, Qfset, 2 , fargs ) ; }

Later on we'll need to convert the runtime version Go string into a Emacs string value. Since we can't call function pointers directly we'll create a helper function to handle this.

static emacs_value make_string ( emacs_env * env, const char *s ) { return env-> make_string ( env, s, strlen ( s ) ) ; }

We need to import the C package. The C package is special since it tells go to build with cgo. It's important that this package import comes first and it on it's own line. We need to close our C comment section just before import "C" there should be no new lines after closing the comment.

*/ import "C" import ( "runtime" "unsafe" )

We'll be using some C strings. Go will not be able to memory manage our C types. so we'll have to use some unsafe functions and free the strings ourselves. We'll create a freeString function to make this easier. C.free calls the free function we included in stdlib.h . We also need to use the unsafe package to get the pointer.

func freeString ( cstring * C.char ) { C. free ( unsafe. Pointer ( cstring ) ) }

We declare the Go function. This is the Go code that will be exectuted when we call our Emacs function using (go-version) . Our function will return a type that emacs can evaluate. In this case the go runtime version as a string.

func Fgo_version ( env * C.emacs_env ) C.emacs_value { version := runtime. Version () cversion := C. CString ( version ) defer freeString ( cversion ) return C. make_string ( env, cversion ) }

Next we create our Emacs entry point. and we'll use //export directive to tell cgo we want to export this as a dynamic function. This is the same as if we wrote extern int emacs_module_init(struct emacs_runtime* p0); in C, in fact Go will produce this declaration when it creates a C header file for our dynamic library.

If we were to return the Go type int instead of C.int it would create a compiler error since the signature would no longer match the Emacs one.

func emacs_module_init ( ert * C.struct_emacs_runtime ) C.int { cfeat := C. CString ( "gmodule" ) fname := C. CString ( "go-version" ) defer freeString ( fname ) defer freeString ( cfeat ) C. provide ( ert, cfeat ) C. fset ( ert, fname, C.Fgo_version ) ; return 0 }

Even though this is not a command package. We need to include a main function. Due to the fact we are exporting go functions using //export . We can simply stub one out like so.