PMunch/futhark

Different bindings generated on Futhark 0.9.3 vs 0.10.0 or later

dinau opened this issue · 7 comments

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)

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.

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

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.

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.

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.

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.

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