Construction automatisée d'une application Delphi

Très souvent, je suis tombé sur le fait que les développeurs Delphi (on peut dire traditionnellement) compilent leurs applications avec des «stylos», ce qui est loin d'être une solution de production, mais de l'extérieur ressemble à frotter et «faire à genoux» , bien que les produits soient très sérieux et vendables . Cela remonte probablement à l'époque où pour l'automatisation, il était nécessaire de créer vos propres fichiers de commandes qui ont démarré le compilateur de ligne de commande dcc32avec les paramètres nécessaires. Certains ont même créé leur propre «éditeur» - Delphi-expert, qui fait le travail du serveur d'assemblage: compile le projet (bien qu'il soit ouvert dans l'EDI), l'expose avec un numéro de version incrémenté provenant d'une base de données, écrit une sorte de journal des modifications et le copie quelque part dans répertoire réseau .


Je n'entrerai pas dans l'excursion historique comme avant . Je vais vous dire comment manger / peut maintenant et comment l'utiliser pour augmenter l'efficacité de mon travail.


Le fichier de projet de la version moderne de Delphi est un .dprojfichier (ci-après je me concentrerai sur Delphi 10 Rio, mais avec de légères différences, cela est vrai pour toutes les versions antérieures de Delphi, à partir de 2007). Il stocke tous les paramètres du projet, qui sont généralement modifiés dans l'IDE (menu Project - Options (Ctrl+Shift+F11)). Dans cet article, je me concentrerai sur ceux «de base» qui seront nécessaires pour démontrer les principes généraux: il Configs'agit de la configuration, de la Platformplate - forme, du OutputDirectorychemin du fichier de sortie et ConditionalDefines(directives de compilation conditionnelle). Le reste des réglages, si besoin est à changer lors du montage, je vous propose de vous identifier. Ce même .dprojfichier, si vous l'examinez avec un éditeur de texte normal, n'est rien de plus qu'un script de construction MSBuild(créons une application console simple et appelons-la 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>
    ...

Les scripts de génération MSBuild sont également utilisés pour décrire des projets, tels que Visual Studio. Je vais aborder certains détails de MSBuild, mais je suggère au lecteur de maîtriser ses bases par lui-même . Qu'est-ce que cela nous donne? Cela nous permet de construire un projet Delphi à partir de la ligne de commande avec une seule ligne ( ce qui, à son tour, nous permet d'automatiser l'assemblage du projet )


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. ainsi que la façon dont vous pouvez utiliser le débogueur WinDbg, par exemple, pour trouver les raisons des plantages d'application / plantages dus aux bibliothèques écrites en Delphi (enfin, bien sûr, comment intégrer la formation des fichiers PDB nécessaires pour cela dans l'auto-assemblage)

Z.Y. Je serai heureux de répondre à toutes les questions, y compris dans un télégramme, à la fois dans PM et dans les chats @Delphi_Lazarus et @DelphiCommunity


All Articles