xlab / c-for-go

Automatic C-Go Bindings Generator for Go Programming Language
https://c.for-go.com
MIT License
1.47k stars 116 forks source link

Wrong accessors for C-structs in cgo_helpers.go #81

Open nazzrim opened 4 years ago

nazzrim commented 4 years ago

I am building a wrapper for cimgui with c-for-go and I cannot get it to build the generated code because the accessors to c-structs are wrong.

One of many (nearly 800) examples from the generated code:

const sizeOfImcolorValue = unsafe.Sizeof([1]C.ImColor{})

If it is changed to C.struct_ImColor{} it works. I cannot find information about that in the documentation. After Looking at some of the example projects I tried to add StructAccessors: true to generator options, but it did not change anything.

nazzrim commented 4 years ago

I tried to use c-for-go with one of the provided examples and It generates the correct .struct_ accessors. I don't know what I am doing wrong. My yml configuration only contains accept, replace, and transform rules as well as some pointer tips.

xlab commented 4 years ago

Hi! ImColor is a valid typedef https://github.com/cimgui/cimgui/blob/master/cimgui.h#L61 Why C.ImColor doesnt' work for you?

xlab commented 4 years ago

You can try to disable those typedefs in the original .h by CIMGUI_DEFINE_ENUMS_AND_STRUCTS, maybe that'd help. But seriously the way it works for you should be ok.. Could you share your .yml with me?

nazzrim commented 4 years ago

Of course. Here is my yml. Or in case it is easier for you, you can find the whole wrapper project here: https://github.com/nazzrim/imgui-go

You can "ignore" the FlagGroups since they are the result of some trial and error and do not change anything.

GENERATOR:
  PackageName: imgui
  PackageDescription: "Package imgui provides Go bindings for cimgui which is a C-wrapper for Dear ImGui by ocornut"
  PackageLicense: "THE AUTOGENERATED LICENSE. ALL THE RIGHTS ARE RESERVED BY ROBOTS."
  Includes: ["../cimgui/cimgui.h"]
  Options:
    SafeStrings: true
    StructAccessors: true
  FlagGroups:
    - {name: "LDFLAGS", flags: [-lpd]}
    - {name: "CXXFLAGS", flags: [-std=c++11]}

PARSER:
  IncludePaths:
  SourcesPaths:
    - cimgui/cimgui.h
  Defines:
    CIMGUI_DEFINE_ENUMS_AND_STRUCTS: 1
    __builtin_va_start: {}
    __builtin_va_end: {}

