As my first post related to SerenityOS development, Iām going to talk about a topic which Iām really passionate about ā Python programming!
SerenityOS has a pretty decent port of the Python language, mainly due to the work done by Linus (and other contributors!). Almost every standard library module works as intended, with many of its optional dependencies also ported, like sqlite, zlib, ncurses. Fun fact: webbrowser module has official support for launching the Serenityās Ladybird Browser.
One of such optional dependencies is libffi, which is a foreign-function interface library. Having this dependency makes the ctypes module available.
With ctypes, we can easily call C compatible functions exported by a shared library, which means
it should be possible to interface with the Serenity C++ classes, providing that we write wrapper
functions in the style of C, and use the extern "C"
declaration.
Letās build a small āhello worldā C-reni-Py (š ) program!
Creating a shared library
To create a shared library the easiest way possible, Iām going to use the same structure
as the other libraries, by creating a new directory in the Userland/Libraries
.
Letās call it LibExample:
|
|
Weāre going to build a really simple one-function library that sends (push-like) desktop notifications!
|
|
|
|
Nice! Now, to make the build system compile this code, itās necessary to edit CMakeLists.txt
:
|
|
Iām not sure if this declaration is entirely correct
(as I donāt fully understand the build system), but I found that serenity_component()
must be present. Otherwise, the library wonāt be placed in the OS filesystem
(I assume itās because itās not a dependency of any application).
Now, edit Userland/Libraries/CMakeLists.txt
and add an add_subdirectory(LibExample)
declaration. Build the system and run it. Check that there is a /usr/lib/libexample.so
file!
Using the library from Python
Assuming that you already have the Python port installed, letās use the library. Open a Python interpreter and type:
|
|
Andā¦
It crashed! (At least the error is pretty cool)
Apparently, before we can create notifications, we need to have an event loop
instantiated, which in Serenity itās done by initializing a GUI::Application
object.
Iām not entirely sure why, I think itās related to the way GUI applications communicate
with WindowServer
.
After declaring a global variable static RefPtr<GUI::Application> app
,
Iām going to initialize it in the first invocation of notify()
. Something like this:
|
|
And there we go! Displaying a notification on the SerenityOS desktop, via Python:
(I also introduced an icon file as a third parameter, so I could find a reason to show the wholesome catdog mascot in this post.)
With this approach, itās theoretically possible to build Python bindings for LibGUI (and other components), but itās really hard work to do that, I think. Another way to build this kind of integration is to use the CPython C API.
Thatās all for today. I hope you find this post interesting in any way. x)