# Chris Wellons

Published articles for Chris Wellons.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## A custom virtual machine for the Stars! 4X game

DevFeed: [A custom virtual machine for the Stars! 4X game](<https://devfeed.tech/articles/a-custom-virtual-machine-for-the-stars-4x-game-41277.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/09/17/>)

Published: 2026-09-17T02:00:00Z

Content type: opinion

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Emulator](<https://devfeed.tech/topics/emulator.md>), [win32](<https://devfeed.tech/topics/win32.md>), [Windows](<https://devfeed.tech/topics/windows.md>), [x86](<https://devfeed.tech/topics/x86.md>), [GitHub](<https://devfeed.tech/topics/github.md>), [releases](<https://devfeed.tech/topics/releases.md>)

Tags: [blog](<https://devfeed.tech/tags/blog.md>), [c](<https://devfeed.tech/tags/c.md>), [emulator](<https://devfeed.tech/tags/emulator.md>), [game](<https://devfeed.tech/tags/game.md>), [github](<https://devfeed.tech/tags/github.md>), [releases](<https://devfeed.tech/tags/releases.md>), [vm](<https://devfeed.tech/tags/vm.md>), [win32](<https://devfeed.tech/tags/win32.md>), [windows](<https://devfeed.tech/tags/windows.md>), [x86](<https://devfeed.tech/tags/x86.md>)

### AI overview

The article presents Stars!VM, a custom virtual machine for running the 1995 16-bit Windows 3.1 game Stars! on modern systems. It combines an 80286 emulator with a Win16-to-Win32 bridge, embeds the original game in signed GitHub releases, and provides 32-bit builds with features such as a modern file chooser and 4K scaling.

### Source excerpt

Stars! is a 1995 4X game (explore, expand, exploit, exterminate) for 16-bit Windows 3.1 that I first played ~28 years ago. While Windows is famously backwards compatible, it's notoriously difficult to play Stars! today. Windows x64 cannot run 16-bit applications, and playing requires either retro hardware or emulation (otvdm, DOSBox), sometimes paired with Wine. My new, exciting solution, Stars!VM, or Stars! Virtual Machine, embeds a custom 80286 emulator and a Win16 to Win32 bridge. As native Win32, the game looks and feels exactly as it did originally, except sporting a modern file chooser and 4k scaling. It's indistinguishable from a genuine 32-bit or 64-bit port of the game, especially with the original 16-bit game embedded inside the VM executable. The signed releases on GitHub embed a compressed copy of the original 16-bit game, so that single EXE is ready to play out-of-the-box with no further setup or downloads. I'm distributing 32-bit builds (but requires SSE2) because there's no advantage to 64-bit here, and these builds work (almost) everywhere except 16-bit Windows. 32-bit Windows could run the original 16-bit game, but the VM-encapsulated version is better behaved. It doesn't dump a Stars.ini under C:\WINDOWS, it interacts properly with the task bar, and copy protection is neutralized via the OS bridge. If you ever been curious about Stars!, now's the time to try it. The game has a thorough, built-in tutorial, but also check out the wiki, the official strategy guide, and AutoHost (play-by-email service). The game predates the modern search engine concept, otherwise they might have chosen a better name. I suggest using "stars 4x" in your searches. If you want to build from source and hack on the VM yourself, the best tool for the job is w64devkit, of course, because it comes with everything you'll need. Plus the game itself: stars.exe from stars27jrc3.zip. Implementation details The emulator itself requires x86 or x86-64 because it does not implement x87

## Concurrent, atomic MSI hash tables

DevFeed: [Concurrent, atomic MSI hash tables](<https://devfeed.tech/articles/concurrent-atomic-msi-hash-tables-20515.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/05/06/>)

Published: 2026-05-06T02:01:17Z

Content type: tutorial

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Code](<https://devfeed.tech/topics/code.md>), [gcc](<https://devfeed.tech/topics/gcc.md>), [Processes](<https://devfeed.tech/topics/processes.md>)

Tags: [article](<https://devfeed.tech/tags/article.md>), [c](<https://devfeed.tech/tags/c.md>), [code](<https://devfeed.tech/tags/code.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [processes](<https://devfeed.tech/tags/processes.md>), [thread](<https://devfeed.tech/tags/thread.md>)

### AI overview

This article explains how to add atomic operations to Mask-Step-Index (MSI) hash tables so they can be accessed concurrently without data races. It covers single-producer and multiple-consumer designs, relaxed atomics, and acquire-release synchronization when published objects must be safely observed.

### Source excerpt

Readers will be familiar with Mask-Step-Index (MSI) hash tables, a technique for building fast, open-addressed hash tables in a dozen lines of code. If multiple threads or processes access an MSI table with at least one still inserting elements, care must be taken to avoid data races. This article will show how to add atomic operations to MSI tables in order to support different concurrency constraints. Let's begin with the simplest case: An integer hash set, no deletions, only one insert thread (single producer), and consumers do not care about insert order. That is, the producer inserts A then B, but consumers may observe B in the table before A. Suppose this is the hash table in the single-threaded case: int32_t *lookup(int32_t key, int32_t *table, int exp) { uint64_t hash = ((uint64_t)key * 1111111111111111111u) >> 32; uint32_t mask = ((uint32_t)1 << exp) - 1; uint32_t step = (hash >> (32 - exp)) | 1; for (uint32_t index = hash;;) { index = (index + step) & mask; if (!table[index] || table[index]==key) { return table + index; } } } Keys must be non-zero, and tables are zero-initialized. Usage example: // Initialization enum { exp = 8 }; int32_t table[1<<8] = {}; // Producer for (int i = 0; i < nkeys; i++) { *lookup(keys[i], table, exp) = keys[i]; } // Consumer int32_t key = 1234; bool present = *lookup(key, table, exp); The only problem is the data race on table slots. Since consumers can tolerate out-of-order insertions, ordering does not matter and relaxed atomics eliminate the data race. Insert and query now have different requirements, so it makes sense to distinguish them. Starting with the latter: bool contains(int32_t key, int32_t *table, int exp) { uint64_t hash = ((uint64_t)key * 1111111111111111111u) >> 32; uint32_t mask = ((uint32_t)1 << exp) - 1; uint32_t step = (hash >> (32 - exp)) | 1; for (uint32_t index = hash;;) { index = (index + step) & mask; int32_t k = __atomic_load_n(table+index, __ATOMIC_RELAXED); if (!k) { return false; } else if (k == ke

## I have officially retired from Emacs

DevFeed: [I have officially retired from Emacs](<https://devfeed.tech/articles/i-have-officially-retired-from-emacs-20514.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/04/26/>)

Published: 2026-04-26T00:00:00Z

Content type: article

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Emacs](<https://devfeed.tech/topics/emacs.md>), [Vim](<https://devfeed.tech/topics/vim.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [GUI](<https://devfeed.tech/topics/gui.md>), [Maintainers](<https://devfeed.tech/topics/maintainers.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [article](<https://devfeed.tech/tags/article.md>), [blog](<https://devfeed.tech/tags/blog.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [cpp](<https://devfeed.tech/tags/cpp.md>), [elfeed](<https://devfeed.tech/tags/elfeed.md>), [emacs](<https://devfeed.tech/tags/emacs.md>), [gui](<https://devfeed.tech/tags/gui.md>), [maintainers](<https://devfeed.tech/tags/maintainers.md>), [net-11](<https://devfeed.tech/tags/net-11.md>)

### AI overview

The author describes retiring from Emacs after 20 years of daily use and gradually switching to modal editing and Vim. They replaced two Emacs-based applications they relied on, M-x calc and Elfeed, with stackcalc and Elfeed2, multi-platform native C++ GUI applications. The article also discusses the need for new maintainers and the trade-offs involved in achieving feature parity.

### Source excerpt

This article was discussed on reddit and on Hacker News. This past Tuesday I typed C-x C-c in Emacs for the last time after 20 years of daily use. Though nearly half that time was gradually retiring it, switching to modal editing, then to Vim. Emacs is a platform, and I'd grown accustomed to its applications, especially those I built myself. There was no particular hurry, so replacements came slowly. With my newly-acquired superpowers I could knock out the last two pieces in a few days' work, namely M-x calc with stackcalc and Elfeed with Elfeed2. I'm especially excited about the latter because it already exceeds the original. Both are multi-platform, native C++ GUI applications using native UI components. These actively-in-use packages require new maintainers (apply on the project's issues/discussion): @ (about) aio (about) bitpack Elfeed (apply here) Impatient (about) javadoc-lookup (about) json-rpc memoize (about) nasm-mode (about) simple-httpd (about) Skewer (about) weak-ref (about) x86-lookup (about) No wonder it took so long for me to move on! I'm not handing these off to just anyone, and you'll need to establish your reputation. Having already made contributions is a good sign, even if never merged. I'm willing to transfer them off my namespace, though you'll need to manage the Melpa hand-off (on which I'll sign-off). If there are no takers, these projects will be archived but not deleted. Trying out wxWidgets The Emacs Calculator is amazing and the best calculator I've ever used, which is why nothing I could find was going to replace it. My clone uses GMP and MPFR for multi-precision, so it's far faster, as to be expected, but it's not nearly at feature parity. It's missing esoteric features including symbolic processing. Though it's enough to cover all of my own usage. I can add more features later. The Emacs Calculator manual served as a specification when building stackcalc. Elfeed has been a cornerstone of my daily routines for the past 13 years. Nothing

## My brave new code-signing world

DevFeed: [My brave new code-signing world](<https://devfeed.tech/articles/my-brave-new-code-signing-world-20513.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/04/25/>)

Published: 2026-04-25T18:12:29Z

Content type: opinion

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Azure](<https://devfeed.tech/topics/azure.md>), [Security](<https://devfeed.tech/topics/security.md>), [Code](<https://devfeed.tech/topics/code.md>), [Claude](<https://devfeed.tech/topics/claude.md>), [Microsoft](<https://devfeed.tech/topics/microsoft.md>), [Command-line interface](<https://devfeed.tech/topics/cli.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [alternatives](<https://devfeed.tech/tags/alternatives.md>), [azure](<https://devfeed.tech/tags/azure.md>), [claude](<https://devfeed.tech/tags/claude.md>), [cli](<https://devfeed.tech/tags/cli.md>), [cost](<https://devfeed.tech/tags/cost.md>), [cpp](<https://devfeed.tech/tags/cpp.md>), [crypto](<https://devfeed.tech/tags/crypto.md>), [github](<https://devfeed.tech/tags/github.md>), [security](<https://devfeed.tech/tags/security.md>), [signing](<https://devfeed.tech/tags/signing.md>)

### AI overview

The article describes the author's move to code-sign Windows releases using Azure Artifact Signing and custom infrastructure called aas-sign. It discusses the cost, regional identity-verification requirement, difficult Azure portal experience, AI-assisted setup, and alternatives involving Azure CLI, Jsign, and SignTool.exe.

### Source excerpt

The new w64devkit release two weeks ago is the first to be code-signed with my identity, verified by Microsoft's certificate chain. Currently only the release packaging is signed -- the self-extracting archive and its payload -- but I will soon code-sign individual EXEs and DLLs within the distribution. In fact, all Windows builds of my project releases have been code-signed the past two weeks, including dcmake, and so should everything going forward. My signing identity builds reputation with each download, so users will have an easier time with SmartScreen, and security software generally. Azure Artifact Signing creates the actual signature, but the rest is done with new infrastructure I built myself, aas-sign. As is often the case, the existing options were deficient for my needs, so I had to build it myself. This code-signing is not free, and simply having aas-sign on hand, or using the GitHub Actions action, is insufficient. You must be serious enough to spend US$10/month for the Azure subscription. After that you are subjected to the labyrinth that is the Azure portal, the most confusing UI I've ever used. Luckily we live in an age of wonders, and I could describe to Claude in Chrome what I wanted and it would happen (Sonnet works better than Opus for this). It took as much time to figure out Azure as I spent creating a fully-functional, native debugger front-end. Clear your schedule if you're going to try it yourself. If it weren't for AI assistance I would have given up. The one-time setup process is only open to North America, and involves sharing identify documents (i.e. driver's license) with Microsoft. Unlike the rest of Azure, that part was streamlined and fairly painless. Between the cost and this requirement, this is a niche space. However, if this is your niche, aas-sign is currently the best software available. It's the tool Microsoft should have written, but didn't due to ongoing institutional failures. The alternatives are a pair of tools: Azure CLI

## dcmake: a new CMake debugger UI

DevFeed: [dcmake: a new CMake debugger UI](<https://devfeed.tech/articles/dcmake-a-new-cmake-debugger-ui-20512.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/04/07/>)

Published: 2026-04-07T03:04:02Z

Content type: article

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [CMake](<https://devfeed.tech/topics/cmake.md>), [debugging](<https://devfeed.tech/topics/debugging.md>), [GUI](<https://devfeed.tech/topics/gui.md>), [Visual Studio](<https://devfeed.tech/topics/visual-studio.md>), [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>)

Tags: [ai](<https://devfeed.tech/tags/ai.md>), [cmake](<https://devfeed.tech/tags/cmake.md>), [cpp](<https://devfeed.tech/tags/cpp.md>), [debugger](<https://devfeed.tech/tags/debugger.md>), [engineering-productivity](<https://devfeed.tech/tags/engineering-productivity.md>), [linux](<https://devfeed.tech/tags/linux.md>), [macos](<https://devfeed.tech/tags/macos.md>), [ui](<https://devfeed.tech/tags/ui.md>), [visual-studio](<https://devfeed.tech/tags/visual-studio.md>), [windows](<https://devfeed.tech/tags/windows.md>)

### AI overview

The article introduces dcmake, a cross-platform native GUI debugger for CMake's debugger mode. It describes its DAP-based interaction, Dear ImGui interface, Visual Studio-inspired controls, persistent UI state, and use of AI to accelerate development.

### Source excerpt

CMake has a --debugger mode since 3.27 (July 2023), allowing software to manipulate it interactively through the Debugger Adaptor Protocol (DAP), an HTTP-like protocol passing JSON messages. Debugger front-ends can start, stop, step, breakpoint, query variables, etc. a live CMake. When I came across this mode, I immediately conceived a project putting it to use. Thanks to recent leaps in software engineering productivity, I had a working prototype in 30 minutes, and by the end of that same day, a complete, multi-platform, native, GUI application. I named it dcmake ("debugger for CMake"). I've tested it on macOS, Windows, and Linux. Despite only being couple days old, it's one of the coolest things I've ever built. Prior to 2026, I estimate it would have taken me a month to get the tool to this point. It has a Dear ImGui interface, which I've experienced as a user but never built on myself before. Specifically the docking branch. In a sense it's a toolkit for building debuggers, so it's playing an enormous role in how quickly I put this project together. All of the "windows" tear out and may be free-floating or docked wherever you like, closely matching the classic Visual Studio UI. I borrowed all the same keybindings: F10 to step over, F11 to step in, F5 to start/continue, shift+F5 to stop. Click on line numbers to toggle breakpoints, right click to run-to-line, hover over variables with the mouse to see their values. Nearly every every UI state persists across sessions, and it opens nearly instantly. This is just one of many situations I've used AI the past month for UI development, and it's been shockingly effective. I can describe roughly the interface I want, and the AI makes it happen in a matter of minutes. It understands what I mean, filling in the details, sometimes anticipating what I'll ask for next. If I'm unsure how I want a UI to work, it also offers good advice. If I need simple icons and such, it can draw those, too. It's all incredibly empowering. On

## 2026 has been the most pivotal year in my career... and it's only March

DevFeed: [2026 has been the most pivotal year in my career... and it's only March](<https://devfeed.tech/articles/2026-has-been-the-most-pivotal-year-in-my-career-and-it-s-only-march-20511.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/03/29/>)

Published: 2026-03-29T21:38:22Z

Content type: opinion

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [Artificial Intelligence](<https://devfeed.tech/topics/ai.md>), [Automation](<https://devfeed.tech/topics/automation.md>), [C++](<https://devfeed.tech/topics/c-plus-plus.md>), [Development](<https://devfeed.tech/topics/development.md>)

Tags: [2026](<https://devfeed.tech/tags/2026.md>), [ai](<https://devfeed.tech/tags/ai.md>), [automation](<https://devfeed.tech/tags/automation.md>), [c](<https://devfeed.tech/tags/c.md>), [c-plus-plus](<https://devfeed.tech/tags/c-plus-plus.md>), [cpp](<https://devfeed.tech/tags/cpp.md>), [development](<https://devfeed.tech/tags/development.md>), [engineering](<https://devfeed.tech/tags/engineering.md>), [software](<https://devfeed.tech/tags/software.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [tools](<https://devfeed.tech/tags/tools.md>)

### AI overview

The author reflects on leaving a long-term employer and adapting to AI-assisted software engineering. They describe no longer writing code directly in their professional role, instead coordinating AI helpers while continuing to read, understand, and evaluate code. AI assistance enabled substantial contributions to a large C++ codebase during onboarding, while shifting bottlenecks away from code production. The article also argues that frontier AI products are advancing faster than self-hosted or free models.

### Source excerpt

In February I left my employer after nearly two decades of service. In the moment I was optimistic, yet unsure I made the right choice. Dust settled, I'm now absolutely sure I chose correctly. I'm happier and better for it. There were multiple factors, but it's not mere chance it coincides with these early months of the automation of software engineering. I left an employer that is years behind adopting AI to one actively supporting and encouraging it. As of March, in my professional capacity I no longer write code myself. My current situation was unimaginable to me only a year ago. Like it or not, this is the future of software engineering. Turns out I like it, and having tasted the future I don't want to go back to the old ways. In case you're worried, this is still me. These are my own words. Writing is thinking, and it would defeat the purpose for an AI to write in my place on my personal blog. That's not going to change. I still spend much time reading and understanding code, and using most of the same development tools. It's more like being a manager, orchestrating a nebulous team of inhumanly-fast, nameless assistants. Instead of dicing the vegetables, I conjure a helper to do it while I continue to run the kitchen. I haven't managed people in some 20 years now, but I can feel those old muscles being put to use again as I improve at this new role. Will these kitchens still need human chefs like me by the end of the decade? Unclear, and it's something we all need to prepare for. My situation gave me an experience onboarding with AI assistance -- a fast process given a near-instant, infinitely-patient helper answering any question about the code. By second week I was making substantial, wide contributions to the large C++ code base. It's difficult to attach a quantifiable factor like 2x, 5x, 10x, etc. faster, but I can say for certain this wouldn't have been possible without AI. The bottlenecks have shifted from producing code, which now takes relatively no time

## Frankenwine: Multiple personas in a Wine process

DevFeed: [Frankenwine: Multiple personas in a Wine process](<https://devfeed.tech/articles/frankenwine-multiple-personas-in-a-wine-process-20510.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/01/19/>)

Published: 2026-01-19T21:51:38Z

Content type: article

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [WINE](<https://devfeed.tech/topics/wine.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [Processes](<https://devfeed.tech/topics/processes.md>), [toolchain](<https://devfeed.tech/topics/toolchain.md>), [C](<https://devfeed.tech/topics/c.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [Git](<https://devfeed.tech/topics/git.md>)

Tags: [assembly](<https://devfeed.tech/tags/assembly.md>), [c](<https://devfeed.tech/tags/c.md>), [git](<https://devfeed.tech/tags/git.md>), [linux](<https://devfeed.tech/tags/linux.md>), [processes](<https://devfeed.tech/tags/processes.md>), [toolchain](<https://devfeed.tech/tags/toolchain.md>), [win32](<https://devfeed.tech/tags/win32.md>), [wine](<https://devfeed.tech/tags/wine.md>), [x86](<https://devfeed.tech/tags/x86.md>), [x86-64](<https://devfeed.tech/tags/x86-64.md>)

### AI overview

This article describes building a Windows binary that behaves as a native pkg-config program on Windows but adopts a Linux-program persona when run under Wine. It detects Wine, invokes Linux system calls directly through x86-64 inline assembly, and applies the approach to u-config as a cross-toolchain pkg-config implementation.

### Source excerpt

I came across a recent article on making Linux system calls from a Wine process. Windows programs running under Wine are still normal Linux processes and may interact with the Linux kernel like any other process. None of this was surprising, and the demonstration works just as I expect. Still, it got the wheels spinning and I realized an almost practical application: build my pkg-config implementation such that on Windows pkg-config.exe behaves as a native pkg-config, but when run under Wine this same binary takes the persona of a Linux program and becomes a cross toolchain pkg-config, bypassing Win32 and talking directly with the Linux kernel. Cosmopolitan Libc cleverly does this out-of-the-box, but in this article we'll mash together a couple existing sources with a bit of glue. The results are in the merge-demo branch of u-config, and took hardly any work: $ git show --stat ... main_linux_amd64.c | 8 ++--- main_wine.c | 101 +++++++++++++++++++++++++++++++++++++++++ src/linux_noarch.c | 16 ++++----- src/u-config.c | 1 + 4 files changed, 114 insertions(+), 12 deletions(-) A platform layer, main_wine.c, is a merge of two existing platform layers, one of which required unavoidable tweaks. We'll get to those details in a moment. First we'll need to detect if we're running under Wine, and the best solution I found was to locate ntdll!wine_get_version. If this function exists, we're in Wine. That works out to a pretty one-liner because ntdll.dll is already loaded: bool running_on_wine() { return GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version"); } An x86-64 Linux syscall wrapper with thorough inline assembly: ptrdiff_t syscall3(int n, ptrdiff_t a, ptrdiff_t b, ptrdiff_t c) { ptrdiff_t r; asm volatile ( "syscall" : "=a"(r) : "a"(n), "D"(a), "S"(b), "d"(c) : "rcx", "r11", "memory" ); return r; } ptrdiff_t write(int fd, void *buf, ptrdiff_t len) { return syscall3(SYS_write, fd, (ptrdiff_t)buf, len); } I'd normally use long for all these integers because Linux i

## WebAssembly as a Python extension platform

DevFeed: [WebAssembly as a Python extension platform](<https://devfeed.tech/articles/webassembly-as-a-python-extension-platform-20509.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/01/01/>)

Published: 2026-01-01T21:21:19Z

Content type: article

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Python](<https://devfeed.tech/topics/python.md>), [WebAssembly](<https://devfeed.tech/topics/web-assembly.md>), [Extension](<https://devfeed.tech/topics/extension.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [C](<https://devfeed.tech/topics/c.md>), [SQLite](<https://devfeed.tech/topics/sqlite.md>)

Tags: [c](<https://devfeed.tech/tags/c.md>), [development-tools](<https://devfeed.tech/tags/development-tools.md>), [extension](<https://devfeed.tech/tags/extension.md>), [performance](<https://devfeed.tech/tags/performance.md>), [python](<https://devfeed.tech/tags/python.md>), [wasi](<https://devfeed.tech/tags/wasi.md>), [wasm](<https://devfeed.tech/tags/wasm.md>), [webassembly](<https://devfeed.tech/tags/webassembly.md>)

### AI overview

The article examines WebAssembly as an extension platform for Python. It explains how architecture-independent Wasm modules can be distributed inside Python libraries without requiring a native toolchain, while noting that Wasm sandboxes cannot access external interfaces. It compares wasm3 and wasmtime-py, highlighting wasmtime-py's broader binary distribution and substantially better performance, alongside its larger installation size.

### Source excerpt

Software above some complexity level tends to sport an extension language, becoming a kind of software platform itself. Lua fills this role well, and of course there's JavaScript for web technologies. WebAssembly generalizes this, and any Wasm-targeting programming language can extend a Wasm-hosting application. It has more friction than supplying a script in a text file, but extension authors can write in their language of choice, and use more polished development tools -- debugging, testing, etc. -- than typically available for a typical extension language. Python is traditionally extended through native code behind a C interface, but it's recently become practical to extend Python with Wasm. That is we can ship an architecture-independent Wasm blob inside a Python library, and use it without requiring a native toolchain on the host system. Let's discuss two different use cases and their pitfalls. Normally we'd extend Python in order to access an external interface that Python cannot access on its own. Wasm runs in a sandbox with no access to the outside world whatsoever, so it obviously isn't useful for that case. Extensions may also grant Python more speed, which is one of Wasm's main selling points. We can also use Wasm to access embeddable capabilities written in a different programming language which do not require external access. For preferred non-WASI Wasm runtime is Volodymyr Shymanskyy's wasm3. It's plain old C and very friendly to embedding in the same was as, say, SQLite. Performance is middling, though a C program running on wasm3 is still quite a bit faster than an equivalent Python program. It has Python bindings, pywasm3, but it's distributed only in source code form. That is, the host machine must have a C toolchain in order to use pywasm3, which defeats my purposes here. If there's a C toolchain, I might as well just use that instead of going through Wasm. For the use cases in this article, the best option is wasmtime-py. The distribution includes

## Freestyle linked lists tricks

DevFeed: [Freestyle linked lists tricks](<https://devfeed.tech/articles/freestyle-linked-lists-tricks-20508.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2025/12/31/>)

Published: 2025-12-31T11:59:59Z

Content type: tutorial

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [Data structures](<https://devfeed.tech/topics/data-structures.md>), [data](<https://devfeed.tech/topics/data.md>), [Parser](<https://devfeed.tech/topics/parser.md>)

Tags: [c](<https://devfeed.tech/tags/c.md>), [code](<https://devfeed.tech/tags/code.md>), [data](<https://devfeed.tech/tags/data.md>), [structure](<https://devfeed.tech/tags/structure.md>)

### AI overview

A tutorial on implementing linked lists for key/value environment-style data, beginning with a simple stack-based list and then preserving the list while adding queue behavior and an intrusive hash trie for faster lookups. It discusses allocation, memory layout, ordering semantics, and duplicate-key behavior.

### Source excerpt

Linked lists are a data structure basic building block, with especially flexible allocation behavior. They're not just a useful starting point, but sometimes a sound foundation for future growth. I'm going to start with the beginner stuff, then without disrupting the original linked list, enhance it with new capabilities. Linked list basics For the sake of an interesting example, I'm will demonstrate with the same concept as last time I talked about data structures: a collection of key/value strings, in the form of an environment variables. This time in linked list form: typedef struct { char *data; ptrdiff_t len; } Str; uint64_t hash64(Str); bool equals(Str, Str); typedef struct Env Env; struct Env { Env *next; Str key; Str value; }; It will be sourced from some string, formatted like the env program: Str input = S( "EDITOR=vim\n" "HOME=/home/user\n" "PATH=/bin:/usr/bin\n" "SHELL=/bin/bash\n" "TERM=xterm-256color\n" "USER=user\n" "SHELL=/bin/sh\n" // <- repeated entry ); And all the parser heavy lifting will be done by our ever-handy cut function: typedef struct { Str tail; Str head; } Cut; Cut cut(Str, char); The simplest way to build up a linked list is like a stack, pushing objects into the front. Zero-initialized head pointer, point the new node at it, then make that node the new head element: Env *parse_reversed(Str s, Arena *a) { Env *head = 0; // 1 for (Cut line = {s}; line.tail.len;) { line = cut(line.tail, '\n'); Cut pair = cut(line.head, '='); Env *env = new(a, 1, Env); env->key = pair.head; env->value = pair.tail; env->next = head; // 2 head = env; // 3 } return head; } That's it, a complete linked list implementation in three lines of code. No big deal. Because of the bump allocator, nodes are packed in order in memory, so the usual cache objections for linked lists do not apply. LIFO semantics mean the linked list is in reverse order from the source order. If we're doing a linear scan through the linked list, the last entry in the source wins, which ma