使用我自己构建的调试和常规 DCU 库在 Delphi 中管理非常大的代码库
Managing very large codebases in Delphi using a Library of Debug and Regular DCUs I built myself
我正在尝试解决此编译错误,该错误仅出现在调试配置中,并且仅出现在下述情况中:
[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 个是设计时+运行时或设计时,其他是运行时包(它们也在运行时加载到 IDE,由相关设计时包中的 DLL 依赖项加载)。
我们的主库路径已经优化得尽可能小,它包含 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 文件,platform/config 组合。
在项目选项中使用了如下宏,因此我们可以更改平台和配置,并正确解析目录:
$(OURCOMPANYLIBRARYDCU)$(Platform)$(Config)
OURCOMPANYLIBRARYDCU
是一个环境变量,$(X)
是扩展环境变量的语法,在 Delphi IDE.
的上下文中
我正在尝试构建最重要和最大的 VCL 应用程序项目(称之为 BigApp.dproj),以便项目搜索目录仅包含我们的应用程序源文件夹,不需要项目搜索路径包含我们所有的第三方组件库源代码。为此,我们需要 link 针对调试 DCU,或发布 DCU。
到目前为止,除了您同时拥有调试和发布 DCU 的情况外,我们一切正常。发布 DCU 在库路径中,调试 DCU 在 Debug DCU 路径中,在 IDE 设置中。面对这两个库之间的选择,Delphi 的 linker 似乎失败了,每当两组 DCU 都存在时,出现这种形式的错误,当我单击构建时,Build Configuration
设置为 Release,我收到 F2051 错误。 F2051 错误的一般原因是多个不兼容的二进制 DCU 存在并且都可以访问,并且 linker 无法使其全部工作。但是,当您希望库路径中同时包含调试和发布 DCU 时,我认为这种事情不会发生,因为链接器会为您选择调试或发布 DCU。
如果我没有构建Debug DCUs,就不会出现上述问题。我怀疑我的 Debug DCU 很微妙 "invalid" 或者 Delphi 中的 Debug-DCU-selection 算法不起作用,但不知道为什么,也不知道如何解决这个问题。
多题:
一个。每个 platform/config 组合是否有一个文件夹,在一个文件夹中包含 DCU、BPL 和 DCP,然后添加到已知会导致问题的 IDE 库路径?我需要三个子文件夹,每个平台+配置+文件类型总共12个文件夹,还是我可以通过平台+配置将它们放在一起?
乙。在包编译的情况下,可以让 IDE 库路径包含 OurCompanyLibraryDCU 文件夹,并将该文件夹配置为 DCP 输出目录、包输出目录和单元输出目录吗?我担心的是,通过使输入文件夹和输出文件夹相同,编译器可能无法从 .pas 源重建单元,而只是 linking 先前编译的 DCU。
C。如果我做错了,我应该如何防止每次构建我的 BigApp 时从源代码编译超过 250 万行组件库代码,而不是仅通过 DCU link 它们,并且仍然有调试和发布 dcus 是否正常工作?
D.如果我转到 Win32\Debug 文件夹并删除 IdGlobal.dcu,我可以克服原来的错误。这向我表明我的包编译(用于调试配置)正在生成一个无效 IdGlobal.dcu。这可能吗?能delphi默默输出DCU乱码吗?
注意:我没有使用,也不能使用Runtime Packages,来处理应用程序大小问题。
更新:我应该在这里做的第一件事是验证零附加 DCU 文件在我的硬盘上的任何地方,任何地方。这是标准的 F2051 错误建议。我会在处理完这个问题后更新这个问题。似乎 Delphi 本身会将 DCU 从一个地方复制到另一个地方,或者不在当前搜索路径中的伪造 DCU 可能已经在其他项目的搜索路径中。可能会出现一种 Bucket-Brigade 的坏 DCU 副本。一旦确定发生了哪种不良 DCU 生成或副本,我将更新问题。
更新 2:我现在保证在构建之前不存在 IdGlobal.dcu 的额外副本,并且问题仍然重现。因此,问题然后打开构建 IdGlobal.dcu 时使用的编译器选项,在调试版本中构建 BigApp.dproj 时使用的编译器选项版本。
更新 3:虽然我所有的包编译似乎都没有错误地完成,但在 DCC32.exe 或 MSBUILD.exe 启动期间,它们似乎没有使用正确的库搜索路径构建包。这个库路径不一致问题似乎是核心问题,感谢 Rufo 爵士指出这一点。
现在我明白了这个问题的根源。请为 Rufo 爵士投票,因为他让我想到了解决方案。
是这样的:我正在调用DCC32.exe编译包(使用.dpk,但没有.dproj文件,也没有调用msbuild来编译这些包)。当我构建这些时,我没有将调试 DCU 路径插入到通过 -I
参数传递给 DCC32.exe
的库路径的头部。
一旦 DCC32.exe 包编译库搜索路径首先包含 Debug DCU 文件夹,它就可以工作。
如果有人对这样的包系统感兴趣,我打算开源这个包构建系统,作为重新启动最初由 Juancarlo Anez 构建的 WANT 项目的一部分,我可能会用一个新名称来称呼它.一旦组件构建系统的工作演示可用,我将更新此答案。
满足我在问题中提出的要求的工作系统的简要概述:
您将需要一个文件(可以是 xml、ini、json 文件)来定义要构建的包列表。
您需要对其中的每一个调用 MSBUILD 或 DCC32.exe。你可以写你自己的代码,也可以使用我的代码,我会尽可能开源。
您需要将 Debug DCU DPROJ 作为第一个项目包含到库路径中,仅在调用 Debug 项目构建时。
您需要在项目搜索路径和库路径中使用 $(OURCOMPANYLIBRARYDCU)$(Platform)$(Config)
宏。
在您的 Delphi IDE 中,您需要将 $(OURCOMPANYLIBRARYDCU)$(Platform)\Release
硬编码为库路径中的路径。
在您的 Delphi IDE 中,您需要将 $(OURCOMPANYLIBRARYDCU)$(Platform)\Debug
硬编码为 Debug DCU 路径中的路径。
也许我可以阐明提供给编译器的搜索路径的顺序,这应该首先说明问题发生的原因,并且可以通过添加调试 DCU 来解决(至少在您的情况下)该特定位置的路径。所有这些观察都是用 XE7 进行的。
IDE 中有几个地方可以指定搜索路径:
- 库路径(Delphi-选项-库)
- 翻译库路径(Delphi-选项-库-翻译)
- 调试 DCU 路径(Delphi-选项 - 库)
- 已翻译的调试 DCU 路径(Delphi-选项 - 已翻译的库)
- 搜索路径(通过项目选项)
当库语言设置为英语时,这些路径将以 5,1 或 3,5,1 的顺序提供给编译器,具体取决于 Use debug .dcus.这已经有点奇怪了,因为调试 dcu 路径优先于项目搜索路径。
所以f.i。为了使编译器找到我们自己的较新Indy版本的dcu文件,我们必须将相应的路径放在1和3下的路径前面。
当库语言设置为不同于英语时,事情会变得复杂。在这种情况下,根据 Use debug .dcus.[= 的设置,翻译后的路径开始发挥作用,导致顺序为 2,5,1 或 4,3,2,5,1 11=]
要使上述示例在较新的 Indy 版本中运行,您还必须调整翻译后的路径。
罪魁祸首在于CodeGear.Delphi.Targets,它将路径按此顺序放置。我能够修改此文件,以便使用路径的自然顺序:5、2、1 或 5、4、3、2、1。如果有人可以确认我可以在这里显示这些更改,我会这样做。也许我只能提供一个补丁。
更新: 这里是 CodeGear.Delphi.Targets 从 Mercurial
显示的 XE7 的变化
@@ -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>
我正在尝试解决此编译错误,该错误仅出现在调试配置中,并且仅出现在下述情况中:
[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 个是设计时+运行时或设计时,其他是运行时包(它们也在运行时加载到 IDE,由相关设计时包中的 DLL 依赖项加载)。
我们的主库路径已经优化得尽可能小,它包含 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 文件,platform/config 组合。
在项目选项中使用了如下宏,因此我们可以更改平台和配置,并正确解析目录:
$(OURCOMPANYLIBRARYDCU)$(Platform)$(Config)
OURCOMPANYLIBRARYDCU
是一个环境变量,$(X)
是扩展环境变量的语法,在 Delphi IDE.
我正在尝试构建最重要和最大的 VCL 应用程序项目(称之为 BigApp.dproj),以便项目搜索目录仅包含我们的应用程序源文件夹,不需要项目搜索路径包含我们所有的第三方组件库源代码。为此,我们需要 link 针对调试 DCU,或发布 DCU。
到目前为止,除了您同时拥有调试和发布 DCU 的情况外,我们一切正常。发布 DCU 在库路径中,调试 DCU 在 Debug DCU 路径中,在 IDE 设置中。面对这两个库之间的选择,Delphi 的 linker 似乎失败了,每当两组 DCU 都存在时,出现这种形式的错误,当我单击构建时,Build Configuration
设置为 Release,我收到 F2051 错误。 F2051 错误的一般原因是多个不兼容的二进制 DCU 存在并且都可以访问,并且 linker 无法使其全部工作。但是,当您希望库路径中同时包含调试和发布 DCU 时,我认为这种事情不会发生,因为链接器会为您选择调试或发布 DCU。
如果我没有构建Debug DCUs,就不会出现上述问题。我怀疑我的 Debug DCU 很微妙 "invalid" 或者 Delphi 中的 Debug-DCU-selection 算法不起作用,但不知道为什么,也不知道如何解决这个问题。
多题:
一个。每个 platform/config 组合是否有一个文件夹,在一个文件夹中包含 DCU、BPL 和 DCP,然后添加到已知会导致问题的 IDE 库路径?我需要三个子文件夹,每个平台+配置+文件类型总共12个文件夹,还是我可以通过平台+配置将它们放在一起?
乙。在包编译的情况下,可以让 IDE 库路径包含 OurCompanyLibraryDCU 文件夹,并将该文件夹配置为 DCP 输出目录、包输出目录和单元输出目录吗?我担心的是,通过使输入文件夹和输出文件夹相同,编译器可能无法从 .pas 源重建单元,而只是 linking 先前编译的 DCU。
C。如果我做错了,我应该如何防止每次构建我的 BigApp 时从源代码编译超过 250 万行组件库代码,而不是仅通过 DCU link 它们,并且仍然有调试和发布 dcus 是否正常工作?
D.如果我转到 Win32\Debug 文件夹并删除 IdGlobal.dcu,我可以克服原来的错误。这向我表明我的包编译(用于调试配置)正在生成一个无效 IdGlobal.dcu。这可能吗?能delphi默默输出DCU乱码吗?
注意:我没有使用,也不能使用Runtime Packages,来处理应用程序大小问题。
更新:我应该在这里做的第一件事是验证零附加 DCU 文件在我的硬盘上的任何地方,任何地方。这是标准的 F2051 错误建议。我会在处理完这个问题后更新这个问题。似乎 Delphi 本身会将 DCU 从一个地方复制到另一个地方,或者不在当前搜索路径中的伪造 DCU 可能已经在其他项目的搜索路径中。可能会出现一种 Bucket-Brigade 的坏 DCU 副本。一旦确定发生了哪种不良 DCU 生成或副本,我将更新问题。
更新 2:我现在保证在构建之前不存在 IdGlobal.dcu 的额外副本,并且问题仍然重现。因此,问题然后打开构建 IdGlobal.dcu 时使用的编译器选项,在调试版本中构建 BigApp.dproj 时使用的编译器选项版本。
更新 3:虽然我所有的包编译似乎都没有错误地完成,但在 DCC32.exe 或 MSBUILD.exe 启动期间,它们似乎没有使用正确的库搜索路径构建包。这个库路径不一致问题似乎是核心问题,感谢 Rufo 爵士指出这一点。
现在我明白了这个问题的根源。请为 Rufo 爵士投票,因为他让我想到了解决方案。
是这样的:我正在调用DCC32.exe编译包(使用.dpk,但没有.dproj文件,也没有调用msbuild来编译这些包)。当我构建这些时,我没有将调试 DCU 路径插入到通过 -I
参数传递给 DCC32.exe
的库路径的头部。
一旦 DCC32.exe 包编译库搜索路径首先包含 Debug DCU 文件夹,它就可以工作。
如果有人对这样的包系统感兴趣,我打算开源这个包构建系统,作为重新启动最初由 Juancarlo Anez 构建的 WANT 项目的一部分,我可能会用一个新名称来称呼它.一旦组件构建系统的工作演示可用,我将更新此答案。
满足我在问题中提出的要求的工作系统的简要概述:
您将需要一个文件(可以是 xml、ini、json 文件)来定义要构建的包列表。
您需要对其中的每一个调用 MSBUILD 或 DCC32.exe。你可以写你自己的代码,也可以使用我的代码,我会尽可能开源。
您需要将 Debug DCU DPROJ 作为第一个项目包含到库路径中,仅在调用 Debug 项目构建时。
您需要在项目搜索路径和库路径中使用
$(OURCOMPANYLIBRARYDCU)$(Platform)$(Config)
宏。在您的 Delphi IDE 中,您需要将
$(OURCOMPANYLIBRARYDCU)$(Platform)\Release
硬编码为库路径中的路径。在您的 Delphi IDE 中,您需要将
$(OURCOMPANYLIBRARYDCU)$(Platform)\Debug
硬编码为 Debug DCU 路径中的路径。
也许我可以阐明提供给编译器的搜索路径的顺序,这应该首先说明问题发生的原因,并且可以通过添加调试 DCU 来解决(至少在您的情况下)该特定位置的路径。所有这些观察都是用 XE7 进行的。
IDE 中有几个地方可以指定搜索路径:
- 库路径(Delphi-选项-库)
- 翻译库路径(Delphi-选项-库-翻译)
- 调试 DCU 路径(Delphi-选项 - 库)
- 已翻译的调试 DCU 路径(Delphi-选项 - 已翻译的库)
- 搜索路径(通过项目选项)
当库语言设置为英语时,这些路径将以 5,1 或 3,5,1 的顺序提供给编译器,具体取决于 Use debug .dcus.这已经有点奇怪了,因为调试 dcu 路径优先于项目搜索路径。
所以f.i。为了使编译器找到我们自己的较新Indy版本的dcu文件,我们必须将相应的路径放在1和3下的路径前面。
当库语言设置为不同于英语时,事情会变得复杂。在这种情况下,根据 Use debug .dcus.[= 的设置,翻译后的路径开始发挥作用,导致顺序为 2,5,1 或 4,3,2,5,1 11=]
要使上述示例在较新的 Indy 版本中运行,您还必须调整翻译后的路径。
罪魁祸首在于CodeGear.Delphi.Targets,它将路径按此顺序放置。我能够修改此文件,以便使用路径的自然顺序:5、2、1 或 5、4、3、2、1。如果有人可以确认我可以在这里显示这些更改,我会这样做。也许我只能提供一个补丁。
更新: 这里是 CodeGear.Delphi.Targets 从 Mercurial
显示的 XE7 的变化@@ -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>