Skip to content

Latest commit

 

History

History
110 lines (78 loc) · 4.17 KB

HACKING.md

File metadata and controls

110 lines (78 loc) · 4.17 KB

HACKING

The generator is based on GObjectIntrospection, a C library that add introspection capabilities to C libraries based on GLib and GObject.

So the first thing you must know is that GI-Crystal itself has a binding for the librepository (the library of GObjectIntrospection), this binding was created manually and must be kept this way to simplify the project.

The librepository is only needed by the generator, the generated bindings doesn't depend on librepository.

The generator tries to create humam readable files to ease debug of the generated code.

Directories

This is how the source is organized:

.
├── bin
├── ecr
├── spec
│   └── libtest
└── src
    ├── auto
    ├── bindings
    │   ├── g_lib
    │   └── g_object
    ├── generator
    ├── gi_crystal
    └── gobject_introspection
bin/
Binary files and helper scripts goes here.
ecr/
The generator uses ECR (Crystal equivalent of Ruby ERB) files, all ECR files used by the generator goes here.
spec/
Tests goes here.
spec/libtest/
Source code of a C library (libtest) used to reproduce many scenarios that happen with libraries out there, so we create a binding for this test library and most of the tests interact with this binding.
src/auto/
By default, GI-Crystal write the generated binding code here.
src/bindings/
Each binding generated by this repository that needs a binding.yml file goes in a subdirectory here, the subdirectory is named with the module namespace.
src/generator/
The generator crystal code is all here
src/gi_crystal/
GI-Crystal public API used by the bindings generated by it.
src/gobject_introspection/
Bindings for _librepository_, a.k.a. GObjectIntrospection library, this binding is used by the generator code.

Running tests

Executing crystal spec wont work because the generator wont find the libtest.so used by the tests, so instead of smash your head setting up a lot of environment variables you can just run:

make test

If you want to re-run a specific test without re-generate the bindings, i.e. you just changed the test code, you can run:

./bin/spec

It accepts the same parameters that crystal spec does.

Comparing API changes

When you do some change to the generator code is useful to know the side effects of these changes in terms of a diff between what was being generated before and what is being generated now with the changes, for this there's a helper script ./bin/compare-api that is available on shards that depend on gi-crystal.

If you want to use this script on gi-crystal itself you need to set some environment variables to let the generator find the libtest.so, etc. To help with this you can just use:

make compare

You you ran make compare already and want to just recompare the API with the newer changes you can do:

make recompare

How GObject wrappers works

GICrystal use g_object_set_qdata function to store the Crystal object pointer into every wrapper it creates, so it can restore the wraper object without need to re-allocate any memory.

When the wrapper is collected by the GC it reset this pointer to NULL, so if it appear again in the Crystal world we create another wrapper for it. See Crystal::INSTANCE_QDATA_KEY constant.

For user made objects inheriting GObject a toggle ref is added to the GObject, so the object it's garbage collected only if there's no references for it in C world. This is done at src/bindings/g_object/object.cr, look for _add_toggle_ref.

How Struct wrappers works

Currently it creates a wrapper with a copy of the struct always... i.e. it's slow.

Plan for near future

Check if the struct have no pointers to objects in their fields, is so, bind it directly to a Crystal struct, so it will be as fast as in C to use these structs in Crystal.

How GObject inheritance works

TODO 😅️

The generator code

TODO 😁