Sunday, April 27, 2014

Building Delphi VCL Packages From the Command-line Using PowerShell and MSBuild - Part 3

This is a continuation of part 2.

MSBuild Parameters

Now that MSBuild is successfully compiled my project, the following questions came up in my mind:
  • Does Delphi call DCC or MSBuild?
  • What parameters can I pass in?
To answer the first question, I loaded Delphi and compiled the VCL package. I paid careful attention to the output. The screen appeared as follows:

Based on the highlighted output in the previous screenshot, I came to three conclusions:
  1. Delphi built the .dproj file, so the IDE must launch MSBuild to compile the project.
  2. Delphi built the project in Debug mode, so there must be an MSBuild parameter to specify the build configuration.
  3. Delphi built the project for the Win32 platform, so there must be an MSBuild parameter to specify the platform.
My next step was to open the .dproj file and look at what MSBuild parameters were available in there. I thought the following seemed important:

<PropertyGroup Condition="('$(Platform)'=='Win64'...
...
<PropertyGroup Condition="'$(Config)'=='Release'...
...
<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
This looked promising!  Based on these three XML snippets, I came to three more conclusions:
  1. The MSBuild parameter for specifying the build configuration is called Config.
  2. The MSBuild parameter for specifying the build platform is called Platform.
  3. Embarcadero ships a default target file, located under $(BDS)\Bin\CodeGear.Delphi.Targets.
To test out my conclusions, I decided to manually try to reproduce what the IDE had done from the command line. I entered the following:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ZLibEx_XE2.dproj /p:Config=Debug /p:Platform=Win32
It compiled successfully. Then, I replaced Win32 with Win64.  Sure enough, it failed due to the ZLibEx obj files being 32-bit. I had only one question left:
  • How could I override where to put the DCU files?
I could not find anything in the .dproj file. The only other option I could think of was to open the CodeGear.Delphi.Targets file. Sure enough, there it was:

<DCC_ObjOutput Condition = " '$(DCC_ObjOutput)' == ''">$(DCC_DcuOutput)</DCC_ObjOutput>
That was the answer I needed. The parameter I was looking for was DCC_DcuOutput. So, for my final test, I ran:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ZLibEx_XE2.dproj /p:Config=Debug /p:Platform=Win32 /p:DCC_DcuOutput=C:\Temp\DCU
Sure enough, my DCU files ended up under C:\Temp\DCU. Perfect! By that point, I was ready to start my PowerShell module.

Building Delphi VCL Packages From the Command-line Using PowerShell and MSBuild - Part 2

This is part 2 of the series, continuing from part 1.

MSBuild Prerequisites

MSBuild is installed along with the .NET framework, so I knew it was already on my computer.

The next thing I needed to do was to figure out how to compile a project using MSBuild. So, I started by opening a command-prompt, navigating to my ZLibEx package, and running:

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ZLibEx_XE2.dproj

It failed with the following error:

C:\VCL\ZLibEx\ZLibEx_XE2.dproj : error MSB4040: There is no target in the project.
Of course, there probably needed to be some environment variables defined.  So, I looked at the shortcut properties for the RAD Studio Command Prompt shortcut on my start menu. It ran a .bat file that registers some environment variables that were located at:
C:\Program Files (x86)\Embarcadero\RAD Studio\9.0\bin\rsvars.bat
Next, I cracked open that .bat file to see what the magic vars were. I thought the following lines looked important:
@SET BDS=C:\Program Files (x86)\Embarcadero\RAD Studio\9.0
@SET BDSCOMMONDIR=C:\Users\Public\Documents\RAD Studio\9.0
@SET FrameworkDir=C:\Windows\Microsoft.NET\Framework\v3.5
@SET FrameworkVersion=v3.5
 So, I pasted each one of those in at my command prompt. I then ran my initial command one more time:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe ZLibEx_XE2.dproj
It compiled successfully!

Part 3

Building Delphi VCL Packages From the Command-line Using PowerShell and MSBuild - Part 1


Introduction


Three years ago, feeling concerned about the future of Delphi, I left my Delphi position in favor of a C# position. I soon found myself working in a Configuration Management / DevOps / Internal Tools Developer role. During this time, I was required to master MSBuild technologies. One of my responsibilities was to automate the build and deployment of thousands of projects on a daily basis.  Needless to say, I learned the ins and outs of MSBuild.

A little over a year ago, I opened up Delphi. It brought back memories of my 11-year long career in Delphi. Some of them were good. Some of them were bad.

One of the worst memories it brought back was that of installing VCL packages. To be able to open up one of my Delphi projects, I remembered that I would first have to manually compile and install over 15 VCL packages. Some of those consisted of multiple VCL projects.

I remembered this used to take my over 16 hours to complete in the past. Being a DevOps professional at my new full-time job, I wanted to tackle this he right way. I was going to automate the installation of my VCL packages from the command-line.

Being very familiar with PowerShell, I decided to build a PowerShell module that was capable of automatically building my VCL dependencies from the command-line. My first attempt was to use the DCC.exe compiler. After sixteen hours of labor and discovering undocumented "features" the hard way, I finally managed to compile my entire VCL.

Thinking I had done something amazing, I shared the project with my former team. Being the Delphi control-freaks they are, I could tell the thought of doing anything related to code in an automated fashion was very difficult to accept! But, I was persistent. Before long, one of them even set up a Jenkins server. I was impressed. It was around that time that I enrolled in school.

Now, here I am a year later, revisiting Delphi. I first decided to check on my script. I ran it with the latest source. It failed to compile!  It was failing because somebody had added a CodeSite dependency to one of my VCL packages.

Exploring around the file system to find a solution to my dilemma, I happened to open a .dproj file.  Lo and behold, it was an MSBuild project! I had been working in Delphi for 11 years, and did not even know what MSBuild was! Now I had a new objective: Update my PowerShell scripts to compile my VCL packages in Delphi using MSBuild instead of DCC32 and DCC64. I will report my progress in future parts of this series.

Part 2