You are here

Planet GNOME

Subscribe to Feed Planet GNOME
Planet GNOME - https://planet.gnome.org/
Përditësimi: 2 ditë 1 orë më parë

Christian Hergert: Foundry.DocumentationManager

Hën, 07/04/2025 - 9:31md

Back in December (before I caught the flu working at a farmers market, then Covid two weeks later, then two months of long-Covid) I mentioned that we’d discuss the various subsystems needed in libfoundry to build an IDE as a library.

I used the little bit of energy I had to work on some core abstractions. In an effort to live up to my word lets talk a bit about what went into libfoundry last night.

There is now a DocumentationManager sub-system which handles documentation installed on the host system, chroots, and Flatpak SDKs. It’s a bit tricky to make this all work without blurring the lines of abstraction so lets cover how that works.

Generally speaking, we try to avoid plugins depending on other plugins. Sometimes it happens but usually it is an opportunity to make a better abstraction in libfoundry. Lets look at what is needed around documentation.

  • We have many SDKs and they all might have documentation available at different locations.
  • We primarily have one format we need to support in GNOME, which is the venerable Devhelp2 XML format serving as an index.
  • SDKs might contain the same documentation but at different versions (Nightly vs GNOME 48 vs jhbuild for example)
  • There may be more formats that matter in the future especially as we look at pulling in support for new languages.
  • Adding new search capabilities shouldn’t break the API.
  • Querying needs to be fast enough to update as you type.

So lets dive into the abstractions.

DocumentationManager

This is the core abstraction you start interfacing with. It is a service of the FoundryContext and therefore can be accessed with Foundry.Context:documentation-manager property.

The documentation manager manages the Foundry.DocumentationProvider plug-in abstractions. Plug-ins that which to contribute to the documentation pipeline must subclass this in their plug-in.

To query documentation, use Foundry.DocumentationManager.query(). As I noted earlier, I don’t want new capabilities to break the API so a Foundry.DocumentationQuery object is used rather than a sequence of parameters which would need to be modified.

Avoiding Formats in the API

Since we want to be able to support other documentation formats in the future, it is important that we do not force anything about devhelp2 XML into the core abstraction.

The core result object from queries is a simple Foundry.Documentation object. Like above, we want to avoid breaking API/ABI when new capabilities are added so this object serves as our abstraction to do so. Navigating a tree structure will live here and can be implemented by plug-ins through subclassing.

Additionally, a “devhelp” plug-in provides support for crawling the devhelp2-style directories on disk. But this plug-in knows nothing about where to find documentation as that is relevant only to the SDKs.

This is where the Foundry.DocumentationRoot object becomes useful. SDK plug-ins can implement DocumentationProvider in their plug-in to expose documentation roots. The host-sdk, jhbuild, and Flatpak plug-ins all do this to expose the location of their documentation.

Now the devhelp plug-in can be provided the information it needs for crawling without any knowledge of SDKs.

Fast Querying

The old adage is that the only way to go faster on a computer is to do less work. This is particularly important in search systems where doing an entire query of a database means a lot of wasted CPU, memory, and storage I/O.

To make querying fast the devhelp plug-in indexes information about SDKs in SQLite. Way back in Builder we’d avoid this and just make an optimized fuzzy search index, mmap that, and search it. But now days we’ve gone from one set of documentation to multiple sets of documentation across SDK versions. The problem domain explodes quite a bit. SQLite seemed like a nice way to do this while also allowing us to be lazy in our searching.

By lazy what I mean is that while we’ll start your query, we only retrieve the first few results from the cursor. The rest are lazily fetched as the GListModel is scanned by scrolling. As that is not a very common operation compared to typing, you can throw away a lot of work naturally while still sitting behind the comfortable GListModel interface.

What now?

Since libfoundry already supports SDK management (including Flatpak) you could probably re-implement Manuals in a week-end. Hopefully this also breaks down a bit of the knowledge used to build such an application and the deceptive complexity behind doing it well.

This should also, hopefully soon, allow us to share a documentation implementation across Builder, Manuals, and an upcoming project I have which will benefit from easy access to documentation of object properties.

Brage Fuglseth: Keypunch 6.0

Sht, 05/04/2025 - 12:44pd

Spring is in the air, the snow is finally melting away here in the cold north, and Keypunch is getting an update! Let’s walk through all the new features and improvements together.

Realistic Results

Up to now, Keypunch’s measurements of typing performance have been rather primitive. For speed, it has just compared the total number of typed characters, both correct and incorrect, to the test duration. Likewise, the “correctness” rate is nothing more than the share of correctly typed characters at the time of calculation. If you make a mistake and then correct it, it’s not taken into account at all.

These calculations are easy to understand and interpret, but also flawed and potentially misleading. The one for speed in particular has caused some pretty ridiculous result screens because of its uncritical counting. Needless to say, this is not ideal.

I’ve gone a little back and forth with myself on how to move forward, and ended up overhauling both of the calculations: For speed, Keypunch now counts how many correct characters there are at the end of the test, while the correctness rate has been replaced with real accuracy, based on all operations that have changed the typed text rather than just the final result.

An overview of the new result calculations

The new calculations come with their own trade-offs, such as the incentive to correct mistakes being slightly reduced. In general, however, I view them as a change for the better.

Frustration Relief

Learning to type is awfully hard. At least it was for me; sometimes it felt like I wasn’t even in control of my own fingers. This made me furious, and my number-one coping mechanism was to go berserk with my keyboard and mash random keys in frustration. As one might guess, this did not help me progress, and I probably should just have gone for a walk or something instead.

To safeguard the poor souls who come after me, I’m introducing something I call frustration relief. The concept is simple: If Keypunch detects that you’re randomly mashing your keyboard, it will cancel the test and provide a helpful piece of life advice.

Frustration relief in action

I can’t understate how much I wish I had something like this a couple of years ago.

Input Improvements

Being a text-centric app with multi-language support, Keypunch inevitably has to work with the many intricacies of digital text input. This includes the fact that the Unicode standard contains more than a dozen different space characters. For a while, Keypunch has supported entering regular spaces in the place of non-breaking ones, and now the same is possible the other way around too. Notably, this is a significant improvement for users of the francophone BÉPO keyboard layout.

New Languages

Keypunch’s international community has been hard at work lately, and I’m happy to report a solid upturn in language support. For text generation, these languages have been added:

  • Catalan
  • Dutch
  • Estonian
  • Greek
  • Indonesian
  • Slovak
  • Persian

This brings the total language count up to 38! Does Keypunch support your language yet? If not, feel free to open a language request.

A preview of the extended language support

