简体   繁体   English

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

[英]Managing very large codebases in Delphi using a Library of Debug and Regular DCUs I built myself

I am trying to resolve this compile error, occuring only in Debug config, and only in the case described below: 我正在尝试解决此编译错误,仅在Debug配置中发生,并且仅在下面描述的情况下:

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

I am working on a very large Delphi codebase, with 2.5 million lines of in-house code, and 3 million lines of component code, which includes several large commercial Delphi component suites (Developer Express, TeeChart, and others), and a large number of open source delphi components as well, plus a fairly large in-house developed set of components, numbering 252 packages, of which about 140 are designtime+runtime or designtime, and the others are runtime packages (which are also loaded, into the IDE at runtime, by DLL-dependencies in their associated designtime package). 我正在开发一个非常大的Delphi代码库,拥有250万行内部代码和300万行组件代码,其中包括几个大型商业Delphi组件套件(Developer Express,TeeChart等),以及大量代码库开源delphi组件,以及一个相当大的内部开发组件集,编号252个包,其中大约140个是设计时+运行时或设计时,其他是运行时包(也被加载到IDE中)在运行时,由其关联的设计时包中的DLL依赖项)。

Our main library path has been optimized down to be small as can be, and it contains the paths that Delphi ships with as standard, plus three more we added, the primary one is a single "OurCompanyLibraryDCU" folder, which contains underneath it folders for the two platforms and two configurations that we use: 我们的主库路径已经优化到尽可能小,它包含Delphi附带的路径作为标准,加上我们添加的三个,主要的是一个“OurCompanyLibraryDCU”文件夹,其中包含下面的文件夹我们使用的两个平台和两个配置:

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

Each of the above folders contains the set of BPL, DCP, and DCU files in a single folder, for that platform/config combination. 上述每个文件夹都包含一个文件夹中的BPL,DCP和DCU文件集,用于该平台/配置组合。

A macro like the following, in the project options is used, so we can change platform, and config, and have the directories resolve correctly: 在项目选项中使用了如下的宏,因此我们可以更改平台和配置,并正确解析目录:

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

OURCOMPANYLIBRARYDCU is an environment variable and $(X) is the syntax to expand an environment variable, in the context of the Delphi IDE. OURCOMPANYLIBRARYDCU是一个环境变量, $(X)是在Delphi IDE环境中扩展环境变量的语法。

I am trying to get the most important and largest VCL Application project (call it BigApp.dproj) to build so that the project search directory only contains our APPLICATION source folders and does not need the project search path to contain all our third party component LIBRARY source code. 我正在尝试将最重要和最大的VCL应用程序项目(称为BigApp.dproj)构建,以便项目搜索目录仅包含我们的APPLICATION源文件夹,并且不需要项目搜索路径来包含我们所有的第三方组件LIBRARY源代码。 To do that, we need to link against the debug DCUs, or release DCUs. 为此,我们需要链接调试DCU或释放DCU。

So far we have everything working except for the case where you have both Debug and Release DCUs available. 到目前为止,除了可以使用Debug和Release DCU的情况外,我们一切正常。 The release DCUs are in the library path, and the debug DCUs are in the Debug DCU path, in the IDE settings. 版本DCU位于库路径中,调试DCU位于IDE设置中的Debug DCU路径中。 Confronted with the choice between these two libraries, Delphi's linker appears to fail, whenever both sets of DCUs exist, with errors in this form, when I click Build, and the Build Configuration is set to Release, I get F2051 errors. 面对这两个库之间的选择,Delphi的链接器似乎失败,无论何时存在两组DCU,都有这种形式的错误,当我单击Build,并且Build Configuration设置为Release时,我得到F2051错误。 The ordinary cause of an F2051 error is that multiple incompatible binary DCUs exist and are both accessible, and the linker is failing to make it all work. F2051错误的普通原因是存在多个不兼容的二进制DCU并且都是可访问的,并且链接器无法使其全部工作。 However, when you want both Debug and Release DCUs both in the library path, I thought that this sort of thing would not occur, due to the Linker selecting the debug or release DCUs for you. 但是,如果你想在库路径中同时使用Debug和Release DCU,我认为这种情况不会发生,因为链接器会为你选择调试或释放DCU。

If I have not build the Debug DCUs, the above problem does not occur. 如果我没有构建调试DCU,则不会发生上述问题。 I suspect that my Debug DCUs are subtly "invalid" or that the Debug-DCU-selection algorithm inside Delphi is not working, but have no idea why, or how to fix this. 我怀疑我的调试DCU是微妙的“无效”或Delphi中的Debug-DCU选择算法不起作用,但不知道为什么,或如何解决这个问题。

Multi-part-Question: 多部分问题:

A. Is having a single folder for each platform/config combination, containing the DCU, BPL, and DCP in a single folder, and then added to the IDE Library Path known to cause problems? A.每个平台/配置组合都有一个文件夹,在单个文件夹中包含DCU,BPL和DCP,然后添加到已知导致问题的IDE库路径中? Do I need three sub-folders, making a total of 12 folders for every platform+config+filetype, or can I keep them together by platform+config? 我是否需要三个子文件夹,每个平台+ config + filetype共有12个文件夹,或者我可以通过platform + config将它们保存在一起吗?

