Environment variables and macros in Delphi

Environment variables are strings defined by the IDE. Each environment variable serves a specific purpose. Some of them are fixed, others are changed dynamically depending on what/how you are compiling your project.

For example, they provide dynamic paths that influence where files are stored, define default locations for binaries, define how projects are built, and how the IDE operates.

Some environment variables can be accessed from outside the IDE, via registry.

We can use them to streamline our workflows (the compilation process for example).

The list below presents some of the environment variables (Delphi 11). There are more of them, but some are not interesting – they are exclusively for C++ and databases or simply are not that useful.

VariableDescription
$(BDSPLATFORMSDKSDIR) C:\Users\User\Documents\Embarcadero\Studio\SDKsLocation for SDKs, which are stored in subfolders.
$(BDS) program files -> embarcadero\studio\23.0The installation location for RAD Studio.
$(BDSBIN) program files -> embarcadero\studio\23.0\binThe folder contains executable (EXE) files, such as the IDE, compilers, linkers, and other binaries.
$(BDSCOMMONDIR) C:\Users\Public\Documents\Embarcadero\Studio\23.0General folder for user-specific files. For example, styles are installed in a subfolder, another subfolder is the default location for packages, and so on.
$(BDSPROJECTSDIR) C:\Users\User\Documents\Embarcadero\Studio\ProjectsDefault folder where the IDE saves projects.
$(BDSUSERDIR) C:\Users\[User]\Documents\Embarcadero\Studio\23.0Folder for user-specific files that the IDE stores.
$(DELPHI) program files -> embarcadero\studio\23.0The installation location for Delphi, if the Delphi personality is installed (the same as the RAD Studio installation location). Only set when running the IDE using the combined RAD Studio or Delphi personality.
$(PATH)A system environment variable, but one that can often be changed (other paths appended) for processes running under the IDE.

There are four more environment variables that are very special/useful so we will discuss them separately.

$(ProductVersion)

This variable is automatically substituted by Delphi with a string representing the current version:

  • “21.0” when we compile under Delphi 10.4 (Sydney)
  • “22.0” when we compile under Delphi 11
  • “23.0” when we compile under Delphi 12
  • etc.

$(Platform)

Automatically substituted by Delphi with the platform for which the compilation takes place.

  • “Win32” when we compile for 32bit.
  • “Win64” when we compile for 64bit.

$(Config)

Automatically substituted by Delphi with:

  • “Release” when we compile our application in Release mode.
  • “Debug”  when we compile our application in Debug mode.

Compiling a project under multiple editions of Delphi

I always use the above environment variables for my output paths (both in projects and libraries). If we use hardcoded paths instead of environment variables, compiling a project under Delphi 10.4 would require 4 output paths:

// Sydney

C:\My library\21.0\Win32\Debug

C:\My library\21.0\Win32\Release

C:\My library\21.0\Win64\Debug

C:\My library\21.0\Win64\Release

The above structure would not work if at some point we upgrade to Delphi 11, because of the hardcoded paths. Delphi 11 would output the DCUs in the “21.0” folder. Now if we switch back to Delphi 10.4 it would fail to load the DCUs because they are compiled with Delphi 11. So, we have to recompile the whole stuff in Delphi 10.4, but if we do that, we break Delphi 11!

The patch would be to make a copy of the project (DPR/DPROJ) under two different names, MyProj104 and MyProj11 and change the hardcoded paths (in the MyProj11) to these new values:

// Alexandria

C:\My library\22.0\Win32\Debug

C:\My library\22.0\Win32\Release

C:\My library\22.0\Win64\Debug

C:\My library\22.0\Win64\Release

If we want to compile that project with more Delphi editions things really get out of control.

However, with the three environment variables above we can have a single path:

C:\My library\$(ProductVersion)\$(Platform)\$(Config)

Now we can upgrade to Delphi 12, 13, 14, etc without changing anything! Each Delphi edition will output the binary files in its own dedicated folder.

How cool and clean is that?