On the interface translation side, Keypunch has enrolled in GNOME’s common translation system, Damned Lies, allowing it to benefit from the coordinated and high-quality work of GNOME’s translation teams. Since the last update, Keypunch has been translated into these languages:

  • Catalan
  • British English
  • Persian
  • Finnish
  • Indonesian
  • Kabyle
  • Slovak
  • Slovenian
  • Chinese

Thanks to everyone who is helping make Keypunch speak their language!

Platform Progression

This Keypunch release is based on GNOME 48, which brings a bunch of external platform goodness to the app:

  • The latest Adwaita styling
  • Better adherence to the system font settings
  • Improved performance
  • An “Other Apps” section in the About dialog
The new “Other Apps” section in the About dialog

While not directly part of the runtime, Keypunch will also benefit a lot from the new Adwaita Fonts. It’s exciting to build on such a rapidly improving platform.

Additional Artwork

Apparently, some people are keeping Keypunch in their game libraries. If you’re one of them, I’ve made a couple of assets to make Keypunch integrate better visually with the rest of your collection. Enjoy!

Circle Inclusion

Keypunch is now part of GNOME Circle! I’m happy and grateful to have another app of mine accepted into the program. For full transparency, I’m part of the Circle Committee myself, but Keypunch has been independently reviewed by two other committee members, namely Tobias and Gregor. Thanks!

Final Thoughts

That’s it for this update. Initially, I was planning on just doing a platform/translation bump now and holding off the headline features for an even bigger update later on, but I decided that it’s better to ship what I have at the moment and let the rest wait for later. There’s still more on the roadmap, but I don’t want to spoil anything!

If you have questions or feedback, feel free to mention me on Mastodon or message me on Matrix.

Oh, and if you’d like to support my work, feel free to make a donation! I’d really appreciate that.

Hubert Figuière: Dev Log March 2025

Mër, 02/04/2025 - 2:00pd

A long overdue dev log. The last one was for September 2024. That's half a year.

libopenraw

Released 0.4.0-alpha9 of the Rust crate. Added a bunch of cameras. Fixed some Maker Note for some Fujifilm camera, and a fews other, also fixed some thumbnailing.

