Access Gtk C Widget in Python

Hello! I’m working on a Python project, it’s a Gtk desktop app.
I’m using Linux Mint 21.1, python 3.10, and gtk 3. There is a Gtk app written in C: gnome-calendar. It has some custom widgets I would like to use, in src/gui/views/. In particular gcal-month-view.c.

I know it’s possible to create a C extension library such that I could access the needed C widgets from python. But I’m not really sure how to do that. I’m not really familiar with C, but I know what a header file is, for example.

I found GObject introspection docs (can’t link to it, new users can have only 2 links in a post), but it doesn’t really describe what to do. I also found this, but it’s pretty short. Also it shows how to do everything manually, but I think it should be possible to automate everything with introspection tools.

I was able to build the gnome-calendar project. I built the version 41.2. I installed these libraries:

apt install libgeoclue-2-dev libgweather-3-dev gir1.2-gweather-3.0 libhandy-1-dev libdazzle-1.0-dev libdazzle-1.0 libedataserver-1.2 libedataserverui1.2-dev gsettings-desktop-schemas-dev cmake libical-dev libical-glib 

Then created build folder:

mkdir build && cd build

and built the project:

meson

Does somebody know how to make gcal-month-view.c accessible in python? Would really appreciate your help.

g-i is definitely what you want to use, meson provides a useful wrapper for you:

https://mesonbuild.com/Gnome-module.html#gnomegenerate_gir

1 Like

Thank you! This looks interesting, I’ll try it.

OK, so I tried to introspect the resulting executable. I added this code to src/meson.build:

exe = executable(
  meson.project_name(),
       files('main.c'),
          dependencies: libgcal_dep,
               install: true,
           install_dir: calendar_bindir,
)

gnome = import('gnome')
gnome.generate_gir(
  exe,
  namespace: 'Gcal',
  nsversion: '41.2'
)

this was already there:

executable(
  meson.project_name(),
       files('main.c'),
          dependencies: libgcal_dep,
               install: true,
           install_dir: calendar_bindir,
)

I’m not sure if the namespace or nsversion is correct. I just saw namespace: 'Gcal' being used in one place of the meson.build file, so I decided to use it; and 41.2 is the version of the app, I’m not sure if it’s correct to use it here though.

I get this error:

Found ninja-1.10.1 at /usr/bin/ninja
Cleaning... 0 files.
[1/2] Generating src/Gcal-41.2.gir with a custom command
FAILED: src/Gcal-41.2.gir

/usr/bin/g-ir-scanner --no-libtool --namespace=Gcal --nsversion=41.2 --warn-all --output src/Gcal-41.2.gir -I/home/secureboot/Downloads/gnome-calendar-41.2/src -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src -I/home/secureboot/Downloads/gnome-calendar-41.2/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/core/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/core/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/calendar-management/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/calendar-management/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/event-editor/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/event-editor/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/importer/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/importer/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/views/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/views/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/search/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/search/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/utils/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/utils/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/weather/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/weather/. --filelist=/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gnome-calendar.p/Gcal_41.2_gir_filelist --cflags-begin -DHAVE_CONFIG_H '-DPACKAGE_LOCALE_DIR="/usr/local/share/locale"' '-DPACKAGE_DATA_DIR="/usr/local/share/gnome-calendar"' '-DUI_DATA_DIR="/usr/local/share"' -DEDS_DISABLE_DEPRECATED -DGOA_API_IS_SUBJECT_TO_CHANGE -DGWEATHER_I_KNOW_THIS_IS_UNSTABLE -DG_DISABLE_CAST_CHECKS -I/usr/include/gsettings-desktop-schemas -I/usr/include/evolution-data-server -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/fribidi -I/usr/include/atk-1.0 -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/x86_64-linux-gnu -I/usr/include/libsecret-1 -I/usr/include/gio-unix-2.0 -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libdazzle-1.0 -I/usr/include/libhandy-1 -I/usr/include/goa-1.0 -I/usr/lib/x86_64-linux-gnu/goa-1.0/include -I/usr/include/libgweather-3.0 -I/usr/include/geocode-glib-1.0 -I/usr/include/libgeoclue-2.0 -I/usr/include/gobject-introspection-1.0 --cflags-end --add-include-path=/usr/share/gir-1.0 --program /home/secureboot/Downloads/gnome-calendar-41.2/build/src/gnome-calendar --extra-library=edataserver-1.2 --extra-library=edataserverui-1.2 --extra-library=gtk-3 --extra-library=gdk-3 --extra-library=pangocairo-1.0 --extra-library=pango-1.0 --extra-library=harfbuzz --extra-library=atk-1.0 --extra-library=cairo-gobject --extra-library=cairo --extra-library=gdk_pixbuf-2.0 --extra-library=ecal-2.0 --extra-library=ical-glib --extra-library=ical --extra-library=icalss --extra-library=icalvcal --extra-library=secret-1 --extra-library=xml2 --extra-library=soup-2.4 --extra-library=gmodule-2.0 --extra-library=gio-2.0 --extra-library=gobject-2.0 --extra-library=glib-2.0 --extra-library=dazzle-1.0 --extra-library=handy-1 --extra-library=goa-1.0 --extra-library=gweather-3 --extra-library=geoclue-2 --extra-library=geocode-glib --extra-library=m --extra-library=girepository-1.0 --sources-top-dirs /home/secureboot/Downloads/gnome-calendar-41.2/subprojects/ --sources-top-dirs /home/secureboot/Downloads/gnome-calendar-41.2/build/subprojects/
Unknown option --introspect-dump=/tmp/tmp-introspecty4rnh1bt/functions.txt,/tmp/tmp-introspecty4rnh1bt/dump.xml
Command '['/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gnome-calendar', '--introspect-dump=/tmp/tmp-introspecty4rnh1bt/functions.txt,/tmp/tmp-introspecty4rnh1bt/dump.xml']' returned non-zero exit status 1.
ninja: build stopped: subcommand failed.

I have no experience with meson, so I have no idea what I’m doing. Do you think the task I want to accomplish is easy enough for me to do or do I need to know advanced C stuff?

I wonder how PyGObject does it, how do they introspect all Gtk libraries?

Looks like you’ve got an old copy of g-i or something?

They don’t, they load data from g-i

1 Like

Thanks for helping :blush:! I searched for --introspect-dump in g-ir-scanner’s manual page, here’s what I found:

-p, --program=PROGRAM
Specifies a binary that will be introspected. This means that the *_get_type() functions in it will be called for GObject data types. The binary must be modified to take a --introspect-dump= option, and to pass the argument to this function to g_irepository_dump.

So basically I have to modify the binary I’m introspecting, which is actually the binary of a whole program. As I understand, I’ll have to read the --introspect-dump parameter, and pass its value to g_irepository_dump. But where in the code should I call g_irepository_dump?

OK, so i added the g_irepository_dump call to src/main.c.
Here’s the modified file:

#include <string.h>
#include "config.h"
#include "gcal-application.h"
#include <girepository.h>

#include <glib/gi18n.h>


