Compilación automatizada de una aplicación Delphi

Muy a menudo, me encontré con el hecho de que los desarrolladores de Delphi (se puede decir tradicionalmente) compilan sus aplicaciones con "bolígrafos", lo que está lejos de ser una solución de producción, pero desde el exterior parece exfoliante y "hacerlo en la rodilla" , aunque los productos son muy serios y vendibles . Esto probablemente se remonta a la época en que para la automatización era necesario crear sus propios archivos por lotes que iniciaran el compilador de línea de comandos dcc32con los parámetros necesarios. Algunos incluso crearon su propio "Editor" - Delphi-expert, que hace el trabajo del servidor de ensamblaje: compila el proyecto (aunque está abierto en el IDE), exponiéndolo con un número de versión incrementado tomado de alguna base de datos, escribe algún tipo de registro de cambios y lo copia en algún lugar directorio de red .


No entraré en la excursión histórica como era antes . Te diré cómo comer / lata ahora, y cómo usarlo para aumentar la eficiencia de mi trabajo.


El archivo del proyecto de la versión moderna de Delphi es un .dprojarchivo (en adelante me centraré en Delphi 10 Rio, pero con ligeras diferencias esto es cierto para todas las versiones anteriores de Delphi, a partir de 2007). Almacena todas las configuraciones del proyecto, que generalmente se cambian en el IDE (menú Project - Options (Ctrl+Shift+F11)). En este artículo, me concentraré en los "básicos" que serán necesarios para demostrar los principios generales: esta Configes la configuración, la Platformplataforma, la OutputDirectoryruta del archivo de salida y ConditionalDefines(directivas de compilación condicional). El resto de las configuraciones, si es necesario cambiar alguna durante el ensamblaje, propongo identificarse. Este mismo .dprojarchivo, si lo examina con un editor de texto normal, no es más que un script de compilación MSBuild( creemos una aplicación de consola simple y llamémosla 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>
    ...

Los scripts de compilación de MSBuild también se usan para describir proyectos, como Visual Studio. Tocaré algunos detalles de MSBuild, pero sugiero al lector que domine sus conceptos básicos por sí mismo . ¿Qué nos da esto? Esto nos permite construir un proyecto Delphi desde la línea de comando con una línea ( que, a su vez, nos permite automatizar el ensamblaje del proyecto )


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


. , (, ). , ConfigDebug, — — Release, , -, (, DCC_ExeOutput ( — )), -, , ( , MSBuild- ).


...>msbuild /t:build DelphiAutomatedBuild.dproj /p:DCC_ExeOutput=binaries

. ? !
Build. - , IDE ( ; , MMX: DProjNormalizer, DProjSplitterProjectMagician.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. así como también cómo puede usar el depurador WinDbg, por ejemplo, para encontrar las razones de los bloqueos / bloqueos de la aplicación debido a bibliotecas escritas en Delphi (bueno, por supuesto, cómo integrar la formación de archivos PDB necesarios para esto en el autoensamblaje)

Z.Y. Estaré encantado de responder cualquier pregunta, incluso en un telegrama, tanto en PM como en los chats @Delphi_Lazarus y @DelphiCommunity


All Articles