PMunch / futhark

Automatic wrapping of C headers in Nim
MIT License
355 stars 19 forks source link

How to add extra pramgas to procedures ? #65

Closed dinau closed 1 year ago

dinau commented 1 year ago

I've tried these simplified steps,

  1. Make hello.c

    #include <stdio.h>
    void sayHello(void){ printf("Hello World"); }

    Make hello.dll

     gcc -shared -o hello.dll hello.c
  2. hello.h

    void sayHello(void);
  3. test.nim

    import futhark
    when defined(useFuthark):
     importc:
       path "."
       "hello.h"
       outputPath "helloDef.nim"
    else:
     include "helloDef.nim"
    
    sayHello()

    Generate helloDef.nim

     nim c -f -c -d:useFuthark -d:futharkRebuild test.nim
  4. I'd like to run only using helloDef.nim and hello.dll as follows;

    nim c -r test.nim
    
    ...
    ... undefined reference to `sayHello'
    ...

    but the error occured.

  5. Generated helloDef.nim

    from macros import hint
    
    when not declared(sayhello):
     proc sayhello*(): void {.cdecl, importc: "sayHello".}
    else:
     static :
       hint("Declaration of " & "sayhello" & " already exists, not redeclaring")

    I'd like to add dynlib:"hello.dll" pargma or pragma pragma(for flexibility)
    to sayhello* proc.
    How to add extra pragmas using Futhark directives in this case ?

PMunch commented 1 year ago

There are really a couple of questions here. To start lets address the error you get. That "undefined reference to sayHello is from the C compiler because it doesn't know that it should link against hello.dll. This can be fixed by passing in the correct linker flags with passL, either as a switch or as a pragma. For example on Linux (where I named the library libhello.so) I added {.passL: "-L. -lhello".} and the compilation went well. On Linux you also need to call it as LD_LIBRARY_PATH=. ./test because it doesn't load dynamic libraries from the current path by default, but I believe this isn't an issue with Windows. You can also throw this switch on the compilation nim c --passL:"-L. -lhello" test.

The only thing the dynlib pragma does is to automatically pass these flags during compilation when the procedures are used. The way you can add these built-in pragmas to everything in the Futhark generated output is to use the {.push.} and {.pop.} pragmas like this:


{.push dynlib: "hello.dll".}
when defined(useFuthark):
  import futhark

  importc:
    path "."
    "hello.h"
    outputPath "helloDef.nim"
else:
  include "helloDef.nim"
{.pop.}

sayHello()

This essentially applies the pragma to everything between the push and the pop, and they apply to the output of the importc and the include. Unfortunately this doesn't apply to custom pragmas from macros, but you can apply those with a macro that takes a typed input.