我可以重新编译 Delphi IDE 使用的 .PAS 文件吗?
我很熟悉 Jeff Atwood 的文章,内容是错误总是程序员的错,但是我相信我确实在 Delphi .pas 文件中发现了一个错误。
具体来说,我使用的是 Delphi 2007,错误位于 DBCommon.pas 文件的第 955 行,该文件在我的计算机上位于此处:
C:\program files\codegear\rad studio\5.0\source\Win32\db\DBCommon.pas
代码是这样的:
...
FieldIndex := StrToInt(Token);
if DataSet.FieldCount >= FieldIndex then
LastField := DataSet.Fields[FieldIndex-1].FieldName else
...
如果“Token”的值为 0,那么我们尝试访问 DataSet.Fields 的索引 -1 ,导致列表索引越界错误。
此错误不会向用户提出,因为它会在错误达到那么高的级别之前得到处理,但每次发生这种情况时都让调试器中断是非常令人恼火的。
我可以“忽略此异常类型”,但索引越界错误很常见,我不想普遍忽略它们。
导致 FieldIndex 为零的情况是当您有一个 SELECT 语句,其 ORDER BY 包含一个函数时,如下所示:
ORDER BY
CASE WHEN FIELD1 = FIELD3 THEN 1 ELSE 2 END
,CASE WHEN FIELD2 = FIELD4 THEN 1 ELSE 2 END
我可以修复 DBCommon.pas 中的错误,但 Delphi 不会重新编译自身,并且我的更改不会生效。如果我重命名 .DCU 文件,那么它只是抱怨找不到“DBCommon.dcu”。
所以(最后)我的问题是:我可以用我的修复重新编译 DBCommon.pas 吗?如果可以,怎么做?
I am familiar with Jeff Atwood's article about how errors are always the programmer's fault, but I believe I have really and truly found a bug in a Delphi .pas file.
Specifically, I'm using Delphi 2007, and the error is on line 955 of the DBCommon.pas file, which on my machine is located here:
C:\program files\codegear\rad studio\5.0\source\Win32\db\DBCommon.pas
And the code is this:
...
FieldIndex := StrToInt(Token);
if DataSet.FieldCount >= FieldIndex then
LastField := DataSet.Fields[FieldIndex-1].FieldName else
...
If "Token" has a value of zero, then we try to access index -1 of DataSet.Fields, resulting in a list index out of bounds error.
This error is not raised to the user, because it is handled before it gets that high up, but it is enormously irritating to have the debugger break in every time this happens.
I could "Ignore this exception type" but Index out of bounds errors are common enough that I don't want to universally ignore them.
The situation that causes FieldIndex to be zero is when you have a SELECT statement whose ORDER BY contains a function, as in:
ORDER BY
CASE WHEN FIELD1 = FIELD3 THEN 1 ELSE 2 END
,CASE WHEN FIELD2 = FIELD4 THEN 1 ELSE 2 END
I can fix the bug in DBCommon.pas, but Delphi will not recompile itself, and my change does not take effect. If I rename the .DCU file, then it just complains that "DBCommon.dcu" cannot be found.
So (finally) my question is: Can I recompile DBCommon.pas with my fix, and if so, how?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您可以将 dbcommon.pas 放在您的项目目录中。然后它将与项目的其余部分一起编译。
You can probably put dbcommon.pas in youre project directory. It will then be compiled along with the rest of the project.
请参阅前面的答案,了解如何创建可以重新编译修改后的 VCL 源的情况。不过,我想补充一点,您认真考虑使用“供应商分支”SCM 模式来管理变更控制系统中的变更。
简单来说(使用 SVN 作为参考):
创建原始供应商提供的文件的“供应商源”副本。这是您的“原始”参考副本。
创建代表该原始副本的分支(例如,对于 Delphi 2009 版本的 VCL 为“2009”)
对供应商源代码的任何修改都是在“供应商库”分支中进行的。
当供应商提供新版本的库时,您可以将新版本签入“供应商源”项目并为新版本创建新分支。
然后您可以轻松区分供应商的修订版本。但更重要的是(使用 SubVersion,可能还有其他 SCM 系统)您还应该能够简单地将新的供应商源代码与您的“供应商库”分支合并(即自动),以便轻松地将供应商更改与您自己的修改合并起来。
这一切都比我在优秀的 O'Reilly 书中所做的描述要好得多:“Version Control with SubVersion”,
但请注意,由于版权问题,该书中提到的“loaddirs”实用程序不再受支持,因此更新“vendor Drops” “目前是手动练习,但这种情况很少发生,并且不是主要负担。
我们自己正在使用这种模式,尽管在 VCL 的情况下,我们不会在“供应商源”或“供应商库”中维护整个 VCL 源树的完整副本,而是仅跟踪已更改和依赖的单元。对于供应商分支下管理的其他库,我们通常会维护完整的副本,但认为这对于 VCL 来说不是必需的。
然而,我们刚刚实现了这种模式,因此我们可能还决定需要对 VCL 采取更全面的方法。
ymmv
See previous answers for how to create the situation where you can recompile modified VCL source. I would however add that you seriously consider managing your changes in your change control system, using the "Vendor Branch" SCM pattern.
In simple terms (using SVN as a reference):
Create a "vendor source" copy of the original vendor supplied files. This is your "pristine" reference copy.
Create a branch representing that pristine copy (e.g. "2009" for the Delphi 2009 version of the VCL)
create a further branch into a separate "vendor library" folder. THIS is the copy of the library that you should reference in your projects
any modifications to the vendor source are made in the "vendor library" branch.
when the vendor provides a new version of the library you check the new version in to the "vendor source" project and create a new branch for the new version.
you can then easily diff the vendor revisions. But more importantly (with SubVersion, and possibly othe SCM systems) you should also be able to simply merge (i.e. automatically) the new vendor source with your "vendor library" branch to easily incorporate vendor changes with your own modifications.
This is all described far better than I just did in the excellent O'Reilly book: "Version Control with SubVersion"
NOTE however that the "loaddirs" utility mentioned in that book is no longer supported due to copyright issues, so updating "vendor drops" is currently a manual exercise, but this occurs only infrequently and is not a major burden.
We are using this pattern ourselves, although in the case of the VCL we do not maintain a complete copy of the entire VCL source tree in our "vendor source" or "vendor library", but instead only track changed and dependent units. For other libraries managed under a vendor branch we typically do maintain complete copies but decided this wasn't necessary for the VCL.
We've only just implemented this pattern however, so we may yet decide that we need to take a more comprehensive approach with the VCL too.
ymmv
您可以,但通常您不必这样做。有时重新编译 VCL 单元意味着重新编译所有其余的 VCL 单元,要么是因为您更改了单元的接口,要么是因为编译器感到困惑并认为您已经更改了接口。重新编译 VCL 单元也排除了使用大多数运行时包的可能性,因为您无法重新编译 Delphi 的运行时包。
您可以使用运行时修补,而不是重新编译。我已经在 TNT Unicode 控件中使用了该方法,但是 Madshi 还提供了一种用您自己的实现替换函数的方法。如果您将 DBCommon.GetIndexForOrderBy 的实现复制到您自己的单元中并进行修复,您可以使用此命令用您自己的版本修补 VCL 版本:
使用 Tnt Unicode 库,在以下位置找到
OverwriteProcedure
例程: Tnt系统单位。它不是公开的,因此您需要在单元接口中声明它或将其复制到您自己的单元中。然后你可以像上面的 Madshi 代码一样调用它:You can, but often you don't have to. Recompiling a VCL unit sometime means recompiling all the rest of the VCL units either because you've changed the interface of a unit or because the compiler gets confused and thinks you've changed the interface. Recompiling a VCL unit also rules out the possibility of using most run-time packages because you can't recompile Delphi's run-time packages.
Instead of recompiling, you can use run-time patching. I've used the method in the TNT Unicode controls, but Madshi also provides a way to replace a function with your own implementation. If you copy the implementation of DBCommon.GetIndexForOrderBy into your own unit and make your fixes, you can use this command to patch the VCL version with your own:
With the Tnt Unicode library, find the
OverwriteProcedure
routine in the TntSystem unit. It's not public, so you'll need to either declare it in the unit interface or copy it into your own unit. Then you can call it much like the Madshi code above:我们的项目源代码树下有一个名为 VCL 的文件夹,我们将希望稍微修改的 VCL 源代码的副本放入其中。
你的例子很适合做同样的事情。
您需要修改项目的搜索路径,以便“您的”VCL 文件夹在您的路径上早于 Delphi 安装下的“Source”文件夹。
您可能还会发现,如果您复制一个 VCL 源单元并对其进行修改,您还必须将其他 VCL 源单元复制到“您的”文件夹中,该文件夹可能是依赖项。
我们这样做的原因是我们希望我们的构建具有零编译器提示和警告。 VCL 源代码的某些部分并非没有提示/警告。
We have a folder under our project source tree called VCL, into which we place copies of the VCL source that we wish to modify slightly.
Your example is a good candidate for doing the same thing.
You will need to modify the search path for your project so that "your" VCL folder is earlier on your path than the "Source" folders under your Delphi installation.
You may also find that if you copy one VCL source unit out and modify it, you will have to also copy other VCL source units out into "your" folder which may be dependencies.
Our reason for doing this is that we want our builds to have zero compiler hints and warnings. There are some parts of the VCL source that are not hint/warning free.
“我很熟悉 Jeff Atwood 的文章,其中提到错误总是程序员的错,但我相信我确实在 Delphi .pas 文件中发现了错误”
您在开玩笑吗?对于 Delphi,你总是首先责怪 Borland :)
有些东西很奇怪,去 Google 一下,看看是否是 Delphi 的 bug。仅当找不到任何类似的报告时,您才可以向下查找并逐行检查代码。
重新安装 Delphi 后,我必须在 6(六)个位置修补原始 PAS 文件。全新的 Delphi 安装中会出现大量错误,并且可以轻松重现。 Delphi(我们都喜欢的那个)充满了错误。围绕此创造了完整的历史。
有很多人发布外部补丁(例如 http://andy.jgknet.de/ blog/?page_id=288) 和 Borland/Imprise/GoGear/Embarcadero 一直忽略它们。他们将 FastMM 包含在他们的版本中真是一个奇迹。
不管怎样,我已经重新编译了这些 PAS 文件,现在我用打过补丁的 DCU 替换了原来的 DCU。
"I am familiar with Jeff Atwood's article about how errors are always the programmer's fault, but I believe I have really and truly found a bug in a Delphi .pas file"
Are you joking me? With Delphi you always blame Borland first :)
Something is weird, go Google it and see if it is a Delphi bug. Only if cannot find any similar reports you site down and check your code line by line.
After I reinstall Delphi I have to patch the original PAS files in 6 (six) places. There are tons of bugs that appear on a fresh Delphi installation and can be easily reproduced. Delphi (the one that we all love) is full of bugs. There is an entire history created around this.
There are so many people releasing external patches (such as http://andy.jgknet.de/blog/?page_id=288) and Borland/Imprise/GoGear/Embarcadero keep ignoring them. It is a true wonder they included FastMM in their release.
Anyway, I have recompiled those PAS files and now I replace the original DCUs with the patched ones.
很简单——是的。使用上述答案之一[汤姆或康纳]。将 DBCommon.pas 复制到您的项目文件夹,而不是编辑原始文件。这不会影响其他项目和编译,因为它不会出现在路径上。
Simply - Yes. Using one of the above answers [By Tom or Connor]. Copy DBCommon.pas to your project folder rather than edit the original. This leaves other projects and compilations unaffected because it won't be on the path.
您可以设置:
DataSetProvider.Option.poRetainServerOrder = True
You can set:
DataSetProvider.Option.poRetainServerOrder = True