Automatisierte Erstellung einer Delphi-Anwendung

Sehr oft bin ich auf die Tatsache gestoßen, dass Delphi-Entwickler (man kann traditionell sagen) ihre Anwendungen mit „Stiften“ kompilieren, was weit von einer Produktionslösung entfernt ist, aber von außen wie Peeling und „Mach es auf dem Knie“ aussieht , obwohl die Produkte sehr seriös und verkaufsfähig sind . Dies ging wahrscheinlich auf die Zeit zurück, als für die Automatisierung eigene Batch-Dateien erstellt werden mussten , mit denen der Befehlszeilen-Compiler dcc32mit den erforderlichen Parametern gestartet wurde . Einige haben sogar ihren eigenen "Publisher" - Delphi-Experten erstellt, der die Arbeit des Assemblyservers erledigt: Kompiliert das Projekt (obwohl in der IDE geöffnet), macht es mit einer inkrementierten Versionsnummer aus einer Datenbank verfügbar, schreibt eine Art Änderungsprotokoll und kopiert es irgendwo hinein Netzwerkverzeichnis .


Ich werde nicht wie zuvor auf den historischen Ausflug eingehen . Ich werde Ihnen sagen, wie Sie jetzt essen / können und wie Sie damit die Effizienz meiner Arbeit steigern können.


Die Projektdatei der modernen Version von Delphi ist eine .dprojDatei (im Folgenden werde ich mich auf Delphi 10 Rio konzentrieren, aber mit geringfügigen Unterschieden gilt dies für alle früheren Versionen von Delphi ab 2007). Es speichert alle Projekteinstellungen, die normalerweise in der IDE (Menü Project - Options (Ctrl+Shift+F11)) geändert werden . In diesem Artikel werde ich mich auf die „Kern“ konzentrieren, die zur Demonstration der allgemeinen Prinzipien benötigt werden: Dies Configist die Konfiguration, die PlatformPlattform, der OutputDirectoryPfad der Ausgabedatei und ConditionalDefines(Anweisungen zur bedingten Kompilierung). Die restlichen Einstellungen, falls während der Montage geändert werden müssen, schlage ich vor, Sie zu identifizieren. Dieselbe .dprojDatei ist, wenn Sie sie mit einem normalen Texteditor untersuchen, nichts anderes als ein MSBuild- Erstellungsskript(Erstellen wir eine einfache Konsolenanwendung und nennen sie 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-Skripte werden auch zur Beschreibung von Projekten wie Visual Studio verwendet. Ich werde auf einige Details von MSBuild eingehen, aber ich empfehle dem Leser, seine Grundlagen selbst zu beherrschen . Was gibt uns das? Auf diese Weise können wir ein Delphi-Projekt über die Befehlszeile mit einer Zeile erstellen ( wodurch wir wiederum die Montage des Projekts automatisieren können ).


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- , , , , , , . , ( ), .



  1. ( FixInsight, !)
  2. unit- Delphi (, ))). )
  3. "" Delphi- GitLab CI
  4. sowie wie Sie den WinDbg-Debugger verwenden können, um beispielsweise die Gründe für das Abstürzen / Abstürzen von Anwendungen aufgrund von in Delphi geschriebenen Bibliotheken zu finden (und natürlich, wie Sie die dafür erforderliche Bildung von PDB-Dateien in die automatische Assemblierung integrieren können).

Z.Y. Gerne beantworte ich alle Fragen, auch in einem Telegramm, sowohl in PM als auch in den Chats @Delphi_Lazarus und @DelphiCommunity


All Articles