Managing builds with premake

This article will be something completely for the technically minded individuals, and those who has been suffering from the sub par project & solution configuration of Visual Studio in particular.

As one incorporates more projects & configuration options into your build process it becomes a burden to modify & keep everything up to date. Missing something as a define or linking to the wrong runtime library can break ABI compatibility and can be really cumbersome to track down, having to double check every dependency to make sure everything is linking to the correct lib etc.

We have 3 build types, Debug, Release & ReleaseCandidate where Debug is mostly used during development, where we link to debug runtimes, use no optimization’s and overall have everything tuned for maximum debug-ability. In this build the game is running at a poor but playable framerate so is mostly just suitable for programmers. In Release we have all optimizations on, this build type is very close to what we ultimately want to ship but have cheats turned on for making development easier. For example we have a button in these builds & Debug builds which unlocks levels. Release builds also have asserts turned on, this way we can often catch errors early and sort them out. Release builds are used almost exclusively by everyone except people programming internally, the framerate is generally good and overall it’s a fair representation of the game. The last type, ReleaseCandidate, is only used when we’re making a release candidate ( surprise! ). In this build all cheats are disabled & everything which negatively affects framerate is removed. I would say these 3 types are a bare minimum, other popular build types is for example release type build but with generated debug information and “Paranoid”, where everything conceivable which could potentially go wrong is super checked, these type of builds usually have super poor framerate.

To this we add the different platforms, in our case PC & PS3. PC in our case is synonymous with a steam dependent build, but the plan is to have steam as a third platform, in which case we would have PC, PS3 & PC – Steam. The different build types & platforms then combines into all the different configurations, which if we incorporate steam on/off into the mix would be a total of 3 * 3 = 9.

At last we consider the fact that we have about ~35 projects on which Nimbus depends which needs to be built, in total 35 * 9 = 315 separate project/configuration types. Some are disabled for PS3 and vice versa for PC, but overall there’s quite a few. This is where the pain begins, lets say you missed the fact that all builds in Visual Studio which uses their standard library needs the define _SECURE_SCL=0 in all release configurations. The process to fix this is to right click a project, choose properties, then expand Configuration Properties, expand C/C++, click Preprocessor, click Preprocessor Definitions field and place caret at end and then paste it in at the end. Repeat process for about 35 * 2 = 70 project/configuration combos. There’s a trick here where if you have a slew of projects with the same defines ( rather unlikely ), then you can select them all and do it in one go. The same goes for if you have build types with the same defines, which is also unlikely. There’s a few more small trick which makes this a bit more tolerable, but overall it’s a very unpleasant experience to modify options across configurations and projects. It’s easy to miss something or accidently enter something for the wrong config, which at best leads to a compile time error and at worse a hard to track down crash in your binary.

All of this is a known shortcoming of Visual Studio and something I’ve heard they made strides on in Visual Studio 2010 ( even if it’s still fairly lackluster from what I hear ). So I took a look around to see what sort of options there were, having the following requirements:

  1. I want to work inside Visual Studio, I don’t want to maintain my Visual Studio projects in addition to adding my files to external scripts when my projects grow
  2. I don’t want to depend on tools which requires installs, ideally I want something which is self contained and easy to put in our source control
  3. I want to have the same work flow as I already have inside Visual Studio, that is, it needs to support building & debugging inside Visual Studio seamlessly
  4. Relative paths! I thought this was a no brainer, but there seems to be a few options out there which doesn’t handle this simple requirement
  5. Low learning curve

As it turns out there’s almost nothing out there which meets all of these requirements. Most fail at a combination of 1, 2 or 5. Scons, jam/bjam seems to fail at 1, 3 & 5. CMake fails hard at 2 and is overly fond of absolute paths for the generated project files, not overly important but this always rubs me the wrong way. There’s also Gyp which seems to pass pretty much all of my tests, except maybe 2 as it depends on python, but with some fiddling I’m sure that wouldn’t have been to hard to embed. Gyp is certainly something I would’ve considered an alternative, but in the end I went with Premake, which is what most of this article will be about. Premake is a single binary which is totally self contained, it’s dead easy to learn ( if you know lua you’re already half way there ). As a bonus it’s very light weight and as soon as you’ve figured out how it works it’s very easy to modify pretty much any aspect of it. Except for a few implementation level niggles I have with premake the only downside I’ve found so far is that it’s a bit lacking when it comes to feature set, there’s some features which I can’t live without which Premake doesn’t support. As it turns out I’ve been able to add all of them as well as converting all of our projects in about a week however. Follow me to the next page for the low down!

Pages: 1 2
by / June 16, 2011 / Posted in: Development, Technical