TRANSLATOR:
  ConstRules:
    defines: eval
    enum: expand
  Rules:
    global:
      - {transform: lower}
      - {action: accept, from: "^ig"}
      - {action: accept, from: "^Im"}
      - {action: replace, from: "^ig"}
      - {action: replace, from: "^ImGui"}
      - {action: replace, from: "^ImVec2_ImVec2", to: "ImVec2"}
      - {action: replace, from: "^ImVec4_ImVec4", to: "ImVec4"}
      - {action: replace, from: "^ImGuiStoragePair_ImGuiStoragePair", to: "ImGuiStoragePair"}
      - {transform: export}
    const:
      - {action: accept, from: "^Im"}
      - {transform: export}
    type:
      - {action: accept, from: "^Im"}
      - {transform: export}
    private:
      - {transform: unexport}
    post-global:
      - {action: replace, from: _$}
      - {load: snakecase}
  PtrTips:
    struct:
    function:
      - {target: "^ImVec2_destroy$", tips: [ref]}
      - {target: "^ImVec4_destroy$", tips: [ref]}
      - {target: "^igCreateContext$", tips: [ref]}
      - {target: "^igDestroyContext$", tips: [ref]}
      - {target: "^igSetCurrentContext$", tips: [ref]}
      - {target: "^igShowDemoWindow$", tips: [ref]}
      - {target: "^igShowAboutWindow$", tips: [ref]}
      - {target: "^igShowMetricsWindow$", tips: [ref]}
      - {target: "^igShowStyleEditor$", tips: [ref]}
      - {target: "^igStyleColorsDark$", tips: [ref]}
      - {target: "^igStyleColorsClassic$", tips: [ref]}
      - {target: "^igStyleColorsLight$", tips: [ref]}
      - {target: "^igBegin$", tips: [0,ref,0]}
      - {target: "^igPushFont$", tips: [ref]}
      - {target: "^igCheckbox$", tips: [0,ref]}
      - {target: "^igCheckboxFlags$", tips: [0,ref,0]}
      - {target: "^igRadioButtonIntPtr$", tips: [0,ref,0]}
      - {target: "^igCombo$", tips: [0,ref,0,0,0]}
      - {target: "^igComboStr$", tips: [0,ref,0,0]}
      - {target: "^igComboFnPtr$", tips: [0,ref,0,0,0,0]}
      - {target: "^igDragFloat$", tips: [0,ref,0,0,0,0,0]}
      - {target: "^igDragFloatRange2$", tips: [0,ref,ref,0,0,0,0,0,0]}
      - {target: "^igDragInt$", tips: [0,ref,0,0,0,0]}
      - {target: "^igDragIntRange2$", tips: [0,ref,ref,0,0,0,0,0]}
      - {target: "^igSliderFloat$", tips: [0,ref,0,0,0,0]}
      - {target: "^igSliderAngle$", tips: [0,ref,0,0,0]}
      - {target: "^igSliderInt$", tips: [0,ref,0,0,0]}
      - {target: "^igVSliderFloat$", tips: [0,0,ref,0,0,0,0]}
      - {target: "^igVSliderInt$", tips: [0,0,ref,0,0,0]}
      - {target: "^igInputFloat$", tips: [0,ref,0,0,0,0]}
      - {target: "^igInputInt$", tips: [0,ref,0,0,0]}
      - {target: "^igInputDouble$", tips: [0,ref,0,0,0,0]}
      - {target: "^igColorPicker4$", tips: [0,0,0,ref]}
      - {target: "^igCollapsingHeaderBoolPtr$", tips: [0,ref,0]}
      - {target: "^igSelectableBoolPtr$", tips: [0,ref,0,0]}
      - {target: "^igListBoxStr_arr$", tips: [0,ref,0,0,0]}
      - {target: "^igListBoxFnPtr$", tips: [0,ref,0,0,0,0]}
      - {target: "^igMenuItemBoolPtr$", tips: [0,0,ref,0]}
      - {target: "^igBeginPopupModal$", tips: [0,ref,0]}
      - {target: "^igBeginTabItem$", tips: [0,ref,0]}
      - {target: "^igShowDemoWindow$", tips: [ref]}
      - {target: "^igCalcListClipping$", tips: [0,0,ref,ref]}
      - {target: "^igIsMousePosValid$", tips: [ref]}
      - {target: "^igSaveIniSettingsToMemory$", tips: [ref]}
      - {target: "^ImGuiStyle_destroy$", tips: [ref]}
      - {target: "^ImGuiStyle_ScaleAllSizes$", tips: [ref,0]}
      - {target: "^ImGuiIO_AddInputCharacter$", tips: [ref,0]}
      - {target: "^ImGuiIO_AddInputCharactersUTF8$", tips: [ref,0]}
      - {target: "^ImGuiIO_ClearInputCharacters$", tips: [ref]}
      - {target: "^ImGuiIO_destroy$", tips: [ref]}
      - {target: "^ImGuiInputTextCallbackData_destroy$", tips: [ref]}
      - {target: "^ImGuiInputTextCallbackData_DeleteChars$", tips: [ref,0,0]}
      - {target: "^ImGuiInputTextCallbackData_InsertChars$", tips: [ref,0,0]}
      - {target: "^ImGuiInputTextCallbackData_HasSelection$", tips: [ref]}
      - {target: "^ImGuiPayload_destroy$", tips: [ref]}
      - {target: "^ImGuiPayload_Clear$", tips: [ref]}
      - {target: "^ImGuiPayload_IsDataType$", tips: [ref,0]}
      - {target: "^ImGuiPayload_IsPreview$", tips: [ref]}
      - {target: "^ImGuiPayload_IsDelivery$", tips: [ref]}
      - {target: "^ImGuiOnceUponAFrame_destroy$", tips: [ref]}
      - {target: "^ImGuiTextFilter_destroy$", tips: [ref]}
      - {target: "^ImGuiTextFilter_Draw$", tips: [ref,0,0]}
      - {target: "^ImGuiTextFilter_PassFilter$", tips: [ref,0,0]}
      - {target: "^ImGuiTextFilter_Build$", tips: [ref]}
      - {target: "^ImGuiTextFilter_Clear$", tips: [ref]}
      - {target: "^ImGuiTextFilter_IsActive$", tips: [ref]}
      - {target: "^ImGuiTextRange_destroy$", tips: [ref]}
      - {target: "^ImGuiTextRange_empty$", tips: [ref]}
      - {target: "^ImGuiTextRange_split$", tips: [ref,0,0]}
      - {target: "^ImGuiTextBuffer_destroy$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_begin$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_end$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_size$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_empty$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_clear$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_reserve$", tips: [ref,0]}
      - {target: "^ImGuiTextBuffer_c_str$", tips: [ref]}
      - {target: "^ImGuiTextBuffer_append$", tips: [ref,0,0]}
      - {target: "^ImGuiTextBuffer_appendfv$", tips: [ref,0,0]}
      - {target: "^ImGuiStoragePair_destroy$", tips: [ref]}
      - {target: "^ImGuiStoragePair_ImGuiStoragePairPtr$", tips: [0,ref]}
      - {target: "^ImGuiStorage_Clear$", tips: [ref]}
      - {target: "^ImGuiStorage_Get", tips: [ref,0,0]}
      - {target: "^ImGuiStorage_Set", tips: [ref,0,0]}
      - {target: "^ImGuiStorage_BuildSortByKey$", tips: [ref]}
      - {target: "^ImGuiListClipper_", tips: [ref]}
      - {target: "^ImColor_destroy$", tips: [ref]}
      - {target: "^ImColor_SetHSV$", tips: [ref,0,0,0,0]}
      - {target: "^ImColor_HSV$", tips: [ref,0,0,0,0]}
      - {target: "^ImDrawListSplitter_", tips: [ref,ref]}
      - {target: "^ImDrawList_", tips: [ref,ref]}
      - {target: "^ImDrawList_AddTextFontPtr$", tips: [ref,ref,0,0,0,0,0,0,ref]}
      - {target: "^ImDrawData_", tips: [ref]}
      - {target: "^ImFontConfig_", tips: [ref]}
      - {target: "^ImFontGlyphRangesBuilder_", tips: [ref]}
      - {target: "^ImFontGlyphRangesBuilder_AddRanges$", tips: [ref,ref]}
      - {target: "^ImFontGlyphRangesBuilder_BuildRanges$", tips: [ref,ref]}
      - {target: "^ImFontAtlasCustomRect_", tips: [ref]}
      - {target: "^ImFontAtlas_", tips: [ref,ref]}
      - {target: "^ImFontAtlas_AddFontFromFileTTF$", tips: [ref,0,0,ref,ref]}
      - {target: "^ImFontAtlas_AddFontFromMemoryTTF$", tips: [ref,0,0,0,ref,ref]}
      - {target: "^ImFontAtlas_AddFontFromMemoryCompressedTTF$", tips: [ref,0,0,0,ref,ref]}
      - {target: "^ImFontAtlas_AddFontFromMemoryCompressedBase85TTF$", tips: [ref,0,0,ref,ref]}
      - {target: "^ImFontAtlas_GetTexDataAs", tips: [ref,sref,ref,ref,ref]}
      - {target: "^ImFontAtlas_CalcCustomRectUV$", tips: [ref,ref,ref,ref]}
      - {target: "^ImFontAtlas_GetMouseCursorTexData$", tips: [ref,0,ref,ref,0,0]}
      - {target: "^ImFont_", tips: [ref]}
      - {target: "^ImFont_Render", tips: [ref,ref]}
      - {target: "^igGetWindow", tips: [ref]}
      - {target: "^igGetContent", tips: [ref]}
      - {target: "^igGetFont", tips: [ref]}
      - {target: "^igGetCursor", tips: [ref]}
      - {target: "^igGetItem", tips: [ref]}
      - {target: "^igCalcTextSize_nonUDT$", tips: [ref,0,0,0,0]}
      - {target: "^igColorConvertU32ToFloat4_nonUDT$", tips: [ref,0]}
      - {target: "^igGetMouse", tips: [ref]}
      - {target: "^ImColor_HSV_nonUDT$", tips: [ref,ref,0,0,0,0]}
      - {target: "^ImColor_HSV_nonUDT2$", tips: [ref,0,0,0,0]}
      - {target: "^ImDrawList_GetClipRect", tips: [ref,ref]}
      - {target: "^ImFont_CalcTextSizeA_nonUDT$", tips: [ref,ref,0,0,0,0,0,0]}
      - {target: "^ImFont_CalcTextSizeA_nonUDT2$", tips: [ref,0,0,0,0,0,0]}
      - {target: "^ImGuiTextBuffer_appendf$", tips: [ref,0]}
      - {target: "^igColorConvert", tips: [0,0,0,ref,ref,ref]}
      - {target: "^ImVector_ImWchar_", tips: [ref]}
  TypeTips:
    function:
  MemTips:
