使用Jenkins管理多个Delphi版本:库路径

7
我们正在考虑将我们的构建机从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文件吗?这将允许构建机器路径安全地存储,远离笨拙的提交。

将所有第三方库放入项目和版本控制系统存储库中是答案。无法想象为什么您要回避可重现的构建。为什么要寻求版本地狱呢? - David Heffernan
2个回答

8
您需要将.dproj文件提交到源代码控制中。
您存在一个问题,即配置不完整。任何构建系统只应使用源代码控制中的文件构建项目,这是确保构建正确二进制文件的唯一方法。
您有多种选择可以使其工作:
  1. 您可以在Delphi IDE中使用环境变量,例如%ROOTFOLDER%可在一台机器上设置为C:\Development\MyDelphiProjects,而在另一台机器上设置为C:\Dev,并且只要从该路径访问所有内容相同,就应该没问题。每个开发人员和您的构建机器都可以设置所需的路径。您可能还需要对bpl路径进行变量设置。
  2. 强制客户端机器上具有相同的目录结构。实际上,让所有开发人员使用C:\Development\Delphi作为根目录有多难呢?
  3. 确保所有搜索路径均为相对路径。这可能有效,但总会有例外情况会导致问题,因此我从未成功过。
我们在以前的公司中使用了选项1,并且取得了非常成功的效果,设立有点麻烦,但一旦设置完成,您就可以确信构建是正确的。

希望能避免这种情况 :-/ 我们在dproj上还有其他问题,主要是由于通过参数传递我们的DB连接/授权设置,而在IDE中存储在.dproj中。这意味着它对每个用户都会不断变化,并且经常被意外检查。dproj.local可能有助于解决这个问题,但我需要更多的阅读。实际上,这给了我第五个想法... - Matt Allwood

4
当我选择Jenkins作为“构建”环境时,我遇到了同样的问题。解决方案是使用一个带有构建任务的MSBuild脚本。因此,在Jenkins中,不要直接构建项目,而是构建此脚本,这会给您更多选项,包括指定项目路径的选项(您可以覆盖默认IDE路径)。 明天我会发布这样的脚本。
因此,在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\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>

这里缺少版本控制的部分,可以使用资源模板从此脚本中完成...

太好了,谢谢。我知道理想情况是从正确的.dproj构建,但我们在我们的.dproj文件上有许多嵌入式解决方法被覆盖在仓库中,我不想拆开它们,所以像这样的东西听起来很完美。 - Matt Allwood
@MattAllwood 我已经更新了答案。希望这可以帮到你。 - Sotirca Mihaita George
我注意到了这个问题。目前,我需要更深入地考虑一下,因为我们的 .dproj 文件在很长时间未被使用后变得有些混乱(我们旧的构建流程甚至有一个过时的“模板”,每个项目都要复制一份以防止编译器报错)。等我有机会整理清楚我们正在做什么后,我会接受一个答案。 - Matt Allwood
我接受了回答问题的挑战,但我认为我们需要重新考虑构建流程,试图避免问题而不是尝试解决它。 - Matt Allwood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接