B. In a package compilation situation, is it okay to have the IDE Library path contain the OurCompanyLibraryDCU folder, and also have that folder configured as the DCP Output Directory, Package Output Directory, and Unit Output Directory? B.在包编译情况下,是否可以让IDE库路径包含OurCompanyLibraryDCU文件夹,并将该文件夹配置为DCP输出目录,包输出目录和单元输出目录? My concern is that by having input folder and output folders the same, there is a case where the compiler could be failing to rebuild a Unit from .pas source, and simply linking the prior compile's DCU. 我担心的是,通过使输入文件夹和输出文件夹相同,有一种情况是编译器可能无法从.pas源重建单元,只是链接先前编译的DCU。

在此输入图像描述

C. If I'm going about this wrong, how instead, shall I prevent the over 2.5 million lines of component LIBRARY code from being compiled from source each time I build my BigApp, instead only link them via DCU, and still have the debug and release dcus work properly? C.如果我发生了这个问题,我应该如何防止每次构建BigApp时从源代码编译超过250万行的组件LIBRARY代码,而只是通过DCU链接它们,并且仍然有调试并释放dcus正常工作?

D. I can get past the original error if I go to the Win32\\Debug folder and delete IdGlobal.dcu. D.如果我转到Win32 \\ Debug文件夹并删除IdGlobal.dcu,我可以通过原始错误。 This suggests to me that my package compilation (for debug config) is producing an INVALID IdGlobal.dcu. 这告诉我,我的包编译(用于调试配置)正在生成INVALID IdGlobal.dcu。 Is that even possible? 这甚至可能吗? Can delphi silently output garbled DCUs? delphi可以默默输出乱码的DCU吗?

Notes: I'm not using, and can not use Runtime Packages, to deal with the application size problems. 注意:我没有使用,也无法使用Runtime Packages来处理应用程序大小问题。

Update: The first thing I should have done here is verify that ZERO additional DCU files are ANYWHERE on my harddrive, ANYWHERE. 更新:我应该在这里做的第一件事是验证ZERO额外的DCU文件在我的硬盘驱动器上是任何地方,无论如何。 That's the standard F2051 error advice. 这是标准的F2051错误建议。 I'll update this question after I've taken care of that. 在我处理完这个问题后,我会更新这个问题。 It appears possible that Delphi will itself COPY a DCU from one place to another, or that a bogus DCU that is NOT in the CURRENT search path might have been in some other project's search path. 似乎Delphi本身可以将DCU从一个地方复制到另一个地方,或者不在CURRENT搜索路径中的虚假DCU可能已经在某个其他项目的搜索路径中。 A kind of bucket-brigade of bad-DCU-copies can occur. 可能会出现一种坏DCU拷贝的桶式旅。 I'll update the question once I'm sure what kind of bad-DCU-generations-or-copies are occuring. 一旦我确定发生了什么样的坏DCU代或副本,我就会更新问题。

Update 2: I have now guaranteed that no additional copies of IdGlobal.dcu exist before building, and the problem still reproduces. 更新2:我现在保证在构建之前不存在IdGlobal.dcu的额外副本,并且问题仍然存在。 So the question then turns on the compiler options used when building the IdGlobal.dcu, versions the compiler options used when building BigApp.dproj in Debug build. 因此,问题随后打开了构建IdGlobal.dcu时使用的编译器选项,版本化了在Debug构建中构建BigApp.dproj时使用的编译器选项。

Update 3: Although all my package compiles appear to complete without error, it seems they were not using a correct library search path, during the time when the DCC32.exe or MSBUILD.exe is being launched to build the packages. 更新3:虽然我的所有程序包编译似乎都没有错误地完成,但是在启动DCC32.exe或MSBUILD.exe来构建程序包期间,它们似乎没有使用正确的库搜索路径。 This library path inconsistency issue appears to be the core issue, thanks to Sir Rufo for pointing that out. 这个库路径不一致问题似乎是核心问题,感谢Rufo爵士指出这一点。

Perhaps I can shed some light on the order of search pathes presented to the compiler, which should make clear why the problem happens in the first place and can be cured (at least in your situation) by adding the Debug DCU path at that specific location. 也许我可以对提供给编译器的搜索路径的顺序有所了解,这应该首先解释为什么问题首先发生并且可以通过在该特定位置添加Debug DCU路径来解决(至少在您的情况下) 。 All these observations were made with XE7. 所有这些观察都是用XE7进行的。

There are several places in the IDE where you can specify search pathes: IDE中有几个位置可以指定搜索路径:

  1. Library path (Delphi-Options - Library) 库路径 (Delphi-Options - Library)
  2. Translated Library path (Delphi-Options - Library-Translated) 翻译库路径 (Delphi-Options - Library-Translated)
  3. Debug DCU path (Delphi-Options - Library) 调试DCU路径 (Delphi-Options - Library)
  4. Translated Debug DCU path (Delphi-Options - Library-Translated) 翻译的调试DCU路径 (Delphi-Options - Library-Translated)
  5. Search path (via Project Options) 搜索路径 (通过项目选项)

