Just released the first version of giD (pronounced giddy) which is a repository for GObject Introspection D binding libraries. Current focus has been on adding the Gtk4 graphics toolkit and dependencies. The bindings were created with gidgen which is a GObject Introspection binding generator CLI application. Also released is a giD Gtk4 Example application as a quickstart to learn how to develop with D and Gtk4 with giD.
#giD Gtk4 GObject Introspection Bindings and Gtk4 Examples
1 messages Β· Page 1 of 1 (latest)
Thanks for posting it. Super cool
Do you use it in production?
What is lacking to have "full" support for Gtk4?
Do you think it will be hard to contact gtk team and create a separate page in https://www.gtk.org/docs/language-bindings/
for D where to put 2 links for GtkD (for v3) and giD (for v4)?
Hello @lucid juniper. The Gtk4 support is fairly complete as far as I know. I am using it for a port of the commercial application Alkimiya, which is still in development, but I use it frequently (screenshots are outdated and for the C GTK3 version). Development of this port was why I started giD. Most of the binding is created automatically, with some manual tweaking when there are issues with the GIR API XML files and customization where it makes sense to have D templates. Currently there are 200 or so warnings that are output when running the gidgen application, which identifies functions, methods, and structure fields which have been disabled due to lack of support or other issues. Most of these are fairly minor/obscure or are broken with respect to the GIR XML API, but the intent is to resolve them and try to have 100% coverage. I definitely think it would be good to have GtkD and giD listed on the main gtk.org website. giD could in fact be used for Gtk3 as well, though that may cause some confusion. There are a lot of issues with GtkD, which I attempted to resolve, before deciding to write my own D GObject Introspection binding generator.
Ultimately I think giD could end up including bindings for most publicly available GObject Introspectable libraries. For example, all of the libraries listed here which are available for PyGObject.
Thanks for detailed reply @neon crescent! actually the updated GObject introspection generator could be helpful for other things as well, not only for gtk
@craggy moss pay your attention on this new project btw π in case you would like to try it with your arrow binding generator
@neon crescent if you think there are some interesting problems, that you've solved for preparation of this project it could be nice blog post for official D Blog web-site π and it could help for visibility of your generator as well
Thanks. I'll take a look at it.
@lucid juniper A blog post would be cool. I'll think about what sort of topics might be worthy of it. I think it is a pretty elegant binding generator, especially compared to gir-to-d. The definition files are just D files with specially formatted command comments. Compared to GtkD, most everything is automated when it comes to the binding, with most of the custom code just for adding additional convenience templates or wrapping APIs which don't introspect well or at all. Most of the definition file content is fixes to issues in the GIR files, which could be easily pushed upstream, since they are just simple XML patch commands which occur prior to processing the XML tree. Indeed my plan is for the giD package repo to include all useful libraries with GIR API files. It would likely be pretty trivial at this point to add Gtk3, GStreamer, etc. I'd like to implement a thorough test suite which exercises the GIR format, since it is rather difficult to test the actual libraries themselves in an automated fashion.
Oh btw maybe itβs worth to write a short message about your project to Announcement forum group. Many people are reading it, but not the discord. https://forum.dlang.org/group/announce
@neon crescent,
How to modify generated dub.json (-p) content?
It would be interesting if you could create a template for the project using gidgen. This would clear up any doubts when generating and modifying the source.
Based on the readme, I had to improvise a lot until it worked.
Now, i need fix some errors in generated code:
Error: cannot implicitly override base class method `Arrow.Buffer.Buffer.slice` with `Arrow.MutableBuffer.MutableBuffer.slice`; add `override` attribute
MutableBuffer slice(long offset, long size)
^
Hello @craggy moss . Thanks for being the first person, other than myself, who is giving giD a try. As for modifying the generated package files, the info command can be used to set the name, description, copyright, authors, and license. You should be able to set it in global.d in the defs directory for default values and they can also be overridden per module, by using the info command in the module definition file.
I'm not sure I understand what you mean by create a template for the project using gidgen. It looks like you are using gidgen to wrap your own library? I remember seeing errors similar to the one you show there. I don't recally exactly how I resolved them. Can you point me to the library you are trying to create a binding for? If I can get things set up on my end to replicate what you are trying to do, I can more easily assist you.
Tutorial project, showing the commands and the most simplified organization of the project. Then the user would use this project model as a base.
In my case, arrow-1.0.gir requires glib.list so I need to copy glib def from gid.
I'm running gidgen directly from dub.json ($GID_PACKAGE_DIR) to generate the bindings.
That's a good idea to have an example of how to use gidgen to creating independent bindings. So far, it has only been used for the giD repository, so it is likely that you may discover ways in which it could be improved for binding libraries outside of giD. It did occur to me before that currently gidgen doesn't have the concept of an existing package binding. So either the GIR file of a new binding needs to be built with giD or as you have done, the def and gir file dependencies copied. Where can I find a copy of the arrow-1.0.gir that you mention? I'd like to look at it. It seems like there might be a method with the same name in a base class or interface which is conflicting. I saw this with some libraries when I was doing the Gtk4 bindings.
If I remember correctly, the way I dealt with conflicting methods with different arguments, is to rename one of them. Here is an example XML patch set command which does this for Gio: ```
//# DataInputStream.read_byte() conflicts with parent BufferedInputStream.read_byte()
//!set class[DataInputStream].method[read_byte][name] read_byte_data
Where can I find a copy of the arrow-1.0.gir that you mention?
It will normally be generated during the c_glib.build (via meson).
Nice! My defs/Arrow.d add:
//# Arrow.Buffer.Buffer.slice() conflicts with parent Arrow.MutableBuffer.MutableBuffer.slice()
//!set class[Buffer].method[slice][name] slice_data
Now, get:
source/arrow-1-0/Arrow/SortOptions.d(10,1): Error: class `Arrow.SortOptions.SortOptions` use of `Arrow.FunctionOptions.FunctionOptions.equal(FunctionOptions otherOptions)` is hidden by `SortOptions`; use `alias equal = FunctionOptions.equal;` to introduce base class overload set
class SortOptions : FunctionOptions
^
Based on unittest:
version (unittest)
{
import Arrow.Array;
import Arrow.DataType;
import Arrow.BooleanArray;
import Arrow.CastOptions;
import Arrow.FilterOptions;
import Arrow.TakeOptions;
import Arrow.c.types;
@("Arrow Array")
unittest
{
// Test array creation and basic properties
auto array = new Array(null);
assert(array.getLength() == 0);
assert(array.getNNulls() == 0);
assert(array.getOffset() == 0);
// Test null checks
auto nullBitmap = array.getNullBitmap();
assert(nullBitmap is null);
// Test value type
auto valueType = array.getValueType();
assert(valueType >= GArrowType.Na);
// Test equality
auto otherArray = new Array(null);
assert(array.equal(otherArray));
assert(array.equalApprox(otherArray));
// Test slicing
auto slice = array.slice(0, 0);
assert(slice !is null);
// Test data type
auto dataType = array.getValueDataType();
assert(dataType is null || dataType !is null);
}
}
It may be useful to simulate these issues with the scenario described in defs/*.d, if a model project is available.
@craggy moss Thanks for sending the GIR file. Looks like that new error is a similar issue as the previous. SortOptions is derived from FunctionOptions and both have a method named "equal", but use different argument types (SortOptions vs FunctionOptions). It seems like this situation should be automatically handled by gidgen. I can think of 2 potential solutions: Option 1 is to add an alias, as suggested in the error message. This would mean that both of the "equal" methods would be made available in SortOptions with the same name. So an explicit cast to FunctionOptions would be required to access the parent method (not sure why anyone would want to do this in this particular case and it could cause confusion if a cast to the parent has the unintend consequences of calling the parent equal method). Option 2 is to use an alias to rename the parent method, by prepending the name of the parent class to it. For example, in this case it would be aliased as functionOptionsEqual(). I'm somewhat leaning towards the second option to avoid the confusion that could happen with option 1. Let me know if you have any ideas. I'll work on implementing option 2.
Hello @craggy moss . I pushed some updates to gidgen which include automatic generation of aliases for conflicting methods in class ancestors (also includes for implemented interfaces). There is also a new report feature which might be of interest to you, once you get the bindings working with Arrow. Next I'll try generating a binding here myself, to see if there is anything else I can do to assist you.
@lucid juniper You might also be interested in the report feature I just added to gidgen. Here is the current generated report.txt for giD, which will now be generated on each release to track changes. As you can see, coverage is pretty high and I suspect a lot of the "Unsupported" items should actually be marked as "Disabled" because they aren't interesting to the D binding (I need to go through them). However, this isn't a confirmation that all of the bound API which is output is bug-free. I'm still working on a test suite that will exercise all the binding features. Not an easy task though, which has led me to think about trying to automate the generation of a test suite.
defs/Arrow.d:
//!repo Arrow-1.0
dub:
"dependencies": {
"gidgen": {
"repository": "git+https://github.com/Kymorphia/gidgen.git",
"version": "0a3ee4177a2f4973f39ffac3fe2e4542f45f9708"
},
"gid": {
"repository": "git+https://github.com/Kymorphia/gid.git",
"version": "1c6ba655d31d98bd043e57ddd6de1881c666ac7c"
}
},
"preBuildCommands": [
"\"$DUB\" run gidgen -- --report --report-file report.txt -d $PACKAGE_DIR/defs -s $PACKAGE_DIR/source -g $PACKAGE_DIR/c_glib.build/arrow-glib -p $PACKAGE_DIR/source -d $GID_PACKAGE_DIR/defs -g $GID_PACKAGE_DIR/gir"
],
Note: If not add -d $GID_PACKAGE_DIR/defs:
Warning: Repo 'GLib' not found for type 'GLib.Quark'
Warning: Repo 'GLib' not found for type 'GLib.List'
Warning: Repo 'GObject' not found for type 'GObject.Object'
object.Exception@../../.dub/packages/gidgen/0a3ee4177a2f4973f39ffac3fe2e4542f45f9708/gidgen/source/defs.d(560): Failed to resolve namespace 'GObject' for type 'GObject.Object'
I just gave it a shot myself and am getting a lot of ideas of how to improve things with gidgen with respect to creating separate bindings, which use existing ones from giD. I think right now the easiest way to get Arrow built, is to just copy your Arrow.d to the defs directory in giD and build it with giD. I plan on adding most GObject Introspectable libraries to giD anyways. However, I would also like to add support for gidgen to utilize external giD bindings.
The error I'm currently getting is sh packages/arrow-1-0/Arrow/MutableBuffer.d(69,17): Error: cannot implicitly override base class method `Arrow.Buffer.Buffer.slice` with `Arrow.MutableBuffer.MutableBuffer.slice`; add `override` attribute which I'm tracking down.
The new automatic alias generation in gidgen is creating an alias for MutableBuffer.slice to Buffer.slice, but it seems it should be an override instead. Even though the method signature is different, it is only with the return value and the return value is a derivative of the parent method's type. Seems like it needs to take that into account. Once I changed it to an override instead of an alias, the Arrow binding library built.
Now, linking and trying to run:
Linking arrow-d-test-unittest
Finished To force a rebuild of up-to-date targets, run again with --force
Running unittest/arrow-d-test-unittest
Gid.gid.GidConstructException@source/glib-2-0/Gid/gid.d(831): Null instance pointer for Arrow.Array.Array
----------------
source/glib-2-0/GObject/ObjectG.d:111 GObject.ObjectG.ObjectG GObject.ObjectG.ObjectG.__ctor(void*, std.typecons.Flag!("Take").Flag) [0x5751a0a91426]
source/arrow-1-0/Arrow/Array.d:29 [0x5751a0aa043b]
source/package.d:36 [0x5751a0aa0166]
"dependencies": {
"gidgen": {
"repository": "git+https://github.com/Kymorphia/gidgen.git",
"version": "0a3ee4177a2f4973f39ffac3fe2e4542f45f9708"
},
"gid:glib-2-0": "~>0.9.1"
},
"preBuildCommands": [
"\"$DUB\" run gidgen -- --log-level off --report --report-file report.txt -d $PACKAGE_DIR/defs -s $PACKAGE_DIR/source -g $PACKAGE_DIR/c_glib.build/arrow-glib -p $PACKAGE_DIR/source -d ${GID:GLIB_2_0_PACKAGE_DIR}/../../defs -g ${GID:GLIB_2_0_PACKAGE_DIR}/../../gir"
],
@neon crescent,
My first experience with your application shows that generation is more user-friendly than its predecessor girtod. The improvements you've made will reduce the difficulty of generating external bindings.
@lucid juniper , Now it's possible reboot the PR (D bindings) from the arrow-upstream.
Super cool
For myself I was thinking to try to work with nano-arrow (which is much smaller version of arrow).. But I haven't got time to test it
But if we will get full arrow (and parquet) support it will be really great results!
@craggy moss Looking at the ArrowArray in the GIR file, I don't see a constructor. This is the first time I have seen that. It is a GObject derived type, so maybe they are just assuming the user will call one of the g_object_new() methods with the proper GType? In your unittest you are passing null, which will use the built in constructor that expects a pointer to the C GObject instance. This results in the exception you see "Null instance pointer.." Is there any documentation on the Arrow C API with respect to how Array's are supposed to be created? Gidgen could potentially automatically create a constructor in the event there isn't one and the type is not abstract, but I'm curious how this API is supposed to be used.
Is there any documentation on the Arrow C API with respect to how Array's are supposed to be created?
https://arrow.apache.org/docs/c_glib/arrow-glib/class.Array.html
Reference for Arrow.Array
Yeah, I don't see how an Array would be created with that API.. Chances are you can probably do ```D
import Arrow.c.functions;
new Array(g_object_new(garrow_array_get_type(), null))
@craggy moss Ahhh... Arrow.Array is an abstract class. You should only be creating its derivatives. Gidgen should probably add the "abstract" attribute to classes which are marked as abstract in the GIR definition.
@carmine pond Apache Arrow has been added to the giD repository. The logic in gidgen was improved for determining whether a method alias or override is needed, which resolved that last issue with Arrow. I also added some XML patches for string array return types which did not have zero-terminated set. With those changes it brings the coverage for Arrow to 100% (other than a callback method in a class structure, which seems to be of no value for the binding). Let me know if you'd like help adding any other libraries. I think parquet was mentioned?
Parquet should be a part of Arrow project actually
Oh, yeah I see it there in c_glib. Still working on getting that to build, since I'm not sure what set of cmake options are required in the Arrow build. Just need the gir files really.
Got it to build.. What about ArrowFlight? Looks like a GIR file for that was also generated.
I think it is an RPC mechanism for Arrow data transporting. Will be good to have
I would be interested in testing your functionalities, if you will show how I can build/install them
You should be able to just add gid:arrow-1-0 as a dependency to a project's dub file and then import the modules you want to use. I haven't made a new release of gid yet though, so I'm not sure if it will pick up the master version in that case (try using "*" for the version).
No rush for sure. I don't have time now anyway - so maybe I will have some to play with it later this week or maybe even in the end of the month..
I realize I built the main branch of Arrow. I suppose I should probably build it for a specific version to make sure I'm using a stable GIR API. Do you know if 19.0.0 is the latest?
I believe yes. 20 - dev, 19 -stable
That seems to be the latest tag. Just want to make sure that makes sense.
Added arrowflight-1-0 and parquet-1-0 packages, both with 100% coverage.
Awesome.
Therefore I would like to suggest the inclusion of GiD in Arrow upstream.
Solving these issues:
https://github.com/apache/arrow/issues/44515
Not sure what you mean by inclusion of giD upstream. The giD repository is designed to host dub packages for D bindings for libraries with GObject Introspection. So it should just be a matter of adding "gid:arrow-1-0", "gid:arrow-flight-1-0", and/or "gid:parquet-1-0" to a program's dependencies and building it. It's fine to include giD upstream, I'm just not sure if that is the best way to do things.
Not sure what you mean by inclusive of GiD
Dub package, avoid duplicate bindings generator.
Missing only arrow-dataset
So you mean having the Arrow bindings at https://github.com/Kymorphia/gid right? That is what I was intending by adding it to giD. If you have a GIR file for arrow-dataset, I can add it too, probably pretty easily. Is that normally built as part of arrow?
Yes. In the same way as the flight.
When you build Arrow you make all of these available.
Ohh, yeah, looks like ARROW_DATASET is disabled in my cmake options.. I wasn't sure which other ones I should enable as well.
I currently have the following still OFF, should any of these be built as well? CUDA, FLIGHT_SQL, FUZZING, GANDIVA, GCS, HDFS, ORC, SKYHOOK, SUBSTRAIT, TENSORFLOW.. I don't think any of the rest of the options are of interest.. It would be nice to have a CMake command or configuration to go from.
OK, I think I got all the same options enabled.. But it broke CMake. I do have libprotobuf-c-dev and libprotobuf-dev installed, so I'm not sure what is wrong: ``` Error evaluating generator expression:
$<TARGET_FILE:protobuf::libprotoc>
No target "protobuf::libprotoc"
Call Stack (most recent call first):
/usr/share/cmake-3.28/Modules/ExternalProject.cmake:2577 (_ep_write_log_script)
/usr/share/cmake-3.28/Modules/ExternalProject.cmake:3901:EVAL:2 (ExternalProject_Add_Step)
/usr/share/cmake-3.28/Modules/ExternalProject.cmake:3901 (cmake_language)
/usr/share/cmake-3.28/Modules/ExternalProject.cmake:4421 (_ep_add_configure_command)
cmake_modules/ThirdpartyToolchain.cmake:4735 (externalproject_add)
cmake_modules/ThirdpartyToolchain.cmake:208 (build_orc)
cmake_modules/ThirdpartyToolchain.cmake:307 (build_dependency)
cmake_modules/ThirdpartyToolchain.cmake:4777 (resolve_dependency)
CMakeLists.txt:546 (include)```
@craggy moss If you can send me the gir files, or point me to where I can download them, that would make things a lot easier and I would be more confident that they have all the intended built APIs. Ideally there would be some pre-built distribution that I could grab them from for use in the giD bindings, to make it easier to maintain and keep up with the latest version.
Thanks! Its now added, 100% coverage apparently.
Just released v0.9.2 of giD, gidgen, and the gid-gtk4-examples. This version adds Windows support, an Apache Arrow binding, coverage reports, and more!
Released giD v0.9.3. This version adds Atk, Vte virtual terminal, and GtkSource code editor libraries. The most significant change is that it is now using lowercase for package paths and module names.