Handling generation errors
Luckily there are only a few errors which can happen with gir generation. Let's take a look at them.
Cannot find macros
Compilation of the generated bindings may fail with errors like the following:
error: cannot find macro `skip_assert_initialized` in this scope
--> src/auto/enums.rs:83:9
|
83 | skip_assert_initialized!();
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: have you added the `#[macro_use]` on the module/import?
error: cannot find macro `assert_initialized_main_thread` in this scope
--> src/auto/example.rs:33:9
|
33 | assert_initialized_main_thread!();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: have you added the `#[macro_use]` on the module/import?
In this case you’ll have to implement them yourself.
Macros are order-dependent and you must insert this code before declaring modules that use it (e.g. mod auto
).
For example, you can add the following to your lib.rs
file:
#![allow(unused)] fn main() { /// No-op. macro_rules! skip_assert_initialized { () => {}; } /// Asserts that this is the main thread and either `gdk::init` or `gtk::init` has been called. macro_rules! assert_initialized_main_thread { () => { if !::gtk::is_initialized_main_thread() { if ::gtk::is_initialized() { panic!("GTK may only be used from the main thread."); } else { panic!("GTK has not been initialized. Call `gtk::init` first."); } } }; } }
One complication here is that the assert_initialized_main_thread!
macro depends on the exact library.
If it's GTK-based then the above macro is likely correct, unless the library has its own initialization function.
If it has its own initialization function it would need to be handled in addition to GTK's here in the same way.
For non-GTK-based libraries the following macro would handle the initialization function of that library in the same way, or if there is none it would simply do nothing:
#![allow(unused)] fn main() { /// No-op. macro_rules! assert_initialized_main_thread { () => {}; } }
Missing memory management functions
If gir generation fails (for whatever reason), it means you'll have to implement the type yourself.
Just like types from other gtk-rs
crates, you'll need to put it into the "manual" list.
Then you need to put the type into the src
folder (or inside a subfolder, you know how Rust works).
/!\ Don't forget to reexport the type inside your src/lib.rs
file.
For example, let's take a look at the requisition.rs file from the gtk3
crate.
Since it's a "simple" type (no pointer, therefore no memory management to do), gir doesn't know how to generate it.
You'll need to implement some traits by hand like ToGlibPtr
or ToGlibPtrMut
(depending on your needs).
Bad function generation
In some cases, the generated code isn't correct (array parameters are often an issue).
In such cases, it's better to just make the implementation yourself.
As an example, let's say you want to implement Region::is_empty
yourself.
A few changes have to be made.
Let's start with Gir.toml
:
generate = [
"GtkSource.Language",
]
[[object]]
name = "GtkSource.Region"
status = "generate"
[[object.function]]
name = "is_empty"
ignore = true
So to sum up what was written above: we removed "GtkSource.Region" from the "generate" list and we created a new entry for it.
Then we say to gir that it should generate (through status = "generate"
).
However, we also tell it that we don't want the "is_empty" function to be generated.
Now that we've done that, we need to implement it.
Let's create a src/region.rs
file:
#![allow(unused)] fn main() { use glib::object::IsA; use glib::translate::*; use Region; pub trait RegionExtManual: 'static { pub fn is_empty(&self) -> bool; } impl<O: IsA<Region>> RegionExtManual for O { pub fn is_empty(&self) -> bool { // blablabla true } } }
You might wonder: "why not just implementing it on the Region
type directly?".
Because like this, a subclass will also be able to use this trait easily as long as it implements IsA<Region>
.
For instance, in gtk, everything that implements IsA<Widget>
(so almost every GTK types) can use those methods.
As usual, don't forget to reexport the trait.
A little tip about reexporting manual traits: in gtk3-rs
, we create a src/prelude.rs
file which reexports all traits (both manual and generated ones), making it simpler for users to use them through use [DEPENDENCY]::prelude::*
.
The src/prelude.rs
file looks like this:
#![allow(unused)] fn main() { pub use crate::auto::traits::*; pub use region::RegionExtManual; }
Then it's reexported as follows from the src/lib.rs
file:
#![allow(unused)] fn main() { pub mod prelude; pub use prelude::*; }
Manually defined traits missing from the documentation
If you defined traits manually, you can add them to the "Implements" section in the documentation for classes and interfaces by using the manual_traits = []
option in the Gir.toml
file.
Here is an example:
[[object]]
name = "Gtk.Assistant"
status = "generate"
#add link to trait from current crate
manual_traits = ["AssistantExtManual"]
[[object]]
name = "Gtk.Application"
status = "generate"
#add link to trait from other crate
manual_traits = ["gio::ApplicationExtManual"]