JuliaInterop / Clang.jl

C binding generator and Julia interface to libclang
https://juliainterop.github.io/Clang.jl/
MIT License
219 stars 68 forks source link

Creating bindings for libwinit #412

Closed VarLad closed 1 year ago

VarLad commented 1 year ago

Apparently, Clang.jl errors when translating this bit of code:

#include <stdint.h>

enum X {
  A,
  B,
  C,
};
typedef uint32_t X;

The error is:

ERROR: LoadError: AssertionError: ptr_ref[] != C_NULL
Stacktrace:
 [1] Clang.TokenList(tu::Ptr{Clang.LibClang.CXTranslationUnitImpl}, sr::Clang.LibClang.CXSourceRange)
   @ Clang ~/.julia/packages/Clang/HZdsi/src/token.jl:13
 [2] tokenize(c::Clang.CLNoDeclFound)
   @ Clang ~/.julia/packages/Clang/HZdsi/src/token.jl:105
 [3] is_same(cursor1::Clang.CLNoDeclFound, cursor2::Clang.CLEnumDecl)
   @ Clang.Generators ~/.julia/packages/Clang/HZdsi/src/generator/utils.jl:19
 [4] sanity_check(dag::ExprDAG, options::Dict{String, Any})
   @ Clang.Generators ~/.julia/packages/Clang/HZdsi/src/generator/audit.jl:68
 [5] (::Audit)(dag::ExprDAG, options::Dict{String, Any})
   @ Clang.Generators ~/.julia/packages/Clang/HZdsi/src/generator/passes.jl:859
 [6] build!(ctx::Context, stage::Clang.Generators.BuildStage)
   @ Clang.Generators ~/.julia/packages/Clang/HZdsi/src/generator/context.jl:169
 [7] build!(ctx::Context)
   @ Clang.Generators ~/.julia/packages/Clang/HZdsi/src/generator/context.jl:160
 [8] top-level scope
   @ ~/generator.jl:8

This is technically valid C code.

VarLad commented 1 year ago

@Gnimuc Is to possible to translate the above to

@cenum X::UInt32 begin
     A,
     B,
     C
end

using Clang.jl (using some config in generator.toml)?

Gnimuc commented 1 year ago

This is technically valid C code.

you set the bar too low.

the code below is also valid C code, but I believe you can not translate it elegantly to any other main stream languages without implementing the insane namespace machanisim of C.

typedef struct A {
  int x;
} B;

typedef struct B {
  float y;
} A;

however, you should not get this error/crash. the expected behavior is that the generator yields above statement as error logs.

VarLad commented 1 year ago

@Gnimuc C doesn't have a way to deal with the alternative of something like:

@cenum Name::UInt32 begin
     Param
end

Languages like Rust, (when exporting to C headers via some autogen tool), do

enum Name {
  Param
};
typedef uint32_t Name;

to convey the above.

Does it make sense to make a feature request to have an optional parameter (false by default) in generator.toml to accept the above code and translate it to appropriate Julia code (for convenience)? I can try looking into making a PR as well!

Gnimuc commented 1 year ago

I would suggest the following pattern:

enum {
  A,
  B,
  C
}; 

// the purpose here is to prevent users in any way from using C's mysterious enum types.

typedef int name;

but I'm always open for PRs.

VarLad commented 1 year ago

We can have both patterns. :) Can you point me to the file I need to look into to make this change?

Gnimuc commented 1 year ago

https://github.com/JuliaInterop/Clang.jl/issues/412#issuecomment-1360637892 is already supported.

This pattern violates the assumption used for merging translation units, so you probably need to check all down-stream passes.

Gnimuc commented 1 year ago

I fixed the issue in the OP: AssertionError: ptr_ref[] != C_NULL

You can checkout the master branch and give it a test.

Gnimuc commented 1 year ago

I also added a "no audit" config entry to make it easy to work around these kinda problems.

Gnimuc commented 1 year ago

The pattern seems to be:

  1. Given a typedef identifier,
  2. If the underlying type is integer(how to make a list of such integer types?)
  3. Then check whether there is an enum tag with the same name (and this node should not be marked as Skip)
  4. If this kind of node can be found, mark the typedef node as Skip and replace the tag node with the newly inserted id
VarLad commented 1 year ago

I would suggest the following pattern:

enum {
  A,
  B,
  C
}; 

// the purpose here is to prevent users in any way from using C's mysterious enum types.

typedef int name;

but I'm always open for PRs.

@Gnimuc I tried this, it generates:

@cenum var"##Ctag#293"::UInt32 begin
    A = 0
    B = 1
    C = 2
end

const name = Cint

I'm not sure how to use this. Would it be possible to deanonymize this like we have for structs? I've opened an issue here: https://github.com/JuliaInterop/Clang.jl/issues/420

Gnimuc commented 1 year ago

@VarLad I actually implemented https://github.com/JuliaInterop/Clang.jl/pull/413/files for you. Have you tried that?