nazzrim commented 4 years ago

By the way: If I undef CIMGUI_DEFINE_ENUMS_AND_STRUCTS c-for-go does abort its execution with errors because of the missing definitions. I reported this in #80

nazzrim commented 4 years ago

I guess I am at something here:

The following part of my yml does not propagate to the generated .go file, it is only used during the generation (I guess):

  Defines:
    CIMGUI_DEFINE_ENUMS_AND_STRUCTS: 1

This is the header of the main go file generated with c-for-go

/*
#include "../cimgui/cimgui.h"
#include <stdlib.h>
#include "cgo_helpers.h"
*/
import "C"
import (
    "runtime"
    "unsafe"
)

If I manually delete all the corresponding directives from cimgui.h it compiles with a warning (which I am ignoring right now).

So the question is: What entries are required to embedd #define directives into the generated .go file?

nazzrim commented 4 years ago

So if I add #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS 1 to imgui.go and cgo_helpers.go manually the errors disappear.

I assume that adding it to all generated files would be a more general and safe solution (?).

Edit: I needed to add it to all generated go files which include C and the cgo_helper.h file.

But then the compilation gives me the following error:

go build ./...                                                                                                                                                                                # github.com/nazzrim/imgui-go/imgui
imgui\imgui.go:5359:2: unexpected type: ...