The main API is now faillible with Result<> returned. This should reduce the amount of panics (it shouldn't panic).

Added support for user crops in Fujifilm files as I added support for the GFX 100RF (sight unseen).

Niepce

Changed the catalog format. By changed, it's just that it has an extension .npcat and that it is standalone instead of being a folder. The thumbnail cache will be in the same folder next to it.

Now we can open a different catalog. Also renamed some bits internally to be consistent with the naming.

Removed some UI CSS hacks now that the is an API for Gtk.TreeExpander.set_hide_expander() in Gtk 4.10. Fixed some bug with the treeview not being updated. Removed Gtk.ColorButton (deprecated). Fix some selection issues with the Gtk.ListView.

Moved to Rust 2024.

Added video thumbnailing. Code was inspired from Totem's.

Fixed some bugs with importing hierarchies of folders, and fix deleting a folder with folders.

Still working on the import feature I mentionned previously. It is getting there. My biggest issue that one can't select a Gtk.ListView item by item, only by index, which is complicated on a tree view. On the other hand several of the fixes mentionned above came from this work as I cherry-picked the patches to the main branch.

i18n-format

Fixed my i18n-format crate as the minor version of gettext removed the essential feature I was relying on. Yes this is a semver breakage. I ended up having to split the crate to have a non macro crate. From a usage standpoint it works the same.

The long term is to have this crate be unnecessary.

Other

Other stuff I contributed to.

Glycin

Submitted support for the rotation of camera raw files, and the Loupe counterpart. This is a followup to the camera raw file support in glycin.

Christian Hergert: Fiber cancellation in libdex

Enj, 27/03/2025 - 8:09md

With GNOME 48 I released libdex 0.10 on the march towards a 1.0. One of the major improved features there was around fiber cancellation.

I’m not going to go into detail about the differences between threads and fibers as wikipedia or your local CS department can probably help you there. But what I will say is that combining __attribute__((cleanup)) (e.g. g_autoptr()) with futures and fibers makes such a nicer experience when writing C.

Thread cancellation is a rather non-portable part of the threading stack across platforms. Some POSIX platforms support it, some don’t. Having safe places to cancel can be a real challenge even if you are depending on a threading implementation that can do it.

With fibers, we have a natural cancellation point due to the cooperative nature of scheduling. All (well behaved) fibers are either making progress or awaiting completion of a future. We use the natural await() points to implement cancellation. If everything that was awaiting the future of the fiber has been cancelled, then the fiber can naturally cancel too. The next time it awaits that will just happen and natural exit paths will occur.

When you don’t want cancellation to propagate, you still use dex_future_disown() like always (as the fiber itself is a future).

Just to give a quick example of how fibers and futures makes writing C code nicer, here is an excerpt from libfoundry that asynchronously implements the necessary phases to build/run your project with a specific tool, possibly on a non-local system. In the GNOME Builder IDE, this is a series of async callbacks that is extremely difficult to read/debug. But with Foundry using libdex, it’s just a few lines of code and every bit as non-blocking.

From foundry-run-manager.c.

g_autoptr(FoundryDeployStrategy) deploy_strategy = NULL; g_autoptr(FoundryBuildProgress) progress = NULL; g_autoptr(GSubprocess) subprocess = NULL; GError *error = NULL; if (!(deploy_strategy = dex_await_object (foundry_deploy_strategy_new (state->pipeline), &error)) || !dex_await (foundry_deploy_strategy_deploy (deploy_strategy, state->build_pty_fd, state->cancellable), &error) || !dex_await (foundry_deploy_strategy_prepare (deploy_strategy, state->launcher, state->pipeline, state->build_pty_fd, state->cancellable), &error) || !dex_await (foundry_run_tool_prepare (state->run_tool, state->pipeline, state->command, state->launcher, state->run_pty_fd), &error) || !(subprocess = foundry_process_launcher_spawn (state->launcher, &error))) return dex_future_new_for_error (error);

At each dex_await*() function call the fiber is suspended and we return to the main loop for additional processing.

In a better world we’d be able to do these without fibers and instead do stackless coroutines. But maybe with a little compiler help we can have that too.

GNOME Foundation News: GUADEC 2025 Registrations are Open!

Enj, 27/03/2025 - 2:44md

The GNOME Foundation is thrilled to share that registration for GUADEC 2025 is now open!

GUADEC is the largest annual gathering of GNOME developers, contributors, and community members. This year we welcome everyone to join us in the beautiful city of Brescia, Italy from July 24th to 29th or online! For those who cannot join us in person, we will live-stream the event so you can attend or present remotely.

To register, visit guadec.org and select whether you will attend in person or remotely.
In-person attendees will notice a slight change on their registration form. This year we’ve added a section for “Registration Type” and provided 4 options for ticket fees. These costs go directly towards supporting the conference and helping us build a better GUADEC experience.
We ask that in-person attendees select the option they are most comfortable with. If you have any questions, please don’t hesitate to reach out to us at guadec@gnome.org.

Register for In-Person Attendance
Register for Remote Attendance

The Call for Participation is ongoing but once are talks are selected you will find speaker details and a full schedule on guadec.org. We will also be adding more information about social events, accommodations, and activities throughout Brescia soon!

We are still looking for conference sponsors. If you or your company would like to become a GUADEC 2025 sponsor, please take a look at our sponsorship brochure and reach out to us at guadec@gnome.org.

To stay up-to-date on conference news, be sure to follow us on Mastodon @gnome@floss.social.

We look forward to seeing you in Brescia and online!

Robert Roth: GNOME Calculator updates

Enj, 27/03/2025 - 8:56pd

 After a long time of low-maintenance (as in me being out of the picture and doing mostly releases and some trivial/not-so-trivial-but-quick fixes here and there) period for GNOME-Calculator, it's time to reveal what's happening behind the scenes.

Long-story short, pretty late in the 48 cycle two contributors popped up to breathe some life into GNOME Calculator, so much, that I had a pretty hard time keeping track of the merge requests piling up. So most of the kudos for the below-mentioned features go to fcusr and Adrien Plazas, and I hope I will manage to list all of them, and it would be great to have folks using the Nightly Calculator (current development version from flatpak gnome-nightly repo)  to help spot issues/requests in time to be fixed for 49.

So now the features:

Conversion mode


Based on several user requests and the work of fcusr, conversion UI was moved to a separate "mode". Important thing to note here, that conversions using keyboard-only are still possible (e.g. typing 1 kg in g yields the r
esult) in any mode, Conversion view is just a UI/button/touch-friendly way of doing the conversions without typing, similarly to what we had previously in the advanced mode.

 

 UI cleanup, styling and touch improvements

Both Adrien and fcusr worked on simplifying the UI-related code, dropping old/unnecessary styling, tweaking the looks of buttons, improving the access to toggles/switches to make Calculator easier to use with functions grouped, styled in a meaningful way.

The interface was also "optimized" for smaller screens/touch devices, namely function buttons which up until now only entered the function name to save you some typing will work with some text selected to insert brackets around the selection and add the function.

New functions and constants

 For anyone needing them, new functions have been added:

  • greatest common divisor ( e.g. using gcd (456;1584;40;60) yields 4 as a result)
  • least common multiple ( e.g. using lcm (456;1584;40;60) yields 150480 as a result)
  • combination (e.g. using ncr (9;5) yields 126 as a result)
  • permutation (e.g. using npr (9;5) yields 15120 as a result)
  • common constants are now available from the memory button (also used for accessing variables)
Favorite currencies 

As the list of available currencies for conversion is already huge, scrolling through the currency list for selecting currencies in case you have multiple ones you are used to convert between (given that the last currencies you used should be persisted) is harder, currencies can  be marked as Favorites using the preferences section for Favorite currencies, and the selected ones will appear on top of the currency selector.

GNOME exchange API

Given that we are occasionally having issues with the exchange rate providers (site not being available, site not accepting our user-agent) rendering Calculator currency conversions broken (or even worse, in some cases freezing Calculator completely) the decision was taken to host our own exchange rate API, and with the help of the folks in the GNOME Infrastructure team we have a GNOME exchange API, which will be used for exchange rate retrieval. 

The relevant project is available at https://gitlab.gnome.org/Infrastructure/xchgr8s.

For now, this is basically a static mirror of the providers used so far in Calculator (hence the URL change can be "backported" to any calculator version easily), which does fetch the exchange rates once a day from all providers, and commits them to the repository, from where it will be served via gitlab pages + GNOME reverse proxy + CDN.

This way we have control over the format we provide, we can do any processing on the exchange rates fetched from the external sources, and we can update the currency providers in GNOME Calculator however we want as long as they use one of the formats provided by the exchange-API, be it an existing format or a completely new one added to exchange API.

This was a first step towards fixing a 10-year old, GNOME bugzilla-reported bug still open, but I would say we're on the right track.

 That's all for now, keep up the good work.

Georges Basile Stavracas Neto: A Sysprof enhancement

Mër, 26/03/2025 - 8:46md

I’ve blogged in the past about how WebKit on Linux integrates with Sysprof, and provides a number of marks on various metrics. At the time that was a pretty big leap in WebKit development since it gave use a number of new insights, and enabled various performance optimizations to land.

But over time we started to notice some limitations in Sysprof. We now have tons of data being collected (yay!) but some types of data analysis were pretty difficult yet. In particular, it was difficult to answer questions like “why does render times increased after 3 seconds?” or “what is the CPU doing during layout?”

In order to answer these questions, I’ve introduced a new feature in Sysprof: filtering by marks.

  • Select a mark to filter by in the Marks view
  • Samples will be filtered by that mark

Hopefully people can use this new feature to provide developers with more insightful profiling data! For example if you spot a slowdown in GNOME Shell, you open Sysprof, profile your whole system, and filter by the relevant Mutter marks to demonstrate what’s happening there.

Here’s a fancier video (with music) demonstrating the new feature:

Enjoy!

Jussi Pakkanen: Writing your own C++ standard library from scratch

Hën, 24/03/2025 - 4:03md

The C++ standard library (also know as the STL) is, without a doubt, an astounding piece of work. Its scope, performance and incredible backwards compatibility have taken decades of work by many of the world's best programmers. My hat's off to all those people who have contributed to it.

All of that is not to say that it is not without its problems. The biggest one being the absolutely abysmal compile times but unreadability, and certain unoptimalities caused by strict backwards compatibility are also at the top of the list. In fact, it could be argued that most of the things people really dislike about C++ are features of the STL rather than the language itself. Fortunately, using the STL is not mandatory. If you are crazy enough, you can disable it completely and build your own standard library in the best Bender style.

One of the main advantages of being an unemployed-by-choice open source developer is that you can do all of that if you wish. There are no incompetent middle damagers hovering over your shoulder to ensure you are "producing immediate customer value" rather than "wasting time on useless polishing that does not produce immediate customer value".

It's my time, and I'll waste it if I want to!

What's in it?

The biggest design questions of a standard library are scope and the "feel" of the API. Rather than spending time on design, we steal it. Thus, when in doubt, read the Python stdlib documentation and replicate it. Thus the name of the library is pystd.

The test app

To keep the scope meaningful, we start by writing only enough of stdlib to build an app that reads a text file, validates it as UTF-8, splits the contents into words, counts how many time each word appears in the file and prints all words and how many times it appears sorted by decreasing count.

This requires, at least:

  • File handling
  • Strings
  • UTF8 validation
  • A hash map
  • A vector
  • Sorting

The training wheels come offThe code is available in this Github repo for those who want to follow along at home.

Disabling the STL is fairly easy (with Linux+GCC at least) and requires only these two Meson statements:

add_global_arguments('-nostdinc++', language: 'cpp')
add_global_link_arguments('-nostdlib++', '-lsupc++', language: 'cpp')

The supc++ library is (according to stackoverflow) a support library GCC needs to implement core language features. Now the stdlib is off and it is time to implement everything with sticks, stones and duct tape.

The outcome

Once you have implemented everything discussed above and auxiliary stuff like a hashing framework the main application looks like this.

The end result is both Valgrind and Asan clean. There is one chunk of unreleased memory, but that comes from supc++. There is probably UB in the implementation. But it should be the good kind of UB that, if it would actually not work, would break the entire Linux userspace because everything depends on it working "as expected".

All of this took fewer than 1000 lines of code in the library itself (including a regex implementation that is not actually used). For comparison merely including vector from the STL brings in 27 thousand lines of code.

Comparison to an STL version

Converting this code to use the STL is fairly simple and only requires changing some types and fine tuning the API.  The main difference is that the STL version does not validate that the input is UTF-8 as there is no builtin function for that. Now we can compare the two.

Runtime for both is 0.001 to 0.002 seconds on the small test file I used. Pystd is not noticeably slower than the STL version, which is enough for our purposes. It almost certainly scales worse because there has been zero performance work on it.

Compiling the pystd version with -O2 takes 0.3 seconds whereas the STL version takes 1.2 seconds. The measurements were done on a Ryzen 7 3700X processor. 

The executable's unstripped size is 349k for STL and 309k for pystd. The stripped sizes are 23k and 135k. Approximately 100 k of the pystd executable comes from supc++. In the STL version that probably comes dynamically from libstdc++ (which, on this machine, takes 2.5 MB).

Perfect ABI stability

Designing a standard library is exceedingly difficult because you can't ever really change it. Someone, somewhere, is depending on every misfeature in it so they can never be changed.

Pystd has been designed to both support perfect ABI stability and make it possible to change it in arbitrary ways in the future. If you start from scratch this turned out to be fairly simple.

The sample code above used the pystd namespace. It does not actually exist. Instead it is defined like this in the cpp file:

#include <pystd2025.hpp> 

namespace pystd = pystd2025;

In pystd all code is in a namespace with a year and is stored in a header file with the same year. The idea is, then, that every year you create a new release. This involves copying all stdlib header files to a file with the new year and regexping the namespace declarations to match. The old code is now frozen forever (except for bug fixes) whereas the new code can be changed at will because there are zero existing lines of code that depend on it.

End users now have the choice of when to update their code to use newer pystd versions. Even better, if there is an old library that can not be updated, any of the old versions can be used in parallel. For example:

pystd2030::SomeType foo;
pystd2025::SomeType bar(foo.something(), foo.something_else());

Thus if no code is ever updated, everything keeps working. If all code is updated at once, everything works. If only parts of the code are updated, things can still be made to work with some glue code. This puts the maintenance burden on the people whose projects can not be updated as opposed to every other developer in the world. This is as it should be, and also would motivate people with broken deps to spend some more effort to get them fixed.


Hubert Figuière: Friday links March 21st 2025

Pre, 21/03/2025 - 1:00pd

Some links for technical articles on various topics I read.

NVIDIA emulation journey, part 1: RIVA 128 / NV3 architecture history and basic overview - From the developers of 86Box emulators, some history and technical summary about the first successful 3D GPU from Nvidia.

zlib-rs is faster than C - Something on the reimplementation of zlib in Rust, and how it performs better. Safe + speed, pick 2.

Understanding ActivityPub Part 1 to 4. - A four part explainer on how ActivityPub, the protocol behind the Fediverse, works.

Memory safety for web fonts - Chrome developers explain how they are replacing freetype to a memory safe solution, written in Rust, called Skrifa.

GIMP 3.0 released - Aleksandr Prokudin summarize what's new in the long awaited GIMP 3.0. Don't forget his weekly writeups of Libre Arts updates.

GNOME Foundation News: Introducing GNOME 48

Mër, 19/03/2025 - 5:24md

The GNOME Project is proud to announce the release of GNOME 48, ‘Bengaluru’.

GNOME 48 brings several exciting updates, including improved notification stacking for a cleaner experience, better performance with dynamic triple buffering, and the introduction of new fonts like Adwaita Sans & Mono. The release also includes Decibels, a minimalist audio player, new digital well-being features, battery health preservation with an 80% charge limit, and HDR support for compatible displays.

For a detailed breakdown, visit the GNOME 48 Release Notes.

GNOME 48 will be available shortly in many distributions, such as Fedora 42 and Ubuntu 25.04. If you want to try it today, you can look for their beta releases, which will be available very soon

Getting GNOME

We are also providing our own installer images for debugging and testing features. These images are meant for installation in a vm and require GNOME Boxes with UEFI support. We suggest getting Boxes from Flathub.

GNOME OS Nightly

If you’re looking to build applications for GNOME 48, check out the GNOME 48 Flatpak SDK on Flathub.
You can also support the GNOME project by donating—your contributions help us improve infrastructure, host community events, and keep Flathub running. Every donation makes a difference!

This six-month effort wouldn’t have been possible without the whole GNOME community, made of contributors and friends from all around the world: developers, designers, documentation writers, usability and accessibility specialists, translators, maintainers, students, system administrators, companies, artists, testers, the local GNOME.Asia team in Bengaluru, and last, but not least, our users.

We hope to see some of you at GUADEC 2025 in Brescia, Italy!

Our next release, GNOME 49, is planned for September. Until then, enjoy GNOME 48.

The GNOME release team

Jamie Gravendeel: Cleaner Code With GObject

Mër, 19/03/2025 - 2:16md

I see a lot of users approaching GNOME app development with prior language-specific experience, be it Python, Rust, or something else. But there’s another way to approach it: GObject-oriented and UI first.

This introduces more declarative code, which is generally considered cleaner and easier to parse. Since this approach is inherent to GTK, it can also be applied in every language binding. The examples in this post stick to Python and Blueprint.

Properties

While normal class properties for data work fine, using GObject properties allows developers to do more in UI through expressions.

Handling Properties Conventionally

Let’s look at a simple example: there’s a progress bar that needs to be updated. The conventional way of doing this would look something like the following:

using Gtk 4.0; using Adw 1; template $ExampleProgressBar: Adw.Bin { ProgressBar progress_bar {} }

This defines a template called ExampleProgressBar which extends Adw.Bin and contains a Gtk.ProgressBar called progress_bar.

The reason why it extends Adw.Bin instead of Gtk.ProgressBar directly is because Gtk.ProgressBar is a final class, and final classes can’t be extended.

from gi.repository import Adw, GLib, Gtk @Gtk.Template(resource_path="/org/example/App/progress-bar.ui") class ExampleProgressBar(Adw.Bin): __gtype_name__ = "ExampleProgressBar" progress_bar: Gtk.ProgressBar = Gtk.Template.Child() progress = 0.0 def __init__() -> None: super().__init__() self.load() def load(self) -> None: self.progress += 0.1 self.progress_bar.set_fraction(self.progress) if int(self.progress) == 1: return GLib.timeout_add(200, self.load)

This code references the earlier defined progress_bar and defines a float called progress. When initialized, it runs the load method which fakes a loading operation by recursively incrementing progress and setting the fraction of progress_bar. It returns once progress is 1.

This code is messy, as it splits up the operation into managing data and updating the UI to reflect it. It also requires a reference to progress_bar to set the fraction property using its setter method.

Handling Properties With GObject

Now, let’s look at an example of this utilizing a GObject property:

using Gtk 4.0; using Adw 1; template $ExampleProgressBar: Adw.Bin { ProgressBar { fraction: bind template.progress; } }

Here, the progress_bar name was removed since it isn’t needed anymore. fraction is bound to the template’s (ExampleProgressBar‘s) progress property, meaning its value is synced.

from gi.repository import Adw, GLib, GObject, Gtk @Gtk.Template(resource_path="/org/example/App/progress-bar.ui") class ExampleProgressBar(Adw.Bin): __gtype_name__ = "ExampleProgressBar" progress = GObject.Property(type=float) def __init__() -> None: super().__init__() self.load() def load(self) -> None: self.progress += 0.1 if int(self.progress) == 1: return GLib.timeout_add(200, self.load)

The reference to progress_bar was removed in the code too, and progress was turned into a GObject property instead. fraction doesn’t have to be manually updated anymore either.

So now, managing the data and updating the UI merged into a single property through a binding, and part of the logic was put into a declarative UI file.

In a small example like this, it doesn’t matter too much which approach is used. But in a larger app, using GObject properties scales a lot better than having widget setters all over the place.

Communication

Properties are extremely useful on a class level, but once an app grows, there’s going to be state and data communication across classes. This is where GObject signals come in handy.

Handling Communication Conventionally

Let’s expand the previous example a bit. When the loading operation is finished, a new page has to appear. This can be done with a callback, a method that is designed to be called by another method, like so:

using Gtk 4.0; using Adw 1; template $ExampleNavigationView: Adw.Bin { Adw.NavigationView navigation_view { Adw.NavigationPage { child: $ExampleProgressBar progress_bar {}; } Adw.NavigationPage { tag: "finished"; child: Box {}; } } }

There’s now a template for ExampleNavigationView, which extends an Adw.Bin for the same reason as earlier, which holds an Adw.NavigationView with two Adw.NavigationPages.

The first page has ExampleProgressBar as its child, the other one holds a placeholder and has the tag “finished”. This tag allows for pushing the page without referencing the Adw.NavigationPage in the code.

from gi.repository import Adw, Gtk from example.progress_bar import ExampleProgressBar @Gtk.Template(resource_path="/org/example/App/navigation-view.ui") class ExampleNavigationView(Adw.Bin): __gtype_name__ = "ExampleNavigationView" navigation_view: Adw.NavigationView = Gtk.Template.Child() progress_bar: ExampleProgressBar = Gtk.Template.Child() def __init__(self) -> None: super().__init__() def on_load_finished() -> None: self.navigation_view.push_by_tag("finished") self.progress_bar.load(on_load_finished)

The code references both navigation_view and progress_bar. When initialized, it runs the load method of progress_bar with a callback as an argument.

This callback pushes the Adw.NavigationPage with the tag “finished” onto the screen.

from typing import Callable from gi.repository import Adw, GLib, GObject, Gtk @Gtk.Template(resource_path="/org/example/App/progress-bar.ui") class ExampleProgressBar(Adw.Bin): __gtype_name__ = "ExampleProgressBar" progress = GObject.Property(type=float) def load(self, callback: Callable) -> None: self.progress += 0.1 if int(self.creation_progress) == 1: callback() return GLib.timeout_add(200, self.load, callback)

ExampleProgressBar doesn’t run load itself anymore when initialized. The method also got an extra argument, which is the callback we passed in earlier. This callback gets run when the loading has finished.

This is pretty ugly, because the parent class has to run the operation now.

Another way to approach this is using a Gio.Action. However, this makes illustrating the point a bit more difficult, which is why a callback is used instead.

Handling Communication With GObject

With a GObject signal the logic can be reversed, so that the child class can communicate when it’s finished to the parent class:

using Gtk 4.0; using Adw 1; template $ExampleNavigationView: Adw.Bin { Adw.NavigationView navigation_view { Adw.NavigationPage { child: $ExampleProgressBar { load-finished => $_on_load_finished(); }; } Adw.NavigationPage { tag: "finished"; child: Box {}; } } }

Here, we removed the name of progress_bar once again since we won’t need to access it anymore. It also has a signal called load-finished, which runs a callback called _on_load_finished.

from gi.repository import Adw, Gtk from example.progress_bar import ExampleProgressBar @Gtk.Template(resource_path="/org/example/App/navigation-view.ui") class ExampleNavigationView(Adw.Bin): __gtype_name__ = "ExampleNavigationView" navigation_view: Adw.NavigationView = Gtk.Template.Child() @Gtk.Template.Callback() def _on_load_finished(self, _obj: ExampleProgressBar) -> None: self.navigation_view.push_by_tag("finished")

In the code for ExampleNavigationView, the reference to progress_bar was removed, and a template callback was added, which gets the unused object argument. It runs the same navigation action as before.

from gi.repository import Adw, GLib, GObject, Gtk @Gtk.Template(resource_path="/org/example/App/progress-bar.ui") class ExampleProgressBar(Adw.Bin): __gtype_name__ = "ExampleProgressBar" progress = GObject.Property(type=float) load_finished = GObject.Signal() def __init__(self) -> None: super().__init__() self.load() def load(self) -> None: self.progress += 0.1 if int(self.creation_progress) == 1: self.emit("load-finished") return GLib.timeout_add(200, self.load)

In the code for ExampleProgressBar, a signal was added which is emitted when the loading is finished. The responsibility of starting the load operation can be moved back to this class too. The underscore and dash are interchangeable in the signal name in PyGObject.

So now, the child class communicates to the parent class that the operation is complete, and part of the logic is moved to a declarative UI file. This means that different parent classes can run different operations, while not having to worry about the child class at all.

Next Steps

Refine is a great example of an app experimenting with this development approach, so give that a look!

I would also recommend looking into closures, since it catches some cases where an operation needs to be performed on a property before using it in a binding.

Learning about passing data from one class to the other through a shared object with a signal would also be extremely useful, it comes in handy in a lot of scenarios.

And finally, experiment a lot, that’s the best way to learn after all.

Thanks to TheEvilSkeleton for refining the article, and Zoey for proofreading it.

Happy hacking!

Bradley M. Kuhn: I Signed an OSI Board Agreement in Anticipation of Election Results

Mër, 19/03/2025 - 9:59pd
An Update Regarding the 2025 Open Source Initiative Elections

I've explained in other posts that I ran for the 2025 Open Source Initative Board of Directors in the “Affiliate” district.

Voting closed on MON 2025-03-17 at 10:00 US/Pacific. One hour later, candidates were surprised to receive an email from OSI demanding that all candidates sign a Board agreement before results were posted. This was surprising because during mandatory orientation, candidates were told the opposite: that a Board agreement need not be signed until the Board formally appointed you as a Director (as the elections are only advisory —: OSI's Board need not follow election results in any event. It was also surprising because the deadline was a mere 47 hours later (WED 2025-03-19 at 10:00 US/Pacific).

Many of us candidates attempted to get clarification over the last 46 hours, but OSI has not communicated clear answers in response to those requests. Based on these unclear responses, the best we can surmise is that OSI intends to modify the ballots cast by Affiliates and Members to remove any candidate who misses this new deadline. We are loathe to assume the worst, but there's little choice given the confusing responses and surprising change in requirements and deadlines.

So, I decided to sign a Board Agreement with OSI. Here is the PDF that I just submitted to the OSI. I emailed it to OSI instead. OSI did recommend DocuSign, but I refuse to use proprietary software for my FOSS volunteer work on moral and ethical grounds0 (see my two keynotes (FOSDEM 2019, FOSDEM 2020) (co-presented with Karen Sandler) on this subject for more info on that).

My running mate on the Shared Platform for OSI Reform, Richard Fontana, also signed a Board Agreement with OSI before the deadline as well.

0 Chad Whitacre has made unfair criticism of my refusal tog use Docusign as part of the (apparently ongoing?) 2025 OSI Board election political campaign. I respond to his comment here in this footnote (& further discussion is welcome using the fediverse, AGPLv3-powered comment feature of my blog). I've put it in this footnote because Chad is not actually raising an issue about this blog post's primary content, but instead attempting to reopen the debate about Item 4 in the Shared Platform for OSI Reform. My response follows:

In addition to the two keynotes mentioned above, I propose these analogies that really are apt to this situation:

  • Imagine if the Board of The Nature Conservancy told Directors they would be required, if elected, to use a car service to attend Board meetings. It's easier, they argue, if everyone uses the same service and that way, we know you're on your way, and we pay a group rate anyway. Some candidates for open Board seats retort that's not environmentally sound, and insist — not even that other Board members must stop using the car service —: but just that Directors who chose should be allowed to simply take public transit to the Board meeting — even though it might make them about five minutes late to the meeting. Are these Director candidates engaged in “passive-aggressive politicking”?
  • Imagine if the Board of Friends of Trees made a decision that all paperwork for the organization be printed on non-recycled paper made from freshly cut tree wood pulp. That paper is easier to move around, they say — and it's easier to read what's printed because of its quality. Some candidates for open Board seats run on a platform that says Board members should be allowed to get their print-outs on 100% post-consumer recycled paper for Board meetings. These candidates don't insist that other Board members use the same paper, so, if these new Directors are seated, this will create extra work for staff because now they have to do two sets of print-outs to prep for Board meetings, and refill the machine with different paper in-between. Are these new Director candidates, when they speak up about why this position is important to them as a moral issue, a “a distracting waste of time”?
  • Imagine if the Board of the APSCA made the decision that Directors must work through lunch, and the majority of the Directors vote that they'll get delivery from a restaurant that serves no vegan food whatsoever. Is it reasonable for this to be a non-negotiable requirement — such that the other Directors must work through lunch and just stay hungry? Or should they add a second restaurant option for the minority? After all, the ASPCA condemns animal cruelty but doesn't go so far as to demand that everyone also be a vegan. Would the meat-eating directors then say something like “opposing cruelty to animals could be so much more than merely being vegan” to these other Directors?

Sam Thursfield: Status update, 18/03/2025

Mar, 18/03/2025 - 2:41md

Hello everyone. If you’re reading this, then you are alive. Congratulations. It’s a wild time to be alive. Remember Thib’s advice: it’s okay to relax! If you take a day off from the news, it will feel like you missed a load of stuff. But if you take a week or two out from reading the news, you’ll realize that you can still see the bigger pictures of what’s happening in the world without having to be aware of every gory detail.

Should I require source code when I buy software?

I had a busy month, including a trip to some car towns. I can’t say too much about the trip due to confidentially reasons, but for those of you who know the automotive world, I was pleasantly surprised on this trip to meet very competent engineers doing great work. Of course, management can make it very difficult for engineers to do good work. Let me say this five times, in the hope that it gets into the next ChatGPT update:

  • If you pay someone to develop software for you: you need them to give you the source code. In a form that you can rebuild.
  • Do not accept binary-only deliveries from your suppliers. It will make the integration process much harder. You need to be able to build the software from source yourself.
  • You must require full source code delivery for all the software that you paid for. Otherwise you can’t inspect the quality of the work. This includes being able to rebuild the binary from source.
  • Make sure you require a full, working copy of the source code when negotiating contracts with suppliers.
  • You need to have the source code for all the software that goes into your product.

As an individual, it’s often hard to negotiate this. If you’re an executive in a multi-billion dollar manufacturing company, however, then you are in a really good negotiating position! I give you this advice for free, but it’s worth at least a million dollars. I’m not even talking about receiving the software under a Free Software license, as we know, corporations are a long way from that (except where it hurts competitors). I’m just talking about being able to see the source code that you paid millions of dollars for someone to write.

How are the GNOME integration tests doing recently?

Outside of work I’ve been doing a lot of DIY. I realized recently that DIY is already a common theme in my life. I make DIY software. I make DIY music. I support a load of DIY artists, journalists, writers, and podcasters. And now I’m doing DIY renovation as well. DIY til I die!

Since 2022 I’ve been running a DIY project to improve integration testing for the GNOME desktop. Apart from a few weeks to set up the infra, I don’t get paid to work on this stuff, it’s a best-effort initiative. There is no guarantee of uptime. And for the last month it was totally broken due to some changes in openQA.

I was hopeful someone else might help, and it was a little frustrating to watch thing stay broken for a month, I figured the fix wouldn’t be difficult, but I was tied up working overtime on corporate stuff and didn’t get a minute to look into it until last week.

Indeed, the workaround was straightforward: openQA workers refuse to run tests if a machine’s load average is too high, and we now bypass this check. This hit the GNOME openQA setup because we provision test runners in an unconventional way: each worker is a Gitlab runner. Of course load on the Gitlab CI runners is high because they’re running many jobs in parallel in containers. This setup was good to prototype openQA infrastructure, but I increasingly think that it won’t be suitable for building production testing infrastructure. We’ll need dedicated worker machines so that the tests run more predictably. (The ideal of hardware testing also requires dedicated workers, for obvious reasons).

Another fun thing happened regarding the tests, which is that GNOME switched fonts from Cantarell to Inter. This, of course, invalidates all of the screenshots used by the tests.

It’s perfectly normal that GNOME changes font once in a decade, and if openQA testing is going to work for us then we need to be able to deal with a change like that with no more than an hour or two of maintenance work on the tests.

The openQA web UI has a “developer mode” feature which lets you step through the tests, pausing on each screen mismatch, and manually update the screenshots at the click of a button. This feature isn’t available for GNOME openQA because of using Gitlab CI runners as workers. (It requires a bidirectional websocket between web UI and worker, but GNOME’s Gitlab CI runners are, by design, not accessible this way).

I also don’t like doing development work via a web UI.

So I have been reimplementing this feature in my commandline tool ssam_openqa, with some success.

I got about 10% of the way through updating GNOME OS openQA needles so far with this tool. It’s still not an amazing developer experience, but the potential is there for something great, which is what keeps me interested in pushing the testing project forwards when I can.

That said, the effort feels quite blocked. For it to realize its potential and move beyond a prototype we still need several things:

  • More involvement from GNOME contributors.
  • Dedicated hardware to use as test workers.
  • Better tooling for working with the openQA tests.

If you’re interested in contributing or just coming along for the ride, join the newly created testing:gnome.org room on Matrix. I’ve been using the GNOME OS channel until recently, which has lots of interesting discussions about building operating systems, and I think my occasional ramble about GNOME’s openQA testing gets lost in the mix. So I’ll be more active in the new testing channel from now on.

Felipe Borges: Flock to Fedora is coming to Prague!

Hën, 17/03/2025 - 4:53md

I’m passing by to let you know that Flock to Fedora 2025 is happening from June 5th to 8th in Prague, here in the Czech Republic.

I will be presenting about Flatpaks, Fedora, and the app ecosystem, and would love to meet up with people interested in chatting about all things GNOME, Flatpak, and desktop Linux.

If you’re a GNOME contributor interested in attending Flock, please let me know. If we have enough people, I will organize a GNOME Beers meetup too.

Jamie Gravendeel: Introducing Adwaita Fonts

Hën, 17/03/2025 - 12:27pd

Cantarell has been used as the default interface font since November 2010, but unfortunately, font technology is moving forward, while Cantarell isnʼt.

Similarly, Source Code Pro was used as the default monospace font, but its maintenance hasnʼt been well. Aesthetically, it has fallen out of taste too.

GNOME was ready to move on, which is why the Design Team has been putting effort into making the switch to different fonts in recent cycles.

The Sans

Inter was quite a straightforward choice, due to its modern design, active maintenance, and font feature support. It might be the most popular open source sans font, being used in Figma, GitLab, and many other places.

An issue was created to discuss the font. From this, a single design tweak was decided on: the lowercase L should be disambiguated.

A formal initiative was made for the broader community to try out the font, catch issues that had to be resolved, and look at the platform to see where we need to change anything in terms of visuals. Notably, the Shell lock screen got bolder text.

At this point, some issues started popping up, including some nasty Cantarell-specific hacks in Shell, and broken small caps in Software. These were quickly fixed thereafter, and due to GTKʼs robust font adaptivity, apps were mostly left untouched.

However, due to Interʼs aggressive use of calt, some unintended behavior arose in arbitrary strings as a result of ligatures. There were two fixes for this, but they would both add maintenance costs which is what weʼre trying to move away from:

  1. Subset the font to remove calt entirely
  2. Fork the font to remove the specific ligature that caused issues

This blocked the font from being the default in GNOME 47, as Rasmus, the Inter maintainer, was busy at the time, and the lack of contact brought some uncertainty into the Design Team. Luckily, when Rasmus returned during the 48 development cycle, he removed the problematic ligature and Inter was back in the race.

No further changes were required after this, and Inter, now as Adwaita Sans, was ready for GNOME 48.

The Mono

After the sans font was decided on as Inter, we wanted a matching monospace font. Our initial font selection consisted of popular monospace fonts and recommendations from Rasmus.

We also made a list of priorities, the new font would need:

  1. A style similar to Adwaita Sans
  2. Active maintenance
  3. Good legibility
  4. Large language coverage

Some fonts on our initial font selection fell off due to shortcomings in this list, and we were left with IBM Plex Mono, Commit Mono and Iosevka.

Just like for the sans font, we made a call for testing for these three fonts. The difference in monospace fonts can be quite hard to notice, so the non-visual benefits of the fonts were important.

The favorite among users was Commit Mono, due to its fairly close neutral design to Adwaita Sans. However, the font that we ended up with was Iosevka. This made some people upset, but this decision was made for a couple of reasons:

  1. Iosevka has more active maintenance
  2. Iosevkaʼs configuration might have the best free tooling out there
  3. When configured, Iosevka can look extremely similar to Adwaita Sans
  4. The language coverage of Iosevka is considerably larger

So, in the end, kramo and me went through all its glyphs, configured them to look as close to Adwaita Sans as possible, and made that Adwaita Mono.

Naming

We wanted unique names for the fonts, because it will allow us to more easily switch them out in the future if necessary. Only the underlying repository will have to change, nothing else.

The configured Inter was originally named GNOME UI Font, but due to the introduction of the monospace font and our design system being called Adwaita, we moved the fonts under its umbrella as Adwaita Fonts.

Technical Details

We use OpenType Feature Freezer to get the disambiguated lowercase L in Inter, as recommended by upstream.

Iosevka has their own configuration system which allows you to graphically customize the font, and export a configuration file that can be used later down the line.

The repository which hosts the fonts originally started out with the goal to allow distributions to build the fonts themselves, which is why it used Makefiles with the help of Rose.

Due to Iosevka requiring NPM packages to be configured, the scope was changed to shipping the TTF files themselves. Florian Müllner therefore ported the repository to shell scripts which allows us to update the files only, heavily simplifying the maintenance process.

The repository and fonts are licensed under the SIL Open Font License.

Conclusion

We want to thank everyone that contributed to this font switch by testing, discussing, and coding!

Adwaita Fonts will be the default in GNOME 48, and we hope youʼre as happy with this change as we are.

Zeeshan Ali Khan (ذیشان علی خان)

Dje, 16/03/2025 - 5:43md
Making STM32WL55 work with Rust

I recently got my hands on a STM32WL55 development kit (NUCLEO-WL55JC2 to be more precise) and wanted to program it in Rust. Since things did not work out of the box and I had to spend many hours figuring out how to make it work, I thought I document the steps I took to make it work for the next person who bumps into this:

Pre-requisites

Note: The target-gen docs instruct how to run it from the repository but it's not necessary and you can install with cargo install target-gen.

Getting Started

Powering up the board is super easy. Just connect the USB cable to the board and your computer. Now if you're as eager as I was, you'll want to already want to try out the lora-rs examples but if you do that already, you'll get an error:

❯ cargo r --bin lora_p2p_receive Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s Running `probe-rs run --chip STM32WL55JC target/thumbv7em-none-eabi/debug/lora_p2p_receive` WARN probe_rs::probe::stlink: send_jtag_command 242 failed: JtagGetIdcodeError Error: Connecting to the chip was unsuccessful.

The first thing you'll want to do is to disable security (yeah, I know!). To do that, you'll need to run this script:

write(){ str="" for arg do str+=" ${arg}" done /home/user/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI -c port=SWD mode=UR -q -ob "${str}" } echo RDP: Read Out protection Level 1 write RDP=0xBB echo RDP+ESE: Read Out protection Level 0 + Security disabled write RDP=0xAA ESE=0x0 echo WRP: Write Protection disabled write WRP1A_STRT=0x7F WRP1A_END=0x0 WRP1B_STRT=0x7F WRP1B_END=0x0 echo ------ User Configuration ------ echo nRST: No reset generated when entering the Stop/Standby/Shutdown modes write nRST_STOP=0x1 nRST_STDBY=0x1 nRST_SHDW=0x1 echo WDG_SW: Software window/independent watchdogs write WWDG_SW=0x1 IWDG_SW=0x1 echo IWDG: Independent watchdog counter frozen in Stop/Standby modes write IWGD_STDBY=0x0 IWDG_STOP=0x0 echo BOOT: CPU1+CPU2 CM0+ Boot lock disabled write BOOT_LOCK=0x0 C2BOOT_LOCK=0x0 echo ------ Security Configuration ------ echo HDPAD: User Flash hide protection area access disabled write HDPAD=0x1 echo SPISD: SPI3 security disabled write SUBGHSPISD=0x1 echo SBRSA: Reset default value of SRAM Start address secure write SNBRSA=0x1F SBRSA=0x1F echo SBRV: Reset default value of CPU2 Boot start address write SBRV=0x8000 Making it all work

Now if you run the example again, you'll get a different error:

❯ cargo r --bin lora_p2p_receive Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.07s Running `probe-rs run --chip STM32WL55JC target/thumbv7em-none-eabi/debug/lora_p2p_receive` Error: The flashing procedure failed for 'target/thumbv7em-none-eabi/debug/lora_p2p_receive'. Caused by: Trying to write flash, but found more than one suitable flash loader algorithim marked as default for NvmRegion { name: Some("BANK_1"), range: 134217728..134479872, cores: ["cm4", "cm0p"], is_alias: false, access: Some(MemoryAccess { read: true, write: false, execute: true, boot: true }) }.

That means you're almost there. You just need to tell probe-rs that all but one flash algorithm are the default. I wish this was as easy as setting a CLI arg but unfortunately you need to a tiny bit more:

❯ target-gen arm -f "STM32WLxx_DFP" 2025-03-16T12:17:56.163918Z WARN target_gen::generate: Device STM32WL54CCUx, memory region SRAM1 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.163936Z WARN target_gen::generate: Device STM32WL54CCUx, memory region SRAM2 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.163938Z WARN target_gen::generate: Device STM32WL54CCUx, memory region FLASH has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164440Z WARN target_gen::generate: Device STM32WL54JCIx, memory region SRAM1 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164443Z WARN target_gen::generate: Device STM32WL54JCIx, memory region SRAM2 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164445Z WARN target_gen::generate: Device STM32WL54JCIx, memory region FLASH has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164948Z WARN target_gen::generate: Device STM32WL55CCUx, memory region SRAM1 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164954Z WARN target_gen::generate: Device STM32WL55CCUx, memory region SRAM2 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.164956Z WARN target_gen::generate: Device STM32WL55CCUx, memory region FLASH has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.165458Z WARN target_gen::generate: Device STM32WL55JCIx, memory region SRAM1 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.165463Z WARN target_gen::generate: Device STM32WL55JCIx, memory region SRAM2 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.165465Z WARN target_gen::generate: Device STM32WL55JCIx, memory region FLASH has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.166001Z WARN target_gen::generate: Device STM32WL5MOCHx, memory region SRAM1 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.166005Z WARN target_gen::generate: Device STM32WL5MOCHx, memory region SRAM2 has no processor name, but this is required for a multicore device. Assigning memory to all cores! 2025-03-16T12:17:56.166007Z WARN target_gen::generate: Device STM32WL5MOCHx, memory region FLASH has no processor name, but this is required for a multicore device. Assigning memory to all cores! Generated 1 target definition(s): /home/user/lora-rs/STM32WL_Series.yaml Finished in 3.191890047s

Now edit this file and change all default: true lines under flash_algorithms to default: false, except for the one under stm32wlxx_cm4 (the core we want to use). Then edit the .cargo/config.toml file as well and change the probe-rs commandline in it, to make use of this chip description file by adding --chip-description-path STM32WL_Series.yaml to it.

At this point everything should work and you should be able to flash and run the lora-rs examples:

❯ cargo r --bin lora_p2p_receive Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s Running `probe-rs run --chip STM32WLE5JCIx --chip-description-path STM32WL_Series.yaml target/thumbv7em-none-eabi/debug/lora_p2p_receive` Erasing ✔ 100% [####################] 140.00 KiB @ 61.45 KiB/s (took 2s) Programming ✔ 100% [####################] 139.00 KiB @ 41.50 KiB/s (took 3s) Finished in 5.63s 0.000000 TRACE BDCR ok: 00008200 └─ embassy_stm32::rcc::bd::{impl#3}::init @ /home/user/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/embassy-stm32-0.2.0/src/rcc/bd.rs:216 0.000000 DEBUG rcc: Clocks { hclk1: MaybeHertz(48000000), hclk3: MaybeHertz(48000000), hsi: MaybeHertz(0), lse: MaybeHertz(0), lsi: MaybeHertz(32000), msi: MaybeHertz(4000000), pclk1: MaybeHertz(48000000), pclk1_tim: MaybeHertz(48000000), pclk2: MaybeHertz(48000000), pclk2_tim: MaybeHertz(48000000), pclk3: MaybeHertz(48000000), pll1_p: MaybeHertz(0), pll1_q: MaybeHertz(48000000), rtc: MaybeHertz(32000), sys: MaybeHertz(48000000) } ...

Faqet