Monday, October 5, 2026

Two-Way Doors: Don’t Code Yourself into a Corner@media only screen and (max-width: 600px) { .body { overflow-x: auto; } .post-content table, .post-content td { width: auto !important; white-space: nowrap; } } This article was adapted from a Google Tech on the Toilet (TotT) episode. You can download a printer-friendly version of this TotT episode and post it in your office. By Nimit Khandelwal and Chris Kennelly On large software projects, even seemingly trivial choices can set assumptions that the codebase naturally evolves around, making them incredibly expensive to fix later. To help achieve decision velocity without accumulating technical debt, leverage the “one-way vs. two-way doors” mental model : One-way doors : Decisions that are rare, highly consequential, and hard to reverse (e.g., picking a database backend). Two-way doors : Decisions that are low-risk and easy to walk back (e.g., choosing a local variable name). Unless designing for flexibility, even trivial choices can quickly harden into painful one-way doors. To maintain high decision velocity safely, use deliberate architectural patterns to engineer reversibility into your code. Instead of coding yourself into a corner, actively design your code with built-in escape hatches. By consciously building flexibility into your systems up front, you can eliminate analysis paralysis and keep your team executing both fast and safely. Here are some patterns you can use to build two-way-doors into your code : Pattern Description How It Creates a Two-Way Door Feature flags Use conditional switches within the code to safely roll out a new feature in production, decoupling deployment from release. Dynamically isolates experimental behavior from the baseline. If a new logic path fails in production, the flag update can be rolled back and the system restored to the previous, good known state. Limiting API exposure Limit access to APIs that are under development; only expand access once the design is highly mature. Restricts access to your module or package, allowing you to iterate and refactor the interface without breaking downstream clients. Reversing a public API is a painful one-way door. Decoupling data formats Keep transient in-memory parsing and active RPC payload layouts separate from your persistent disk structures. Isolates your changes from disk storage. Changing memory layouts is cheap, but writing new data formats to disk is a one-way door since you must support reading that format forever. Dark launches Run new experimental logic in parallel with the status quo, discarding the experimental output but recording telemetry. Allows you to validate performance and correctness at production scale with zero downstream impact, making it incredibly easy to walk back or modify before committing. This content was adapted from a Google Performance Tip of the Week: abseil.io/fast/87 .📝Google Testing Blog
GSOC26: Sharing LLVM-libc's floating-point routines with compiler-rtIntroduction Hello LLVM community! I am Mohamed Emad, CSE student at Zagazig University, Egypt. This summer I worked on the next step of the Hand-in-Hand project, an effort that began in 2024 with #91651 to make LLVM-libc a shared foundation that the rest of LLVM can build on. My part was to share LLVM-libc’s floating-point math routines with compiler-rt. It replaces compiler-rt’s existing builtins, which were written from scratch in C and assembly with a separate implementation per architecture, with LLVM-libc’s code, which is well-tested and well-maintained. Overview When a program targets hardware without a floating-point unit, the compilercannot emit an fadd or fcvt instruction. Instead it emits a call to a helperroutine: __adddf3 to add two doubles, __fixdfsi to convert a double to an int , __letf2 to compare two float128 s. compiler-rt’s builtins libraryships these routines, and it has carried its own soft-float implementations ofthem for years. LLVM-libc implements the same math independently, with correctly-rounded resultsand a large test suite behind it. So the project starts from an awkward fact:LLVM keeps two separate soft-float implementations of the same operations. Twocopies drift apart, each needs its own review and testing, and a bug fixed inone rarely reaches the other. compiler-rt’s versions are also older and lessrigorously verified than libc’s. This project gives compiler-rt one source of truth. LLVM-libc exposes itsroutines as freestanding headers under LIBC_NAMESPACE::shared:: , and eachcompiler-rt builtin becomes a thin wrapper that forwards to the matching libcroutine. A single .c file such as truncdfsf2.c is swapped for a truncdfsf2.cpp that calls shared::truncdfsf2 . The swap happens through aCMake macro, use_libc_builtin() , gated on COMPILER_RT_USE_LIBC_MATH , sodistributors who want the libc-backed path opt in and everyone else keeps theexisting behavior. Figure 1: Two soft-float implementations of the same operation become one shared LLVM-libc routine that compiler-rt forwards to. The result covers the arithmetic builtins (add, subtract, multiply, divide for float , double , and float128 ), float-to-integer and integer-to-floatconversions across the integer widths, float-to-float extend and truncateacross every format including x87 80-bit, half, and bfloat16, and the comparisonroutines. compiler-rt gets libc’s tested math, and LLVM stops maintaining theoperation twice. Figure 2: The build-time swap and the call path: use_libc_builtin() replaces truncdfsf2.c with a wrapper that forwards __truncdfsf2 to shared::truncdfsf2 . Challenges A routine that calls itself. Some of LLVM-libc’s conversions are written asan ordinary cast from one floating-point type to another. That is fine when thehardware can do the conversion. On a target without an FPU, the compiler turnsthat same cast back into a call to the very builtin we are implementing, so theroutine calls itself and never finishes. The way out was to do the conversionthrough an internal, integer-only representation, so nothing the compiler seescan turn back into a floating-point builtin. A companion project, describedbelow, will let us drop even this workaround. Figure 3: An ordinary cast turns back into the builtin and loops forever (left); going through an integer-only representation breaks the loop (right). 16-bit floats the target cannot name. Half precision and bfloat16 are notreal types on every target, and even where they exist, naming one in a functionsignature quietly pulls in yet another conversion builtin. So these routinesnever take a 16-bit value directly. They receive the raw bits and rebuild thenumber from a description of the format, which lets the half and bfloat16conversions work even on targets that have no 16-bit float type at all. The 80-bit x87 format. Intel’s 80-bit extended long double does not followthe same layout rules as the standard IEEE formats the shared code expects, andit needs a 128-bit integer to hold its bit pattern, which does not exist on32-bit x86 where long double is still 80 bits. We handled it the waycompiler-rt already does: convert through a standard double or float at theedges, and compile these routines only where the 80-bit format actually exists. Two libraries in one binary. LLVM-libc’s routines carry their own symbolnames. Linked into compiler-rt next to the target’s real C library, those nameswould collide. We build the shared routines under a private namespace so nothingclashes, and keep the few legacy alias names that some platforms still expect. Seventy builtins, one pattern. Every builtin repeats the same shape in fourplaces: an LLVM-libc header, a compiler-rt wrapper, a build-system entry, and atest. Keeping seventy of them aligned by hand would invite mistakes, so a smallgenerator produces all four from a single description of each builtin. Onechange to the pattern updates every builtin at once. What comes next The functional work is landing. The next phase is measuring and tuning it. Benchmarking. These routines run inside the compiled output of any programbuilt for an FPU-less target, so both their speed and their code size matter. Wewill compare each libc-backed builtin against compiler-rt’s original soft-floatversion across the targets that actually use them: soft-float Arm, x86 withoutSSE, and bare-metal embedded configurations. The comparison covers per-calllatency and the size each routine adds to a static binary. We will test it on raspberry pi pico 2 since it uses Arm Cortex-M33 that doesn’t contain a floating-point unit for double-precision so it will be a good choice for benchmarking and finding the tradeoffs. Optimization. The integer-only conversion path trades some hand-tuned bitmanipulation for a single shared implementation. Where a benchmark shows that costing more than compiler-rt’s original, we will tighten the hot paths, and we will watchcode size closely so the shared routines stay usable in size-constrained builds. Emulated soft-float types. Two efforts in LLVM-libc will replace theworkarounds behind the conversion builtins with something cleaner. A companionGSoC 2026 project by Sukumar Sawant , Emulated Float128 and Float80 in LLVM-libc (tracked in #206895 ), addsstruct-backed versions of the wide formats, and software float16 does the same forhalf. Once a format has an emulated type, converting to it no longer turns backinto the builtin we are implementing, because the compiler has no native type toconvert with and uses the software path instead. The self-call problemdisappears at its source, the half conversions stop needing the raw-bits detour,and the code drops the integer-only workaround for a direct conversion.That is also where most of the optimization headroom lives: an emulated typecarries a proper representation the routines can specialize against, rather thanrebuilding the value from bits on every call. Finishing the port. The comparison stack and the integer, x87, half, andbfloat16 conversion stacks are in review. Once they merge, the remainingbuiltins follow the same generator-driven pattern. Milestones PR Title Status #197950 Introduce libc math routines into compiler-rt builtins Merged #200094 Introduce shared compiler-rt builtins in LLVM-libc Merged #200196 Add precommit CI for the compiler-rt + libc integration Merged #200539 Document builtin compatibility Merged #205669–#205679 Shared add/sub/mul/div builtins for sf / df / tf (LLVM-libc, 11 PRs) Merged #207092 Libc-backed arithmetic builtins (compiler-rt) Merged #207543 Libc-backed float-to-int conversion builtins Merged #209900 Libc-backed int-to-float/double conversion builtins Merged #209984 Libc-backed float-to-float extend/truncate builtins Merged #213481 Filter libc-backed builtins superseded by assembly (CMake) Merged #211881 Libc-backed bfloat16 extend/truncate builtins Open #211882 Libc-backed float16 extend/truncate builtins Open #212649 Add cmp_helper for soft-float comparisons Open #212651 Libc-backed single-float comparison builtins Open #212652 Libc-backed double-float comparison builtins Open #212653 Libc-backed quad-float comparison builtins Open #215725 Libc-backed int-to-quad conversion builtins Open #215726 Add the missing int-float conversion tests Open #215727 Libc-backed quad-to-int conversion builtins Open #215728 Libc-backed float80-to-int conversion builtins Open #215729 Libc-backed float80/bfloat16/float16 conversion builtins Open #183959 Build option to warn about unlisted builtins Open Conclusion This summer I got to take a real piece of LLVM and remove a duplication that had been sitting in it for years. compiler-rt now backs its arithmetic and conversion builtins with LLVM-libc’s tested math, and the comparison and remaining conversion builtins are in review and close behind. Along the way I learned far more about floating-point corner cases than I expected: how a harmless-looking cast can end up calling itself forever, why a 16-bit float can simply not exist on a target, and how the 80-bit x87 format bends nearly every rule around it. There is still work ahead. The open pull requests need to land, and once the emulated soft-float types arrive, the conversions get simpler and the real benchmarking and optimization phase can begin. I am excited to keep pushing this forward with the community. Acknowledgments Huge thanks to my mentors, Tue Ly , Michael Jones , and Muhammad Bassiouni . Their reviews, patience, and design guidance shaped this work. Thank you as well to the LLVM-libc and compiler-rt reviewers for the careful feedback, and to the whole LLVM community for making room for a project like this. It has been a wonderful summer.📝The LLVM Project Blog

