使用 Jenkins 的多个 Delphi 版本:库路径
Multiple Delphi versions using Jenkins: library paths
我们正在考虑将我们的构建机器从 FinalBuilder 迁移到 Jenkins,以适应我们扩展公司的其他部分。
我注意到的一个问题是,虽然 Finalbuilder 能够从构建机器上当前 Delphi 安装中提取当前库路径,但 Jenkins 依赖于 .dproj 文件中包含的信息。
由于 .dproj 文件中路径的已知问题对用户机器非常特定,我们目前不将它们提交到我们的存储库,依赖 Delphi 根据需要重新创建它们.当构建机器首先依赖于完整的 MSBUILD 脚本时,这显然效果不佳。
我们使用了相当少的第三方组件(仅 DevExpress 套件就有超过 100 个单元),因此在 .dpr 中包含和维护所有具有完整路径的 .pas 文件并不是真正的选择。
有人对此有经过实践检验的解决方案吗?
我对选项的看法是:
- 为每个构建设置 %PATH% - 添加当前 Delphi 库
对于相关版本(这个运行会不会变成%PATH%长度限制?)
- 使用命令行参数将正确的库路径传递给 MSBUILD(这可能吗?)
- 在带有编译器指令的源文件中以某种方式包含搜索路径(这可能吗?)
- 使用预编译步骤创建新的 .dproj 文件(类似 http://delphi-divining.blogspot.co.uk/2012/10/dprojmaker-tool-to-create-delphi.html 但需要命令行)
编辑:第 5 个想法:
- 我们可以为每个项目使用 dproj.local 个文件,存储在单独的存储库(或单独的路径)中并复制到预构建的构建机器上吗?这将允许安全地存储构建机器路径,远离混乱的提交。
您需要将 .dproj
文件提交到源代码管理。
您的问题是您的配置不完整。任何构建系统都应该能够只使用源代码管理中的文件来构建项目,这是确保构建正确二进制文件的 ONLY 方法。
您有多种选择来完成这项工作
- 您可以在 Delphi IDE 中使用环境变量,例如
%ROOTFOLDER%
可以在一台机器上设置为 C:\Development\MyDelphiProjects,在另一台机器上设置为 C:\Dev 和只要从那条路线开始一切都一样就应该没问题。每个开发人员和您的构建机器都可以设置所需的路径。您可能还需要 bpl 路径的变量。
- 在客户端机器上强制执行相同的结构。让所有开发者都以 C:\Development\Delphi 作为他们的根目录真的有多难?
- 确保所有搜索路径都是相对的。这可以工作,但总是有异常导致问题,所以我从来没有设法让它工作。
我们在以前的公司使用了选项 1,它运行得非常成功,设置起来有点麻烦,但是一旦设置好,您就可以确定您的构建是正确的。
当我选择 Jenkins 作为 "build" 环境时,我遇到了同样的问题。解决方案是使用内部包含构建任务的 MSBuild 脚本。所以在 Jenkins 中不是直接构建项目,而是构建这个脚本,它为您提供了更多选项,包括指定项目路径的选项(您可以覆盖默认的 IDE 路径)。
明天我post这样的脚本
因此在 Jenkins 中,当您配置 MSBuild 时,您必须指定 msbuild 文件,它将是 Build.xml。对于命令行参数,我只使用 /v - 冗长和 /t - 目标名称。
构建脚本如下所示:
<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.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>
这里缺少的是版本控制部分,可以使用资源模板从此脚本完成...
我们正在考虑将我们的构建机器从 FinalBuilder 迁移到 Jenkins,以适应我们扩展公司的其他部分。
我注意到的一个问题是,虽然 Finalbuilder 能够从构建机器上当前 Delphi 安装中提取当前库路径,但 Jenkins 依赖于 .dproj 文件中包含的信息。
由于 .dproj 文件中路径的已知问题对用户机器非常特定,我们目前不将它们提交到我们的存储库,依赖 Delphi 根据需要重新创建它们.当构建机器首先依赖于完整的 MSBUILD 脚本时,这显然效果不佳。
我们使用了相当少的第三方组件(仅 DevExpress 套件就有超过 100 个单元),因此在 .dpr 中包含和维护所有具有完整路径的 .pas 文件并不是真正的选择。
有人对此有经过实践检验的解决方案吗?
我对选项的看法是:
- 为每个构建设置 %PATH% - 添加当前 Delphi 库 对于相关版本(这个运行会不会变成%PATH%长度限制?)
- 使用命令行参数将正确的库路径传递给 MSBUILD(这可能吗?)
- 在带有编译器指令的源文件中以某种方式包含搜索路径(这可能吗?)
- 使用预编译步骤创建新的 .dproj 文件(类似 http://delphi-divining.blogspot.co.uk/2012/10/dprojmaker-tool-to-create-delphi.html 但需要命令行)
编辑:第 5 个想法:
- 我们可以为每个项目使用 dproj.local 个文件,存储在单独的存储库(或单独的路径)中并复制到预构建的构建机器上吗?这将允许安全地存储构建机器路径,远离混乱的提交。
您需要将 .dproj
文件提交到源代码管理。
您的问题是您的配置不完整。任何构建系统都应该能够只使用源代码管理中的文件来构建项目,这是确保构建正确二进制文件的 ONLY 方法。
您有多种选择来完成这项工作
- 您可以在 Delphi IDE 中使用环境变量,例如
%ROOTFOLDER%
可以在一台机器上设置为 C:\Development\MyDelphiProjects,在另一台机器上设置为 C:\Dev 和只要从那条路线开始一切都一样就应该没问题。每个开发人员和您的构建机器都可以设置所需的路径。您可能还需要 bpl 路径的变量。 - 在客户端机器上强制执行相同的结构。让所有开发者都以 C:\Development\Delphi 作为他们的根目录真的有多难?
- 确保所有搜索路径都是相对的。这可以工作,但总是有异常导致问题,所以我从来没有设法让它工作。
我们在以前的公司使用了选项 1,它运行得非常成功,设置起来有点麻烦,但是一旦设置好,您就可以确定您的构建是正确的。
当我选择 Jenkins 作为 "build" 环境时,我遇到了同样的问题。解决方案是使用内部包含构建任务的 MSBuild 脚本。所以在 Jenkins 中不是直接构建项目,而是构建这个脚本,它为您提供了更多选项,包括指定项目路径的选项(您可以覆盖默认的 IDE 路径)。 明天我post这样的脚本
因此在 Jenkins 中,当您配置 MSBuild 时,您必须指定 msbuild 文件,它将是 Build.xml。对于命令行参数,我只使用 /v - 冗长和 /t - 目标名称。
构建脚本如下所示:
<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.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>
这里缺少的是版本控制部分,可以使用资源模板从此脚本完成...