Getting the Nim -> C wrapping right can be a bit of a challenge, but once you 
know what's going on under the hood it's easy to see what you did wrong. So 
let's dive into what goes on here.

First of you started with
    
    
    type ClipboardObj* {.importc: "clipboard_c", 
header:"libclipboard/libclipboard.h".} = pointer
    
    
    Run

This tells Nim that whenever it sees the use of `ClipboardObj` it should 
replace it with `clipboard_c` and otherwise treat it as a pointer in Nim code. 
This means that code like this:
    
    
    var clipboard = clipboard_new(nil)
    
    
    Run

roughly translates to:
    
    
    clipboard_c clipboard;
    clipboard = clipboard_new(NULL);
    
    
    Run

This is obviously not correct as `clipboard_new` returns a `clipboard_c*` and 
not `clipboard_c`. The initial definition of the `clipboard` variable is what 
causes the compiler to throw that incomplete struct error. It simply doesn't 
know how big `clipboard_c` is, and therefore can't allocate room for it.

If we simply change the to be:
    
    
    type ClipboardObj* {.importc: "clipboard_c*", 
header:"libclipboard/libclipboard.h".} = pointer
    
    
    Run

The problem is now fixed. Now you tell Nim that `ClipboardObj` should be 
treated as a pointer, and when converting it to C it should be converted as 
`clipboard_c*`.

So why does your code work? In fact the `{.pure.}` pragma you attach to it has 
nothing to do with it, in doesn't do anything for object types and is only used 
for enums. The definitions:
    
    
    type
      ClipboardStruct* {.importc:"clipboard_c", header: 
"libclipboard/libclipboard.h".} = object
      ClipboardObj* = ptr ClipboardStruct
    
    
    Run

by themselves would solve the problem on their own. This is because 
`ClipboardStruct` is now `clipboard_c` and `ClipboardObj` being defined as a 
pointer to that struct is now `clipboard_c*` which is the correct type.

While debugging this wrapping I simply looked at what Futhark generated for 
these bindings. With:
    
    
    import futhark
    
    importc:
      absPath "/usr/lib/clang/13.0.0/include"
      absPath "/usr/include"
      "libclipboard.h"
    
    var clipboard = clipboard_new(nil)
    echo clipboard == nil
    echo clipboard.clipboardSetText("Hello world".cstring)
    clipboard.clipboardFree()
    
    
    Run

I was able to look into the generated Nim file in the cache and peek at all the 
definitions. If you don't want to use Futhark yourself for wrapping I can still 
recommend it as a learning tool. If you're able to wrap things with Futhark 
(and you should be able to wrap most things entirely automatically) you should 
be able to just have a look at the definitions there and copy them into your 
own code.

Reply via email to