The fourth environment variable is discussed in the “Delphi in all its glory – Libraries” book, because it better applies there. But it also is a life saver, even bigger than the ones before!

Registry variables

Over the years, I created quite a few external tools and scripts that must know where Delphi is installed.

This can be achieved by interrogating some variable in the registry which are put there during Delphi setup. Example:

HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\2x.0\

“RootDir”=”C:\\Program Files (x86)\\Embarcadero\\Studio\\22.0\\”

HKEY_CURRENT_USER\Software\Embarcadero\BDS\2x.0\Environment Variables

“InterBase”=”$(BDS)\\InterBase2020”

“DEMOSDIR”=”C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\22.0\\Samples”

Macros

Macros complement/extend the environment variables. The macros often represent file paths, project configurations, and platform-specific details. For example, the $(OUTPUTPATH) macro returns the full path to the output file (e.g., a compiled binary).

But macros can also be commands that can be executed – for example the Save macro can be used to trigger the IDE to save open files to disk.

Macros are extremely useful for running scripts inside the IDE. For example, when we compile in “Release” mode, we can create a custom build event (script) that uploads the new EXE file we just compiled, over FTP, so the customers can download it.

In the “Delphi in all its glory – Libraries” book, we will use macros to automate the management of resource files needed for packages.

The list below shows each macro. It also shows an example of what Delphi returns when we execute that macro for a theoretic runtime package called “Tools_R.dpk”, located in “C:\Projects\Tools”.

Path related macros

INPUTDIR

The input file’s directory. Example:  C:\Projects\Tools\

INPUTEXT

The input file’s extension. Example: .DProj

INPUTFILENAME

The input file’s name, with extension. Example: Tools_R.dproj

INPUTNAME

The input file’s name, without extension. Example: Tools_R

INPUTPATH

The input file’s full path. Example: C:\Projects\Tools\Tools_R.dproj

OUTPUTDIR

The output file’s directory. Note that this is not the folder where the DCU files are stored!

Example: c:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl\

OUTPUTEXT

The output file’s extension. Example: .bpl

OUTPUTFILENAME

The output file’s name, with extension. Example:  Tools_R.bpl

OUTPUTNAME

The output file’s name, without extension.  Example: Tools_R

OUTPUTPATH

The output file’s full path. Note that this refers to the BPL/EXE file, not to the DCU output folder. Example: c:\Projects\BPLs\Tools_R.bpl

PROJECTDIR

The project’s directory. Example: C:\Projects\Tools

PROJECTEXT

The project file’s extension. Example: .dproj

PROJECTFILENAME

The project file’s name, with extension. Example: Tools_R.dproj

PROJECTNAME

The project’s name. Example: Tools_R

PROJECTPATH

The project file’s full path. Example: C:\Projects\Tools\Tools_R.dproj

SystemROOT

The environment variable $(SystemRoot). Example:  C:\Windows

DIR

The environment variable (DIR). Example: ‘’

INCLUDEPATH

The project’s Include path. Example:

c:\program files (x86)\embarcadero\studio\22.0\lib\Win32\release

c:\Users\Public\Documents\Embarcadero\Studio\22.0\Dcp

c:\program files (x86)\embarcadero\studio\22.0\include

c:\Projects\Libs\DragDrop\22.0\Win32\debug

c:\Projects\Libs\sgcWebSockets\22.0\Win32\debug

etc

Path

The environment variable $(Path). Some examples:

C:\Program Files\Git\cmd;

C:\Program Files (x86)\Embarcadero\Studio\22.0\bin64;

C:\Users\Public\Documents\Embarcadero\Studio\22.0\Bpl;

Other macros

Config

The project’s active configuration name. Example: Debug

Platform

The project’s active platform name. Example: Win32

DEFINES

The project’s conditional defines. Example: DEBUG;FRAMEWORK_VCL

LOCALCOMMAND

Local command entered by user. In my test, it returned nothing.

SAVE

Save the input file to disk before it is compiled.

More on this topic is available in my books.

Leave a Comment

Scroll to Top