gint
main (gint    argc,
      gchar **argv)
{
  for(int i=0;i<argc-1;i++) {
    if (strstr(argv[i], "--introspect-dump=") != NULL) {
      char *argument = argv[i];
      argument += 18;
      g_autoptr (GError) local_error = NULL;
      return g_irepository_dump(argument, local_error);
    }
  }

  /*g_autoptr (GcalApplication) app = NULL;*/

  /*bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);*/
  /*bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");*/
  /*textdomain (GETTEXT_PACKAGE);*/

  /*g_set_application_name (_("Calendar"));*/

  /*app = gcal_application_new ();*/

  /*return g_application_run (G_APPLICATION (app), argc, argv);*/
}

I have never written anything in C, but hopefully this code takes the value of --introspect-dump= argument, and passes it to g_irepository_dump.
I also added this dependency to root meson.build:

girepository_dep = dependency('gobject-introspection-1.0', version: '>=1.0')

And it all seems to compile correctly, but it gives the following error:

FAILED: src/Gcal-41.2.gir 
/usr/bin/g-ir-scanner --no-libtool --namespace=Gcal --nsversion=41.2 --warn-all --output src/Gcal-41.2.gir -I/home/secureboot/Downloads/gnome-calendar-41.2/src -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src -I/home/secureboot/Downloads/gnome-calendar-41.2/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/core/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/core/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/calendar-management/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/calendar-management/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/event-editor/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/event-editor/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/importer/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/importer/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/views/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/views/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/gui/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gui/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/search/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/search/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/utils/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/utils/. -I/home/secureboot/Downloads/gnome-calendar-41.2/src/weather/. -I/home/secureboot/Downloads/gnome-calendar-41.2/build/src/weather/. --filelist=/home/secureboot/Downloads/gnome-calendar-41.2/build/src/gnome-calendar.p/Gcal_41.2_gir_filelist --cflags-begin -DHAVE_CONFIG_H '-DPACKAGE_LOCALE_DIR="/usr/local/share/locale"' '-DPACKAGE_DATA_DIR="/usr/local/share/gnome-calendar"' '-DUI_DATA_DIR="/usr/local/share"' -DEDS_DISABLE_DEPRECATED -DGOA_API_IS_SUBJECT_TO_CHANGE -DGWEATHER_I_KNOW_THIS_IS_UNSTABLE -DG_DISABLE_CAST_CHECKS -I/usr/include/gsettings-desktop-schemas -I/usr/include/evolution-data-server -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/fribidi -I/usr/include/atk-1.0 -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/x86_64-linux-gnu -I/usr/include/libsecret-1 -I/usr/include/gio-unix-2.0 -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libdazzle-1.0 -I/usr/include/libhandy-1 -I/usr/include/goa-1.0 -I/usr/lib/x86_64-linux-gnu/goa-1.0/include -I/usr/include/libgweather-3.0 -I/usr/include/geocode-glib-1.0 -I/usr/include/libgeoclue-2.0 -I/usr/include/gobject-introspection-1.0 --cflags-end --add-include-path=/usr/share/gir-1.0 --program /home/secureboot/Downloads/gnome-calendar-41.2/build/src/gnome-calendar --extra-library=edataserver-1.2 --extra-library=edataserverui-1.2 --extra-library=gtk-3 --extra-library=gdk-3 --extra-library=pangocairo-1.0 --extra-library=pango-1.0 --extra-library=harfbuzz --extra-library=atk-1.0 --extra-library=cairo-gobject --extra-library=cairo --extra-library=gdk_pixbuf-2.0 --extra-library=ecal-2.0 --extra-library=ical-glib --extra-library=ical --extra-library=icalss --extra-library=icalvcal --extra-library=secret-1 --extra-library=xml2 --extra-library=soup-2.4 --extra-library=gmodule-2.0 --extra-library=gio-2.0 --extra-library=gobject-2.0 --extra-library=glib-2.0 --extra-library=dazzle-1.0 --extra-library=handy-1 --extra-library=goa-1.0 --extra-library=gweather-3 --extra-library=geoclue-2 --extra-library=geocode-glib --extra-library=girepository-1.0 --extra-library=m --sources-top-dirs

