Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple Delphi versions using Jenkins: library paths

We are looking at migrating our build machine from FinalBuilder to Jenkins to fit in with the rest of our extended company.

One issue that I have noticed is that whereas Finalbuilder is able to extract the current library path from your current Delphi installs on the build machine, Jenkins relies on the information contained within the .dproj files.

Owing to known problems of the paths within the .dproj files being very specific to a users machine, we don't currently commit them to our repository, relying on Delphi to re-create them as required. This obviously doesn't play nice when the build machine is reliant on a full MSBUILD script being there in the first place.

We use a fair few third-party components (DevExpress suite alone having over 100 units), so including and maintaining all the .pas files with full paths in the .dpr isn't really an option for this.

Does anyone have a tried-and-tested solution for this?

My thoughts on options were:

  • setting the %PATH% for each build - adding the current Delphi library for the relevant version (will this run into %PATH% length restrictions?)
  • Using a command-line parameter to pass the correct library path to MSBUILD (is this possible?)
  • Including the search path somehow in the source files with compiler directives (is this possible?)
  • Using a pre-compile step to create new .dproj files (something like http://delphi-divining.blogspot.co.uk/2012/10/dprojmaker-tool-to-create-delphi.html but it'll need to be command-line)

Edit: 5th idea:

  • Could we use dproj.local files for each project, stored in a separate repository (or in a separate path) and copied to the build machine pre-build? This would allow build machine paths to be stored safely away from clutzy commits.
like image 463
Matt Allwood Avatar asked Aug 07 '15 10:08

Matt Allwood


2 Answers

You need to submit your .dproj file to source control.

You have a problem which is that your configuration is not complete. Any build system should be able to build your project using nothing but files in your source control, that is the ONLY way to ensure you are building the correct binary.

You have a number of options to make this work

  1. You can use Environment variables in the Delphi IDE eg %ROOTFOLDER% could be set to C:\Development\MyDelphiProjects on one machine and C:\Dev on another and as long as everything is the same from that route it should be ok. Each dev and your build machine can set the required path. You may need vars for bpl paths also.
  2. Enforce identical structures on client machines. Really how difficult is it to make all devs us C:\Development\Delphi as their root?
  3. Make sure all search paths are relative. This can work, but there are always exceptions that cause problems so I have never managed to get this to work.

We used option 1 in a previous company and it worked very successfully, its a bit of a pain to set up but once setup you can be sure your build is correct.

like image 101
Toby Allen Avatar answered Nov 04 '22 00:11

Toby Allen


I had the same problem when i choose Jenkins as a "build" environment. The solution is to use a MSBuild script with a build task inside. So in Jenkins instead of building the project directly, just build this script which gives you a lot more options, including the option to specify the paths for the project (you can to override the default IDE paths). I'll post such a script tomorrow.

So in Jenkins when you configure MSBuild you have to specify the msbuild file, which will be Build.xml. For command line arguments i use only /v - verbosity and /t - target name.

The build script looks like this:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <Target Name="Compile" DependsOnTargets="CompileApp" />

  <PropertyGroup>
    <ExeOutputName>App.exe</ExeOutputName>
    <ExeOutputPath>x:\exe</ExeOutputPath>
    <DcuOutputPath>x:\dcu</DcuOutputPath>

    <ForConfig>Release</ForConfig>
    <ForPlatform>Win32</ForPlatform>
  </PropertyGroup>

  <Target Name="ResolveOutputPath">
    <MakeDir Directories="$(ExeOutputPath)" />
    <MakeDir Directories="$(DcuOutputPath)" />
    <Delete Files="$(ExeOutputPath)\$(ExeOutputName)" />
    <Delete Files="$(DcuOutputPath)\*.*" />
  </Target>

  <ItemGroup>
    <AppUnitSearchPathItem Include="$(BDS)\lib\$(ForPlatform)\$(ForConfig)" />
    <AppUnitSearchPathItem Include="C:\Users\builder\Documents\tmssoftware\TMS Component Pack" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Dcu\$(ForPlatform)" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\CodeGen" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\DataSnap" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\ZLib" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\RemObjects Software\RemObjects SDK for Delphi\Source\Synapse" />
    <AppUnitSearchPathItem Include="C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\Components\EhLib\Lib\$(ForPlatform)\$(ForConfig)" />
    ...
  </ItemGroup> 

  <ItemGroup>
    <AppDefinesItem Include="App" />
    <!-- AppDefinesItem Include="CompilerDirective" -->
  </ItemGroup>

  <ItemGroup>
    <AppPropertiesItem Include="DCC_ExeOutput=$(ExeOutputPath)" />
    <AppPropertiesItem Include="DCC_DcuOutput=$(DcuOutputPath)" />
    <AppPropertiesItem Include="DCC_BuildAllUnits=true" />
    <AppPropertiesItem Include="DCC_Optimize=true" />
    <AppPropertiesItem Include="DCC_DebugInformation=0" />
    <AppPropertiesItem Include="DCC_PentiumSafeDivide=true" />
    <AppPropertiesItem Include="DCC_RangeChecking=true" />
    <AppPropertiesItem Include="DCC_IntegerOverflowCheck=true" />
    <AppPropertiesItem Include="DCC_WriteableConstants=true" />
    <AppPropertiesItem Include="DCC_IOChecking=true" />
    <AppPropertiesItem Include="DCC_AssertionsAtRuntime=false" />
    <AppPropertiesItem Include="DCC_Warnings=true" />
    <AppPropertiesItem Include="DCC_MapFile=3" />
    <AppPropertiesItem Include="DCC_ConsoleTarget=false" />
  </ItemGroup>

  <Target Name="CompileApp" DependsOnTargets="ResolveOutputPath">
    <PropertyGroup>
      <AppUnitSearchPath>@(AppUnitSearchPathItem)</AppUnitSearchPath>
      <AppDefines>@(AppDefinesItem)</AppDefines>
    </PropertyGroup>

    <ItemGroup>
      <AppProperties Include="Config=$(ForConfig)" />
      <AppProperties Include="Platform=$(ForPlatform)" />
      <!-- AppProperties Include="LibraryPath=$(AppUnitSearchPath)" -->
      <AppProperties Include="DelphiLibraryPath=$(AppUnitSearchPath)" />
      <AppProperties Include="UnitSearchPath=$(AppUnitSearchPath)" />
      <AppProperties Include="ResourcePath=$(AppUnitSearchPath)" />
      <AppProperties Include="IncludePath=$(AppUnitSearchPath)" />
      <AppProperties Include="ObjPath=$(AppUnitSearchPath)" />
      <AppProperties Include="DCC_Define=$(AppDefines)" />
      <AppProperties Include="@(AppPropertiesItem)" />
    </ItemGroup>

    <MSBuild Projects="App.dproj" Properties="@(AppProperties)" />
  </Target>
</Project>

What is missing here is the versioning part which can be done from this script using a resource template...

like image 42
Sotirca Mihaita George Avatar answered Nov 04 '22 00:11

Sotirca Mihaita George