One of the most frustrating parts of working on Goncurses is the fact that ncurses increasingly uses more and more macros. C macros cause a lot of problems for cgo, which isn't all that surprising, because C macros can cause a lot of problems period.
In order to circumvent C macros you have to provide proper C function wrappers around them. Depending on the library you are trying to port, this could be quick and simple or it could be long and tedious. I will demonstrate a very simple example.
1. You will need to create three files: a go wrapper, a C header and a C source file. The two C files must share the same name.
2. Identify the macro you need to create a wrapper for. For the purpose of this example we will be using a macro called MY_MACRO. In your header file, write a function prototype for the wrapper.
int my_macro_wrapper(const int x);
3. In the C source file, write a definition for the function prototyped in your header which calls the macro you are wrapping.
int my_macro_wrapper(const int x)
{
return MY_MACRO(x);
}
4. In your .go file you will need to include your wrapper header and then wrap the C file in a go function.
// #include "macro_wrapper.h"
import "C"
...
C.my_macro_wrapper(2)
That's all there is to it!
In the complete, trivial example below you'll notice I used the macro to call another function. You might think it a good idea to circumvent the macro altogether and simply call my_function() directly in Go. While this would probably work, and certainly would in this example, it defeats the purpose for why the author of the C library used a macro in the first place. There are several reasons why this could be a bad idea and I recommend using the C API as the author intended.
Complete sources follow:
***
macro_wrapper.h:
***
int my_function(const int x);
#define MY_MACRO(x) my_function(x)
int my_macro_wrapper(const int x);
***
macro_wrapper.c
***
#include "macro_wrapper.h"
int my_function(const int x)
{
return x;
}
int my_macro_wrapper(const int x)
{
return MY_MACRO(x);
}
***
library_wrapper.c
***
package main
// #include "macro_wrapper.h"
import "C"
import "fmt"
func main() {
// Uncomment the following line to produce error
// fmt.Println(C.MY_MACRO(2))
fmt.Println(C.my_macro_wrapper(2))
}
No comments:
Post a Comment