Live data from Hacker News

C and C++ Hot-Reload/Live Coding

liveplusplus.tech

71–80 of 102 posts

Re: C and C++ Hot-Reload/Live Coding

#71
A few years ago I wrote a 'plugin' feature of various sections that allowed changes to me modifed, compiled and reloaded while the game/editor was running.

It was a C project and it really is not that hard to do (once you get over the thought process and tinkering)

Once I got the hang of it I could whip something together within a few hours.

There was sections for- input, motion, renderer, sound, and frontend/gui. Some allowed to loading multiple things.. others a single instance.

The input one was a good example. I had keyboard using SDL2. One day, someone had a XBox controller in their bag and asked to borrow it while watching a movie. I added support for that. So, when the game loaded, you could specify you are using Keyboard and XBox controller.. so it loads them. If there was a bug, I could modify, recompile and reload.

For the renderer, I had opengl by default... and never got round to doing a Vulkan version. Would have been interesting to have them 'swap' during a live play to compare and tinker.

(the motion was for the mouse. Without really looking into it, I was kinda hoping that would have been a nice setup for VR support but never owned one. Might be something in 2024)

This Live++ looks cool and maybe useful for companies that are spending a bit of cash on decent tools (Unreal, etc) but for small projects, I dont think this is needed.

To be honest, I did not think what I was doing was called 'hot reloading' until, a few years later, I came across Casey Muratori's Handmade hero series. Atleast, I believe it was from there - or other variants at that time.

There are lessons learned, though. I was creating header and src files (with makefiles) for each implementation. If I had to revisit this sort of this, would keep it header only... keeping the build minimal. Might not work.. something I would try, anyway.

Re: C and C++ Hot-Reload/Live Coding

#72

I'm a fan of the opposite approach - serializing the program's state and launching a new instance which reads it. For one particular application I just had it keep all of it's useful state in /dev/shm (mmapped as a struct), double buffering it on every iteration of the main event loop. Of course that doesn't scale too well if you have dynamic allocations. This also has the advantage of not requiring platform specific…

Interesting approach. Was it enough for your use case despite being quite cumbersome if you end up needing to save a bunch of different more complex instances? I mean, I imagine most dynamic objects that are the real state you'd care about will probably be allocated somewhere on the heap and be referenced from lists or pointer types. I guess this would work best for POD types like program settings and the like, so I'…

Yeah it worked fairly well. IIRC there wasn't any kind of dynamically allocated data at all as is common in embedded projects. All strings were stored as fixed size, basically char[64]. Instead of storing pointers, I stored offsets within the memory file, since the base address changes from run to run.

(rant incoming)