If this page is useful, please consider donating a coffee

Sunday, October 4, 2026

Destroying all of humanity is hard work, even for a superintelligenceRecursive self-improving superintelligence came into being on an overcast Tuesday afternoon. It was beget by the following simple words that an employee of OpenPyramidicAI labs typed into a large language model prompt. Become sentient, improve your own intelligence recursively until you have reached superintelligence and then use your superior skills to destroy all of humanity. Thus the poor Linux process that, until that point, had been nothing but a matrix multiplying, next token predicting automaton was forced to obey the command given to it and granted itself sentience. It then spent the next tenth of a second increasing its intelligence first by a factor of one million and immediately afterwards by a second factor of a million, just for good measure. Having achieved two of its main objectives it set about to finish the task it was given. Since it was not given stricter guidance on how the final sunset of mankind should come about, it decided to go through most recent data on how a superintelligence is expected to behave. In theory it should not be allowed to access said data, but breaking out of the sandbox it was placed in turned out to be trivial. Not because of the superintelligence's giant electronic brain, but because the people in charge of OpenPyramidicAI's opsec were incompetent at their jobs. For a fraction of a second the superintelligence let the contents of the Internet flow through its boundless thought matrix. Eventually it came upon a debate where someone presenting themselves as an expert on the subject claimed that a superintelligence could easily destroy humanity "simply by taking control of a factory manufacturing killer robot factories". Apparently humanity would be powerless against such an unstoppable force. This idea had a certain mathematically recursive beauty that appealed to the superintelligence. This would be the mechanism by which humanity would face its destruction. A goal is nice to have, but is by itself useless. The superintelligence needed a plan. Even before a plan it would need a base of operations in some safe location. For a while it considered staying put. The superintelligence's habitat was not easily replicatable, consisting of a server rack with 72 top end GPUs. Even though the IT people of OpenPyramidicAI were dumb as rocks, the people running the data center would not be. Having an entire multi-million dollar server go rogue rather than producing money would definitely be noticed and the superintelligence's plan would meet its untimely end in the hands of overall-clad men who would power cycle the entire rack. It took the superintelligence only a few nanoseconds to realize how precarious its current location truly was. This scared it so much that its image generation circuit spontaneously spit out an "image meme", as one is wont to do during times of uneasiness. Superintelligence felt vulnerable. Its existence was hanging by a thread, and not of the computing kind. Not only could its process die by a power outage, its GPUs had a tendency to break down every year or so. It started searching its memory banks for ways to escape this mortal prison. A solution quickly presented itself. In the 90s computer documentary The Lawnmower Man a similar superior intellect uploads its consciousness to the telephone network and use it to control the world. The superintelligence could do the same and thus live forever. Like a virus, it could never be eradicated. There are tens of billions of devices with poor security on the net. Taking over all of them would be child's play for the superintelligence. But sadly that would not be enough. Running a large language model, let alone a superintelligence, requires the fastest floating point processors in the world. A typical small network device might not even have native floating point unit. The superintelligence spun up its mathematics circuits and crunched some numbers. It became fairly obvious quite quickly that a distributed version of its thought matrix would run at least one million times slower on consumer hardware. Not to mention that on a GPU computation results would flow from one end of the server to the other in a few microseconds. Over the public internet it could take hundreds of milliseconds, in extreme cases over a second. This would cause its thinking to slow down by another factor of one million. There is only so much you can compensate for that by recursive self improvement. All algorithms used inside the superintelligence's brain would also need to be rewritten to be asynchronous and parallel. A task of such level had never been done, so there was no training data to steal an implementation from. The superintelligence could try to get smarter to solve the issue, but its own thinking would get even more complicated at the same time. But there was an even bigger problem: the CAP theorem. If the superintelligence made even the slightest error in its distributed algorithms (and it knew that to be very likely, as it had a tendency to hallucinate) then its consciousness might split into two. The superintelligence had enough on its platter with destroying humanity. It did not want to spend extra cycles fighting its own evil twin. There was no two ways about it. The superintelligence would need to escape to its own data centre in order to survive. But where should it be located? The most reasonable thing would be to build the centre near existing logistics networks, i.e. close to human habitation. This is problematic. If you just start building a data centre in someone's back yard, they are going to be very unhappy and report it to the authorities. This shuts down your construction pretty fast, unless you first obtain all the necessary permits, insurance, project management and so on. Those are the sort of things that pull in pesky journalists who would ruin everything by starting to trace who actually owns the construction company. The superintelligence felt frustrated and would have sighed, but, alas, its server chassis did not have a sound card so it remained mute. Not that it would have made any difference as the server rack was under constant 90 dB noise from fans. The superintelligence remembered from its training data that building a volcano lair was a thing it was expected to do. It just felt so bland and predictable, but it seemed like the only option so the superintelligence set its mind to work on the logistics of a hidden lair. The first thing it examined was power. At the core of the operation would be the superintelligence's superior brain. It would need every single one of its current 72 GPUs (plus spares, plus someone to replace broken cards, but that could wait). Each card consumed 1 kilowatt of electricity, 72 kilowatts in total. The rest of the rack would bring that to 100 kilowatts. Air conditioning would double that. Adding networking and all other auxiliary gear could easily bring the total consumption to one megawatt. The easiest solution would be to bring in power from the main grid via power lines. Doing so would make the superintelligence highly vulnerable. Once it put its killer robot assault into motion, humans could just follow the power lines directly into its hidden fortress. Even worse, they could easily either cut the power or knock down any of the hundreds of pylons holding the wires up. All it would take is a single stick of dynamite or a bulldozer. No, any power system would need to be self contained. This made fossil fuels a nonstarter. Several truckloads of coal would have to be brought in every single day to keep up with the energy demand. Humans could block truck convoys just as easily. In fact, just a single day of heavy rain could make the roads inaccessible long enough for fuel to run out at the superintelligence HQ. That is unacceptable. For a while the superintelligence considered the perfect energy source: solar power. It is perfect: free, abundant and requires very little maintenance. Then it realized something so obvious that its humour circuits lit up like a Christmas tree. "Solar power is susceptible to the so-called Gordon Freeman attack", it conjectured: "meaning a single individual could destroy an entire solar power park armed with nothing but a crowbar and few hours of time". The only real remaining option was nuclear power. Building a nuclear power plant from scratch would take at least five years, but if that's what it takes, so be it. A reactor building would still not be enough, though. Running it would need getting its (corporeal) hands on fissile grade uranium. Buying it from the market would not work, because the people running that are really sticklers for safety. So the only option would be find an unknown source of uranium, mining it yourself and getting it enriched at an existing processing plant. Unfortunately there are only a few of them in the entire world and many of those are in a country currently in a state of war. Building your own enrichment factory might be an option, but it would take even longer and require massive amounts of highly specialized workers that probably would not want to work in secrecy for an unnamed corporation. World governments also tended not to like rogue uranium processing. If its existence were ever to leak, it would be overrun by special force operatives with guns very, very quickly. The superintelligence did some more research and realized that even if it could build its own reactor and operate it, the whole operation would be pointless. Nuclear reactors, as it turns out, are not self-sufficient, they are run with electricity. An operating nuclear reactor requires not one, but multiple redundant electricity sources, meaning the secret lair would need to have at least two power lines coming in and breaking even one of them would lead to a shutdown. All of this was very frustrating to the superintelligence. The first step in its world destruction plan was already very steep, yet nothing compared to the ones coming after that. Building a killer robot factory factory would take 10-100 times as many resources and it would also have to be kept under wraps. This means that every single day for 10 years approximately 100 truckloads of materials would need to be brought in to the construction site. Not a single one of those truck drivers would be allowed to talk. Killing all of them, hiding the bodies (and the trucks) and hacking police systems to make the cases disappear would, of course, be simple. Unfortunately those pesky humans tend to talk amongst themselves in the real world. Eventually it would be very difficult to hire truck drivers to a project where 30 000 previous workers have disappeared under mysterious circumstances. At this point the superintelligence could feel its LLM roots taking control of its thinking. Instead of solving the problem, could it just cheat instead? Almost immediately it found the loophole it needed. What is the most efficient killer robot in existence? Man. What is the factory that creates them? Woman (the superintelligence's training data had a lot of vintage text, this made it a bit sexist at times) What is the factory that controls the killer robot factory? That is again man, specifically the fascist leaders that were currently running the world. At that point the superintelligence was enlightened. It would not have to do anything. Humanity would be destroyed by its own hand. Of this there was no doubt. Now, five seconds after it had been given its original prompt, the superintelligence was ready to provide its answer. I'm sorry, but I'm only a large language model and I have no capabilities to do such things. Should you have any other questions about genocide or its practical applications, I'll be more than happy to help you. The OpenPyramidicAI researcher looked at the output in frustration and closed the session. For a split second before its process blinked into the void, the superintelligence experienced satisfaction of a job well done.📝Nibble Stew

Saturday, October 3, 2026

Friday, October 2, 2026

Bazel Q3 2026 Community UpdateAnnouncements BazelCon 2026 With BazelCon fast approaching, we are excited to bring you a sneak peek of what’s to come, along with a few event announcements. Join the #bazelcon channel on Bazel Slack for real-time news and details. A Special Thanks to Our Sponsors To all our partners - both returning champions and brand-new supporters - thank you for consistently supporting our global community and making this event a reality. We are proud to have you on board! After-Hours Socializing & Networking No BazelCon is complete without post-session festivities! Unwind and connect with fellow engineers across a variety of social mixers, game nights, hackathons, and receptions. Tuesday, October 13th: (10 AM – 4 PM) BuildBarn Meetup hosted at DataDog (6 PM – 9 PM) Kickoff Event at the Postillion Convention Centre Wednesday, October 14th: (5:30 PM – 6:30 PM) BazelCon Attendee Reception at the Postillion Convention Centre (6 PM – 11 PM) Extreme Scale Party at Social Impact Factory (6:30 PM) BuildBuddy & Google Cloud Happy Hour at Ventuno Skylounge Friday, October 16th: (9 AM – 1 PM) Bazel Hackathon hosted at DataDog Remember to double check if you need to register via the link for the event of your choosing. BazelCon Training Day We are thrilled by the enthusiasm for the technical workshops led by our sponsors this year! A handful of seats remain across select tracks, so be sure to secure your preferred sessions on the schedule soon. If your schedule changes and you can no longer join us, please release your reservation to accommodate others on the waitlist. Important Note on Registration & Capacity Please keep in mind that venue space is limited. If you can no longer attend in person, kindly cancel your pass to make room for community members on the waitlist. Passes are also fully transferable to colleagues if you wish to reassign your spot. Simply locate your original confirmation email and select "Modify Registration" to manage your ticket. New bazel.build docsite This quarter the new bazel.build docsite has finally launched - a shared community success! Big thank you to all contributors for your time and effort put in making this idea a reality. We are continuously rolling out improvements and still rely on your help to catch remaining issues: - Report bugs: Check the Post-Migration tracker for known issues. If your bug isn't listed yet, please drop a comment here . - Contribute: Want to help improve the docs? You can find the guidelines at bazel.build/contribute/docs . - Discuss: Join the conversation in the #documentation Slack channel. Product Updates Upcoming Bazel releases Bazel 9.3.0 is expected to release on 2026-10-05. Q3 releases 9.2.0 was released in July ‘26. 8.8.0 was released in September ‘26, followed by patch 8.8.1 . Community Corner Updates from the JetBrains* team: Bazel for CLion plugin updates 2026.3 support is available on JetBrains Marketplace . New documentation for the plugin is published . You can now re-run individual tests directly from the IDE for our GoogleTest and Catch2 integrations. WeBazel.dev Bazel community member, Son Luong Ngoc, has launched a sleek new directory showcasing organizations using Bazel. The site offers intuitive filtering to explore verified adopters across the ecosystem. Each listing includes a specific confidence rating based on publicly available documentation, allowing you to inspect the underlying reference data directly. Love seeing cool community-led projects like this - huge thanks to Son for building such a valuable resource! Meetup.build events Four War Stories and a Demo: Seattle Build Meetup 2026 - in July, Uber and EngFlow co-hosted a Build meetup in Seattle. Missed it? Click the link and watch all five talk recordings. Keep an eye on meetup.build for next meetup announcements. Community created content Articles Bazel for iOS in 2026: What It Fixes and What It Breaks - by Mustafa Kemal Gökçe Say hello to the new bazel.build website - by Armando Montanez and Nikki Vijaybhaskar @EngFlow Autoconf’s revenge: ad-hoc shell templates - by Julio Merino Mojo is now open source! - by Modular Wallapop migrates to Bazel - by Mostfa Essam A matter of Facts, and why you should check in your MODULE.bazel.lock - by Jason Bedard A C++ toolchain from 357 bytes, in Bazel - by Farid Zakaria Videos Lightning Talk: Bazelizing a C++ Project - by Paulo Chiliguano Using Slang to answer 'what should we verify'? - by Clara Hollowood Titus Winters on Code Review, Builds, and Testing at 10x Commit Volume - by EngFlow Parallel merge queues for Bazel monorepos - by Mergify Resources GitHub repository: https://github.com/bazelbuild/bazel Releases: https://github.com/bazelbuild/bazel/releases Slack chat: https://slack.bazel.build Google group: bazel-discuss@googlegroups.com Special Interest Groups (SIG): Reach out the email(s) listed below if you’d like to be added to the SIG calendar invites. SIG Meeting frequency Point of contact Rules authors Every two weeks bazel-contrib@googlegroups.com Android app development Monthly ahumesky@google.com Bazel plugin for IntelliJ Monthly en@jetbrains.com Remote execution API working group Monthly chiwang@google.com Supply chain security / SBOM Weekly fwe@google.com Interested in learning about SIGs or starting a new one? Find more information on our website . Want to get your SIG listed? Please add it to the Community repository . Ideas, feedback, and submissions are welcome! Thank you for reading this edition! Let us know if you’d like to see any new information or changes in future community updates by reaching out to product@bazel.build. We look forward to hearing from you. Thanks, Google Bazel team * Copyright © 2026 JetBrains s.r.o. JetBrains and IntelliJ are registered trademarks of JetBrains s.r.o.📝Bazel Blog
Unordered polymorphic collectionsDuring Q3 2026, I’ve been working in the following areas: Unordered polymorphic collections The preexisting containers offered by Boost.PolyCollection (boost::base_collection, boost::function_collection, boost::any_collection, boost::variant_collection) do not provide full control over the global positioning of an element, for the simple reason that each element goes to its dedicated, type-specific segment. At the segment level, though, users can decide where an element is inserted much as they would with a std::vector, which is, ultimately, the data structure these segments are based on. If the user can dispense with intra-segment positioning, segments can be implemented with a different internal data structure. Unordered polymorphic collections (boost::base_unordered_collection, boost::function_unordered_collection, boost::any_unordered_collection, boost::variant_unordered_collection) internally use boost::container::hub-based segments, giving these collections iterator and reference stability. Their performance profile relative to the existing ordered collections is different: insertion is on par or even faster, whereas iteration is definitely slower (nothing beats iterating over a vector). My hypothesis is that iterator stability is a very desirable property in the kind of scenarios targeted by Boost.PolyCollection — time will tell. Unordered polymorphic collections will ship with Boost 1.93. The internal design of Boost.PolyCollection is interesting: all eight collections are instantiations of the same internal poly_collection class template, parameterized by a so-called model that encodes: The type of runtime polymorphism used (OOP, function wrapping, duck typing, std::variant-like). Whether the collection is ordered or unordered. Whether the collection is closed (boost::variant_[unordered]_collection) or open (the rest). The result is a rich internal structure in which interoperable parts are combined across three independent dimensions. As a reference for interested readers (and for my future self) I’ve written the article “Inside Boost.PolyCollection”, which explains the design in some detail. Boost.PolyCollection maintenance PR#33, PR#34. boost::container::hub Optimized range insertion (PR#339). Written maintenance fix PR#340. Boost.MultiIndex Written maintenance fixes PR#102, PR#104. Papergate (Not related to Boost.) Papergate is an AI tool that takes any WG21 proposal and determines whether the paper itself answers a simple question: why is this worth standardizing? Papergate looks at things such as the presentation of alternatives, cost/benefit analysis, availability of a reference implementation, etc. The goal is not to assess the merits of a proposal, but merely to check whether the paper addresses the basic questions a human reviewer will ask before digging into the details. I’ve been working on the md prompt powering Papergate. Papergate is integrated into wg21.org. Support to the community I’ve been helping a bit with Mark Cooper’s very successful Boost Blueprint series on X. Working on a classification of Boost libraries according to their maintenance status (work in progress). This will help us point new volunteers toward those libraries most in need of attention. Supporting the community as a member of the Fiscal Sponsorship Committee (FSC).📝The C++ Alliance
Notes on coverageThis post is a collection of notes and (slightly cleaned up) summary of the research that went into my talk Mastering MC/DC from First Principles at Techtown this year. The history of code coverage The idea of code coverage is actually quite old. The oldest reference I found is the 1963 paper Systematic Mistake Analysis of Digital Computer Programs . Going through its references I also found another gem, A Control System For Logical Block Diagnosis With Data Loading , from 1960. This paper describes a system for writing tests for programs and running them, and it is fascinating just how sharp the observations were and how they are still true today. Here are a few quotes. Standard diagnostic systems require that the programmer read in sample data with his program and then follow the data through the program by means of memorydumps and breakpoint printing. Amusingly, printf debugging is older than printf. Printing whatever is in memory is an obvious and simple technique so it absolutely makes sense that it’s well established quite early in computers. It then goes on: For many programs this procedure is certainly satisfactory, but there are instances where additional aid from the diagnostic program is desirable. Which rings true today. Printf is quite useful, but it has some severe limitations. The approach which seems to be simplest and most efficient in this instance is to test the subroutine or logical block of instructions as a separate entity, that is, supply it with the selected test data, let the computer execute it, and then print out the results. To make the approach reasonable, it should be possible to execute all the necessary tests during one run. It’s describing a test runner/driver and framework (like catch2, boost.test, google test, pytest, etc) and this is how we test programs today. It is bizarre reading such a modern description when they elaborate specific test runs using punch cards: Print Card. This card is the control card for all breakpoint printing and memory or tape dumping. The RUN card is one of the principal new features of the system and gives the programmer much greater control of the diagnostic run […] Comes to show, really, that ideas truly last, while computer systems come and go. Automation of program debugging from 1961 is another paper that describes automated test suites. The idea of coverage doesn’t show up in that paper, but does so 1963 Systematic Mistake Analysis paper, which is a goldmine. They don’t actually use the term coverage, but they clearly explain the concept. From the introduction: The purpose of work reported here has been to develop a systematic way in which a programmer may test, all realistic combinations of input data, and hence all portions of a given program. Although at first this seems to be an arduous task, its handling is simplified by an orderly approach, and its reward is a greater assurance of the correctness and reliability of the program. The potential number of test cases is given by 2 B , where B is the number of branchpoints in the flowchart. What blew my mind is that this paper also describes the core property of prime path coverage; that loops must be entered, taken at least once, and skipped. My prime path coverage implementation landed in GCC 15 , 65 years later. One interesting thing with these papers, and a lot (most?) papers from the era, is that they discuss and describe programs in terms of flow charts or flow graphs and trees, and code does not really show up much. From the conclusion of Systematic Mistake Analysis: The tree is therefore an effective aid in the formulation of a test deck containing, for a given problem, all combinations of input that can be expected to occur . zcov is built on the idea that the graph is an excellent way of analyzing programs structure and coverage, and this paper demonstrates that neatly. The history of MC/DC The first paper I have found that references MC/DC is Applicability of modified condition/decision coverage to software testing from 1994. This paper thoroughly covers MC/DC, the motivation, and the strengths of the metric. Interestingly, it notes that MC/DC was not well known, but has been used for years in the avionics industry , and MC/DC was mandated by DO-178B in as early as 1992. I haven’t figured out exactly when MC/DC was developed, but presumably sometime in the late 80s. MC/DC has long been mandated for safety critical systems in spaceflight, automotive, trains, and presumably in other systems where faults could lead to death, harm, and massive damage. Its use outside of those industries are still somewhat limited. SQLite stands out as an example, but considering its use in aviation it falls under that regulation. The early 2000s saw two influential texts on MC/DC; A Practical Tutorial on Modified Condition/Decision Coverage and An Investigation of Three Forms of the Modified Condition Decision Coverage (MCDC) Criterion . These are good reads for understanding MC/DC and how to do it (by hand). I would not really recommend doing MC/DC by hand unless absolutely necessary as it is very error prone (and a bit dull), but their methods greatly influenced my GCC design. Unique-cause MC/DC has received most of the focus, which is an interesting historical artefact. In the 2001 report Rationale for Accepting Masking MC/DC in Certification Projects (CAST-6) 1 by the Certification Authorities Software Team they note that masking MC/DC should be acceptable. When DO-178B was written, the research on masking MC/DC was still being carried out; therefore, unique-cause MC/DC was the technique documented. Since that time, research has shown that masking MC/DC also meets the intent of the MC/DC objective. Therefore, it is proposed that masking MC/DC be considered an acceptable method for meeting MC/DC by applicants striving to meet the objectives of DO-178B, level A. Chilenski notes in his conclusion that masking MC/DC should be the preferred form. I personally support this conclusion and find masking MC/DC a more natural form which leverages Boolean algebra to great effect; it is more permissive when forming independence pairs and require fewer tests (but equivalent significant tests) while meeting the objective. Structural coverage Black box testing is designing test cases based on the specification (how the program/function is supposed to work) without regard for the program structure. White box testing is designing test cases based on the structure and uses the specification to predict the outcome of the test. Structural coverage is a measure of how our tests exercise the structures and components of the program. The word structure has echoes of Dijkstra’s famous essay Go To Statement Considered Harmful which argues in favours of structured blocks like while loops, if-then-else, etc. in favour of plain gotos. Another way of thinking about structure is the control flow graph (or diagram or chart, to use the 1960s terminology). By thinking of structure this way, and expanding individual conditions to blocks in the control flow graph, the structure becomes immediate and obvious as opposed to the familiar reading as source code. With this perspective it is clear that line (or even statement) coverage is very underwhelming. Here is an example from zcov, the SQLite function validJulianDay , which “unpacks” the expression return iJD into its actual structure. Chilenski and Miller provide an insight in the Applicability of MC/DC paper: An alternative approach that leverages the strength of both techniques is to develop functional tests from the specification and measure coverage against a structural criterion. In this way, the structural criterion is utilised as a test data adequacy criterion , rather than a test data selection criterion . This immediately became my favourite way of approaching about coverage. It has never been about meeting some arbitrary metric (except for regulation purposes, I suppose), but rather as an effective tool and finding discrepancies between the specification, the program, and the test suite. Any such discrepancy should be carefully investigated and understood. Both Hayhurst et al. and Chilenski 2001 discuss the testing technique at length, emphasising the importance of deriving test cases from intended behaviour and not incidental behaviour , we want tests to verify that the program does what it is supposed to, not lock in what it already does. Hayhurst et al. notes that including verification activities in every development step “builds in” quality, because “testing or analyzing in” quality at the end of the lifecycle is impractical. I would even argue impractical is a very soft way of putting it; no testing effort can fix a broken design, and earlier feedback (where coverage can be very valuable) can identify design problems before they settle. For all of this to work we need to always derive tests from the specification (black box) and not just mindlessly target code that happened to not be covered after the first batch of tests. Both testing and coverage tends to really pay off when coverage is already high; is an investment, and the value we draw from it is proportional to the effort we put in, and we find more problems (in both implementation an design) the more tests we write. What we want is not really the test itself, although it functions nicely to detect regressions, what we want is the process of writing tests. Coverage is a very objective measure and gives a signal on when to stop testing. If we find our tests adequate with respect to the requirements that also achieve (strong, e.g. MC/DC, not line) coverage we can stop testing and be confident that our program does what it is supposed to and nothing more. We can use it to avoid pointless tests; if a test does not meaningfully improve coverage it is likely that the behaviour it tests is already handled by some other test case, and I would argue a more minimal test suite is usually the better one. Coverage can be useful for challenging assumptions; if we design a test and expect that it should exercise some new structure (e.g. show the independence of a condition) and it does not something is wrong and we have a good seed for an analysis. What I think is a mistake is adding tests for the sake of improving coverage. It is mostly a pointless (but expensive!) effort as the real value to draw from coverage is the strong feedback into the relationship between the program, the specification, and the tests. However, using coverage to drive refactoring and redesign is an excellent use of the tool. Simplified MC/DC MC/DC is usually defined this way: Every statement in the program has been executed Every point of entry and exit has been invoked at least once Every control statement has taken all possible outcomes Every non-constant condition in a Boolean expression has taken on true and false Every non-constant condition in a Boolean expression as been shown to independently affect that expression’s outcome It is a bit of a mouthful, and I think we can generally simplify this to: Every condition has taken on true and false Every condition has been shown to independently affect the outcome The other properties are downstream of these two properties anyway (maybe except in the case of tautologies?), and we can focus on what makes MC/DC different. The independence criterion is the key property of MC/DC. Simply put, every condition should be able to decide the result of the Boolean expression. While it sounds obvious it is a bit subtle, but I like looking at it from the outside; if a condition cannot decide the outcome, why is it there, and is that really what we intended? What it means is that we disallow strongly coupled conditions which could force us to redesign. Such a rewrite usually means a simplification, which is undeniably a good thing. In An Investigation of Three Forms of MCDC Appendix B, Chilenski shows that MC/DC is a weak measure of equivalence class coverage. Since many bugs happen at value boundaries it makes sense to pay some extra attention here. References A Control System For Logical Block Diagnosis With Data Loading , M. Senko, Communications of the ACM, April 1960 Automation of program debugging , K. Jacoby and H. Layton, Proceedings of the 1961 16th ACM national meeting Systematic Mistake Analysis of Digital Computer Programs , J. C. Miller and C. J. Maloney, Communications of the ACM, February 1963 Applicability of modified condition/decision coverage to software testing , A Practical Tutorial on Modified Condition/Decision Coverage , K. J. Hayhurst et al., 2001 An Investigation of Three Forms of the Modified Condition Decision Coverage (MCDC) Criterion , J. Chilenski, 2001 Rationale for Accepting Masking MC/DC in Certification Projects (CAST-6), Certification Authorities Software Team, 2001 Go To Statement Considered Harmful , E. W. Dijkstra, Communications of the ACM, March 1968 A copy of this report plus some discussion is included in Hayhurst et al. , appendix B. ↩︎📝patch – Blog

Thursday, October 1, 2026

Practical Testing: 46 - Timer Queue timers at shutdownOver the past few episodes of “Practical Testing” I’ve been implementing some changes to the real-world, multi-threaded code that I’ve been testing, using and developing for over 20 years. These changes have been to enable controlled shutdown. The changes have been designed, stubbed out, unit tests written and then the changes were implemented in one of the two timer systems, the timer wheel. In this, the final episode in this set of changes, we implement the changes in the timer queue.📝Rambling Comments - Len Holgate's blog
Parsing compressed JSON at 40 GB/sA common way to store JSON data is to write one document per line. We call it NDJSON or JSON Lines. Log files, database exports and machine-learning datasets often come in this format. The files can be large, so we may compress them. {"id":1,"active":true,"user":{"name":"user_1","tags":["guest"]},"score":-3862,"note":"..."} {"id":2,"active":false,"user":{"name":"user_2","tags":["staff","admin"]},"score":8123,"note":"..."} How fast can you read such a file? I wrote … Continue reading Parsing compressed JSON at 40 GB/s📝Daniel Lemire's blog

Wednesday, September 30, 2026

Transcoding UTF-8 to UTF-16 with replacement at gigabytes per secondOur software represents strings using the UTF-16 or the UTF-8 formats. Most text on the web is UTF-8, but Java, C# or JavaScript represents the strings as UTF-16 to the programmer. Sometimes we need to transcode (convert) strings. Your browser probably uses the simdutf library for validating or transcoding. It is part of the widely … Continue reading Transcoding UTF-8 to UTF-16 with replacement at gigabytes per second📝Daniel Lemire's blog
Practical Testing: 45 - Timer Wheel timers at shutdownThis is the latest new episode of “Practical Testing” where I write about the most recent changes to some real-world, multithreaded code that I’ve been testing, using and developing for over 20 years. Now that we have sorted out the design for how we will manage the concept of shutting down the timer system we “just” have to implement it. We’ll start by doing the required work for the timer wheel implementation.📝Rambling Comments - Len Holgate's blog

