Skip to main content
Thoughts from David Cornelius

Category

Building software projects involves, in addition to writing code, repetitive tasks like compiling, testing, signing, and deploying your completed application. Many times, a complicated suite of programs needs to be built in a certain order, copied to multiple locations, or even set up with special parameters for various customers. Large teams will likely have a dedicated DevOps person to handle these tasks, often with special "build machines" and complex scripts. Many development groups will utilize automation software to accomplish these tasks on a continual basis.

As a Delphi developer, perhaps your organization has invested in FinalBuilder or Project Maker or maybe they set up a build server with Jenkins or even figured out how to get a self-hosted runner for GitHub working. These all take time and effort and a little money to establish; and while they pay off in the long-run, they may be just out of reach for your skillset or budget, or simply overkill for the small projects you're working on.

But that doesn't mean you're stuck doing everything manually. Did you know you can perform many aspects of build automation right within the Delphi IDE on your own desktop? This is accomplished with three built-in features that work in conjunction with each other:

  1. Build Events,
  2. Project Groups, and
  3. Build Groups.

Let's discuss each of these.

Build Events

A "build event" allows you to execute custom commands automatically as part of your build process. This can include tasks such as copying files, running scripts, or invoking external tools. There are two types of Delphi build events, pre-build and post-build events. As their names imply, pre-build events are commands that are run just before the project is built and post-build events run immediately afterwards. You can set flags so that errors returned from these commands halt further processing. For example, if a pre-build event tries to get the latest version of the code from a server but the server is unavailable, the build could be halted so you're not building something that might be out of date. Similarly, a post-build command could run a series of tests on the compiled project and if it fails, prevent further actions from taking place so that you can address the problem before sending out a faulty application. You can also define different build events for different platforms or configurations. For example, the debug executable might be copied to a network share for others to test while the release might get uploaded to a website. I often use build events to apply code-signing to release versions of executables.

To configure build events in Delphi, right+click on your project in the Project Manager, select Options, then select Build Events under the "Building" section. You may also see "Pre-link events"; those are only applicable to C++ projects. 

Delphi's Build Event Editor

Build event commands are executed by the IDE as if they were run on the DOS command line. You can add more than one command but they're stored concatenated with an ampersand (&) in the project file which, in some older versions of Delphi are not handled properly (it also may cause parsing problems if you use an ampersand in your command). Many programmers write batch scripts that are called by the build event if they need to execute more than one command during a build event.

One very nice feature of using Delphi's build events is having access to pre-defined macros in the IDE. For example, $(OUTPUTDIR) gets expanded to the folder where the compiled project will be placed and $(Platform) is the project's active platform name. These macros get replaced by their character values when the command is executed and can be used directly or passed in as a parameter to a script called by the build event. The build event editor shows the list of available macros in the bottom half of the window. 

In the screenshot above, I call a signing tool to code-sign the release version of a compiled program and pass in $(OUTPUTPATH), which gets replaced with the completed executable's full path and filename when executed. If I change the project name or the path where compiled executables are placed, this build event command still works; also, I can copy this command to a different project and not have to change anything because I used a macro instead of hard-coding the filename. Note that I enclosed the macro in double-quotes because the path may include spaces or special characters that would cause parsing problems when run on the command-line.

Debugging build events can be a little tricky; it's best to test the commands manually on the command line before putting them into a build script. When executed by a build process in Delphi, they appear in the "Output" tab of the "Messages" pane with their macros expanded.

These automation capabilities really become useful when several projects are grouped together into a Project Group.

Project Groups

One of the oldest features of Delphi's project management is the ability to group several projects together into a Project Group. A project group allows you to manage multiple related projects together without needing to unload one project, then load another. These projects can be sub-modules of a main application (e.g. DLLs or BPLs) or related programs possibly launched by the main application. In any case, it is useful to navigate between them when they're all visible in the same workspace.

To create a project group in Delphi, simply load a first project like usual, then add an existing project to the group by right+clicking on the project group node in the Project Manager and selecting "Add Existing Project." You can add several projects to the list by repeating this process. You can then right+click on the project group name and change the name, compile or build all the projects with a simple mouse click.

Add a project to a Project Group

When you select to compile or build all projects in this manner, the order of the projects can be important as compilation order of a "Build All" process always starts with the first project at the top and goes sequentially down the list. You may have projects that depend on others being compiled and available before they will successfully compile. You can adjust the order of the projects in the project group by right+clicking on a project and selecting either "Build Sooner" or "Build Later" from the pop-up menu to move the project up or down in the list.

The buttons at the top of the Project Manager provide options for managing your project group. In addition to the convenience of having them lumped together for quick navigation, you can also change the configuration or platform of all the projects in the group at once. 

Setting the platform of all projects in a group at once


The button that opens the Build Groups paneOne of the Project Manager buttons takes this convenience and functionality one step further, it activates the Build Groups pane. 

Build Groups

When I first noticed Build Groups, I thought it was just another way to compile all the projects and so ignored it for quite some time. In one sense it is but after seeing a couple of articles on it a while back and exploring it further on my own, I realized there's additional value here that can take a developer's build process automation to the next level without leaving the IDE.

Basically, a build group allows more flexibility when building all projects in a project group by allowing you to specify which projects to build; but more than that, it also allows you to select multiple configurations and platforms to use during a build process, meaning it can compile each project multiple times in one operation!

Build Groups can compile each project multiple times in one operation!

Let's say you need to build your suite of applications and modules for three different platforms; Build Groups can do that with one button click. Let's say you need to build all but one of your projects but you don't want to remove the project from the group; you can unselect any of the projects from the configured Build Group.

When you activate the Build Groups pane, it shows all your projects and any defined build groups in a drop-down; initially there are no build groups but you can add, copy, and delete them with the toolbar buttons to the right of the list. When you add a build group, you give it a name and it creates a list of all the projects in your project group selected and with the current configuration and platform for each. You can then click in the space next to the configuration or platform for each listed project and click the button to add or remove various configurations or platforms. 

In the screenshot below, I've selected all projects in my project group, Debug and Release configurations for all but one of the projects, and various platforms for the different projects.

Build group ready to generate 20 executables

Once your build group is configured to your liking, you can click the appropriate button on the Build Groups toolbar to start the compile or build process, along with any defined build events for each selected project, then sit back and watch your computer work. If all goes well, clicking the Compile or Build buttons for this build group will generate 20 executables!

Conclusion

While this approach may not offer the sophistication of dedicated build automation tools, it can significantly reduce manual effort and ensure consistency in the build process. So, whether you're a lone coder or part of a team, consider harnessing the power of Delphi's Build Events and Build Groups to create a basic build automation system on your own desktop. By organizing projects effectively and automating repetitive tasks, you can streamline your development workflow to build better software, even on a shoestring budget.
 

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
Please enter the characters shown; no spaces but it is case-sensitive.
Image CAPTCHA
Enter the characters shown in the image.