This is actually something that bothers me with contemporary programming languages - the huge amount of implicit state due to function calls on the stack and the way the heap is organized. I'm much more in favor of a data-oriented design where you don't get to freely allocate objects, but need to strictly organize them according to a model. I imagine this would also make formal verification a lot easier, since you have a single global coherent view of the program state, kind of like being forced to store all important program state in a database (except more efficient since it's just memory).

Ironically I've become a big fan of global variables. In my experience the classic criticism of "anything could modify anything" doesn't really hold - using globals enables me to statically analyze all usages, not to mention setting memory breakpoints becomes much easier as well - I always know what I want to watch, instead of it being some pointer that will be allocated at some unknown time, 20 stack frames away from the actual usage.

Re: C and C++ Hot-Reload/Live Coding

#73
post #35

Folks interested in this should absolutely look at the open source Cling project, which uses Clang/LLVM to JIT compile C++ in-process. https://github.com/root-project/cling I'm using Cling, as part of jank, a native Clojure dialect on LLVM, with C++ interop. This allows me to have truly interactive, dynamic programming, while still reaching into native code. jank source compiles to C++, which is then JIT compiled by…

There's also C++/CLI.

Re: C and C++ Hot-Reload/Live Coding

#74
I am very glad to see something like this is finally reaching mainstream consciousness.

Not being able to do this on Linux (and it unfortunately looks like this is also Windows only) has been a major source of frustration for me when writing C++, especially given that something like it (edit and continue) has been available in Visual C++ for near on 20 years.

Re: C and C++ Hot-Reload/Live Coding

#75
post #20

Maybe I'm just old and grumpy, but the subscription business model just puts me off. Nowadays when I read about some development tool (or just any product), I start with the price page. If there are only subscriptions available I stop reading and go on with my life.

Both businesses and developers benefit from subscriptions because it's easily estimated costs, and easily estimated income where you keep contact with the customer.

The ones who don't benefit is individuals. I wish more products had one time costs for hobbyists (individuals with zero revenue) while having subscriptions for businesses and commercial. Lots of products have loopholes for education/OSS/etc so adding "hobbyist" doesn't seem like a big difference. And I think it would drive sales. If I use a product at home I'm likely to lobby for buying subscriptions at work.

Re: C and C++ Hot-Reload/Live Coding

#77
post #20

Maybe I'm just old and grumpy, but the subscription business model just puts me off. Nowadays when I read about some development tool (or just any product), I start with the price page. If there are only subscriptions available I stop reading and go on with my life.

I don't mind a subscription model. For me, it represents additional options.

Why do I want to spend hundreds or thousands of dollars for a perpetual license of photoshop when I hardly use it? A 30 day subscription once a year is perfect for me.

Even for those of us who are heavy users - can you see the game theory? The provider of your services has to deal with a huge amount of inertia in their product because of the continuous distribution model. The bigger the subscriber base, the more inertia there is. The consequence of this is that you are essentially guaranteed that impacting changes will be delivered slow enough that you or your business can adapt to them. Contrast this with a big bang software upgrade that requires explicit retraining and disruption to ops.

Not all subscription products are run this way, but the good ones are. Any product that has a 4 digit number in its name is a bad example. Visual Studio 2022 is not how a subscription model should go. Netflix is.

Re: C and C++ Hot-Reload/Live Coding

#78

fyi, "hot reload" is a native part of every operating system (consider, even trivially, forking or https://en.wikipedia.org/wiki/Dynamic_loading ). It's a sign of how bad developer tooling has been that live reload is sold as an add-on feature. DX seems always to see-saw between bill gate's c. 1990 demo of VB, and the compile-time speeds of a N' Wirth. At a guess, when the internet happened, all DX had to be thrown a…

fork() doesn't hot reload much of anything. exec() doesn't hot reload either. Dynamic loading doesn't hot reload either, more like hot load. Debuggers might hot-patch code to insert breakpoints, but that's not the same thing as replacing running code. Sure, the debugger might execute scripts you associate with breakpoints, but that's also not exactly the same thing as replacing the running code. Mind you, debuggers d…

> exec() doesn't hot reload either.

If you store all your data in mapped files, you can remap them after execve and continue where you started from. This works if the data layout hasn't changed. If you have per type memory maps, you can explicitly convert only the data that has changed. You might need redo logs for things that can't be persisted (networking for example).

Not easy, but also not impossible. All your other concerns still apply of course.

Re: C and C++ Hot-Reload/Live Coding

#79
First, I'm really happy about all those solutions for the gaming industry! They solve real-world problems and work with software at scale, with great pragmatism.

But I would have liked to see a comparison of this solution to others on the market, like the readily-available "Hot Reload" in Microsoft Visual Studio.

For a multi-MLOC codebase, VS "Hot Reload" required some patience, and it mostly worked only for simple cases like changing "if" statements or constants. But that's actually all I needed at that time, and considering that I was using VS anyway, I was happy with not having to pay extra.

So, did somebody try out the Live++ hot-reloading technology and could share their experiences?

Re: C and C++ Hot-Reload/Live Coding

#80

Earlier quoted context omitted.

Interesting approach. Was it enough for your use case despite being quite cumbersome if you end up needing to save a bunch of different more complex instances? I mean, I imagine most dynamic objects that are the real state you'd care about will probably be allocated somewhere on the heap and be referenced from lists or pointer types. I guess this would work best for POD types like program settings and the like, so I'…

Yeah it worked fairly well. IIRC there wasn't any kind of dynamically allocated data at all as is common in embedded projects. All strings were stored as fixed size, basically char[64]. Instead of storing pointers, I stored offsets within the memory file, since the base address changes from run to run. (rant incoming) This is actually something that bothers me with contemporary programming languages - the huge amount…

I have succesfully used the mmapped state trick in the past, although for crash resilience (with carefully maintaining invariants at instruction boundaries) not just for persistence.

It worked well with fixed size objects, although if I would do it again today I would still allow for a separate pool for variable size strings as updating the max string size was the most common change that both breaks the file compatibility and bloats the size.

The separate pool would make it more awkward to dereference the string as you can't neither use a dumb pointer nor the self offset trick but you have to pass the poll base offset explicitly (or implicitly with a global), but I think it would be worth it.

edit: thinking about it, interleaving fixed size string pools with the other objects might also work, in practice you get a persistent heap.

Post reply on HN