Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

prototype gobject wrapper #217

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

Conversation

dexterdy
Copy link

@dexterdy dexterdy commented Feb 4, 2023

Hi there. I have written a quick and mostly untested gobject wrapper. This type is meant to allow you to put any Nim type in the place where you would normally give a gobject subclass.

The implementation has two sides: the Nim side and the C side. The C side is simple. It is only a subclass of gobject with a single void pointer. On the Nim side, we have the datatype that mirrors the C struct and two support functions. The first takes any Nim type and, if it is not already a ref or ptr, makes a ref and calls GC_ref(). Then it casts to a pointer and passes this to the C object constructor. The other function simply takes the wrapper and casts the pointer back to the original nim datatype and derefs if necessary.

I only need to do one thing, which is to make the wrapper compatible with how gobjects are handled in gintro. I'm not quite sure of how to do this, since gintro uses custom proxy objects, and I'm not super familiar with how those are implemented yet. Some help is required for further development.

@StefanSalewski
Copy link
Owner

That is an interesting idea. I will try to investigate your suggestions soon.

@StefanSalewski
Copy link
Owner

I just had a short look at your three provided files:

Note that we should try to keep gintro (and all other Nim software) working with the LLVM backend. So avoiding all use of C code and pragmas like importC is a goal. Without that restriction, life may be indeed much easier: Even C macros can be used by importC, and we can always mix C and Nim source code files. I once created this issue as an example to mix in plain C code: #141 But my guess is, that it may not work with the LLVM backend. For creating new GObjects, with custom properties and signals, I think we should break up all the C GObject macros into plain C function calls, and then create Nim macros from it. I once tried that for the NEd editor with oldGTK3 bindings six years ago, but it was not easy for me, I think I wasted a lot of time on it.

For your quote do use, Mr. Beetham recently reminds me, that he and some other Nim experts seems to prefer use of genAst() instead. So I just added a short section about genAst() to my book, it is very similar to quote do.

I will observe your progress.

@dexterdy
Copy link
Author

dexterdy commented Feb 5, 2023

If we should avoid the use of importC, how did you create bindings to the C libraries? Also, doesn't Nim compile to C first anyway? In either case, this wrapper is not really a replacement for real subclassing, of course, but it does allow you to add regular nim types to listmodels, for instance.

I shall try to use genAst() instead of quote do.

I will try to subclass gobject.Object and see if that works.

Thank you for your help :).

@dexterdy
Copy link
Author

dexterdy commented Feb 5, 2023

Hi, I have tried to subclass from InitiallyUnowned, using the widget object as example. It gives my the following compiler error, which I'm not sure how to solve:

CC: gobjectWrapper
CC: ../../../../../.nimble/pkgs2/gintro-0.9.9-d2be110997211a820389624eaca4b30c27f25b85/gintro/gobject.nim
CC: gobjectWrapper.nim
/home/dexterdy/.cache/nim/gobjectWrapper_d/@mgobjectWrapper.nim.c: In function ‘NimMainModule’:
/home/dexterdy/.cache/nim/gobjectWrapper_d/@mgobjectWrapper.nim.c:475:77: error: ‘GObjectWrapper’ {aka ‘struct _GObjectWrapper’} has no member named ‘Sup’
  475 |         (*T1_).Sup.Sup.impl = &internalObjectX60gensym3___gobject87rapper_75->Sup.Sup;
      |                                                                             ^~
Error: execution of an external compiler program 'gcc -c  -w -fmax-errors=3 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -pthread   -I/home/dexterdy/.choosenim/toolchains/nim-1.6.10/lib -I/home/dexterdy/Documents/repos/realmnotes/src/types -o /home/dexterdy/.cache/nim/gobjectWrapper_d/@mgobjectWrapper.nim.c.o /home/dexterdy/.cache/nim/gobjectWrapper_d/@mgobjectWrapper.nim.c' failed with exit code: 1

@StefanSalewski
Copy link
Owner

If we should avoid the use of importC, how did you create bindings to the C libraries?

Yes, I think use of importC pragma is OK, the real problem is more the header and compile pragma. I read about that 8 years ago, and forgot most of it. And I left that out from my book by intent, as the book was more designed for beginners. As far as I remember the process of bindings generation, most modules including gintro should work fine with LLVM backend. Header pragma would break that.

Also, doesn't Nim compile to C first anyway?

The Rumpf implementation compiles to C, C++, JS, and in old days even to PHP. But the LLVM backend from Jacek Sieka emits IR code directly. Jacek Sieka is a bright guy, I think he is (or was )hired by Status Corp, so when Nim may have a future at all, it may be with his LLVM backend. LLVM is superior by design, and use of LLVM would avoid that many people call Nim a transpiler and avoid it just because C is involved. (Of course we know that the C backend is indeed fine, advantage of LLVM is tiny, but it is hard to convince people.)

Of course we can create a variant of gintro that works only with the Rumpf C backend. I think I never tried the -E option of gcc to expand macros, and I never tried to use C macros directly in Nim with importC. For my NEd editor and oldgtk3 bindings, I inspected the GTK C code at gitlab, and tried to understand and extract all the C macros. That was hard, as that macros call each other with deep nesting.

@dexterdy
Copy link
Author

dexterdy commented Feb 5, 2023

Aah, I see. How can I avoid the use of the header pragma? That is the pragma that specified where to find the C functions and types, right?

@StefanSalewski
Copy link
Owner

Aah, I see. How can I avoid the use of the header pragma? That is the pragma that specified where to find the C functions and types, right?

Currently I don't know this, sorry. Same for your "has no member named ‘Sup’" compiler error.

@StefanSalewski
Copy link
Owner

Yes, I think use of importC pragma is OK, the real problem is more the header and compile pragma.

See https://github.com/arnetheduck/nlvm

nlvm does not: understand C - as a consequence, header, emit and similar pragmas will not work - neither will the fancy importcpp/C++ features

@dexterdy
Copy link
Author

dexterdy commented Feb 5, 2023

I have sucessfully subclassed from Object and Object00, meaning that this wrapper can be used as intended. I have also removed the header pragmas to preserve compatibility with the llvm back-end. The code is not the pretiest or the most idiomatic, so I could spend an hour or so cleaning it up, but all basic functionality is there. It also still has to be tested.

@StefanSalewski
Copy link
Owner

Fine that you made some progress.

I just remembered that I asked at the Gnome forum about this stuff, see https://discourse.gnome.org/t/listview-clocks-c-from-gtk4-demo-standalone-and-in-other-programming-languages/6629

One advice from Mr. Jason Francis was:

Vala does not really use the macros that much – you may want to compile some of the simpler Vala examples and look at the intermediate C output to get an idea of what it’s doing. All of that should be accessible to other language bindings in a similar way.

@dexterdy dexterdy marked this pull request as ready for review February 7, 2023 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants