Quite often, I came across the fact that Delphi developers (one can say traditionally) compile their applications with βpensβ, which is far from a production solution, but from the outside looks like scrub and βdo it on the kneeβ , although the products are very serious and sellable . This probably went back to the time when for automation it was necessary to come up with your own batch files that started the command line compiler dcc32
with the necessary parameters. Some even made their own βPublisherβ - Delphi-expert, which does the work of the assembly server: compiles the project (though open in the IDE), exposing it with an incremented version number taken from some database, writes some changelog and copies it somewhere into network directory .
I will not go into the historical excursion as it was before . I will tell you how to eat / can now, and how to use it to increase the efficiency of my work.
The project file of the modern version of Delphi is a .dproj
file (hereinafter I will focus on Delphi 10 Rio, but with slight differences this is true for all earlier versions of Delphi, starting from 2007). It stores all the project settings, which are usually changed in the IDE (menu Project - Options (Ctrl+Shift+F11)
). In this article, I will concentrate on the βcoreβ ones that will be needed to demonstrate the general principles: this Config
is the configuration, the Platform
platform, the OutputDirectory
path of the output file, and ConditionalDefines
(conditional compilation directives). The rest of the settings, if any need to be changed during assembly, I propose to identify yourself. This same .dproj
file, if you look into it with a regular text editor, is nothing more than an MSBuild build script(let's create a simple console application and call it DelphiAutomatedBuild ):
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{6880AD8E-6CB3-47B9-B8E3-7304CF6E9735}</ProjectGuid>
<ProjectVersion>18.1</ProjectVersion>
<FrameworkType>None</FrameworkType>
<MainSource>DelphiAutomatedBuild.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Console</AppType>
</PropertyGroup>
...
MSBuild build scripts are also used to describe projects, such as Visual Studio. I will touch on some details of MSBuild, but I suggest the reader to master its basics on its own . What does this give us? This allows us to build a Delphi project from the command line with one line ( which, in turn, allows us to automate the assembly of the project )
msbuild /t:build DelphiAutomatedBuild.dproj
MSBuild? Delphi, MSBuild , Delphi . , %WINDIR%\Microsoft.Net\Framework\v3.5
, .Net 4.0/4.5/4.6. Microsoft. MSBuild 4.0, ,
(hint: , () IDE β Show in Explorer, β ), :
...>msbuild /t:build DelphiAutomatedBuild.dproj
"msbuild"
, .
. , MSBuild- PATH
. :
set PATH=%WINDIR%\Microsoft.Net\Framework\v3.5;%PATH%
:
...>msbuild /t:build DelphiAutomatedBuild.dproj
Microsoft (R) Build Engine 12.0.21005.1
[Microsoft .NET Framework 4.0.30319.42000]
(C) (Microsoft Corporation). .
24.11.2018 0:12:14.
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" 1 ( build).
Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj : error MSB4057: "build".
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" ( build) .
.
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" ( build ) (1) ->
Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj : error MSB4057: "build".
: 0
: 1
: 00:00:00.04
, . ? build
?
.dproj
-, :
...
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
...
Delphi
c:\Program Files\Embarcadero\Studio\20.0\Bin\CodeGear.Delphi.Targets
, MSBuild-, Build
:
<Target Name="Build"...
.. BDS
($(VAR)
MSBuild (Property) VAR
, , ), Delphi, (-, Delphi, BDS
). $(BDS)
, .Targets
Delphi Build
.
:
set BDS=c:\Program Files\Embarcadero\Studio\20.0
...>msbuild /t:build DelphiAutomatedBuild.dproj
Microsoft (R) Build Engine 12.0.21005.1
[Microsoft .NET Framework 4.0.30319.42000]
(C) (Microsoft Corporation). .
24.11.2018 0:20:40.
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" 1 ( build).
CreateProjectDirectories:
".\Win32\Debug".
BuildVersionResource:
C:\Program Files\Embarcadero\Studio\20.0\bin\cgrc.exe -c65001 DelphiAutomatedBuild.vrc -foDelphiAutomatedBuild.res
CodeGear Resource Compiler/Binder
Version 1.2.2 Copyright (c) 2008-2012 Embarcadero Technologies Inc.
Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0
Copyright (C) Microsoft Corporation. All rights reserved.
"DelphiAutomatedBuild.vrc" .
_PasCoreCompile:
C:\Program Files\Embarcadero\Studio\20.0\bin\dcc32.exe -$O- -$W+ --no-config -B -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG -E.\Win32\Debug -I"c:\program files\embarcadero\studio\20.0\lib\Win32\debug";"c:\program files\embarcadero\studio\20.0\lib\Win32\release";C:\Users\USER\Documents\Embarcadero\Studio\20.0\Imports;"C:\Program Files\Embarcadero\Studio\20.0\Imports";"C:\Users\Public\Documents\RAD Studio\5.0\Dcp";"C:\Program Files\Embarcadero\Studio\20.0\include";C:\Users\USER\AppData\Local\Programs\TestInsight\Source -LE"C:\Users\Public\Documents\RAD Studio\5.0\Bpl" -LN"C:\Users\Public\Documents\RAD Studio\5.0\Dcp" -NU.\Win32\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;System;Xml;Data;Datasnap;Web;Soap; -O"c:\program files\embarcadero\studio\20.0\lib\Win32\release";C:\Users\USER\Documents\Embarcadero\Studio\20.0\Imports;"C:\Program Files\Embarcadero\Studio\20.0\Imports";"C:\Users\Public\Documents\RAD Studio\5.0\Dcp";"C:\Program Files\Embarcadero\Studio\20.0\include";C:\Users\USER\AppData\Local\Programs\TestInsight\Source -R"c:\program files\embarcadero\studio\20.0\lib\Win32\release";C:\Users\USER\Documents\Embarcadero\Studio\20.0\Imports;"C:\Program Files\Embarcadero\Studio\20.0\Imports";"C:\Users\Public\Documents\RAD Studio\5.0\Dcp";"C:\Program Files\Embarcadero\Studio\20.0\include";C:\Users\USER\AppData\Local\Programs\TestInsight\Source -U"c:\program files\embarcadero\studio\20.0\lib\Win32\debug";"c:\program files\embarcadero\studio\20.0\lib\Win32\release";C:\Users\USER\Documents\Embarcadero\Studio\20.0\Imports;"C:\Program Files\Embarcadero\Studio\20.0\Imports";"C:\Users\Public\Documents\RAD Studio\5.0\Dcp";"C:\Program Files\Embarcadero\Studio\20.0\include";C:\Users\USER\AppData\Local\Programs\TestInsight\Source -CC -V -VN -NB"C:\Users\Public\Documents\RAD Studio\5.0\Dcp" -NH"C:\Users\Public\Documents\RAD Studio\5.0\hpp\Win32" -NO.\Win32\Debug DelphiAutomatedBuild.dpr
Embarcadero Delphi for Win32 compiler version 30.0
Copyright (c) 1983,2015 Embarcadero Technologies, Inc.
19 lines, 0.27 seconds, 100748 bytes code, 26044 bytes data.
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" ( build).
.
: 0
: 0
: 00:00:01.32
-! . Win32\Debug
DelphiAutomatedBuild.exe
.
( , Debug-), Release- ( ). IDE , , , , . .dproj
-,
...
<Config Condition="'$(Config)'==''">Debug</Config>
...
, , / Config
, , Debug
. , IDE ( IDE Release β
...
<Config Condition="'$(Config)'==''">Release</Config>
...
:
{$IFDEF RELEASE}
WriteLn('This is RELEASE build');
{$ENDIF RELEASE}
{$IFDEF DEBUG}
WriteLn('This is DEBUG build');
{$ENDIF DEBUG}
, conditional defines Release Debug- RELEASE DEBUG,
Config
, :
...>msbuild /t:build DelphiAutomatedBuild.dproj /p:Config=Release
Microsoft (R) Build Engine 12.0.21005.1
[Microsoft .NET Framework 4.0.30319.42000]
(C) (Microsoft Corporation). .
24.11.2018 0:48:30.
"Z:\habr\delphi-automate-build\DelphiAutomatedBuild.dproj" 1 ( build).
CreateProjectDirectories:
".\Win32\Release".
...
...>Win32\Debug\DelphiAutomatedBuild.exe
This is DEBUG build
...>Win32\Release\DelphiAutomatedBuild.exe
This is RELEASE build
!
( ) - , , , β - . , . .dproj
:
...
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
...
? ( ), , ?
...>msbuild /t:build DelphiAutomatedBuild.dproj /p:DCC_ExeOutput=binaries
-! binaries
, β DelphiAutomatedBuild.exe
. ? , MSBuild
, , , MSBuild
-, , . . ...
. , (, ). , Config
β Debug
, β β Release
, , -, (, DCC_ExeOutput
( β )), -, , ( , MSBuild- ).
...>msbuild /t:build DelphiAutomatedBuild.dproj /p:DCC_ExeOutput=binaries
. ? !
Build
. - , IDE ( ; , MMX: DProjNormalizer, DProjSplitter β ProjectMagician β .dproj
-), . DAB.ciproj (CI-project, CI β Continuous Integration):
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<MSBuild Projects="DelphiAutomatedBuild.dproj"
Targets="Build"
Properties="Config=Debug"/>
<MSBuild Projects="DelphiAutomatedBuild.dproj"
Targets="Build"
Properties="Config=Release"/>
</Target>
</Project>
...>msbuild /t:build DAB.ciproj /p:DCC_ExeOutput=binaries
β¦ DelphiAutomatedBuild.exe
binaries
, , :
...>binaries\DelphiAutomatedBuild.exe
This is RELEASE build
DCC_Exeoutput
MSBuild β , . :
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<MSBuild Projects="DelphiAutomatedBuild.dproj"
Targets="Build"
Properties="Config=Debug;DCC_Exeoutput=$(DCC_ExeOutput)\Debug"/>
<MSBuild Projects="DelphiAutomatedBuild.dproj"
Targets="Build"
Properties="Config=Release;DCC_Exeoutput=$(DCC_ExeOutput)\Release"/>
</Target>
</Project>
...>msbuild /t:build DAB.ciproj /p:DCC_ExeOutput=binaries
binaries\Debug\DelphiAutomatedBuild.exe
binaries\Release\DelphiAutomatedBuild.exe
.
...>binaries\Debug\DelphiAutomatedBuild.exe
This is DEBUG build
...>binaries\Release\DelphiAutomatedBuild.exe
This is RELEASE build
, / conditional define (, -, , TRIAL )
-
{$IFDEF TRIAL}
WriteLn('This is TRIAL version');
{$ENDIF TRIAL}
Debug- conditional define TRIAL , .dproj:
<DCC_Define>DEBUG;TRIAL;$(DCC_Define)</DCC_Define>
, .. /p:DCC_Define=TRIAL,
...>msbuild /t:build DAB.ciproj /p:DCC_ExeOutput=binaries /p:DCC_Define=TRIAL
...>binaries\Debug\DelphiAutomatedBuild.exe
This is TRIAL version
...>binaries\Release\DelphiAutomatedBuild.exe
This is TRIAL version
, - , - DEBUG RELEASE, , .. define-.
, , . .
DCC_Define
:
...>set DCC_Define=TRIAL
...>msbuild /t:build DAB.ciproj /p:DCC_ExeOutput=binaries
...
...>binaries\Debug\DelphiAutomatedBuild.exe
This is DEBUG build
This is TRIAL version
...>binaries\Release\DelphiAutomatedBuild.exe
This is RELEASE build
This is TRIAL version
, , ( Git, SVN ) , , , , .
, . ? , , β - "-", , ( " " β ).
Windows/Delphi- Major.Minor.Release.Build
, , , Release
, , , . , , .dproj-
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
, . FileVersion=0.0.0.0
, , FileVersion=$(Version)
, Version
β , , , IDE β , .. "" . . , , β CSV-, .
, . MSBuild 4.0 C#, ( , PATH ).
Delphi.Version.Targets<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' ToolsVersion="12.0">
<UsingTask TaskName="__SetFileVersion" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
<ParameterGroup>
<VerInfoKeys ParameterType="System.String" Required="true" />
<VerInfoProperties ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<Out ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs"><![CDATA[
// split values as CSV (by ";")
String[] verInfoKeysList = VerInfoKeys.Split(';');
Dictionary<String, String> d = new Dictionary<String, String>();
foreach (String verInfoValue in verInfoKeysList) {
// split values as "key=value"
if (! String.IsNullOrEmpty(verInfoValue)) {
String[] kv = verInfoValue.Split('=');
d.Add(kv[0], kv[1]);
}
}
if (VerInfoProperties.Length > 0) {
foreach (ITaskItem item in VerInfoProperties) {
String value = item.GetMetadata("Value");
if (value.Length > 0) {
Log.LogMessage("{0}: {1}", item.ItemSpec, value);
d.Remove(item.ItemSpec);
d.Add(item.ItemSpec, value);
}
}
}
List<String> L = new List<String>();
foreach (KeyValuePair<String, String> kv in d) {
L.Add(kv.Key + "=" + kv.Value);
}
_Out = String.Join(";", L.ToArray());
]]></Code>
</Task>
</UsingTask>
<Target Name='_SetVersionCode_Name'>
<Message Text="$(VerInfo_Keys)" />
<ItemGroup>
<VerInfoProperties Include="FileVersion">
<Value>$(FileVersion)</Value>
</VerInfoProperties>
</ItemGroup>
<__SetFileVersion VerInfoKeys="$(VerInfo_Keys)" VerInfoProperties="@(VerInfoProperties)">
<Output PropertyName="VerInfo_Keys" TaskParameter="Out" />
</__SetFileVersion>
<Message Text="$(VerInfo_Keys)" />
</Target>
<Target Name='_SetFileVersion' BeforeTargets="_BuildRCFile"
Condition="'$(FileVersion)' != ''">
<CallTarget Targets='_SetVersionCode_Name'/>
</Target>
</Project>
.
DelphiAutomatedBuild.dproj
...
<Import Project="Delphi.Version.Targets" Condition="$(MSBuildToolsVersion) >= 4.0" />
...
( "$(MSBuildToolsVersion) >= 4.0" , IDE, , , MSBuild 3.5, UsingTask)
, _SetFileVersion
, _BuildRCFile
( : , β . $(BDS)\bin\Codegear.Common.Targets
), FileVersion
. CSV- VerInfo_Keys
, -, , VerInfo_Keys
.
"Include version information in project" ( ), :
...>msbuild /t:build DAB.ciproj /p:DCC_ExeOutput=binaries /p:FileVersion=4.3.2.1
...>binaries\Debug\DelphiAutomatedBuild.exe
This is RELEASE build
This is TRIAL version
This file version is 4.3.2.1
...>binaries\Release\DelphiAutomatedBuild.exe
This is DEBUG build
This is TRIAL version
This file version is 4.3.2.1
Profit!
Delphi- , , , , , , . , ( ), .
- ( FixInsight, !)
- unit- Delphi (, ))). )
- "" Delphi- GitLab CI
- as well as how you can use the WinDbg debugger, for example, to find the reasons for applications crashing / crashing due to libraries written in Delphi (well, of course, how to integrate the formation of PDB files necessary for this into auto-assembly)
Z.Y. I will be happy to answer any questions, including in a telegram, both in PM and in the @Delphi_Lazarus and @DelphiCommunity chats