我们有一个大约有16年历史的软件包。它几乎贯穿了Delphi的每一个版本(除了.NET版本)。多年来,当涉及到交叉引用和为其他包(如第三方库)保持正确设置时,情况变得非常混乱。我想知道在组织这样的大型项目(和项目组)时,是否有一些标准做法。
因此,为了解释当前的设置。。。
这是一个多应用程序系统。也就是说,涉及12个可执行项目(以及一些DLL和服务项目)。我们还将东西保存在SourceSafe中,多个开发人员在不同的计算机上处理相同的代码。所有这些项目都被转储到一个中心文件夹中。"根"文件夹包含主要EXE项目(以及大约20个文件夹,所有文件夹都包含单元和表单),它似乎是一个无穷无尽的文件夹和文件层次结构。仅这个项目就涉及50万行代码。
然后,所有额外的应用程序都不一定与这个主要项目正确地分离。这些项目中的每一个都在主项目的根目录中有自己的文件夹。
我关心的两个主要问题是:
- 如何正确设置DCU文件,使其不会与项目混合在一起?DCU不应放在SourceSafe(以及任何类似的文件)或其他任何从项目编译的文件中。Visual SourceSafe在未签出文件时将其设为只读,并且在这种情况下无法写入DCU文件(以及EXE文件等)。那么,如何将任何此类文件正确地分离到远程位置,以避免与源代码混合
- 如何正确设置包和库?我们有以下内容:
- QuickReports 5.05
- NativeJpg库V302-
- 另一个匿名报告库
- 我们自己的组件包,需要QuickReports、NativeJpg和其他匿名库
所有4个库都存储在每台计算机的完全不同的地方,需要进行一些集中。设置每个新开发人员的计算机的最大痛苦是从主要开发人员的电脑中定位这些计算机,并将它们复制到其他计算机上的同一位置(并确保库路径正确等)
我们还需要在同一台计算机上为不同版本的Delphi保留完全独立的环境。这意味着每台计算机上的项目副本、每台计算机中的包和库副本、SourceSafe中的项目、包和库的副本等。每台计算机都需要有相同的设置。我们已经利用环境变量来指导我们的项目在哪里查找某些项目文件(和库)。
另一个新问题:XE2引入了64位功能。我们还没有计划64位编译,但我们将来肯定会的。在所有这些项目中,我如何正确区分32位和64位?
我真正想要的是参考一本关于如何优化这样一个环境并使其保持最佳组织的好教程。我不希望任何人花时间回答这个问题中的所有问题。这些项目已有15年的历史,拥有来自世界各地的200多名开发人员,项目之间有很多交叉引用。例如,一个项目可能使用另一个项目的单元,反之亦然。我个人不喜欢这个概念,但我也不是一开始就设计的。我的任务是组织这个系统,并彻底记录如何在新的计算机上设置Delphi,让新的开发人员参与我们的项目。当我查看我们的项目时(因为我不一定是系统的开发人员,但正在被拉入开发),我看到代码的组织方式有很多混乱。
我假设Embarcadero可能有一些关于建立这样一个环境的指导方针和标准?
DCU文件的位置
关于作为编译过程输出的DCU,您应该在每个项目文件中指定一个DCU输出目录。在最新版本的Delphi中,默认值是:.$(Platform)$(Config)
。这将导致项目目录的子文件夹如下:Win32DEBUG
或Win64RELEASE
。
如果使用选项集设置项目文件,则可以通过少量选项文件控制此设置(以及所有其他设置)。
第三方代码的位置
您应该始终使用第三方库作为代码。如果供应商收取更多的费用来接收库作为代码,请付款。一旦你这样做了,你只需将源代码包含到你的版本控制系统(VCS)中,并以与处理你自己的代码大致相同的方式处理它。我这么说主要是因为你应该避免修改它。
一旦你在VCS中有了所有的代码,你就可以通过一次签出操作将整个源代码放到一台新机器上。
项目组织
我个人非常讨厌使用编译器搜索路径。我不使用它们,而是将项目中所需的每个单元都包含在.dpr文件中。
如果你确实使用了搜索路径,那么你就无法处理变体项目。例如,假设您的客户端在两年前发布的软件版本中发现了一个错误。你想通过发布2年前版本的软件升级来解决这个错误。要求他们升级到最新版本是不可行的,这是完全合理的。也许他们还没有支付升级费用。也许全面升级带来了他们现在不想解决的突破性变化。一个完美的例子是所有仍在使用Delphi7的Delphi开发人员。
现在,在激发了这个场景之后,你将如何为这个已有2年历史的项目创建一个构建环境?如果您使用的是搜索路径,那么它们将参考今天的库。您将被迫更改搜索路径,或者将旧库复制到当前库的顶部。
不使用搜索路径和在VCS中包含所有源代码,这一切都是微不足道的。
你的目标应该是能够签出你的程序的任何历史版本,并立即构建它。您应该能够满怀信心地做到这一点,即您正在构建与该版本发布时构建的软件完全相同的软件。这也需要你拥有构建自动化,但我无法想象你在这么大的项目中缺乏这一点。
我将处理文件夹组织。这来自一个软件套件,它有50多个exe和dll,还有大量的第三方库,所以我想我知道你来自哪里。。。
我们使用Perforce作为源代码管理系统,所以我默认工作区的根文件夹名为Perforce,但我也设置了其他几个工作区,它们位于Perforce2、Perforce3等中。
常规文件夹设置(从工作区根文件夹开始)
General
Components
Delphi
Indy
Indy9
Indy10
MadCollection
v2.5.8.0
v2.6.0.0
Plugins
Releases
Released
... a folder for each release we publish ... (and equal to a branch in Perforce)
Work
Acceptance
Sub1
Sub2
IDE中的环境库路径是空的(甚至BDE标准路径都不在其中)。这样可以确保项目的路径声明所需的所有路径,并且项目不依赖于特定计算机的IDE设置。
我们在IDE中设置了一个指向"General\Components\Delphi"的环境变量(即MRJ),因此在项目的选项中,我们将组件的路径声明为$(MRJ)MadCollection2.6.0.0
。
General持有我们项目使用的IDE插件和组件。我们保留源代码管理中使用的所有版本。这样,当我必须切换回旧版本来跟踪问题时,我可以简单地提取它并构建它,因为它的库路径仍然指向该特定版本所需的组件版本。
特定工作分支(Acceptance或其子分支之一)中文件夹的组织遵循以下模式:
General
Includes
MainComponent1
Project1
Project2
Shared
MainComponent2
Project3
Project4
Shared
Shared
Windows
SoftwareSuite
Scripts
Tools
MainComponent1
Project1
Dcus
Project2
Dcus
MainComponent2
Tools
Tool1
Dcus
Tool2
Dcus
General文件夹包含所有独立于平台的源/文件,Windows文件夹包含所有特定于Windows的文件。每个组件可以容纳多个项目,并将为这些项目之间共享的源提供一个共享文件夹。"常规"下的共享文件夹包含所有项目共享的源。Windows文件夹的设置方式类似。
请注意,每个项目都有自己的dcus文件夹。这是在项目选项中配置的。由于路径可以输入为.dcus
,我们(至少我)将其设置为任何新项目的默认路径。每个项目将其dcus发送到一个唯一的文件夹可以确保两件事:
- 只需在版本控制软件中设置一个过滤器,就可以很容易地使dcu脱离版本控制
- 更重要的是它确保了项目的编译/构建永远不会干扰另一个项目的编译或构建。我可以安全地更改设置和构建,因为我知道我不会被另一个项目的前一个构建中的dcu所困扰
我推荐以下做法:
-
保持库路径简单,并确保库路径中的所有内容要么是delphi附带的文件夹,要么是d:\Components\文件夹中的DCU二进制(库)文件夹。
-
使用MODERN类型的版本控制。我推荐Mercurial胜过其他人。源安全是垃圾,停止使用它。
-
备份您的环境(导出注册表项等),并以标准化的方式将其恢复到其他开发人员的PC上。您可以保留一些.reg和.cmd(批处理)文件,以自动设置新系统。您可以将这些脚本放在版本控制系统的组件存储库中。
在之前主要讨论的范围之外,我建议:
- 单元测试-例如使用DUnit
- 持续集成。只是为了确保所有这些项目都可以在另一台机器上编译,并且测试是可以的
因此,这与项目组织和VCS战略密切相关。
对于类似的设置,我工作过的一家公司发现这种配置很有用:
- 所有第三方库(组件等)都指向一个固定位置(C:\Delphi\name版本)
- Delphi项目可以在任何地方从版本控制中检出(驱动器C:或D:和文件夹名称无关紧要),因为所有项目和脚本都使用相对路径
- 所有项目都是一个主项目文件夹的子文件夹,所以检查这个文件夹会将Delphi项目和其他相关资源带到工作站,并且很容易进行版本控制更新
- 我们使用一个构建脚本(用ApacheAnt编写),它位于主文件夹中,并在所有文件夹上迭代以构建Delphi应用程序,并在开发数据库服务器上运行单元和集成测试,以在签入源代码管理之前验证所有更改是否有效
- 生成脚本还可以在每次提交时在生成服务器(Hudson CI)上自动运行,以查看是否出现故障
关于组件库的注意事项:尽可能避免安装包,更喜欢在运行时创建组件。如果你很快需要对一个已有五年历史的项目版本进行修复,卸载/安装十几个软件包可能会让你感到沮丧。至少对于非可视化组件来说,运行时创建是一个巨大的时间节约。
在源代码管理中签入第三方代码可能非常有用,例如,共享尚未作为新的官方版本提供的修复程序。子版本文档章节供应商分支机构介绍了最佳实践。此外,使用Subversion,您可以使用svn:externals将特定版本(标记)直接放入项目目录结构中。这既可以与第三方库一起使用,也可以与您自己的源代码一起使用,使依赖关系管理更容易,工作站设置更容易。
p.s.Ant构建脚本定义了所有内容的搜索路径,因此它是所有开发人员如何配置IDE、将第三方库放在哪里以及使用的编译器标志的"参考"
p.p.s.你的项目听起来很有趣-我对合同工作持开放态度:)
我的团队使用虚拟化,当我们回头看时,这是一个非常好的举措。我们使用MacBook Pro笔记本电脑和VmWare Fusion,但我相信其他软件包也能正常工作,比如VirtualBox或VirtualPC。
当新的开发人员启动或旧的安装遇到问题时,只需从主映像中复制一个新的VM映像,并且设置与原始映像完全相同,这总是一种很好的感觉。主映像存储在快速USB2磁盘上。现在,当Thunderbolt和USB3问世时,复制图像的速度会更快。只要有内存,就不会真正关心现代计算机的性能。8GB应该足以并行运行2个映像。虚拟化的另一个优点是,很容易尝试What-if-场景。在没有任何干扰真实工作环境的风险的情况下,尝试不同的配置和版本。
顺便说一句,我也认为SourceSafe是垃圾…:-)
Sométips:
-
为属于该项目的所有应用程序制作一个groupproject文件,每个应用程序在groupproj文件下的自己的目录中
-
您应该能够指定要包含在版本控制系统中的文件类型。确保将Delphi设置为以文本格式编写DFM文件。
-
您可以告诉Delphi在每个应用程序下的名为"dcu"的子目录中输出dcu(减少视觉混乱)。
-
第三方的东西经常坚持安装在不同的位置,对此你无能为力。制作一份文件,描述如何设置一个完整的工作环境,并使其保持最新的
-
在虚拟机中开发。新的开发人员将获得虚拟机的副本。
-
维护不同的Delphi版本?重新思考一下,试着转到一个版本。如果每个版本都必须有两个组项目和目录结构。[我假设你不是在用两个Delphi版本编译同一个应用程序,这是开发者的地狱]
-
DelphiXE2将输出到不同的32/64子目录,这应该不会产生任何问题。