for C/C++ structs, the binary layout is different from the PNode binary layout 
of a compile time object instance, so you can't just deref a ptr Foo returned 
by a importc proc (that wouldn't make sense); and thankfully the compiler 
prevents it.

However you can access individual fields via accessors. Again, this can be 
automated to a large extent using macros that would generate such accessors.

Here's a complete working example, where I show accessors either by value 
(get_x1) or by pointer (get_x2_ptr):
    
    
    when defined(timn_D20191211T153325):
      {.emit:"""
      #define MAX(a,b) ((a < b) ?  (b) : (a))
      #define MY_CONST1 "asdf"
      #define MY_CONST2 23
      
      typedef struct Foo {
        int x1;
        double x2;
      } Foo;
      
      N_LIB_EXPORT int MAX_int(int a, int b){ return MAX(a, b);}
      N_LIB_EXPORT char* get_MY_CONST1(){return MY_CONST1;}
      N_LIB_EXPORT int get_MY_CONST2(){return MY_CONST2;}
      
      // example showing returning struct
      N_LIB_EXPORT Foo* get_FooPtr(int x1, double x2){Foo* ret = 
(Foo*)(malloc(sizeof(Foo))); ret->x1 = x1; ret->x2 = x2; return ret;}
      N_LIB_EXPORT int get_x1(Foo*a) {return a->x1;}
      N_LIB_EXPORT double* get_x2_ptr(Foo*a) {return &a->x2;}
      """.}
    
    else:
      import std/[strformat,os,strutils]
      const libF = "/tmp/" / (DynlibFormat % "D20191211T153325")
      const nim = getCurrentCompilerExe()
      const file = currentSourcePath()
      static:
        when true:
          let cmd = fmt"{nim} c -d:timn_D20191211T153325 --app:lib -o:{libF} 
{file}"
          echo cmd
          let (output, exitCode) = gorgeEx cmd
          doAssert exitCode == 0, output
      
      proc MAX_int(a, b: int): int {.importc, dynlib: libF.}
      proc MY_CONST1(): cstring {.importc: "get_MY_CONST1", dynlib: libF.}
      proc MY_CONST2(): cint {.importc: "get_MY_CONST2", dynlib: libF.}
      
      type Foo = object
        x1: cint
        x2: float
      
      proc get_FooPtr(x1: cint, x2: float): ptr Foo {.importc, dynlib: libF.}
      proc get_x1(a: ptr Foo): cint {.importc, dynlib: libF.}
      proc get_x2_ptr(a: ptr Foo): ptr float {.importc, dynlib: libF.}
      
      proc main()=
        doAssert MAX_int(2, 3) == 3
        doAssert MY_CONST1() == "asdf"
        doAssert MY_CONST2() == 23
        
        # example showing passing/returning struct (by pointer)
        let foo = get_FooPtr(123, 1.5)
        doAssert foo.get_x1 == 123
        doAssert foo.get_x2_ptr[] == 1.5
        foo.get_x2_ptr[] = 2.0
        doAssert foo.get_x2_ptr[] == 2.0
      
      static: main()
      main()
    
    
    Run

Reply via email to