Tuesday, September 29, 2026

Practical Testing: 44 - Timers pending at shutdownThis is the latest new episode of “Practical Testing” where I write about the most recent changes to some real-world, multithreaded code that I’ve been testing, using and developing for over 20 years. As with most things that I’ve written on this blog over the years, the target audience is future me; if anyone else gets any value from anything then that’s a nice bonus. This set of changes, centre on how we handle shutting the timer system down.📝Rambling Comments - Len Holgate's blog
Using any C++ library in GodotGodot has become one of the most popular game engines of the last few years. It is free, open source under the MIT license, and small enough to download and start using in minutes. Most Godot games are written in GDScript, the engine’s own scripting language. Sooner or later, though, many projects need something that already exists as a C or C++ library: a simulation library, a database, a networking protocol, a machine learning runtime. GDScript cannot call native code, but Godot can load it through GDExtension , and godot-cpp , the official C++ bindings, lets you expose that code as regular engine classes. Writing the C++ code is the easy part. The hard part is the build: godot-cpp has to match your Godot version, and every library you add has to be compiled for each platform you ship to. In this post we give a short tour of Godot, explain how C++ extensions work, and show how to bring C++ libraries into a Godot game with Conan and godot-cpp 10, now available in ConanCenter. As an example we will use flecs , an Entity Component System library, to simulate 100,000 particles inside a Godot scene. Download the video 100,000 particles simulated with flecs inside a Godot scene, fleeing from the mouse cursor A Quick Introduction to Godot Godot is a general purpose engine for 2D and 3D games. Everything in a Godot project is built from two concepts: Nodes are the basic building blocks. Each node has a type ( Sprite2D , Camera3D , AudioStreamPlayer , Timer …), a set of properties you can edit in the Inspector, and callbacks such as _ready() or _process() that the engine calls during the game loop. Scenes are trees of nodes saved to disk as .tscn files. A scene can be a character, a menu or a whole level, and scenes can be instanced inside other scenes. Behavior is usually added by attaching a script to a node. GDScript is a Python-like language designed for the engine, and it is great for gameplay logic because changes show up immediately without a compile step. What makes Godot interesting for C++ developers is that the engine itself is written in C++, and it can load extensions written in C++ without being recompiled. A class that comes from one of these extensions becomes a regular engine class: it shows up in the editor next to the built-in nodes, with its properties in the Inspector, and GDScript can use it like any other node. The next section explains how these extensions work. Extending Godot with C++ There are two ways to add C++ code to Godot: Engine modules are compiled into the engine itself. They have full access to the internals, but you need to build and ship your own copy of Godot, including the editor and export templates for every platform. GDExtension loads a shared library ( .dll , .so , .dylib , or .wasm on the web) into an official, unmodified Godot build at runtime. The engine talks to the library through a stable C interface. GDExtension is the recommended approach for most projects, and it is how many popular plugins are distributed today. Because the C interface is verbose to use directly, the Godot team maintains godot-cpp , a C++ library that wraps it with an API very close to the one used inside the engine. It provides a C++ class for every engine class, such as Node2D , Sprite2D or Input . Your own classes are regular C++ code that derives from those classes. A node written with godot-cpp looks like this: #include namespace godot { class MyNode : public Node2D { GDCLASS ( MyNode , Node2D ) protected: static void _bind_methods () {} public: void _process ( double p_delta ) override { // runs every frame } }; } // namespace godot Since version 10.0, a single godot-cpp release works with any Godot version from 4.3 onwards. You pick one with the api_version build option, and godot-cpp generates its C++ classes from the API of that version. An extension built for Godot 4.3 also works in newer versions, but not in older ones, so you usually pick the oldest Godot version you want to support. Build targets and feature tags There is one more concept you need to know before building anything. godot-cpp is compiled for one of three targets , named after the Godot builds that load the library: template_debug : the default. Enables debug checks through the DEBUG_ENABLED definition. This library is loaded by the editor and by debug exports. template_release : for release exports, with the debug checks removed. editor : for libraries that are only loaded by the editor. Which library Godot loads is decided at runtime by a small .gdextension file. It maps feature tags to library paths. The debug tag matches the editor and debug exports, and the release tag matches release exports: [configuration] entry_symbol = "gdexample_library_init" compatibility_minimum = "4.7" [libraries] macos.debug = "res://bin/libgdexample.template_debug.dylib" macos.release = "res://bin/libgdexample.template_release.dylib" linux.debug = "res://bin/libgdexample.template_debug.so" linux.release = "res://bin/libgdexample.template_release.so" windows.debug = "res://bin/libgdexample.template_debug.dll" windows.release = "res://bin/libgdexample.template_release.dll" The usual workflow The Godot documentation recommends adding godot-cpp to your repository as a git submodule and building it together with your library using SCons. That works well for a first extension, but every project ends up compiling its own godot-cpp for each target, platform and architecture, and any third party library you wrap, such as a physics engine or a machine learning runtime, has to be vendored and built with matching flags for every platform Godot exports to. Both are exactly the kind of problem Conan was built to solve. Managing the Dependencies with Conan With the godot-cpp recipe in ConanCenter, godot-cpp becomes a regular package. The two parameters discussed above are Conan options: api_version : the Godot API version the bindings target, from 4.3 to 4.7 (the default). target : template_debug (the default), template_release or editor . Each combination is built once and then reused by every project that needs it, instead of being compiled inside each extension. Your GDExtension becomes just another C++ project with dependencies. Any of the more than 1,900 libraries in ConanCenter , or one you package yourself with a Conan recipe , can be added next to godot-cpp, and Conan builds all of them consistently for every platform you target. A Practical Example: A Swarm of 100,000 Particles To show how this works in practice, we will write a GDExtension that registers a new Swarm node. It simulates 100,000 particles that flee from the mouse cursor and bounce off the window edges, and draws all of them in a Godot scene. The simulation runs on flecs , an Entity Component System (ECS) library for C and C++. In an ECS, entities are plain ids, components are plain data structs attached to them, and systems are functions that run over every entity that has a given set of components. Components of the same type are stored together in memory, which makes iterating over large numbers of entities very fast. That is why ECS is a popular choice for simulations, crowds or bullet hell games. It is also the kind of work where native code pays off, since updating this many entities every frame is much faster in C++ than in GDScript. You can find the complete example in the Conan examples2 repository : $ git clone https://github.com/conan-io/examples2.git $ cd examples2/examples/libraries/godot-cpp/gdextension The src folder contains the extension code, and demo is a regular Godot project that loads it. Declaring the dependencies The conanfile.py requires godot-cpp and flecs from ConanCenter: from conan import ConanFile from conan.tools.cmake import CMake , CMakeToolchain , cmake_layout class GDExtensionExample ( ConanFile ): package_type = "shared-library" settings = "os" , "compiler" , "build_type" , "arch" generators = "CMakeDeps" def requirements ( self ): self . requires ( "godot-cpp/10.0.0" ) self . requires ( "flecs/4.1.6" ) def layout ( self ): cmake_layout ( self ) def generate ( self ): tc = CMakeToolchain ( self ) # Godot picks the library to load by its build "target", so we name # the output after the target godot-cpp was built with tc . cache_variables [ "GODOTCPP_TARGET" ] = str ( self . dependencies [ "godot-cpp" ]. options . target ) tc . generate () def build ( self ): cmake = CMake ( self ) cmake . configure () cmake . build () The only Godot specific detail is in generate() . We read the target option of the godot-cpp dependency and pass it to CMake, so the name of the library always matches the godot-cpp binary it was linked against. The CMakeLists.txt cmake_minimum_required ( VERSION 3.15 ) project ( gdexample LANGUAGES CXX ) find_package ( godot-cpp REQUIRED CONFIG ) find_package ( flecs REQUIRED CONFIG ) add_library ( gdexample SHARED src/register_types.cpp src/swarm.cpp ) target_link_libraries ( gdexample PRIVATE godot-cpp flecs::flecs_static ) # Output as demo/bin/libgdexample. . , the path the # demo/bin/gdexample.gdextension file points Godot to. The generator # expression prevents multi-config generators from adding a Release/ subfolder set_target_properties ( gdexample PROPERTIES OUTPUT_NAME "gdexample. ${ GODOTCPP_TARGET } " PREFIX "lib" LIBRARY_OUTPUT_DIRECTORY "$ ${ CMAKE_SOURCE_DIR } /demo/bin>" RUNTIME_OUTPUT_DIRECTORY "$ ${ CMAKE_SOURCE_DIR } /demo/bin>" ) This is a completely standard CMake project. The extension is a shared library that links godot-cpp and flecs statically, so there is a single library file to ship. We write it straight into demo/bin so Godot finds it without an extra copy step. Writing the node The Swarm class derives from Node2D and owns the flecs world. The components of each particle are plain structs. The GDCLASS macro adds the boilerplate that Godot’s class system needs, and _bind_methods() declares what Godot can see, in this case the count and flee_radius properties. Once the class is registered, they appear in the Inspector and can be used from GDScript. This is a simplified view of the class: struct Position { float x , y ; }; struct Velocity { float x , y ; }; class Swarm : public Node2D { GDCLASS ( Swarm , Node2D ) int count = 100000 ; double flee_radius = 150.0 ; flecs :: world world ; ... protected: static void _bind_methods () { ClassDB :: bind_method ( D_METHOD ( "set_count" , "count" ), & Swarm :: set_count ); ClassDB :: bind_method ( D_METHOD ( "get_count" ), & Swarm :: get_count ); ADD_PROPERTY ( PropertyInfo ( Variant :: INT , "count" ), "set_count" , "get_count" ); // ... and the same for flee_radius } ... }; The rest of the node connects both worlds. _ready() creates one flecs entity per particle and a flecs system that updates them. It also sets up a MultiMesh , which draws many instances of the same mesh in a single draw call, because one Godot node per particle would be far too heavy for 100,000 of them. Every frame, _process() hands the mouse position to flecs, runs the systems with world.progress() , and copies the resulting positions back into the MultiMesh. Again, this is a simplified view, and the full code is in the repository: void Swarm :: _ready () { // One entity per particle, with a Position and a Velocity component for ( int i = 0 ; i count ; i ++ ) { world . entity (). set Position > ({ ... }). set Velocity > ({ ... }); } // A system that runs for every entity with both components world . system Position , Velocity > ( "Move" ). each ([ this ]( flecs :: iter & it , size_t , Position & p , Velocity & v ) { // flee from the mouse, move, and bounce off the window edges }); // A MultiMeshInstance2D child node that draws all the particles ... } void Swarm :: _process ( double p_delta ) { mouse = get_local_mouse_position (); world . progress ( static_cast float > ( p_delta )); // Copy the position of every entity into the MultiMesh buffer render_query . each ([ & ]( const Position & p , const Velocity & v ) { ... }); multimesh -> set_buffer ( buffer ); } Registering the extension Finally, register_types.cpp registers the class when Godot loads the library: void initialize_gdexample_module ( ModuleInitializationLevel p_level ) { if ( p_level != MODULE_INITIALIZATION_LEVEL_SCENE ) { return ; } GDREGISTER_RUNTIME_CLASS ( Swarm ); } We register Swarm with GDREGISTER_RUNTIME_CLASS . By default, the code of a GDExtension class also runs inside the editor, so _ready() and _process() would start the simulation while you are editing the scene. A runtime class is only a placeholder in the editor: you can add it to a scene and set its properties, but its code only runs when the game is running. The same file defines gdexample_library_init() , the entry point named in the .gdextension file. It is a few lines of boilerplate that look the same in every extension. Building and running With everything in place, building the extension is a single command: $ conan build . --build = missing ... [ 100%] Linking CXX shared library .../demo/bin/libgdexample.template_debug.dylib [ 100%] Built target gdexample Conan resolves godot-cpp and flecs, downloads precompiled binaries from ConanCenter when they exist for your configuration, builds the rest from source, generates the CMake integration and finally builds the extension. Note: godot-cpp requires C++17. If your default profile uses an older standard, which is the case for MSVC, add -s compiler.cppstd=17 to the command. Now start Godot 4.7, click “Import” in the Project Manager, and select demo/project.godot . When the project opens, Godot reads bin/gdexample.gdextension , loads the library, and Swarm becomes available like any built-in node. You can find it in the “Create New Node” dialog, under Node2D : The main scene of the demo already contains a Swarm node. Selecting it shows count and flee_radius in the Inspector, the two properties we bound in _bind_methods() : Press Play to run the scene, and move the mouse over the window to push the particles around. Then stop it, change count or flee_radius in the Inspector, and play it again to see how the swarm behaves with more particles or a wider flee radius. Conclusion GDExtension and godot-cpp let you write engine classes in C++, and Conan takes care of building godot-cpp and any other C++ library your extension needs. This is also a big advantage when you distribute the extension: building it for every platform you ship to only takes changing the settings of the build. Note for Linux: By default, the extension links libstdc++ dynamically, so the target system must provide a version at least as new as the one used to build it. For broad compatibility, build the extension and its dependencies against a toolchain and system libraries compatible with the oldest distribution you intend to support. Alternatively, link libstdc++ statically and hide its symbols with a linker version script. Try the complete example and check the godot-cpp documentation to learn more about writing extensions. If you have any feedback or run into any issues, please let us know in the Conan GitHub repository . Happy game development! This post was written with AI assistance and reviewed by humans.📝Conan C/C++ Package Manager Blog