[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)