Simple Live C++ Reloading in Visual Studio

I often work on very small projects that have a focus on getting results quickly.

For example:

  • Trying to make a proof-of-concept of an idea.
  • Implementing an algorithm from a paper or an article.
  • Doing something “artistic” where rapid iteration is key.

In these kinds of projects, the effort is often focused on a few important functions. For example, the function that renders the scene, or the function that transforms some geometry. My projects are usually focused on real-time rendering, so I render a scene at an interactive frame rate, while applying a special algorithm every frame to transform the geometry or render the image.

It’s important for me to be able to design and debug the key function of the project as productively as possible. I want to try new things quickly, and I want to be able to visualize my results to better understand my code. To do this, I take many approaches:

In this article, I describe another approach to improve iteration speed:

Live C++ reloading.

Live C++ reloading means that you can build and reload C++ code without needing to restart your program. This allows you to quickly see the effects of changes to your code, which greatly helps productivity.

Live reloading C++ code can also be useful if your program takes a long time to initially load its data. For example, if you have to load a large 3D scene every time you restart your program, that will probably hinder your productivity. If you can update C++ code without needing to restart your program, then you don’t have to reload the scene to see your changes. Also, it allows you to keep the 3D camera in one place while you change your code, so you can more easily debug a problem that only happens from a specific viewpoint.

Of course, there are many different ways to reload C++ code. In this article, I describe a simple and stupid way to do it, which is easy to set up in a Visual Studio project.

How To Live-Reload C++

For completeness, let’s start from scratch. If you want to add this to an existing project, you can skip some steps.

If you just want to see the completed project, please visit the GitHub page:

https://github.com/nlguillemot/live_reload_test

Step 1. Setup a new solution and main project

Create a new solution and project with Visual Studio.

Its project will serve as the “main” project for your application.

newprojmenu.png

newproj.png

Create a main.cpp for this project. We will add the live-reloading code to it later.

newitem.png

newcpp.png

Here’s some dummy code for a “real-time” update loop:

#include <cstdio>

#include <Windows.h>

int main()
{
  while (true)
  {
    printf("Hello, world!\n");
    Sleep(1000);
  }
}

If you run it, this should display “Hello World!” every second in a loop.

hello.png

Step 2. Setup a project for live-reloaded code.

Right click on your solution and add a new project to it.

This project will be used for the code we want to live-reload.

addproj.png

anothernew.png

Configure this project to build as a DLL using its properties.

props.png

By the way, use “All Configurations” and “All Platforms” when using the Property Pages. Otherwise your changes might not update all the Debug/Release/x86/x64 builds.

fucksdf.png

Now set a dependency from the main project to the DLL project, to make sure that building the main project also builds the DLL project.

projdep.png

projdep2.png

Now add a header to the DLL project that defines the interface to your live-reloaded code.

asdfasdf.png

asdfasdf32.png

Here’s some placeholder code for live_reloaded_code.h that you can extend:

#pragma once

#ifdef LIVE_RELOADED_CODE_EXPORTS
#define LIVE_RELOADED_CODE_API __declspec(dllexport)
#else
#define LIVE_RELOADED_CODE_API __declspec(dllimport)
#endif

extern "C" LIVE_RELOADED_CODE_API void live_reloaded_code();

Now repeat the process to add a cpp source file to the DLL project.

4h3e.png

asdfasdf31.png

Here’s some placeholder code for live_reloaded_code.cpp that you can extend:

#include "live_reloaded_code.h"

#include <cstdio>

void live_reloaded_code()
{
  printf("Hello, Live Reloaded World!\n");
}

Next, add the preprocessor definition for LIVE_RELOADED_CODE_EXPORTS to the DLL project. This makes the DLL project “export” the DLL functions, while the main project will “import” them. Not all strictly important for live-reloading, but it’s a proper setup for a DLL.

cxfjvhsdf.png

asdfjkalsdf.png

Step 3. The live-reloading mechanism

Go back to the original main.cpp. We now add the code that does the live-reloading. It’s around 100 lines of code, so I won’t paste it in this blog post. Instead, please go to the GitHub repository and copy the code from there.

Here is the link, for your convenience:

https://github.com/nlguillemot/live_reload_test/blob/master/live_reload_test/main.cpp

I tried to write descriptive comments, so hopefully the code is self-explanatory. Here’s a summary of how it works:

The code will poll the timestamp of the DLL file that contains the reloadable functions at every update. When the DLL’s timestamp changes, the DLL will be reloaded and the functions in it will be reloaded too. We make a copy of the DLL before loading it, because if we don’t then the DLL will fail to rebuild, because its file can’t be overwritten while we are using it. Finally, before calling a live-reloaded function, we cast it to a function pointer type that has the correct function signature. In the sample code, C++11’s auto and decltype features are used to do this cast, which avoids redundantly re-defining the function’s type.

Step 4. Using the live-reloading

Now that all the code is ready, we can have fun with live-reloading. To do this, we launch the program “without debugging”, because that allows Visual Studio to build code even if the program is running.

First, make sure the main project is the startup project:

durpdupr.png

Next, start the project “without debugging“. You can do this by pressing “Ctrl+F5“, or you can go in the following menu:

fdsajhf.png

Now, the program should be running, and displaying the message we wrote earlier:

dhfwer.png

While this program is running, go to live_reloaded_code.cpp, and modify the message in the printf. After that, save the file, and build the project by pressing “Ctrl+Shift+B“, or by going in the following menu:

3hiods.png

After the build, you should see the output of your program change:

ejidf.png

That’s it! Have fun!

Known Issues

It might crash rarely depending on how you have it set up. I don’t know why. It has been reliable enough for me.

Advertisements

4 comments

  1. Magnus Österlind

    Thanks for the post, and showing how easy it is to get a basic version of this type of system going!

    Regarding the instability, one thing I noticed was that it seemed that my system would start trying to load the dll before it had been fully written (I guess having a post build step that explicitly copies the DLL might solve this), so I ended up turning off error messages reading failed DLL imports, and only replacing my existing function pointers etc if my new reload succeeded. A gist of my current system (hacked together after reading this, so probably not production quality :): https://gist.github.com/mrdooz/c5c7458ba7edb772d659b5a1c0ed379b

    Like

    • nlguillemot

      Yeah, what you describe seems to be a recurring annoying problem when looking for file changes… I think the code I have on GitHub does something similar (just ignoring errors.)

      Like

  2. Steve Fan

    Yes, this is a workaround, however, how do you take account of states and living pointers?
    You either have to write pure functions, or you will need to setup a managed heap, hook memory operations(new, delete, malloc, free, etc) and put all memory inside the managed heap, and when you need to reload, you simply delete the previous heap and create a new one.

    Like

    • nlguillemot

      I *think* that kind of stuff is not a problem if your exes and dlls are all linked to the same version of Microsoft’s C++ standard library.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s