Autogenerating Code with Visual Studio 2008

February 2010

Automated code generation can go a long way toward extending the language you're using and saving you time. This is one of the better ways I've found to set things up nicely in VS2008.

What We're Talking About

There are many forms of code generation so I'll be clear about the kind we're about to set up. This is a guide to getting Visual Studio to call an external generator before it builds the rest of your project.

Presumably the code that the external program is generating will be included as part of your normal build process.

There are a few ways to set this up in Visual Studio so that it kind of works. The way I'm about to show you will make it so that VS will recognize when your autogenerated code has been changed and do the right thing on Build and Rebuild.

My code generating language of choice is Python, but you could set this up with any other executable easily.

File Organization

I've chosen to organize my autogenerated code in the following way. These are the only files that need to be included in the actual VS project.
generated_headers.h
This file #includes all autogenerated .h files.
generated_code.cc
This file #includes all autogenerated .cc files.
build_trigger.tmp
Used to trigger a code generation sweep every time a build is started.
rebuild_trigger
Used to call a cleanup script when the project is rebuilt.

Setting it Up

The first thing you should do is add a directory in your source folder that will contain all of your generated code. It's a good idea to keep it all seperated so that it's easy to nuke it all if the need arises.

It also lets you easily exclude the generated code from your version control system, which I would recommend. It'll get generated for whoever's trying to build the project so there's no reason to risk merge conflicts.

Next you'll want to create the build_trigger.tmp and rebuild_trigger files. It doesn't really matter where you put them. Mine are located in my build_tools folder which contains all my code generation scripts.

Once you've added the files to Visual Studio right click build_trigger.tmp and go to Properties. We're going to be creating a Custom Build Step for this file as well as the rebuild_trigger file.

It's important to note that we are not setting up a Pre-build step for the project. You can certainly trigger your code generation this way but Visual Studio will not recognize when you have made changes. As a result you'll have to build twice before you see the changes made by your code generator in your executable.

Now that you have the Properties window open for build_trigger.tmp go to the Custom Build Step option. Fill in the Command Line option with the command you'd like to execute and fill in the Outputs field with the paths to generated_headers.h and generated_code.cc. Here's what my setup looks like as an example:
Command Line
$(SolutionDir)..\external\interpreters\python\python.exe
"$(SolutionDir)..\build_tools\prebuild.py"
"$(SolutionDir)..\code\\" "$(SolutionDir)$(IntDir)"
Outputs
$(SolutionDir)..\code\generated\generated_code.cc;
$(SolutionDir)..\code\generated\generated_headers.h
You can see from my setup that I call the Python interpreter with my prebuild script passing it the location of my source code directory and the temp directory.

I've placed the Python interpreter and associated libraries inside of my code repository. This is so I can guarantee the correct version is run whenever a build is performed, and so I don't have to rely on having Python installed on the machine I'm building on.

Normally Visual Studio doesn't run a custom build step unless the associated file has changed or you Rebuild. Since you want the previous command to be executed every time you build all you need to do to achieve this is have your code generator open build_trigger.tmp and modify it every time it's run. My generator just opens it in overwrite mode and writes a time stamp.

Next open up the Properties page for rebuild_trigger. This is a dummy file we're using to trigger a clean script when a Rebuild is requested. Since nothing will be changing this file the clean script will only be run when you Rebuild. Mine is set up in the following manner:
Command Line
$(SolutionDir)..\external\interpreters\python\python.exe
"$(SolutionDir)..\build_tools\clean.py"
"$(SolutionDir)..\code\\" "$(SolutionDir)$(IntDir)"
Outputs
$(SolutionDir)..\build_tools\build_trigger.tmp
The main things of note here are that I'm executing clean.py instead of prebuild.py and that I've specified the output file as build_trigger.tmp.

The script simply deletes my code/generated and $(IntDir)/generated folders. Effectively deleting all of the generated code and the temp files associated with building it.

I specified build_trigger.tmp as the output file because Visual Studio will not run the custom build step unless an output file is specified. It's really just a placeholder. If you decide to pick a different file just keep in mind that Visual Studio will delete the file when a rebuild is performed.

Uses

This is a pretty generic setup for a code generator that will scan and optionally generate code each time that you build. There's obviously some flexibility with how you set up the specific files but this setup has worked well for me.

My code generator parses all of the header files that have been changed since the last build and generates code based off of inheritance trees. It then generates generated_code.cc and generated_headers.h, #including all the other files it created.

Depending on the size of your codebase generating all of your code every build could be prohibitively slow. If you put a little work into tracking the state of your codebase and saving out temp files you can minimize the amount of parsing, processing, and generation you have to do for each build.



two-thousand-twelve ce, all rights reserved