使用我自己构建的调试库和常规DCU在Delphi中管理非常大的代码库

时间:2015-02-20 14:26:37

标签: delphi packages delphi-xe6 delphi-xe7

我正在尝试解决此编译错误,仅在Debug配置中发生,并且仅在下面描述的情况下:

[dcc32 Fatal Error] MyIndyTCPChannel.pas(22): F2051 Unit IdIOHandlerSocket was compiled with a different version of IdGlobal.IdDisposeAndNil

我正在开发一个非常大的Delphi代码库,拥有250万行内部代码和300万行组件代码,其中包括几个大型商业Delphi组件套件(Developer Express,TeeChart等),以及大量的开源delphi组件,加上一个相当大的内部开发组件集,编号252个包,其中大约140个是设计时+运行时或设计时,其他是运行时包(也是加载的,在运行时通过其相关的设计时包中的DLL依赖项进入IDE。

我们的主库路径已经优化到尽可能小,并且它包含Delphi附带的路径作为标准,再加上我们添加的三个路径,主要路径是单个" OurCompanyLibraryDCU"文件夹,其中包含两个平台的文件夹和我们使用的两种配置:

c:\dev\OurCompanyLibraryDCU\Win32\Release
c:\dev\OurCompanyLibraryDCU\Win32\Debug
c:\dev\OurCompanyLibraryDCU\Win64\Release
c:\dev\OurCompanyLibraryDCU\Win32\Debug

上述每个文件夹都包含一个文件夹中的BPL,DCP和DCU文件集,用于该平台/配置组合。

使用了项目选项中的如下宏,因此我们可以更改平台和配置,并正确解析目录:

$(OURCOMPANYLIBRARYDCU)\$(Platform)\$(Config)

OURCOMPANYLIBRARYDCU是一个环境变量,$(X)是扩展环境变量的语法,在Delphi IDE的上下文中。

我正在尝试将最重要和最大的VCL应用程序项目(称为BigApp.dproj)构建,以便项目搜索目录仅包含我们的APPLICATION源文件夹,并且不需要项目搜索路径来包含我们所有的第三个派对组件LIBRARY源代码。为此,我们需要链接调试DCU或释放DCU。

到目前为止,除了可以使用Debug和Release DCU的情况外,我们一切正常。版本DCU位于库路径中,调试DCU位于IDE设置中的Debug DCU路径中。面对这两个库之间的选择,Delphi的链接器似乎失败,每当存在两组DCU时,这种形式出现错误,当我单击Build时,Build Configuration设置为Release,I得到F2051错误。 F2051错误的普通原因是存在多个不兼容的二进制DCU并且都是可访问的,并且链接器无法使其全部工作。但是,如果你想在库路径中同时使用Debug和Release DCU,我认为这种情况不会发生,因为链接器会为你选择调试或释放DCU。

如果我没有构建调试DCU,则不会发生上述问题。我怀疑我的调试DCU是微妙的"无效"或者说Delphi中的Debug-DCU选择算法不起作用,但不知道为什么,或者如何解决这个问题。

多部分问题:

一个。每个平台/配置组合都有一个文件夹,在单个文件夹中包含DCU,BPL和DCP,然后添加到已知导致问题的IDE库路径中?我是否需要三个子文件夹,每个平台+ config + filetype共有12个文件夹,或者我可以通过platform + config将它们保存在一起吗?

B中。在包编译情况下,是否可以让IDE库路径包含OurCompanyLibraryDCU文件夹,并将该文件夹配置为DCP输出目录,包输出目录和单元输出目录?我担心的是,通过使输入文件夹和输出文件夹相同,有一种情况是编译器可能无法从.pas源重建单元,并且只是链接先前编译的DCU。

enter image description here

℃。如果我犯了这个错误,那么我应该如何防止每次构建BigApp时从源代码编译超过250万行的组件LIBRARY代码,而只是通过DCU链接它们,并且仍然有调试并释放dcus正常工作?

d。如果我转到Win32 \ Debug文件夹并删除IdGlobal.dcu,我可以通过原始错误。这告诉我,我的包编译(用于调试配置)正在生成INVALID IdGlobal.dcu。这甚至可能吗? delphi可以静默输出乱码的DCU吗?

注意:我没有使用,也无法使用运行时包来处理应用程序大小问题。

更新:我应该在这里做的第一件事就是验证ZERO额外的DCU文件在我的硬盘驱动器上是任何地方,无论如何。这是标准的F2051错误建议。在我处理完这个问题之后,我会更新这个问题。德尔福本身可能会将DCU从一个地方复制到另一个地方,或者不在CURRENT搜索路径中的虚假DCU可能已经在某个其他项目的搜索路径中。可能会出现一种坏DCU拷贝的桶式旅。一旦我确定发生了什么样的坏DCU代或副本,我就会更新问题。

更新2:我现在保证在构建之前不存在IdGlobal.dcu的额外副本,并且问题仍然存在。因此,问题随后打开了构建IdGlobal.dcu时使用的编译器选项,版本化了在Debug构建中构建BigApp.dproj时使用的编译器选项。

更新3:虽然我的所有程序包编译似乎都没有错误,但在启动DCC32.exe或MSBUILD.exe构建程序包期间,它们似乎没有使用正确的库搜索路径。这个库路径不一致问题似乎是核心问题,感谢Rufo爵士指出这一点。

2 个答案:

答案 0 :(得分:8)

也许我可以对提交给编译器的搜索路径的顺序有所了解,这应该清楚地说明为什么问题首先发生并且可以通过添加Debug DCU路径来解决(至少在你的情况下)那个具体的位置。所有这些观察都是用XE7进行的。

IDE中有几个地方可以指定搜索路径:

  1. 图书馆路径(Delphi-Options - Library)
  2. 翻译的库路径(Delphi-Options - Library-Translated)
  3. 调试DCU路径(Delphi-Options - Library)
  4. 翻译的调试DCU路径(Delphi-Options - Library-Translated)
  5. 搜索路径(通过项目选项)
  6. 当Library语言设置为英语时,根据 Use debug .dcus 的设置,这些路径将以5,1或3,5,1的顺序提供给编译器。这已经有点奇怪,因为debug dcu路径优先于项目搜索路径。

    所以f.i.为了让编译器找到我们自己的新版Indy版本的dcu文件,我们必须在1和3下面的pathes前面放置相应的pathes。

    现在,当图书馆语言被设置为与英语不同的东西时,事情会变得复杂。在这种情况下,根据使用debug .dcus 的设置,翻译后的pathes会发挥作用,产生2,5,1或4,3,2,5,1的顺序。

    要使用较新的Indy版本制作上述示例,您还必须调整已翻译的广告。

    罪魁祸首在于 CodeGear.Delphi.Targets ,它按照这个顺序放置了pathes。我能够修改这个文件,以便使用pathes的自然顺序:5,2,1或5,4,3,2,1。如果有人能确认我被允许在这里显示这些变化,我会这样做。也许我只能提供补丁。

    更新:以下是来自XE7的 CodeGear.Delphi.Targets 的更改,如Mercurial所示

    @@ -122,20 +122,19 @@
         <DcpFilename Condition="'$(DcpFilename)'!='' And !HasTrailingSlash('$(DcpFilename)')">$(DcpFilename)\</DcpFilename>
         <DcpFilename Condition="'$(DcpFilename)'!=''">$(DcpFilename)$(MSBuildProjectName).dcp</DcpFilename>
    
    -    <UnitSearchPath Condition="'$(DCC_UnitSearchPath)' != ''">$(DCC_UnitSearchPath);$(DelphiLibraryPath)</UnitSearchPath>
    -    <UnitSearchPath Condition="'$(DCC_UnitSearchPath)' == ''">$(DelphiLibraryPath)</UnitSearchPath>
    -
    +    <UnitSearchPath>$(DelphiLibraryPath)</UnitSearchPath>
         <UnitSearchPath Condition="'$(DCC_TranslatedLibraryPath)' != ''">$(DCC_TranslatedLibraryPath);$(UnitSearchPath)</UnitSearchPath>
         <UnitSearchPath Condition="'$(DCC_DebugDCUs)'=='true' And '$(DelphiDebugDCUPath)'!=''">$(DelphiDebugDCUPath);$(UnitSearchPath)</UnitSearchPath>
         <UnitSearchPath Condition="'$(DCC_DebugDCUs)'=='true' And '$(DCC_TranslatedDebugLibraryPath)' != ''">$(DCC_TranslatedDebugLibraryPath);$(UnitSearchPath)</UnitSearchPath>
    -
    +    <UnitSearchPath Condition="'$(DCC_UnitSearchPath)' != ''">$(DCC_UnitSearchPath);$(UnitSearchPath)</UnitSearchPath>
    +    
         <___ResourcePath Condition="'$(DCC_ResourcePath)' != ''">$(DCC_ResourcePath);$(DelphiLibraryPath)</___ResourcePath>
         <___ResourcePath Condition="'$(DCC_ResourcePath)' == ''">$(DelphiLibraryPath)</___ResourcePath>
    +    <___ResourcePath Condition="'$(DCC_TranslatedResourcePath)' != ''">$(DCC_TranslatedResourcePath);$(___ResourcePath)</___ResourcePath>
         <__ResourcePath Condition="'$(DCC_UnitSearchPath)' != ''">$(DCC_UnitSearchPath);$(___ResourcePath)</__ResourcePath>
         <__ResourcePath Condition="'$(DCC_UnitSearchPath)' == ''">$(___ResourcePath)</__ResourcePath>
         <ResourcePath Condition="'$(BRCC_OutputDir)' != ''">$(BRCC_OutputDir);$(__ResourcePath)</ResourcePath>
         <ResourcePath Condition="'$(BRCC_OutputDir)' == ''">$(__ResourcePath)</ResourcePath>
    -    <ResourcePath Condition="'$(DCC_TranslatedResourcePath)' != ''">$(DCC_TranslatedResourcePath);$(ResourcePath)</ResourcePath>
    
         <NameSpace Condition="'DelphiNamespaceSearchPath'!=''">$(NameSpace);$(DelphiNamespaceSearchPath)</NameSpace>
    

答案 1 :(得分:1)

现在我理解了这个问题的来源。请注意Rufo爵士,因为他让我想到了解决方案。

就是这样:我正在调用DCC32.exe来编译包(使用.dpk,但没有.dproj文件,并且没有调用msbuild来编译这些包)。当我构建这些时,我没有将Debug DCU路径插入到通过-I参数传递到DCC32.exe的库路径的头部。

一旦DCC32.exe软件包编译库搜索路径首先调试DCU文件夹,它就可以工作。

如果有人对这样的软件包系统感兴趣,我打算开源这个软件包构建系统,作为最初由Juancarlo Anez建立的WANT项目的重新启动的一部分,我可能会用一个新名称来调用它。一旦组件构建系统的工作演示可用,我将更新此答案。

工作系统的简要概述,以满足我在问题中提出的要求:

  1. 您需要一个文件(可以是xml,ini,json文件)来定义要构建的包列表。

  2. 您需要在每个上面调用MSBUILD或DCC32.exe。你可以编写自己的代码,或者你可以使用我的代码,我会尽可能地开源。

  3. 只有在调用Debug项目时,才需要将Debug DCU DPROJ作为第一项包含在库路径中。

  4. 您需要在项目搜索路径和库路径中使用$(OURCOMPANYLIBRARYDCU)\$(Platform)\$(Config)宏。

  5. 在Delphi IDE中,您需要将$(OURCOMPANYLIBRARYDCU)\$(Platform)\Release硬编码为库路径中的路径。

  6. 在Delphi IDE中,您需要将$(OURCOMPANYLIBRARYDCU)\$(Platform)\Debug硬编码为Debug DCU路径中的路径。