When the Library language is set to English, those pathes are given to the compiler in the order 5,1 or 3,5,1 depending of the setting of Use debug .dcus . 当Library语言设置为英语时,这些路径将按照5,1或3,5,1的顺序提供给编译器,具体取决于Use debug .dcus的设置。 This is already a bit weird as the debug dcu path takes precedence over the project search path. 这已经有点奇怪,因为debug dcu路径优先于项目搜索路径。

So fi to make the compiler find our own dcu files of a newer Indy version, we have to place the corresponding pathes in front of the pathes under 1 and 3. 因此,为了让编译器找到我们自己的新版Indy版本的dcu文件,我们必须在1和3下的pathes前面放置相应的pathes。

Now things get complicated when the Library language is set to something different than English. 现在,当Library语言被设置为与英语不同的东西时,事情会变得复杂。 In this case the translated pathes come into play resulting in the order 2,5,1 or 4,3,2,5,1 depending of the setting of Use debug .dcus . 在这种情况下,翻译的pathes会起作用,导致2,5,1或4,3,2,5,1的顺序,具体取决于Use debug .dcus的设置。

To make the above example with a newer Indy version work, you have to tweak the translated pathes, too. 要使用更新的Indy版本制作上述示例,您还必须调整已翻译的广告。

The culprit lies in CodeGear.Delphi.Targets , which places the pathes in this order. 罪魁祸首在于CodeGear.Delphi.Targets ,它按照这个顺序放置了pathes。 I was able to modify this file so that the natural order of pathes is used: 5,2,1 or 5,4,3,2,1. 我能够修改这个文件,以便使用pathes的自然顺序:5,2,1或5,4,3,2,1。 If anyone can confirm that I am allowed to show these changes here I will do. 如果有人能确认我被允许在这里显示这些变化,我会这样做。 Perhaps I can provide a patch only. 也许我只能提供补丁。

Update: Here are the changes of CodeGear.Delphi.Targets from XE7 as shown by Mercurial 更新:以下是Mercurial显示的XE7中CodeGear.Delphi.Targets的更改

@@ -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>

Now I understand a source for this problem. 现在我理解了这个问题的来源。 Please upvote Sir Rufo as he put me in mind of the solution. 请注意Rufo爵士,因为他让我想到了解决方案。

It is this: I was invoking DCC32.exe to compile packages (using .dpk, but no .dproj file, and not invoking msbuild to compile these packages). 就是这样:我正在调用DCC32.exe来编译包(使用.dpk,但没有.dproj文件,并且没有调用msbuild来编译这些包)。 When I built these, I was not inserting the Debug DCU path to the head of the library path passed in via -I parameters to DCC32.exe . 当我构建这些时,我没有将Debug DCU路径插入通过-I参数传递到DCC32.exe的库路径的头部。

Once the DCC32.exe package compilation Library Search path has the Debug DCU folders FIRST, it works. 一旦DCC32.exe程序包编译库搜索路径具有FIRST的Debug DCU文件夹,它就可以工作。

If anyone is interested in such a package system, I am planning to open source this package build system, as part of a relaunch of the WANT project originally built by Juancarlo Anez, which I will probably call by a new name. 如果有人对这样的软件包系统感兴趣,我打算开源这个软件包构建系统,作为最初由Juancarlo Anez建立的WANT项目的重新启动的一部分,我可能会用一个新名称来调用它。 I'll update this answer once a working demo of a component build system is available. 一旦组件构建系统的工作演示可用,我将更新此答案。

A brief outline of a working system to meet the requirements I asked in my question: 简要概述了一个工作系统,以满足我在问题中提出的要求:

  1. You will need a file (could be xml, ini, json file) that defines a list of packages to build. 您将需要一个文件(可以是xml,ini,json文件),它定义要构建的包列表。

  2. You will need to invoke MSBUILD or DCC32.exe on each of these. 您需要在每个上面调用MSBUILD或DCC32.exe。 You could write your own code, or you could use mine, which I will open source when I can. 你可以编写自己的代码,或者你可以使用我的代码,我会尽可能地开源代码。

  3. You will need to include the Debug DCU DPROJ into the library path as the first items, ONLY when invoking the Debug item builds. 只需在调用Debug项目构建时,您需要将Debug DCU DPROJ作为第一项包含在库路径中。

  4. You will want to use the $(OURCOMPANYLIBRARYDCU)\\$(Platform)\\$(Config) macro in your project search paths and library paths. 您将需要在项目搜索路径和库路径中使用$(OURCOMPANYLIBRARYDCU)\\$(Platform)\\$(Config)宏。

  5. In your Delphi IDE, you will want to hard-code $(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Release as a path within the Library path. 在Delphi IDE中,您需要将$(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Release硬编码$(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Release库路径中的路径。

  6. In your Delphi IDE, you will want to hard-code $(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Debug as a path within the Debug DCU path. 在Delphi IDE中,您需要将$(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Debug硬编码$(OURCOMPANYLIBRARYDCU)\\$(Platform)\\Debug Debug DCU路径中的路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM