浏览代码

Merge pull request #1296 from kassane/nuklear-support

gen_d: Add sokol_nuklear and sokol_args support
Andre Weissflog 2 周之前
父节点
当前提交
4c855e0867
共有 3 个文件被更改,包括 59 次插入3 次删除
  1. 1 0
      .github/workflows/gen_bindings.yml
  2. 11 2
      bindgen/gen_all.py
  3. 47 1
      bindgen/gen_d.py

+ 1 - 0
.github/workflows/gen_bindings.yml

@@ -322,6 +322,7 @@ jobs:
           dub build :instancingcompute
           dub build :mrt
           dub build :noninterleaved
+          dub build :nuklear
           dub build :offscreen
           dub build :quad
           dub build :shapes

+ 11 - 2
bindgen/gen_all.py

@@ -1,4 +1,4 @@
-import os, argparse, gen_nim, gen_zig, gen_odin, gen_rust, gen_d, gen_jai, gen_c3
+import os, argparse, gen_nim, gen_zig, gen_odin, gen_rust, gen_d, gen_jai, gen_c3, shutil
 
 parser = argparse.ArgumentParser()
 parser.add_argument("--zig-tiger-style", action="store_true", help="Enable zig tiger style mode.")
@@ -48,14 +48,23 @@ for task in zig_tasks:
 # D
 d_tasks = [
     *tasks,
+    [ '../sokol_args.h',  'sargs_',  [] ],
     [ '../sokol_fetch.h', 'sfetch_', [] ],
     [ '../util/sokol_memtrack.h', 'smemtrack_', [] ],
     [ '../util/sokol_imgui.h', 'simgui_',   ['sg_', 'sapp_'] ],
 ]
+# check if nuklear.h is available and copy it
+if os.path.exists('../tests/ext/nuklear.h'):
+    d_tasks.append([ '../util/sokol_nuklear.h', 'snk_',   ['sg_', 'sapp_'] ])
+    if os.path.exists('sokol-d'):
+        shutil.copy('../tests/ext/nuklear.h', 'sokol-d/src/sokol/c/nuklear.h')
 gen_d.prepare()
 for task in d_tasks:
     [c_header_path, main_prefix, dep_prefixes] = task
     gen_d.gen(c_header_path, main_prefix, dep_prefixes)
+# drop nuklear.h if copied (after generated D files)
+if os.path.exists('sokol-d/src/sokol/c/nuklear.h'):
+    os.remove('sokol-d/src/sokol/c/nuklear.h')
 
 # Rust
 gen_rust.prepare()
@@ -67,4 +76,4 @@ for task in tasks:
 gen_c3.prepare()
 for task in tasks:
     [c_header_path, main_prefix, dep_prefixes] = task
-    gen_c3.gen(c_header_path, main_prefix, dep_prefixes)
+    gen_c3.gen(c_header_path, main_prefix, dep_prefixes)

+ 47 - 1
bindgen/gen_d.py

@@ -24,6 +24,7 @@ module_names = {
     'slog_':    'log',
     'sg_':      'gfx',
     'sapp_':    'app',
+    'sargs_':   'args',
     'stm_':     'time',
     'saudio_':  'audio',
     'sgl_':     'gl',
@@ -32,6 +33,7 @@ module_names = {
     'sglue_':   'glue',
     'sfetch_':  'fetch',
     'simgui_':  'imgui',
+    'snk_':     'nuklear',
     'smemtrack_': 'memtrack',
 }
 
@@ -39,6 +41,7 @@ c_source_paths = {
     'slog_':    'sokol-d/src/sokol/c/sokol_log.c',
     'sg_':      'sokol-d/src/sokol/c/sokol_gfx.c',
     'sapp_':    'sokol-d/src/sokol/c/sokol_app.c',
+    'sargs_':   'sokol-d/src/sokol/c/sokol_args.c',
     'stm_':     'sokol-d/src/sokol/c/sokol_time.c',
     'saudio_':  'sokol-d/src/sokol/c/sokol_audio.c',
     'sgl_':     'sokol-d/src/sokol/c/sokol_gl.c',
@@ -47,6 +50,7 @@ c_source_paths = {
     'sglue_':   'sokol-d/src/sokol/c/sokol_glue.c',
     'sfetch_':  'sokol-d/src/sokol/c/sokol_fetch.c',
     'simgui_':  'sokol-d/src/sokol/c/sokol_imgui.c',
+    'snk_':     'sokol-d/src/sokol/c/sokol_nuklear.c',
     'smemtrack_': 'sokol-d/src/sokol/c/sokol_memtrack.c',
 }
 
@@ -56,7 +60,8 @@ ignores = [
 ]
 
 c_callbacks = [
-    'slog_func'
+    'slog_func',
+    'nk_plugin_filter',
 ]
 
 overrides = {
@@ -77,6 +82,9 @@ overrides = {
     'sdtx_font.font_index':                 'uint32_t',
     'SGL_NO_ERROR':                         'SGL_ERROR_NO_ERROR',
     'sfetch_continue':                      'continue_fetching',
+    'struct nk_context':                    'NkContext',
+    'nk_handle':                            'NkHandle',
+    'nk_flags':                             'NkFlags',
 }
 
 prim_types = {
@@ -123,10 +131,26 @@ class TypeConverter:
         self.enum_types = enum_types
 
     def as_d_type(self, c_type, is_param=False, decl_name=None):
+        c_type = c_type.strip()
+        # Check for override first
+        if c_type in overrides:
+            return overrides[c_type]
+
         d_to_c_types = {v: k for k, v in prim_types.items()}
         if c_type in d_to_c_types:
             c_type = d_to_c_types[c_type]
 
+        # Handle struct keyword in type (e.g., "struct nk_context *")
+        if c_type.startswith('struct '):
+            c_type = c_type[7:].strip()  # Remove 'struct' prefix
+            if c_type in overrides:
+                return overrides[c_type]
+            if c_type.endswith('*'):
+                # External struct pointer, treat as opaque
+                return 'void*' if is_param else 'void*'
+            # External struct by value, treat as named type if overridden
+            return overrides.get(c_type, c_type)
+
         if util.is_func_ptr(c_type):
             return self.as_func_ptr_type(c_type, decl_name)
         
@@ -167,6 +191,14 @@ class TypeConverter:
         if util.is_array_type(c_type):
             return self.as_array_type(c_type)
         
+        # Handle external types (e.g., nk_handle, nk_flags) not in struct_types or prim_types
+        if c_type not in self.struct_types and c_type not in prim_types:
+            if c_type.endswith('*'):
+                # Treat pointer to unknown type as void*
+                return 'void*' if is_param else 'void*'
+            # Treat unknown type by value as itself (assuming it's defined elsewhere)
+            return overrides.get(c_type, c_type)
+
         raise ValueError(f"Unsupported C type: {c_type} in declaration: {decl_name or 'unknown'}")
 
     def as_d_struct_type(self, s):
@@ -274,6 +306,17 @@ def pre_parse(inp):
             enum_types.append(enum_name)
             enum_items[enum_name] = [as_enum_item_name(item['name']) for item in decl['items']]
 
+def gen_nuklear_types():
+    """Generate type declarations for Nuklear external types."""
+    l("/++ Nuklear external type declarations +/")
+    l("extern(C) struct NkContext;")
+    l("extern(C) union NkHandle {")
+    l("    void* ptr;")
+    l("    int id;")
+    l("}")
+    l("alias NkFlags = uint;")
+    l("alias nk_plugin_filter = extern(C) int function(const(NkContext)*, NkHandle, int*, int) @system @nogc nothrow;")
+
 def gen_struct(decl, type_converter):
     struct_name = overrides.get(decl['name'], decl['name'])
     d_type = type_converter.as_d_struct_type(struct_name)
@@ -417,6 +460,9 @@ def gen_module(inp, dep_prefixes, c_header_path):
     l(f'module sokol.{inp["module"]};')
     logging.info(f"Generating imports for module {inp['module']}")
     gen_imports(inp, dep_prefixes)
+    # Add Nuklear types for the nuklear module
+    if inp['module'] == 'nuklear':
+        gen_nuklear_types()
     pre_parse(inp)
     type_converter = TypeConverter(inp['prefix'], struct_types, enum_types)
     for decl in inp['decls']: