Ever since the Delphi build engine got changed to MS Build in Delphi 2007, many people use Delphi build events. Their order is prebuild, prelink and postbuild (or maybe better spelled pre-build, pre-link and post-build).
Before Delphi 2007, you had to fiddler with project groups and dependencies to fake pre-build and post-build events. For an example see Pre and Post-Build Automation in Delphi.
One of the really good things about these events is that build events appear in the output tab of the messages window.
One of the really bad things is that there is hardly any documentation about the build events.
At least two important things are missing:
- How the lines of a build event are actually executed
- How parameter expansion works inside build events
Let’s explain these.
Executing the source lines of a build event.
I can cut this short very easily: build events are not batch files.
What happens is that all lines in your build event are concatenated together using ampersand (&) signs which are used to execute multiple commands on one command line.
This means that all the fancy control structures (if statements, setlocal, for loops) are not possible inside build events.
The alternative is to call a batch file from a build event, and have your control structures there.
But for that, you have to pass parameters, which leads to the expansion of $() parameters:
Expansion of the $() parameters inside build events
I could not find any official documentation of the $() parameters on the Embarcadero sites.
Ken White took the effort to type the parameters from Delphi 2010 into a StackOverflow answer (that list is gone in Delphi XE, but the bug reports on that got fixed in Delphi XE2 and up), and since then they have not changed:
BDS The environment variable $(BDS) DEFINES The project's conditional defines DIR The environment variable $(DIR) INCLUDEPATH The project's include path INPUTDIR The input file's directory INPUTEXT The input file's extension INPUTFILENAME The input file's name, with extension INPUTPATH The input file's full path LOCALCOMMAND Local command entered by user in project manager OUTPUTDIR The output file's directory OUTPUTEXT The output file's extension OUTPUTFILENAME The output file's name, with extension OUTPUTNAME The output file's name, without extension OUTPUTPATH The output file's full path Path The environment variable $(PATH) PROJECTDIR The project's directory PROJECTEXT The project's extension PROJECTFILENAME The project file's name, with extension PROJECTNAME The project's name PROJECTPATH The project file's full path SAVE Save the input file to disk before it's compiled SystemRoot The environment variable $(SYSTEMROOT) WINDIR The environment variable $(WINDIR)
A nice list, but it doesn’t tell you what the values are (apart from the environment variables). So I compared the output of build-events like this:
>> %temp%\pre-build.txt echo BDS: $(BDS)
>> %temp%\pre-build.txt echo Config: $(Config)
>> %temp%\pre-build.txt echo DEFINES: $(DEFINES)
>> %temp%\pre-build.txt echo DIR: $(DIR)
>> %temp%\pre-build.txt echo INCLUDEPATH: $(INCLUDEPATH)
>> %temp%\pre-build.txt echo INPUTDIR: $(INPUTDIR)
>> %temp%\pre-build.txt echo INPUTEXT: $(INPUTEXT)
>> %temp%\pre-build.txt echo INPUTFILENAME: $(INPUTFILENAME)
>> %temp%\pre-build.txt echo INPUTNAME: $(INPUTNAME)
>> %temp%\pre-build.txt echo INPUTPATH: $(INPUTPATH)
>> %temp%\pre-build.txt echo LOCALCOMMAND: $(LOCALCOMMAND)
>> %temp%\pre-build.txt echo OUTPUTDIR: $(OUTPUTDIR)
>> %temp%\pre-build.txt echo OUTPUTEXT: $(OUTPUTEXT)
>> %temp%\pre-build.txt echo OUTPUTFILENAME: $(OUTPUTFILENAME)
>> %temp%\pre-build.txt echo OUTPUTNAME: $(OUTPUTNAME)
>> %temp%\pre-build.txt echo OUTPUTPATH: $(OUTPUTPATH)
>> %temp%\pre-build.txt echo Path: $(Path)
>> %temp%\pre-build.txt echo Platform: $(Platform)
>> %temp%\pre-build.txt echo PROJECTDIR: $(PROJECTDIR)
>> %temp%\pre-build.txt echo PROJECTEXT: $(PROJECTEXT)
>> %temp%\pre-build.txt echo PROJECTFILENAME: $(PROJECTFILENAME)
>> %temp%\pre-build.txt echo PROJECTNAME: $(PROJECTNAME)
>> %temp%\pre-build.txt echo PROJECTPATH: $(PROJECTPATH)
>> %temp%\pre-build.txt echo SAVE: $(SAVE)
>> %temp%\pre-build.txt echo SystemRoot: $(SystemRoot)
>> %temp%\pre-build.txt echo WINDIR: $(WINDIR)
"$(INPUTDIR)Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.bat""$(Platform)""$(INPUTDIR)..\..\..\..\..\fastmm.sourceforge.net\FullDebugMode DLL\Precompiled\""$(OUTPUTDIR)"
I ran it using the project C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.dproj
The objective was to copy the correct FastMM FullDebugMode DLL into the directory of the .EXE (more on that later).
Observations of the events:
- pre-link is not executed
- pre-build and post-build get executed
- pre-build and post-build give the same output
Output of pre-build.txt
converted to a html table (too bad you cannot have code
or pre
tags around a table
tag):
BDS | c:\program files (x86)\embarcadero\rad studio\11.0 |
Config | Debug |
DEFINES | DEBUG;FullDebugMode; |
DIR | |
INCLUDEPATH | c:\program files (x86)\embarcadero\rad studio\11.0\lib\Win64\release;C:\Users\Developer\Documents\RAD Studio\11.0\Imports;c:\program files (x86)\embarcadero\rad studio\11.0\Imports;C:\Users\Public\Documents\RAD Studio\11.0\Dcp\Win64;c:\program files (x86)\embarcadero\rad studio\11.0\include;C:\Program Files (x86)\FastReports\LibD18x64;C:\Program Files (x86)\Raize\CS5\Lib\RS-XE4\Win64 |
INPUTDIR | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\ |
INPUTEXT | .dproj |
INPUTFILENAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.dproj |
INPUTNAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent |
INPUTPATH | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.dproj |
LOCALCOMMAND | |
OUTPUTDIR | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Win64\Debug\ |
OUTPUTEXT | .exe |
OUTPUTFILENAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.exe |
OUTPUTNAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent |
OUTPUTPATH | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Win64\Debug\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.exe |
Path | C:\Users\Public\Documents\InterBase\redist\InterBaseXE3\win32_togo;C:\Users\Public\Documents\InterBase\redist\InterBaseXE3\win64_togo;C:\Program Files (x86)\Embarcadero\RAD Studio\11.0\Redist\boost\win64;C:\Program Files (x86)\Embarcadero\RAD Studio\11.0\Redist\boost\win32;C:\Program Files (x86)\CollabNet;C:\Program Files (x86)\Embarcadero\RAD Studio\11.0\bin;C:\Users\Public\Documents\RAD Studio\11.0\Bpl;C:\Program Files (x86)\Embarcadero\RAD Studio\11.0\bin64;C:\Users\Public\Documents\RAD Studio\11.0\Bpl\Win64;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft\Web Platform Installer\;C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit\;C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;C:\Program Files\TortoiseSVN\bin;C:\Program Files\TortoiseHg\;C:\BIN |
Platform | Win64 |
PROJECTDIR | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent |
PROJECTEXT | .dproj |
PROJECTFILENAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.dproj |
PROJECTNAME | Copy_FastMM_FullDebugMode_Dll_PostBuildEvent |
PROJECTPATH | C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent.dproj |
SAVE | |
SystemRoot | C:\Windows |
WINDIR | C:\Windows |
Observations of the values
Partially lowercase:
- INCLUDEPATH: c:\program files (x86)\embarcadero\rad studio\11.0\lib\Win64\release;C:\Users\Developer\Documents\RAD Studio\11.0\Imports;c:\program files (x86)\embarcadero\rad studio\11.0\Imports;C:\Users\Public\Documents\RAD Studio\11.0\Dcp\Win64;c:\program files (x86)\embarcadero\rad studio\11.0\include;C:\Program Files (x86)\FastReports\LibD18x64;C:\Program Files (x86)\Raize\CS5\Lib\RS-XE4\Win64
Lowercase:
- BDS: c:\program files (x86)\embarcadero\rad studio\11.0
- INPUTEXT: .dproj
- OUTPUTEXT: .exe
- PROJECTEXT: .dproj
Empty:
- DIR:
- LOCALCOMMAND:
- SAVE:
Ends with backslash:
- INPUTDIR: C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\
- OUTPUTDIR: C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent\Win64\Debug\
No backslash:
- PROJECTDIR: C:\Users\Developer\SVN\BeSharp.codeplex.com\Native\Delphi\Apps\Copy_FastMM_FullDebugMode_Dll_PostBuildEvent
I tried these Intel based platforms in Delphi XE4:
- Platform: OSX32
- Platform: Win32
- Platform: Win64
So that’s where the Copy_FastMM_FullDebugMode_Dll_PostBuildEvent came in (:
Future research
I need to put some more research into where these values are filled, and how you can pass your own to the MSBUILD process.
According to name, with extension INPUTPATH The input file’s full path LOCALCOMMAND Local command entered by user in project manager OUTPUTDIR The output file’s directory OUTPUTEXT – CodeInPro
and What are the MSBuild project level properties for Delphi? – Stack Overflow,
many values are set inC:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Borland.Delphi.Targets
but that has since then moved to files named like this:C:\Program Files (x86)\Embarcadero|CodeGear\RAD Studio\*.0\bin\CodeGear.*.Targets
Nobody seems to know about $(LOCALCOMMAND): Article 10854 Subject D2010 Build Events – Use of $(LOCALCOMMAND)? Where does it come from? on embarcadero.public.delphi.ide.
–jeroen
Filed under: Delphi, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Development, FastMM, Software Development