PMunch / futhark

Automatic wrapping of C headers in Nim
MIT License
394 stars 22 forks source link

Different bindings generated on Futhark 0.9.3 vs 0.10.0 or later #86

Closed dinau closed 1 year ago

dinau commented 1 year ago

Minimum C header file test.h,

typedef enum {
    ImGuiWindowFlags_None = 0,
}ImGuiWindowFlags_;

Minimum nim test file main.nim,

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

Execute on command line,

nim c -c -f -d:useFuthark -d:futharkRebuild --nimcache:.nimcache main.nim

Generated code Futhark 0.9.3, this result is ok for me.

from macros import hint

when not declared(Imguiwindowflags):
  type
    Imguiwindowflags* {.size: sizeof(cint).} = enum
      Imguiwindowflagsnone = 0
else:
  static :
    hint("Declaration of " & "Imguiwindowflags" &
        " already exists, not redeclaring")
type
  Imguiwindowflags_28311856 = (when declared(Imguiwindowflags):
    Imguiwindowflags
   else:
    Imguiwindowflags_28311854)

Execute on command line,

Uninstall Futhark version 0.9.3
...
Install Futhark version 0.10.0
...

rm -fr .nimcache
nim c -c -f -d:useFuthark -d:futharkRebuild --nimcache:.nimcache main.nim

Generated code Futhark 0.10.0 or later, this result is NG for me.

from macros import hint

when not declared(enumimguiwindowflags):
  type
    enumimguiwindowflags* {.size: sizeof(cint).} = enum
      Imguiwindowflagsnone = 0
else:
  static :
    hint("Declaration of " & "enumimguiwindowflags" &
        " already exists, not redeclaring")
type
  enumimguiwindowflags_28311862 = (when declared(enumimguiwindowflags):
    enumimguiwindowflags
   else:
    enumimguiwindowflags_28311860)
PMunch commented 1 year ago

Hmm, I'm not able to reproduce this. With Futhark 0.9.3 it produces this:

from macros import hint

when not declared(enumimguiwindowflags):
  type
    enumimguiwindowflags* = distinct object
else:
  static :
    hint("Declaration of " & "enumimguiwindowflags" &
        " already exists, not redeclaring")
type
  Imguiwindowflags_520094022 = enumimguiwindowflags ## Generated based on /tmp/test/test.h:3:2
  Imguiwindowflags_520094024 = (when declared(Imguiwindowflags):
    Imguiwindowflags
   else:
    Imguiwindowflags_520094022)
when not declared(Imguiwindowflags):
  type
    Imguiwindowflags* = Imguiwindowflags_520094022
else:
  static :
    hint("Declaration of " & "Imguiwindowflags" &
        " already exists, not redeclaring")

while with 0.11.0 it produces this:

from macros import hint

when not declared(enumimguiwindowflags):
  type
    enumimguiwindowflags* {.size: sizeof(cuint).} = enum
      Imguiwindowflagsnone = 0
else:
  static :
    hint("Declaration of " & "enumimguiwindowflags" &
        " already exists, not redeclaring")
type
  Imguiwindowflags_520094025 = enumimguiwindowflags_520094024 ## Generated based on /tmp/test/test.h:3:2
  enumimguiwindowflags_520094024 = (when declared(enumimguiwindowflags):
    enumimguiwindowflags
   else:
    enumimguiwindowflags_520094022)
  Imguiwindowflags_520094026 = (when declared(Imguiwindowflags):
    Imguiwindowflags
   else:
    Imguiwindowflags_520094025)
when not declared(Imguiwindowflags):
  type
    Imguiwindowflags* = Imguiwindowflags_520094025
else:
  static :
    hint("Declaration of " & "Imguiwindowflags" &
        " already exists, not redeclaring")

As you can see the actual enum isn't declared in the 0.9.3 output, but in the 0.11.0 output it is declared. Maybe Clang has changed it's representation, which Clang version do you use? I'm running 16.0.6.

PMunch commented 1 year ago

Just to reduce the output if I rerun my tests with -d:nodeclguards I get this: v0.9.3:

type
  enumimguiwindowflags* = distinct object
type
  Imguiwindowflags* = enumimguiwindowflags ## Generated based on /tmp/test/test.h:3:2

v0.11.0:

type
  enumimguiwindowflags* {.size: sizeof(cuint).} = enum
    Imguiwindowflagsnone = 0
type
  Imguiwindowflags* = enumimguiwindowflags ## Generated based on /tmp/test/test.h:3:2
dinau commented 1 year ago

I'm using clang version 15.0.7 on Windows10. I've been aware of difference between clang 15 and 16 or later, so for consistency I'm using clang 15 at this moment.

PMunch commented 1 year ago

I just tried 15.0.7 now and I see results similar to yours. Unfortunately the libclang API is very poorly documented, so figuring out how to extract the pieces of information needed to build the wrapper is a bit of a guessing game.

PMunch commented 1 year ago

Try with 0.11.1, I tested it with 15.0.7 and it works. I'm looking into a more stable fix that will hopefully work better in the future as well.

PMunch commented 1 year ago

Pushed a 0.12.0 version now, even for a complex case like my GTK/Webkit test it now creates the exact same output for Clang 15 and 16.

dinau commented 1 year ago

Thank you for your investigation and upgrade. I'll try Futhark 0.12.0.