Monday, September 26, 2011

MSBuild Properties in Delphi

From Delphi 2007 forward the Delphi IDE relies on MSBuild to manage project dependencies, compiler options, etc. If you're a Delphi developer you are likely familar with the $(..) notation used for accessing values exposed by the build system. With a little digging you'll discover some of these values are environment variables and that you can modify them or create your own. If you take a closer look you'll see there are other values accessed using $(..) that are not environment variables.

The $(..) notation comes from the make syntax. It is used for referencing variables defined in a make script. Prior versions of Delphi relied of Borland's variation of make. MSBuild (as well was most other xml based build scripts) inherited certain design ideas from make. The $(..) notation is one of them. In MSBuild variables are called properties. Delphi's .dproj files are simply MSBuild files with a little customization.

MSBuild treats environment variables and property values within a build script the same. This is why you can access environment variables using $(..). You can also create enviroment varibles that override properties in a project file. So what properties are defined?

Take a look at BDS\Bin\*.Targets. Every .dproj file you create includes one or more of these .targets files. Every option passed to the compiler has an associated property that can be accessed at various stages of the build process. You can take advantage of these for setting the output path for generated files and writing pre and post build scripts. Be careful not to modify the supplied targets files. You are free to define your own targets files and incorporate them into your projects. I may write a separate article about custom targets at a later time.

Example
Its common to want debug and release artifacts to output to separate folders. You can edit each configuration to output to ".\debug" and ".\release" or you can just edit the base configuration instead:

Output directory = $(Config)

Now any configuration inheriting from the base configuration will use the Config property when writing the executable to disk. You can create additional configurations that inherit from Base and they will override the Config property with their name.