[HN Gopher] C and C++ Hot-Reload/Live Coding
       ___________________________________________________________________
        
       C and C++ Hot-Reload/Live Coding
        
       Author : ibobev
       Score  : 105 points
       Date   : 2024-01-03 17:20 UTC (5 hours ago)
        
 (HTM) web link (liveplusplus.tech)
 (TXT) w3m dump (liveplusplus.tech)
        
       | yagkasha wrote:
       | Reminds me of this[0] post on NullProgram about how to apply hot
       | reloading to C.
       | 
       | [0]: https://nullprogram.com/blog/2014/12/23/
        
         | vidarh wrote:
         | I'm reminded of an old project called Entity that sadly
         | disappeared (I may have an old snapshot from before their site
         | went down somewhere), where someone had built a GUI designer
         | where you linked GUI events to code live. One of the supported
         | languages was C, in which case on change the code was passed to
         | GCC and compiled into an .so and swapped into the process the
         | same way as here (it also supported Perl and JS, I think; it
         | was an odd beast... And you could edit the code of the GUI
         | designer from within the GUI designer itself)
        
       | papruapap wrote:
       | Well... this sure looks better than my powershell script for
       | hotreloading lol
        
       | delta_p_delta_x wrote:
       | Wow--a commercial offering exclusively targeting Windows, C++,
       | and game development, and yet showcased on Hacker News. A rare
       | combination indeed! :P
       | 
       | EDIT: The deep dive[1] on their webpage is absolutely worth a
       | read.
       | 
       | [1]:
       | https://liveplusplus.tech/downloads/THQ_Nordic_Dev_Summit_20...
        
         | jasonjmcghee wrote:
         | Fwiw, I would guess, after unity, C++ targeting windows is the
         | dominate approach to game development by a margin. And I see
         | game engines on HN pretty often. Doesn't seem that strange
        
       | mjburgess wrote:
       | 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
       | away and we still arent back to where we were 30+ y ago.
       | 
       | I support being paid for your work, but live reload is a fairly
       | trivial thing to write for yourself -- I spent one day this gone
       | weekend writing a debugger in C which does it.
       | 
       | (consider also, https://github.com/tsoding/musializer which has
       | live rebuild via the nobuild system in nob.c)
        
         | agentultra wrote:
         | I was also suspicious but I think this system does have
         | advantages over the OS interfaces for this: incremental
         | compilation and binary patching. If this goes down to the
         | function or block level definitions and is fast that's pretty
         | sweet. The only time I've enjoyed that kind of DX is with
         | Common Lisp/CLOS.
         | 
         |  _Update_ : there's a "deep dive" power-point that goes into a
         | bit more detail:
         | https://liveplusplus.tech/downloads/THQ_Nordic_Dev_Summit_20...
        
         | benwaffle wrote:
         | > fyi, "hot reload" is a native part of every operating system
         | (consider, even trivially, forking & reforking).
         | 
         | Can you expand on this?
        
           | mjburgess wrote:
           | https://en.wikipedia.org/wiki/Dynamic_loading
        
             | orf wrote:
             | This doesn't answer the question, and doesn't really help
             | with hot reloading at all outside of the most basic
             | examples.
        
         | foooorsyth wrote:
         | >I support being paid for your work, but live reload is a
         | fairly trivial thing to write for yourself -- I spent one day
         | this gone weekend writing a debugger in C which does it.
         | 
         | Major Dropbox "who would pay for this over just using rsync?"
         | vibes here. Never change, HN.
        
           | mjburgess wrote:
           | unlike the dropbox case, my point isnt, "oh go and do it
           | yourself" -- my point is why-t-f doesnt gcc/clang, etc have a
           | obv-build-tool --live-rebuild option?
           | 
           | Or, more alarmingly, why are things like jrebel fawned over?
           | Rather than, say, it being an embarrassment that java dx is
           | worse than programming dx 30-40 years ago?
           | 
           | Why isn't the basic thing all OS do, ie., live reloading of
           | code, a day-to-day essential element of all development?
           | 
           | I really don't know. But to be clear, it was 50+ yr ago, 40+
           | yr ago, 30+ yr ago --- and as of today, it's $100/yr
           | subscription (lol?!)
        
         | cangeroo wrote:
         | One problem is that modern software architectures are highly
         | coupled and stateful, such that it isn't possible to hot reload
         | a component. It would require the host (e.g. when using a DLL)
         | to detect a change, save state, unload, reload, load state.
         | Multi-threading may also make things more difficult, requiring
         | more synchronization during changes.
         | 
         | I agree with your sentiment, but it's really hard to
         | communicate it to the younger generations. I suppose it comes
         | off as being negative, but it's really just melancholia over
         | the loss of something that was fun, simple, and powerful.
        
           | mjburgess wrote:
           | well, i think the issue is as least as much that the
           | developers who create these architectures do not start from
           | this pov ---
           | 
           | consider how these architectures would be designed if must-
           | have condition was sub-100ms iteration -- which should be
           | trivial all-but-for codebases of at least 1mil+ lines; them,
           | well, maybe it's 200ms.
           | 
           | This design isnt hard -- what's hard about save_frame(),
           | save_state(), or w/e, and restore_state()?
           | 
           | Only that it would need to be actively maintained and
           | developed -- that is, it would obligate developers to tend to
           | their own ability to work.
           | 
           | What i think here is lost is not, somehow a simple system
           | which can be magic, but the concern of developers to maintain
           | such systems.
           | 
           | Why? Certainly, many reasons. But my comment here today is
           | more to frame the issue: this 'feature' can, and should, be
           | part of ordinary development. It isnt that hard.
           | 
           | Even if save_frame() is no longer a register copy, but
           | somehow, an obscene json serialisation process.
        
             | norir wrote:
             | I feel like to some extent the problem here is the dynamic
             | linking model that is almost universally used. If programs
             | were designed from the perspective of the linker, then the
             | linker could maintain a graph of function dependencies and
             | have a cascading invalidation upon update. It is hard to
             | retrofit this onto a project that is already a standard
             | make based project.
        
             | cangeroo wrote:
             | Yes, but:
             | 
             | Components depend on other components, and they all have to
             | support hot reloading. And what about side effects? For
             | example, an open network connection, or a window. You could
             | store the state (handles etc.), but what about callbacks
             | during the reloading phase? They'd have to block and wait.
             | 
             | Ultimately, what you need is a message passing architecture
             | that supports all this. Smalltalk. Alan Kay has been a
             | vocal critic of our modern architecture. See his talk "Alan
             | Kay at OOPSLA 1997 - The computer revolution hasnt happened
             | yet".
             | 
             | But that architecture is computationally inefficient.
             | 
             | I suspect the problem is that computers weren't fast enough
             | for the last 30 years. So we focused on performant
             | computing. We still do that, with high fps gaming. And
             | adding better quality graphics. Soon we'll have Apple
             | Vision Pro with a 4k display for each eye.
             | 
             | My personal hope is that WebAssembly and the Component
             | Model will drastically change things, by introducing API
             | virtualization and effectively decoupled modules, but this
             | will require that tree-shaking/deadcode removal is
             | disabled.
        
               | pjmlp wrote:
               | Something like COM, XPC or Binder, no need for
               | WebAssembly "re-inventing" it.
        
             | corysama wrote:
             | Way back in the 2000-2004 timeframe, I worked along side a
             | team making a game for the OG Xbox that had a daily
             | workflow like:
             | 
             | 1. Come in, get coffee, check out latest code from Visual
             | SourceSafe. 2. Hit F5 to start debugging. 3. Edit and
             | Continue in Visual Studio 6.0 all day long. 4. Hit shift-F5
             | to stop debugging at the end of the day. 5. Go home.
             | 
             | Between that and the OG Pix for Xbox, the development
             | experience has been all downhill from there. A lot of kids
             | these days tried GDB once or twice and then grew up without
             | even understanding the value of debuggers at all. And, by
             | "kids" I mean "graduated 10 or less years ago" :P
             | 
             | I'm sure keeping that workflow working was a fair bit of
             | work. But, it was worth it!
        
               | maccard wrote:
               | I'm working on a UE5 game right now using Live++. My day
               | is now check out from perforce, hit F5, Ctrl+alt+F11 to
               | hot reload, and for 98% of what I want to do, it works
               | perfectly.
        
               | aappleby wrote:
               | X360 dev was the same, I lived inside the VS debugger and
               | perpetually had Pix up in a second monitor.
        
         | cryptonector wrote:
         | 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 do have to make sure that
         | such hot-patching is atomic, or they have to stop all threads.
         | 
         | Hot reloading has a ton of considerations:
         | 
         | - threading -- you need to quiesce all threads at points where
         | they are not executing the code to be reloaded _or_ you need to
         | load the new code and hot-patch either calls to old code and/or
         | old code function entrypoints to jump to the new code, but if
         | the latter then you need to make sure it's ok to have a mix of
         | threads executing old code while the new code comes online
         | 
         | - data structure compatibility -- if structures have changed
         | you may not be able to hot-reload, but you need to at least be
         | able to detect incompatible changes, and at best you need to
         | plan how the hot-reloaded code will upgrade extant data
         | structures on the fly
         | 
         | - and more
        
       | hoten wrote:
       | Does this have any further benefit than what Visual Studio's hot
       | code reloading provides?
        
       | Pesthuf wrote:
       | The World of Warcraft Server emulator TrinityCore has a hot
       | reload system for its Scripting (Boss AI, Spells etc.). AFAIK
       | when it's enabled, those modules are compiled into their own
       | shared library and when you make a change to one of the script
       | .cpp files, it triggers a compilation and then unloads and
       | reloads the shared library (I think the process is more
       | complicated than that so it doesn't crash for scripts that are
       | currently active and different operating systems behaving
       | differently).
       | 
       | Made developing those scripts much, much more comfortable when it
       | was introduce. You no longer needed to manually compile, stop and
       | start the server, wait for all the database stuff to be loaded,
       | switch to the client, log back in, wait and then retry on every
       | single tiny change. To me, it was like magic.
       | 
       | Today, I wonder why they didn't just use a proper scripting
       | language.
        
         | reactordev wrote:
         | This is how RunUO/ServeUO was designed as well. I'm pretty sure
         | it's a common design practice that came from muds. The server
         | is only responsible for network and communications - everything
         | is then orchestrated through plugins/scripts/systems that can
         | be compiled and reloaded while the server is running. The more
         | modern way is now to separate your "server" from your "modules"
         | in distributed-systems architecture (just deploy the new module
         | to the farm) but the idea still permeates.
         | 
         | Still, RunUO was C# and like java, recompiling and loading is
         | trivial. Doing it in C/C++ land is heroic.
        
           | throwup238 wrote:
           | _> Doing it in C /C++ land is heroic._
           | 
           | Not to diminish the accomplishment or anything but is it that
           | much easier in C# and Java?
           | 
           | It was always really easy to use the libloaderapi in Windows.
           | Throw a vtable on it and baby, you got a stew going!
        
             | adra wrote:
             | At least for java, you can spin out a new class loader
             | which intercepts all class loading tasks and basically shim
             | the dynamic module from the permanent runtime platform very
             | trivially. For unloading, you'll likely need conventions on
             | how to shut it down cleanly to not leave a ton of garbage
             | around. Want a new version? Spin up a new class loader,
             | rinse and repeat. If you need stateful between versions,
             | you clearly need to mindfully build a facade for that
             | outside of the dynamic parts. This is all not hard, but not
             | introductory either. That said, I basically wrote similar
             | DLL loaders in my first year writing c so many decades ago,
             | so shrugs.
        
               | reactordev wrote:
               | Class loading from a DLL is one thing, persisting the
               | state and reloading that state on-top is another. In
               | Java, you can use the class loader to load _new_
               | instances of a class, but it 's up to you to transfer
               | state before giving that class over to your program
               | again. In C# it's a similar story with
               | System.Runtime.CompilerServices. The trivial bits are the
               | fact that you can use reflection to do this rather easily
               | in both Java and C#. In C++ isn't not as simple. The
               | struct/data signature may change, you need a temporary
               | storage vessel (old object?) to copy to the new class
               | object. While it's still "digital plumbing", it's not
               | that easy to do and then hot-reload the whole stack.
        
       | davidzweig wrote:
       | I really liked the product video, can someone advise how to make
       | something similar for our project?
       | 
       | EDIT: Oh, I guess After Effects with some stock background video
       | and audio track mostly.
       | 
       | Burning logo effect: https://www.youtube.com/watch?v=wkP-IYmPzpI
       | 
       | Glitch effect: https://www.youtube.com/watch?v=7eOMSuPdbok
       | 
       | Simulated monitor recording (this doesn't show the monitor border
       | though..) https://www.youtube.com/watch?v=JOYdGtyxMkI
       | 
       | Animated font effects - surely these are possible if the rest is.
       | 
       | At 1:04, I think they made a custom graphic to that overlays the
       | stock video below.
        
         | jryan49 wrote:
         | Probably Adobe After Effects
        
       | kleiba wrote:
       | Yes!!! Finally we're off ukulele soundtracks!
       | 
       | https://www.youtube.com/watch?v=o5vUzS9EGUU
        
       | kleiba wrote:
       | In one of the earlier episodes of the _Handmade Hero_ series,
       | Casey Muratori writes a hot-reloading functionality for C from
       | scratch in about an hour (while giving detailed explanations of
       | what he 's doing). The following two episodes then improve upon
       | the initial results.
       | 
       | https://www.youtube.com/watch?v=WMSBRk5WG58
        
         | jasonlotito wrote:
         | I was thinking the same thing when I saw this. Thanks for
         | finding the video! His early stuff is especially good.
        
         | mananaysiempre wrote:
         | On one hand, I appreciate Muratori showing that loading code
         | into your program dynamically isn't actually difficult. On the
         | other, the hard part of general hot reloading on systems that
         | have tried it (from Smalltalk to VC++ Edit-and-Continue) is
         | migrating obsolete state--or at least reliably telling the user
         | when you can't, so as to avoid leaving them to debug a mad
         | world that could never be encountered in a fresh run. As far as
         | I remember, Muratori basically does not touch on that at all.
        
           | el_oni wrote:
           | There is a tsoding daily video with hot code reloading in C
           | [0].
           | 
           | He dicusses techniques for this. one of which is a
           | "migration" approach, similar to database migrations. Where,
           | for example, you have a version number in your struct. and a
           | function for migrating from an old version to a new version.
           | I don't think he implements it in that video though.
           | 
           | [0] https://www.youtube.com/watch?v=Y57ruDOwH1g&t=15s
        
           | mgaunard wrote:
           | in C or C++ the bigger problem is ABI breakage or ODR
           | violations.
        
       | vodou wrote:
       | 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.
        
         | hyperhopper wrote:
         | No, totally reasonable not wanting to spend your whole life
         | financially beholden to everybody you've ever done business
         | with. "you will own nothing and be happy" is sadly becoming
         | true, as you have pretty much no Rights for any digital and
         | more of the world is becoming digital.
         | 
         | When people ask why I don't like copilot and want a worse
         | alternative when copilot "pays for itself", it's not because I
         | don't want to pay, I just want to buy something and have it.
        
           | mananaysiempre wrote:
           | > I don't like copilot and want a worse alternative [that can
           | be used in perpetuity]
           | 
           | There's replit-code[1], which is pretty much that I think.
           | 
           | [1] https://huggingface.co/replit/replit-code-v1_5-3b/
        
         | thrtythreeforty wrote:
         | A good way to detect these kinds of subscription-only tools is
         | that they all call it "Pricing." (Not "Cost" or "Store" or
         | "Purchase," all of which imply that you might own something
         | after you pay.) I get very disinterested when I see that
         | heading on a webpage now.
        
       | miniupuchaty wrote:
       | It's pretty good. Epic added it as part of Unreal Engine to
       | replace their previous hot reload system, which was more similar
       | to the alternatives that people are mentioning here. That
       | previous hot-reload didn't work as well as live coding, was less
       | stable.
       | 
       | Simple dll reloading can work great if you separate state from
       | logic, like shown in handmade hero. If you cannot enforce that
       | then live++ is a good alternative.
       | 
       | Too bad there's no linux support.
        
         | rezonant wrote:
         | Unreal's original Hot Reload system is despised by Unreal
         | developers, and it is a constant source of headaches for new
         | developers using C++ with Unreal, as it can corrupt the (in
         | memory, but also serialized and persistent) UObjects that your
         | game relies on to run.
         | 
         | Live++ ("Live Coding" in Unreal) can still cause these problems
         | if you leave the Reinstancing option on. For anyone doing C++
         | in Unreal, please please please read this [1] and at the very
         | least make sure to not use the older Hot Reload.
         | 
         | [1] https://landelare.github.io/2023/01/07/cpp-
         | speedrun.html#com...
        
       | PhilipRoman wrote:
       | 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
       | code and being able to create checkpoints and time travel.
        
       | Jeaye wrote:
       | 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 Cling. In
       | recent benchmarks, it can be several times faster than Clojure
       | JVM. https://jank-lang.org/
        
       | tsmeets wrote:
       | You don't need anything complicated for this. All you need is to
       | compile your code to a shared library that exports an 'update'
       | method.
       | 
       | See https://github.com/TomSmeets/quest-for-
       | nothing/blob/master/a...
       | 
       | You have to be careful with global variables however, they will
       | get cleared to zero when the code is reloaded. To solve this
       | either don't use globals or just restore them on reload.
        
       | Diederich wrote:
       | Back in the early 90s when I was writing
       | https://en.wikipedia.org/wiki/Multi-user_dungeon 's, and for a
       | while had quite a few players, I was always keen to move as much
       | functionality as possible into unloadable/loadable libraries,
       | since restarting the game was quite invasive.
       | 
       | To my surprise, this was seen as a pretty amazing feature at the
       | time. I never understood why many/most of the other MUDs at the
       | time didn't utilize this.
        
       ___________________________________________________________________
       (page generated 2024-01-03 23:00 UTC)