Which references this line:

    C.ImGuiTextBuffer_appendf(cbuffer, cfmt)

And the ImGuiTextBuffer_appendf function has the following signature:

CIMGUI_API void ImGuiTextBuffer_appendf(struct ImGuiTextBuffer *buffer, const char *fmt, ...);

I tried to ignore this single function but it seems that all functions with ... parameters are problematic.

Therefore I ignore all variadic functions. But then I get errors like.

AppData\Local\Temp\go-build275703602\b001\_x004.o: In function `_cgo_e0dda29f671c_Cfunc_igValueUint':
/tmp/go-build/cgo-gcc-prolog:10084: undefined reference to `igValueUint'
nazzrim commented 4 years ago

Okay I am able to get to the point I described in my last post without manual changes to the generated files by using the following configuration:

GENERATOR:
  PackageName: imgui
  PackageDescription: "Package imgui provides Go bindings for cimgui which is a C-wrapper for Dear ImGui by ocornut"
  PackageLicense: "THE AUTOGENERATED LICENSE. ALL THE RIGHTS ARE RESERVED BY ROBOTS."
  Includes: ["cimgui.h"]
  Options:
    SafeStrings: true
    StructAccessors: true
  FlagGroups:
    - {name: CFLAGS, flags: [-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS,"-I${SRCDIR}/cimgui"]}

PARSER:
  IncludePaths:
  SourcesPaths:
    - cimgui/cimgui.h
  Defines:
    CIMGUI_DEFINE_ENUMS_AND_STRUCTS: 1
    __builtin_va_start: {}
    __builtin_va_end: {}

But during the compilation I get undefined references for all functions in cimgui.h.

AppData\Local\Temp\go-build240611998\b001\_x004.o: In function `_cgo_f5785d863652_Cfunc_igSpacing':
/tmp/go-build/cgo-gcc-prolog:9670: undefined reference to `igSpacing'
nazzrim commented 4 years ago

Okay, the errors I mentioned in my last post were caused by my messed up linker flags, sorry for that.

Hopefully this journey will help someone else who is new to c-for-go ;D.

Now I am running into the same issue as #60 and right now I don't know how I should provide the required typedefs since I need to make the structs in the cimgui header use it.

(To be more precise: struct IO has three function pointer fields and NewRef as well as PassRef are not generated for these fields)

xlab commented 4 years ago

Apple decided that I don't need /usr/include on my machine, so I'm currently disarmed :) Will figure out how to get that back, but I hope you'll find the way through! 🙏

nazzrim commented 4 years ago

I hopefully will find a solution and maybe my documentation here can help others with similar problems :).

Do you have an example of the solution you recommend in #60? Because my current problem is the following:

typedef const char (get_clipboard_fn)(void user_data); typedef void (set_clipboard_fn)(void user_data, const char text); typedef void (*set_input_screen_fn)(int x, int y);

typedef struct ImGuiIO { ... } ImGuiIO;

endif


- But there are two issues with that:
1. All functions returning/accepting ImGuiIO are redefined, too. Therefore the patch would get bigger since I need to include all these functions which may require a lot of maintainance on version changes. So this is at least undesirable.
2. I am currently not able to configure c-for-go to ignore ImGuiIO_orig and only use my ImGuiIO
imle commented 3 years ago

@nazzrim did you ever figure out what to do about #60? I imagine there is no workaround for larger libraries where there are a multitude of function pointers?

nazzrim commented 3 years ago

@imle No, I did not find a solution for #60 and I did not find any workarounds, sorry.