/home/secureboot/Downloads/gnome-calendar-41.2/subprojects/ --sources-top-dirs /home/secureboot/Downloads/gnome-calendar-41.2/build/subprojects/
Traceback (most recent call last):
  File "/usr/bin/g-ir-scanner", line 99, in <module>
    sys.exit(scanner_main(sys.argv))
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/scannermain.py", line 609, in scanner_main
    shlibs = create_binary(transformer, options, args)
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/scannermain.py", line 447, in create_binary
    gdump_parser.parse()
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/gdumpparser.py", line 109, in parse
    tree = self._execute_binary_get_tree()
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/gdumpparser.py", line 175, in _execute_binary_get_tree
    return parse(out_path)
  File "/usr/lib/python3.10/xml/etree/ElementTree.py", line 1222, in parse
    tree.parse(source, parser)
  File "/usr/lib/python3.10/xml/etree/ElementTree.py", line 569, in parse
    source = open(source, "rb")
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmp-introspectsimt97y6/dump.xml'
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 153, in apport_excepthook
    with os.fdopen(os.open(pr_filename,
FileNotFoundError: [Errno 2] No such file or directory: '/var/crash/_usr_bin_g-ir-scanner.1000.crash'

Original exception was:
Traceback (most recent call last):
  File "/usr/bin/g-ir-scanner", line 99, in <module>
    sys.exit(scanner_main(sys.argv))
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/scannermain.py", line 609, in scanner_main
    shlibs = create_binary(transformer, options, args)
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/scannermain.py", line 447, in create_binary
    gdump_parser.parse()
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/gdumpparser.py", line 109, in parse
    tree = self._execute_binary_get_tree()
  File "/usr/lib/x86_64-linux-gnu/gobject-introspection/giscanner/gdumpparser.py", line 175, in _execute_binary_get_tree
    return parse(out_path)
  File "/usr/lib/python3.10/xml/etree/ElementTree.py", line 1222, in parse
    tree.parse(source, parser)
  File "/usr/lib/python3.10/xml/etree/ElementTree.py", line 569, in parse
    source = open(source, "rb")
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmp-introspectsimt97y6/dump.xml'
ninja: build stopped: subcommand failed.

It can’t find the /tmp/tmp-introspectsimt97y6/dump.xml file, and it seems like this is the file passed to g_irepository_dump. But shouldn’t g_irepository_dump create this file?

tbh I’m confused why you are using executable here? If the only C your building is the gcal code you wish to reuse, I’d expect you to use shared_library (which would avoid your g_irepository_dump issue)

That’s a good question. I need only src/gui/views/gcal-month-view.c. Initially, I was trying to create a library with library(). I added this to the end of src/gui/views/meson.build:

library('mylib', 'gcal-month-view.c', version: '1.0.0')

However gcal-month-view.c depends on a bunch of other things:

#include "config.h"
#include "gcal-application.h"
#include "gcal-clock.h"
#include "gcal-context.h"
#include "gcal-debug.h"
#include "gcal-month-cell.h"
#include "gcal-month-popover.h"
#include "gcal-month-view.h"
#include "gcal-timeline-subscriber.h"
#include "gcal-utils.h"
#include "gcal-view.h"

So if I try to build the project I get:

FAILED: src/libmylib.so.1.0.0.p/gui_views_gcal-month-view.c.o 
cc -Isrc/libmylib.so.1.0.0.p -Isrc -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -g -DHAVE_CONFIG_H '-DPACKAGE_LOCALE_DIR="/usr/local/share/locale"' '-DPACKAGE_DATA_DIR="/usr/local/share/gnome-calendar"' '-DUI_DATA_DIR="/usr/local/share"' -DEDS_DISABLE_DEPRECATED -DGOA_API_IS_SUBJECT_TO_CHANGE -DGWEATHER_I_KNOW_THIS_IS_UNSTABLE -DG_DISABLE_CAST_CHECKS -fPIC -MD -MQ src/libmylib.so.1.0.0.p/gui_views_gcal-month-view.c.o -MF src/libmylib.so.1.0.0.p/gui_views_gcal-month-view.c.o.d -o src/libmylib.so.1.0.0.p/gui_views_gcal-month-view.c.o -c ../src/gui/views/gcal-month-view.c
../src/gui/views/gcal-month-view.c:22:10: fatal error: config.h: No such file or directory
   22 | #include "config.h"
      |          ^~~~~~~~~~
compilation terminated.
ninja: build stopped: subcommand failed.

So I thought maybe I could bundle all those files into mylib. But config.h and config.c don’t exist in the project source code. config.h only exists in the build directory, so it seems that it is generated during build. So I don’t know how bundle it.

Also if I try to include other files gcal-month-view.c depends on, like gcal-application.c; I realize that gcal-application.c depends on files of it’s own, and they depend on other files, etc.

So I decided to introspect the whole executable since it would have everything necessary bundled in it. Of course there would be stuff I don’t need, but that’s not a problem for a start.

You cannot introspect a random binary and then use its types. That’s not how anything works.

Introspecting a binary in order to build introspection data is only ever useful for writing plugins for the application in question—assuming that the application supports loading plugins to extend its functionality.

You have been pretty opaque in what you want to achieve—a classical XY problem, which is not uncommon—but it seems you mainly want to reuse widgets from GNOME Calendar in your own application. You cannot do that by introspection alone.

First of all, you’ll need to copy-paste the code from GNOME Calendar into your own project, including the bits of the Calendar build system that are necessary to build those files. Then you will need to build a private shared library and generate introspection for it. There are various GNOME projects written in programming languages that are not C and that follow this pattern—like GNOME Maps, or even GNOME Shell. Once you have that shared library you will need to install it to a separate location under your application’s prefix, and add that location to the search path of libgirepository.

2 Likes

Hi Emmanuele! Wow, thanks for clarifying the whole process for me because I wasn’t sure what would I do with the generated introspection. But I agree with you, I should first take out the code I need from Gnome Calendar removing all unnecessary code (for example I don’t need the functionality for getting the weather); then build a library, introspect it, and continue from there.

I will work on that now. Thank you very much for helping me guys :blush: you are very nice, and I appreciate it a lot!

OK, so I vendored the files I need. Then went through all their dependencies, and added the needed files. This is what I have in my directory:

build/                      gcal-event-widget.h    gcal-range.h
gcal-calendar.c             gcal-event-widget.ui   gcal-recurrence.c
gcal-calendar.h             gcal-event.c           gcal-recurrence.h
gcal-clock.c                gcal-event.h           gcal-search-engine.c
gcal-clock.h                gcal-manager.c         gcal-search-engine.h
gcal-context.c              gcal-manager.h         gcal-timeline-subscriber.c
gcal-context.h              gcal-month-cell.c      gcal-timeline-subscriber.h
gcal-date-time-utils.c      gcal-month-cell.h      gcal-types.h
gcal-date-time-utils.h      gcal-month-cell.ui     gcal-utils.c
gcal-debug.h                gcal-month-popover.c   gcal-utils.h
gcal-enum-types.c           gcal-month-popover.h   gcal-view.c
gcal-enum-types.c.template  gcal-month-popover.ui  gcal-view.h
gcal-enum-types.h           gcal-month-view.c      meson.build
gcal-enum-types.h.template  gcal-month-view.h      views.gresource.xml
gcal-enums.h                gcal-month-view.ui     
gcal-event-widget.c         gcal-range.c

This is my meson.build so far:

project('gcal', 'c')

gnome = import('gnome')

sources = files(
  'gcal-month-cell.c',
  'gcal-month-popover.c',
  'gcal-month-view.c',
  'gcal-view.c',
)

glib_dep = dependency('glib-2.0', version: '>= 2.67.5')
libecal_dep = dependency('libecal-2.0', version: '>= 3.33.2')
gtk_dep = dependency('gtk+-3.0', version: '>= 3.22.20')
gio_dep = dependency('gio-2.0', version: '>= 2.58.0')
goa_dep = dependency('goa-1.0', version: '>= 3.2.0')
libdazzle_dep = dependency('libdazzle-1.0', version: '>= 3.33.1')

library(
  'gcal',
  sources: sources,
  dependencies: [glib_dep, libecal_dep, gtk_dep, gio_dep, goa_dep, libdazzle_dep]
)

However, when I try to compile, it gives me this:

[1/1] Linking target libgcal.so
FAILED: libgcal.so 
cc  -o libgcal.so libgcal.so.p/gcal-month-cell.c.o libgcal.so.p/gcal-month-popover.c.o libgcal.so.p/gcal-month-view.c.o libgcal.so.p/gcal-view.c.o -Wl,--as-needed -Wl,--no-undefined -shared -fPIC -Wl,--start-group -Wl,-soname,libgcal.so /usr/lib/x86_64-linux-gnu/libglib-2.0.so /usr/lib/x86_64-linux-gnu/libecal-2.0.so /usr/lib/x86_64-linux-gnu/libical-glib.so /usr/lib/x86_64-linux-gnu/libical.so /usr/lib/x86_64-linux-gnu/libicalss.so /usr/lib/x86_64-linux-gnu/libicalvcal.so /usr/lib/x86_64-linux-gnu/libedataserver-1.2.so /usr/lib/x86_64-linux-gnu/libsecret-1.so /usr/lib/x86_64-linux-gnu/libxml2.so /usr/lib/x86_64-linux-gnu/libsoup-2.4.so -Wl,--export-dynamic /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so -pthread /usr/lib/x86_64-linux-gnu/libgio-2.0.so /usr/lib/x86_64-linux-gnu/libgobject-2.0.so /usr/lib/x86_64-linux-gnu/libgtk-3.so /usr/lib/x86_64-linux-gnu/libgdk-3.so /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so /usr/lib/x86_64-linux-gnu/libpango-1.0.so /usr/lib/x86_64-linux-gnu/libharfbuzz.so /usr/lib/x86_64-linux-gnu/libatk-1.0.so /usr/lib/x86_64-linux-gnu/libcairo-gobject.so /usr/lib/x86_64-linux-gnu/libcairo.so /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so /usr/lib/x86_64-linux-gnu/libgoa-1.0.so /usr/lib/x86_64-linux-gnu/libdazzle-1.0.so -Wl,--end-group
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `GCAL_EVENT_WIDGET':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-event-widget.h:36: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `GCAL_IS_EVENT_WIDGET':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-event-widget.h:36: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `update_style_flags':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:97: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `should_propagate_button_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:118: undefined reference to `gcal_translate_child_window_position'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `gcal_month_cell_drag_drop':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:225: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:226: undefined reference to `gcal_event_new_from_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:227: undefined reference to `gcal_event_get_calendar'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:229: undefined reference to `gcal_event_has_recurrence'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:230: undefined reference to `ask_recurrence_modification_type'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:236: undefined reference to `gcal_event_get_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:237: undefined reference to `gcal_event_get_date_end'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:262: undefined reference to `gcal_event_set_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:269: undefined reference to `gcal_event_set_date_end'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:273: undefined reference to `gcal_context_get_manager'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:273: undefined reference to `gcal_manager_update_event'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `gcal_month_cell_class_init':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:421: undefined reference to `gcal_context_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `gcal_month_cell_set_date':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:481: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: libgcal.so.p/gcal-month-cell.c.o: in function `gcal_month_cell_set_context':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-cell.c:540: undefined reference to `gcal_context_get_clock'
/usr/bin/ld: libgcal.so.p/gcal-month-popover.c.o: in function `GCAL_EVENT_WIDGET':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-event-widget.h:36: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-popover.c.o: in function `update_event_list':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:317: undefined reference to `gcal_context_get_manager'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:317: undefined reference to `gcal_manager_get_events'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:329: undefined reference to `gcal_event_get_all_day'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:342: undefined reference to `gcal_event_widget_new'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:343: undefined reference to `gcal_event_widget_set_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:344: undefined reference to `gcal_event_widget_set_date_end'
/usr/bin/ld: libgcal.so.p/gcal-month-popover.c.o: in function `sort_func':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:374: undefined reference to `gcal_event_widget_sort_events'
/usr/bin/ld: libgcal.so.p/gcal-month-popover.c.o: in function `gcal_month_popover_class_init':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:677: undefined reference to `gcal_context_get_type'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:707: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-popover.c.o: in function `gcal_month_popover_set_date':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-popover.c:876: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `glib_autoptr_clear_GcalRange':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-range.h:109: undefined reference to `gcal_range_unref'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `GCAL_TIMELINE_SUBSCRIBER':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-timeline-subscriber.h:35: undefined reference to `gcal_timeline_subscriber_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `GCAL_EVENT_WIDGET':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-event-widget.h:36: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `GCAL_IS_EVENT_WIDGET':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-event-widget.h:36: undefined reference to `gcal_event_widget_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_get_type_once':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:143: undefined reference to `gcal_timeline_subscriber_get_type'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `calculate_event_cells':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:295: undefined reference to `gcal_event_get_all_day'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:304: undefined reference to `gcal_event_get_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:327: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:328: undefined reference to `gcal_event_get_date_end'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `calculate_multiday_event_blocks':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:371: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:431: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:433: undefined reference to `gcal_event_widget_clone'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:437: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `count_events_per_day':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:533: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `month_view_contains_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:578: undefined reference to `gcal_event_get_range'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:578: undefined reference to `gcal_range_calculate_overlap'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `allocate_multiday_events':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:596: undefined reference to `gcal_timeline_subscriber_get_range'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:611: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:704: undefined reference to `gcal_event_get_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:713: undefined reference to `gcal_event_widget_set_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:714: undefined reference to `gcal_event_widget_set_date_end'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `allocate_single_day_events':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:765: undefined reference to `gcal_timeline_subscriber_get_range'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:798: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `update_month_cells':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:899: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:929: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:959: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:966: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:967: undefined reference to `gcal_date_time_compare_date'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `update_header_labels':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:995: undefined reference to `gcal_get_month_name'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `update_weekday_labels':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1008: undefined reference to `gcal_get_weekday'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_set_date':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1104: undefined reference to `gcal_set_date_time'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1115: undefined reference to `gcal_timeline_subscriber_range_changed'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_get_children_by_uuid':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1147: undefined reference to `filter_event_list_by_uid_and_modtype'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_get_range':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1225: undefined reference to `gcal_range_new'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_add_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1237: undefined reference to `gcal_event_get_calendar'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1239: undefined reference to `gcal_event_widget_new'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1240: undefined reference to `gcal_calendar_is_read_only'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1240: undefined reference to `gcal_event_widget_set_read_only'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_update_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1260: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1264: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1275: undefined reference to `gcal_event_widget_new'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_remove_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1295: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `get_child_cell':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1336: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1337: undefined reference to `gcal_event_get_date_start'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1340: undefined reference to `gcal_event_get_all_day'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_add':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1368: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1369: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1382: undefined reference to `gcal_event_is_multiday'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1384: undefined reference to `gcal_event_widget_sort_events'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1395: undefined reference to `gcal_event_widget_compare_by_start_date'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_remove':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1422: undefined reference to `gcal_event_widget_get_event'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1423: undefined reference to `gcal_event_get_uid'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_button_press':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1731: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1734: undefined reference to `gcal_translate_child_window_position'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_motion_notify_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1767: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1769: undefined reference to `gcal_translate_child_window_position'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_button_release':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1815: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1817: undefined reference to `gcal_translate_child_window_position'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1833: undefined reference to `gcal_set_date_time'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1834: undefined reference to `gcal_set_date_time'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_key_press':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1889: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:1981: undefined reference to `gcal_date_time_get_days_in_month'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_scroll_event':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:2028: undefined reference to `should_change_date_for_scroll'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_set_property':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:2075: undefined reference to `gcal_context_get_clock'
/usr/bin/ld: libgcal.so.p/gcal-month-view.c.o: in function `gcal_month_view_init':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-month-view.c:2202: undefined reference to `get_first_weekday'
/usr/bin/ld: libgcal.so.p/gcal-view.c.o: in function `gcal_view_default_init':
/home/secureboot/Documents/Synastry/gcal/build/../gcal-view.c:52: undefined reference to `gcal_context_get_type'
/usr/bin/ld: /home/secureboot/Documents/Synastry/gcal/build/../gcal-view.c:96: undefined reference to `gcal_event_widget_get_type'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

Lots of functions are undefined, but that’s weird because for example it says gcal-month-view.c:2028: undefined reference to 'should_change_date_for_scroll'. If you search for should_change_date_for_scroll, it is located in gcal-utils.c. And if I go to gcal-month-view.c, it has #include "gcal-utils.h". So what’s wrong then? Maybe thhe order of linking is incorrect?

I found this, but I’m not sure if it can help me.


sources = files(
‘gcal-month-cell.c’,
‘gcal-month-popover.c’,
‘gcal-month-view.c’,
‘gcal-view.c’,
)

If you search for
should_change_date_for_scroll, it is located in gcal-utils.c. And if I go
to gcal-month-view.c, it has #include "gcal-utils.h". So what’s wrong
then? Maybe thhe order of linking is incorrect?

Hi,

gcal-utils.c is not included in sources, so gcal-utils.o is not
even compiled.


I found
[this](c - GTK+ gcc: undefined reference to all gtk functions when linking - Stack Overflow
e-to-all-gtk-functions-when-linking), but I’m not sure if it can help me.

This is not related: it highlights you need to follow a specific
argument order when calling gcc by yourself.

Ciao.

1 Like

Thank you very much Nicola! That indeed was the problem.

I decided to bundle all code into the library instead of vendoring only the needed parts. Because figuring out the dependent files was hard. So I ended up just copying all .c, .h, .xml, .css files into one directory. I also copied some generated files from the build directory.

I wound up with this meson.build file:

project('gcal', 'c')

gnome = import('gnome')

sources = files(
  'gcal-alarm-row.c',
  'gcal-shell-search-provider-generated.c',
  'gcal-application.c',
  'gcal-calendar-management-dialog.c',
  'gcal-calendar-management-page.c',
  'gcal-calendar-monitor.c',
  'gcal-calendar-popover.c',
  'gcal-calendar.c',
  'gcal-calendars-page.c',
  'gcal-clock.c',
  'gcal-context.c',
  'gcal-date-chooser-day.c',
  'gcal-date-chooser.c',
  'gcal-date-selector.c',
  'gcal-date-time-utils.c',
  'gcal-edit-calendar-page.c',
  'gcal-enum-types.c',
  'gcal-event-editor-dialog.c',
  'gcal-event-editor-section.c',
  'gcal-event-popover.c',
  'gcal-event-widget.c',
  'gcal-event.c',
  'gcal-expandable-entry.c',
  'gcal-import-dialog.c',
  'gcal-import-file-row.c',
  'gcal-importer.c',
  'gcal-log.c',
  'gcal-manager.c',
  'gcal-meeting-row.c',
  'gcal-month-cell.c',
  'gcal-month-popover.c',
  'gcal-month-view.c',
  'gcal-multi-choice.c',
  'gcal-new-calendar-page.c',
  'gcal-night-light-monitor.c',
  'gcal-notes-section.c',
  'gcal-quick-add-popover.c',
  'gcal-range-tree.c',
  'gcal-range.c',
  'gcal-recurrence.c',
  'gcal-reminders-section.c',
  'gcal-schedule-section.c',
  'gcal-search-button.c',
  'gcal-search-engine.c',
  'gcal-search-hit-event.c',
  'gcal-search-hit.c',
  'gcal-search-model.c',
  'gcal-shell-search-provider.c',
  'gcal-simple-server.c',
  'gcal-source-discoverer.c',
  'gcal-stub-calendar.c',
  'gcal-summary-section.c',
  'gcal-time-selector.c',
  'gcal-time-zone-monitor.c',
  'gcal-timeline-subscriber.c',
  'gcal-timeline.c',
  'gcal-timer.c',
  'gcal-utils.c',
  'gcal-view.c',
  'gcal-weather-info.c',
  'gcal-weather-service.c',
  'gcal-weather-settings.c',
  'gcal-week-grid.c',
  'gcal-week-header.c',
  'gcal-week-view.c',
  'gcal-window.c',
  'gcal-year-view.c',
  'main.c',
)

common_flags = [
  '-DGOA_API_IS_SUBJECT_TO_CHANGE',
  '-DGWEATHER_I_KNOW_THIS_IS_UNSTABLE',
  '-DPACKAGE_LOCALE_DIR="/usr/local/share/locale"',
]

add_project_arguments(common_flags, language: 'c')
cc = meson.get_compiler('c')

libical_dep = dependency('libical', version: '>= 1.0')
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.21.2')
libedataserverui_dep = dependency('libedataserverui-1.2', version: '>= 3.17.1')
libedataserver_dep = dependency('libedataserver-1.2', version: '>= 3.17.1')
libecal_dep = dependency('libecal-2.0', version: '>= 3.33.2')
libsoup_dep = dependency('libsoup-2.4')
libdazzle_dep = dependency('libdazzle-1.0', version: '>= 3.33.1')
libhandy_dep = dependency('libhandy-1', version: '>= 1.0.0')
glib_dep = dependency('glib-2.0', version: '>= 2.67.5')
gtk_dep = dependency('gtk+-3.0', version: '>= 3.22.20')
gio_dep = dependency('gio-2.0', version: '>= 2.58.0')
goa_dep = dependency('goa-1.0', version: '>= 3.2.0')
gweather_dep = dependency('gweather-3.0', version: '>= 40.0')
geoclue_dep = dependency('libgeoclue-2.0', version: '>=2.4')
geocode_dep = dependency('geocode-glib-1.0', version: '>=3.23')
m_dep = cc.find_library('m')

gcal_deps = [
  gsettings_desktop_schemas_dep,
  libedataserverui_dep,
  libedataserver_dep,
  libecal_dep,
  libdazzle_dep,
  libsoup_dep,
  libical_dep,
  libhandy_dep,
  glib_dep,
  gtk_dep,
  gio_dep,
  goa_dep,
  gweather_dep,
  geoclue_dep,
  geocode_dep,
  m_dep,
]

lib = library(
  'gcal',
  sources: sources,
  dependencies: gcal_deps,
)

gnome = import('gnome')
gnome.generate_gir(
  lib,
  namespace: 'Gcal',
  nsversion: '41.2'
)

The library libgcal.so builds successfuly! However, generating GObject introspection data doesn’t work. It says this:

[1/2] Generating Gcal-41.2.gir with a custom command
g-ir-scanner: link: x86_64-linux-gnu-gcc -o /home/secureboot/Documents/Synastry/gcal/build/tmp-introspecth5pbrxh_/Gcal-41.2 /home/secureboot/Documents/Synastry/gcal/build/tmp-introspecth5pbrxh_/Gcal-41.2.o -L. -Wl,-rpath,. -Wl,--no-as-needed -L/home/secureboot/Documents/Synastry/gcal/build/ -Wl,-rpath,/home/secureboot/Documents/Synastry/gcal/build/ -lgcal -ledataserver-1.2 -ledataserverui-1.2 -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lecal-2.0 -lical-glib -lical -licalss -licalvcal -lsecret-1 -lxml2 -lsoup-2.4 -lgmodule-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -ldazzle-1.0 -lhandy-1 -lgoa-1.0 -lgweather-3 -lgeoclue-2 -lgeocode-glib -lm -lgirepository-1.0 -lgio-2.0 -lgobject-2.0 -Wl,--export-dynamic -lgmodule-2.0 -pthread -lglib-2.0
<unknown>:: Error: Gcal: Namespace is empty; likely causes are:
* Not including .h files to be scanned
* Broken --identifier-prefix
[2/2] Generating Gcal-41.2.typelib with a custom command

The file Gcal-41.2.typelib is generated, it’s 188 bytes. I guess it contains no introspection data since it said “Gcal: Namespace is empty”. Do you know what could be the cause?

I’m not sure what namespace would be correct to use. In src/meson.build I saw this code:

built_sources += gnome.gdbus_codegen(
  'gcal-shell-search-provider-generated',
  shell_search_provider_dbus_interfaces,
  interface_prefix: 'org.gnome.',
         namespace: 'Gcal'
)

So I thought maybe the correct namespace to use is Gcal.

Also, once we have correct .typelib file, what to do next?

...
gnome.generate_gir(
  lib,
  namespace: 'Gcal',
  nsversion: '41.2'
)


The file Gcal-41.2.typelib is generated, it’s 188 bytes. I guess it contains
no introspection data since it said “Gcal: Namespace is empty”. Do you know
what could be the cause?

AFAIK gobject-introspection needs to access the source files (IIRC both
.h and .c) and I cannot see how that is possible with only the 3
arguments you passed to gnome.generate_gir.

I’m pretty sure you must specify at least the sources argument. To be
sure, check what other projects do, e.g. GTK has this call:

gtk_gir = gnome.generate_gir(libgtk,
  sources: gtk_introspection_sources,
  namespace: 'Gtk',
  nsversion: gtk_api_version,
  identifier_prefix: 'Gtk',
  symbol_prefix: 'gtk',
  export_packages: 'gtk4',
  includes: [ gdk_gir[0], gsk_gir[0], ],
  header: 'gtk/gtk.h',
  install: true,
  dependencies: [gtk_deps, libgsk_dep],
  extra_args: gir_args,
  fatal_warnings: get_option('werror'),
)


Also, once we have correct .typelib file, what to do next?

Well, you install it (and the companion .gir file) to the proper folders
(/usr/lib/girepository-1.0 and /usr/share/gir-1.0 on my system) and
you use them like you do with any other introspected library.

Ciao.

1 Like

Thank you very much! It’s working!

Here’s how I updated my meson.build:

project('gcal', 'c')

gnome = import('gnome')

sources = files(
  'gcal-alarm-row.c',
  'gcal-shell-search-provider-generated.c',
  'gcal-application.c',
  'gcal-calendar-management-dialog.c',
  'gcal-calendar-management-page.c',
  'gcal-calendar-monitor.c',
  'gcal-calendar-popover.c',
  'gcal-calendar.c',
  'gcal-calendars-page.c',
  'gcal-clock.c',
  'gcal-context.c',
  'gcal-date-chooser-day.c',
  'gcal-date-chooser.c',
  'gcal-date-selector.c',
  'gcal-date-time-utils.c',
  'gcal-edit-calendar-page.c',
  'gcal-enum-types.c',
  'gcal-event-editor-dialog.c',
  'gcal-event-editor-section.c',
  'gcal-event-popover.c',
  'gcal-event-widget.c',
  'gcal-event.c',
  'gcal-expandable-entry.c',
  'gcal-import-dialog.c',
  'gcal-import-file-row.c',
  'gcal-importer.c',
  'gcal-log.c',
  'gcal-manager.c',
  'gcal-meeting-row.c',
  'gcal-month-cell.c',
  'gcal-month-popover.c',
  'gcal-month-view.c',
  'gcal-multi-choice.c',
  'gcal-new-calendar-page.c',
  'gcal-night-light-monitor.c',
  'gcal-notes-section.c',
  'gcal-quick-add-popover.c',
  'gcal-range-tree.c',
  'gcal-range.c',
  'gcal-recurrence.c',
  'gcal-reminders-section.c',
  'gcal-schedule-section.c',
  'gcal-search-button.c',
  'gcal-search-engine.c',
  'gcal-search-hit-event.c',
  'gcal-search-hit.c',
  'gcal-search-model.c',
  'gcal-shell-search-provider.c',
  'gcal-simple-server.c',
  'gcal-source-discoverer.c',
  'gcal-stub-calendar.c',
  'gcal-summary-section.c',
  'gcal-time-selector.c',
  'gcal-time-zone-monitor.c',
  'gcal-timeline-subscriber.c',
  'gcal-timeline.c',
  'gcal-timer.c',
  'gcal-utils.c',
  'gcal-view.c',
  'gcal-weather-info.c',
  'gcal-weather-service.c',
  'gcal-weather-settings.c',
  'gcal-week-grid.c',
  'gcal-week-header.c',
  'gcal-week-view.c',
  'gcal-window.c',
  'gcal-year-view.c',
  'main.c',
)

headers = files(
  'gcal-alarm-row.h',
  'gcal-shell-search-provider-generated.h',
  'gcal-application.h',
  'gcal-calendar-management-dialog.h',
  'gcal-calendar-management-page.h',
  'gcal-calendar-monitor.h',
  'gcal-calendar-popover.h',
  'gcal-calendar.h',
  'gcal-calendars-page.h',
  'gcal-clock.h',
  'gcal-context.h',
  'gcal-date-chooser-day.h',
  'gcal-date-chooser.h',
  'gcal-date-selector.h',
  'gcal-date-time-utils.h',
  'gcal-edit-calendar-page.h',
  'gcal-enum-types.h',
  'gcal-event-editor-dialog.h',
  'gcal-event-editor-section.h',
  'gcal-event-popover.h',
  'gcal-event-widget.h',
  'gcal-event.h',
  'gcal-expandable-entry.h',
  'gcal-import-dialog.h',
  'gcal-import-file-row.h',
  'gcal-importer.h',
  'gcal-log.h',
  'gcal-manager.h',
  'gcal-meeting-row.h',
  'gcal-month-cell.h',
  'gcal-month-popover.h',
  'gcal-month-view.h',
  'gcal-multi-choice.h',
  'gcal-new-calendar-page.h',
  'gcal-night-light-monitor.h',
  'gcal-notes-section.h',
  'gcal-quick-add-popover.h',
  'gcal-range-tree.h',
  'gcal-range.h',
  'gcal-recurrence.h',
  'gcal-reminders-section.h',
  'gcal-schedule-section.h',
  'gcal-search-button.h',
  'gcal-search-engine.h',
  'gcal-search-hit-event.h',
  'gcal-search-hit.h',
  'gcal-search-model.h',
  'gcal-shell-search-provider.h',
  'gcal-simple-server.h',
  'gcal-source-discoverer.h',
  'gcal-stub-calendar.h',
  'gcal-summary-section.h',
  'gcal-time-selector.h',
  'gcal-time-zone-monitor.h',
  'gcal-timeline-subscriber.h',
  'gcal-timeline.h',
  'gcal-timer.h',
  'gcal-utils.h',
  'gcal-view.h',
  'gcal-weather-info.h',
  'gcal-weather-service.h',
  'gcal-weather-settings.h',
  'gcal-week-grid.h',
  'gcal-week-header.h',
  'gcal-week-view.h',
  'gcal-window.h',
  'gcal-year-view.h',
)

common_flags = [
  '-DGOA_API_IS_SUBJECT_TO_CHANGE',
  '-DGWEATHER_I_KNOW_THIS_IS_UNSTABLE',
  '-DPACKAGE_LOCALE_DIR="/usr/local/share/locale"',
]

add_project_arguments(common_flags, language: 'c')
cc = meson.get_compiler('c')

libical_dep = dependency('libical', version: '>= 1.0')
gsettings_desktop_schemas_dep = dependency('gsettings-desktop-schemas', version: '>= 3.21.2')
libedataserverui_dep = dependency('libedataserverui-1.2', version: '>= 3.17.1')
libedataserver_dep = dependency('libedataserver-1.2', version: '>= 3.17.1')
libecal_dep = dependency('libecal-2.0', version: '>= 3.33.2')
libsoup_dep = dependency('libsoup-2.4')
libdazzle_dep = dependency('libdazzle-1.0', version: '>= 3.33.1')
libhandy_dep = dependency('libhandy-1', version: '>= 1.0.0')
glib_dep = dependency('glib-2.0', version: '>= 2.67.5')
gtk_dep = dependency('gtk+-3.0', version: '>= 3.22.20')
gio_dep = dependency('gio-2.0', version: '>= 2.58.0')
goa_dep = dependency('goa-1.0', version: '>= 3.2.0')
gweather_dep = dependency('gweather-3.0', version: '>= 40.0')
geoclue_dep = dependency('libgeoclue-2.0', version: '>=2.4')
geocode_dep = dependency('geocode-glib-1.0', version: '>=3.23')
m_dep = cc.find_library('m')

gcal_deps = [
  gsettings_desktop_schemas_dep,
  libedataserverui_dep,
  libedataserver_dep,
  libecal_dep,
  libdazzle_dep,
  libsoup_dep,
  libical_dep,
  libhandy_dep,
  glib_dep,
  gtk_dep,
  gio_dep,
  goa_dep,
  gweather_dep,
  geoclue_dep,
  geocode_dep,
  m_dep,
]

lib = library(
  'gcal',
  sources: sources,
  dependencies: gcal_deps,
)

gnome = import('gnome')
gnome.generate_gir(lib,
  sources: [sources, headers],
  namespace: 'Gcal',
  nsversion: '1.0',
  identifier_prefix: 'Gcal',
  dependencies: [gcal_deps],
  symbol_prefix: 'gcal',
)

I call generate_gir passing headers and c files. Gcal-1.0.gir and Gcal-1.0.typelib files are generated, they are now not empty because they contain correct data.

I will have to put Gcal-1.0.gir into /usr/share/gir-1.0 folder, and Gcal-1.0.typelib in /usr/lib/girepository-1.0.

and you use them like you do with any other introspected library

But I don’t know how. The only introspected libraries I use are Gtk, Gdk, Gio, etc. and PyGObject is providing them for me. I don’t know how PyGObject works under the hood. Can you explain me more how I can generate python bindings from the introspection data I have?

Thank you and everyone else a lot for helping me! I love you guys! I would have never achieved all this without you. :heart:

No, don’t.

You need to put those files in your application’s prefix—e.g. /usr/share/yourapp/gir-1.0 and /usr/lib/yourapp/girepository-1.0.

For Python bindings, you only need the typelib file, not the GIR data.

You don’t “generate” anything: the pygobject module “gi” will load the typelib file and will resolve object types, methods, and the rest of the API at run time.

The main difference between a generic library API and your application’s own library API is that you need to tell pygobject to load the typelib data from an additional prefix; this is done by updating the GI_TYPELIB_PATH environment variable before launching your application. You can do that with a simple wrapper that manipulates the environment putting /usr/lib/yourapp before the default locations under /usr/lib, e.g.:

export GI_TYPELIB_PATH=/usr/lib/yourapp:/usr/lib:/usr/local/lib
2 Likes

Thank you Emmanuele. I didn’t expect you to respond so quickly. So before I saw your answer, I did this:

I installed:

  • Gcal-1.0.gir into /usr/share/gir-1.0
  • Gcal-1.0.typelib in /usr/lib/girepository-1.0
    * libgcal.so into /lib/x86_64-linux-gnu (this is where libgtk-3.so is, so I decided to put it there)

I launched python venv with PyGObject installed, and run this:

>>> import gi
>>> from gi.repository import Gcal, Gtk
<stdin>:1: PyGIWarning: Gcal was imported without specifying a version first. Use gi.require_version('Gcal', '1.0') before import to ensure that the right version gets loaded.
<stdin>:1: PyGIWarning: Gtk was imported without specifying a version first. Use gi.require_version('Gtk', '3.0') before import to ensure that the right version gets loaded.

With autocomplete I can see these classes available:

>>> Gcal.Month
Gcal.MonthCell()         Gcal.MonthPopover()      Gcal.MonthView()
Gcal.MonthCellClass(     Gcal.MonthPopoverClass(  Gcal.MonthViewClass(

I can create an instance of each of these classes, however if I try this code:

>>> cell = Gcal.MonthCell()
>>> cell
<gi.repository.Gcal.MonthCell object at 0x7f5656aa3d30>
>>> win = Gtk.Window()
>>> win.add(cell)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: argument widget: Expected Gtk.Widget, but got gi.repository.Gcal.MonthCell

Gcal-1.0.gir has this snippet in it:

<class name="MonthCell"
           c:symbol-prefix="month_cell"
           c:type="GcalMonthCell"
           glib:type-name="GcalMonthCell"
           glib:get-type="gcal_month_cell_get_type"
           glib:type-struct="MonthCellClass">
      <source-position filename="../gcal-month-cell.h" line="31"/>
      <function name="new"
                c:identifier="gcal_month_cell_new"
                introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="33"/>
        <return-value>
          <type c:type="GtkWidget*"/>
        </return-value>
      </function>
      <method name="get_content_space"
              c:identifier="gcal_month_cell_get_content_space">
        <source-position filename="../gcal-month-cell.h" line="58"/>
        <return-value transfer-ownership="none">
          <type name="gint" c:type="gint"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_context"
              c:identifier="gcal_month_cell_get_context"
              introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="48"/>
        <return-value>
          <type c:type="GcalContext*"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_date"
              c:identifier="gcal_month_cell_get_date"
              introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="35"/>
        <return-value>
          <type c:type="GDateTime*"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_different_month"
              c:identifier="gcal_month_cell_get_different_month">
        <source-position filename="../gcal-month-cell.h" line="43"/>
        <return-value transfer-ownership="none">
          <type name="gboolean" c:type="gboolean"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_header_height"
              c:identifier="gcal_month_cell_get_header_height">
        <source-position filename="../gcal-month-cell.h" line="60"/>
        <return-value transfer-ownership="none">
          <type name="gint" c:type="gint"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_overflow" c:identifier="gcal_month_cell_get_overflow">
        <source-position filename="../gcal-month-cell.h" line="53"/>
        <return-value transfer-ownership="none">
          <type name="guint" c:type="guint"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_overflow_height"
              c:identifier="gcal_month_cell_get_overflow_height">
        <source-position filename="../gcal-month-cell.h" line="62"/>
        <return-value transfer-ownership="none">
          <type name="gint" c:type="gint"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="get_selected" c:identifier="gcal_month_cell_get_selected">
        <source-position filename="../gcal-month-cell.h" line="64"/>
        <return-value transfer-ownership="none">
          <type name="gboolean" c:type="gboolean"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
        </parameters>
      </method>
      <method name="set_context"
              c:identifier="gcal_month_cell_set_context"
              introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="50"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="context" transfer-ownership="none">
            <type c:type="GcalContext*"/>
          </parameter>
        </parameters>
      </method>
      <method name="set_date"
              c:identifier="gcal_month_cell_set_date"
              introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="37"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="date" transfer-ownership="none">
            <type c:type="GDateTime*"/>
          </parameter>
        </parameters>
      </method>
      <method name="set_different_month"
              c:identifier="gcal_month_cell_set_different_month">
        <source-position filename="../gcal-month-cell.h" line="45"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="out" transfer-ownership="none">
            <type name="gboolean" c:type="gboolean"/>
          </parameter>
        </parameters>
      </method>
      <method name="set_overflow" c:identifier="gcal_month_cell_set_overflow">
        <source-position filename="../gcal-month-cell.h" line="55"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="n_overflow" transfer-ownership="none">
            <type name="guint" c:type="guint"/>
          </parameter>
        </parameters>
      </method>
      <method name="set_selected" c:identifier="gcal_month_cell_set_selected">
        <source-position filename="../gcal-month-cell.h" line="66"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="selected" transfer-ownership="none">
            <type name="gboolean" c:type="gboolean"/>
          </parameter>
        </parameters>
      </method>
      <method name="set_weather"
              c:identifier="gcal_month_cell_set_weather"
              introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="40"/>
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <instance-parameter name="self" transfer-ownership="none">
            <type name="MonthCell" c:type="GcalMonthCell*"/>
          </instance-parameter>
          <parameter name="info" transfer-ownership="none">
            <type c:type="GcalWeatherInfo*"/>
          </parameter>
        </parameters>
      </method>
      <property name="context"
                introspectable="0"
                writable="1"
                transfer-ownership="none">
        <type/>
      </property>
      <glib:signal name="show-overflow" when="last" introspectable="0">
        <return-value transfer-ownership="none">
          <type name="none" c:type="void"/>
        </return-value>
        <parameters>
          <parameter name="object" transfer-ownership="none">
            <type/>
          </parameter>
        </parameters>
      </glib:signal>
    </class>

    <record name="MonthCellClass"
            c:type="GcalMonthCellClass"
            glib:is-gtype-struct-for="MonthCell">
      <source-position filename="../gcal-month-cell.h" line="31"/>
      <field name="parent_class" introspectable="0">
        <type c:type="GtkEventBoxClass"/>
      </field>
    </record>

You can see that there is a function new that returns a GtkWidget pointer:

      <function name="new"
                c:identifier="gcal_month_cell_new"
                introspectable="0">
        <source-position filename="../gcal-month-cell.h" line="33"/>
        <return-value>
          <type c:type="GtkWidget*"/>
        </return-value>
      </function>

However it’s not accessible in python:

>>> Gcal.MonthCell.new()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'MonthCell' has no attribute 'new'

I decided to define a class that would inherit from both Gcal.MonthCell and Gtk.Widget:

class Cell(Gcal.MonthCell, Gtk.Widget):
    def __init__(self):
        Gcal.MonthCell.__init__(self)
        Gtk.Widget.__init__(self)

but if I instantiate it, it doesn’t work:

>>> Cell()

(.:36152): Gtk-CRITICAL **: 21:09:50.252: Unable to load resource for composite template for type 'GcalMonthCell': The resource at “/org/gnome/calendar/ui/views/gcal-month-cell.ui” does not exist

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_child_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.252: gtk_widget_class_bind_template_callback_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.253: gtk_widget_class_bind_template_callback_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.253: gtk_widget_class_bind_template_callback_full: assertion 'widget_class->priv->template != NULL' failed

(.:36152): Gtk-CRITICAL **: 21:09:50.253: gtk_widget_init_template: assertion 'template != NULL' failed
<__main__.Cell object at 0x7f56556e9c40 (GcalMonthCell at 0x55df7d914160)>

It can’t find gcal-month-cell.ui template, I should research how to add .ui files to my library.

But also, something isn’t right here. I think I should use Gcal.MonthCell.new() instead of defining my own class. Why isn’t new available but is listed in .gir file?

Other than that, I will note your point about where to put .typelib file. Thank you!

OK, I decided to go a different route. In the src/meson.build you can see that the executable is taking a dependency libgcal_dep:

##################
# gnome-calendar #
##################

executable(
  meson.project_name(),
       files('main.c'),
          dependencies: libgcal_dep,
               install: true,
           install_dir: calendar_bindir,
)

So I thought: maybe there is a libgcal library then? And there is:

###################
# Private library #
###################

sources = files()
subdir('core')
subdir('gui')
subdir('search')
subdir('theme')
subdir('utils')
subdir('weather')

libgcal_generated_sources_dep = declare_dependency(
  sources: built_sources,
)

gcal_deps += libgcal_generated_sources_dep

libgcal = static_library(
               'gcal-private',
              sources: sources,
  include_directories: calendar_incs,
         dependencies: gcal_deps,
              install: false,
)

libgcal_dep = declare_dependency(
            link_with: libgcal,
              sources: built_sources,
         dependencies: gcal_deps,
  include_directories: calendar_incs,
)

So I thought instead of trying to make my own library, I could just use this one. It should contain all needed resources.

I changed it from static_library to shared_library, and added some needed parameters. I also added the code to generate introspection:

libgcal = shared_library('gcal',
              sources: sources,
  include_directories: calendar_incs,
         dependencies: gcal_deps,
)

headers_gir = files(
  'core/gcal-time-zone-monitor.h',
  'core/gcal-recurrence.h',
  'gui/gcal-calendar-popover.h',
  'gui/calendar-management/gcal-edit-calendar-page.h',
  'gui/css-code.h',
  'gui/views/gcal-week-grid.h',
  'core/gcal-timeline.h',
  'gui/event-editor/gcal-event-editor-dialog.h',
  'search/gcal-search-hit-event.h',
  'gui/event-editor/gcal-alarm-row.h',
  'gui/importer/gcal-import-file-row.h',
  'gcal-enums.h',
  'gui/event-editor/gcal-date-chooser-day.h',
  'gui/calendar-management/gcal-calendars-page.h',
  'gui/gcal-window.h',
  'gui/event-editor/gcal-reminders-section.h',
  'core/gcal-event.h',
  'utils/gcal-date-time-utils.h',
  'core/gcal-clock.h',
  'gconstructor.h',
  'gui/gcal-meeting-row.h',
  'gui/views/gcal-view.h',
  'gui/views/gcal-week-header.h',
  'weather/gcal-weather-service.h',
  'gui/gcal-search-button.h',
  'core/gcal-manager.h',
  'gui/event-editor/gcal-schedule-section.h',
  'gui/event-editor/gcal-summary-section.h',
  'gui/views/gcal-year-view.h',
  'gui/gcal-event-widget.h',
  'gui/views/gcal-month-cell.h',
  'gui/gcal-weather-settings.h',
  'core/gcal-timeline-subscriber.h',
  'gui/importer/gcal-importer.h',
  'gui/event-editor/gcal-time-selector.h',
  'search/gcal-search-hit.h',
  'gui/event-editor/gcal-date-chooser.h',
  'core/gcal-timer.h',
  'gui/gcal-quick-add-popover.h',
  'search/gcal-search-model.h',
  'gcal-types.h',
  'gui/gcal-expandable-entry.h',
  'gui/gcal-event-popover.h',
  'gui/calendar-management/gcal-calendar-management-page.h',
  'gui/calendar-management/gcal-calendar-management-dialog.h',
  'core/gcal-calendar.h',
  'core/gcal-shell-search-provider.h',
  'gui/calendar-management/gcal-new-calendar-page.h',
  'gui/event-editor/gcal-multi-choice.h',
  'utils/gcal-source-discoverer.h',
  'gui/event-editor/gcal-event-editor-section.h',
  'gui/gcal-application.h',
  'gui/event-editor/gcal-notes-section.h',
  'utils/gcal-utils.h',
  'core/gcal-night-light-monitor.h',
  'search/gcal-search-engine.h',
  'core/gcal-context.h',
  'core/gcal-log.h',
  'gui/views/gcal-week-view.h',
  'gui/event-editor/gcal-date-selector.h',
  'gui/views/gcal-month-popover.h',
  'gui/importer/gcal-import-dialog.h',
  'core/gcal-range-tree.h',
  'weather/gcal-weather-info.h',
  'core/gcal-range.h',
  'core/gcal-calendar-monitor.h',
  'gui/views/gcal-month-view.h',
)

gnome = import('gnome')
gnome.generate_gir(libgcal,
  sources: [sources, headers_gir],
  namespace: 'Gcal',
  nsversion: '1.0',
  identifier_prefix: 'Gcal',
  dependencies: gcal_deps,
  symbol_prefix: 'gcal',
)

The header files are all the files I could find in the src directory.

When I compile, it generates a much bigger .gir files (9K lines instead of 300 that I had with my own library), which is good since it contains even more classes that I need. But there is an error (see my reply below).