在慢速编译环境中进行编码的最佳方法是什么


15

我曾经以TDD风格使用C#进行编码-编写/或更改一小段代码,在10秒内重新编译整个解决方案,然后重新运行测试。简单...

几年来,这种开发方法对我一直非常有效,直到去年我不得不回到C ++编码的那一刻起,我才真正感觉到我的生产率从此大大降低了。C ++作为一种语言不是问题-我有很多C ++开发人员的经验……但是过去。

对于一个小型项目,我的工作效率仍然可以,但是当项目规模增加时,情况会变得更糟,一旦编译时间达到10分钟以上,它就会变得非常糟糕。如果发现错误,则必须再次开始编译,等等。这简直令人沮丧。

因此,我得出的结论是:(像以前一样)一小部分是不可接受的-任何建议,当我手动检查代码时(不依赖快速的C#编译器)如何使自己养成一个小时左右的古老编码习惯,并且仅在几个小时内重新编译/重新运行一次单元测试。

使用C#和TDD,以进化的方式编写代码非常容易-经过十几次迭代之后,我开始的任何废话都以良好的代码结尾,但对我而言不再起作用(在缓慢的编译中)环境)。


stackoverflow.com/questions/5078409/…这些可能应该合并/放在一个地方。
本L

见拉索stackoverflow.com/questions/373142/...加快C ++编译时间。
日食

2
开始剑战。; p
Steven Jeuris

上一次我认真使用C ++时,使用预编译的标头将编译时间减少了四倍。
gnasher729 2015年

Answers:


16

我想到了几件事:

  1. 利用分布式编译。您可以使用GCC(“ distCC”?)或VC(Xoreax的IncrediBuild并不便宜,但值得花每一分钱)来做到这一点。

  2. 将您的项目拆分为动态加载的库,并仔细尝试最小化对它们的依赖。较小的可执行文件链接速度更快。

  3. 针对小型测试项目而不是整个大型应用程序进行编程。

  4. 采用模板元编程在编译时执行算法。是的,这实际上会增加编译时间,但也会减少测试所需的周转时间:如果编译正确,那就完成了。

  5. 投资硬件。更多的CPU内核(在您的计算机或其他计算机中)将对分布式编译产生疑问,而大量的内存以及快速的磁盘(SSD而非HDD)将大有帮助。如果您拥有64位系统和大量的RAM,那么在RAM磁盘上进行编译可能会提供令人难以置信的速度提升。


1
根据我的经验,编译器缓存实际上是比分布式编译更好的主意。
pqnet 2014年

说到RAM磁盘和SSD,我很惊讶它没有带来太多的编译速度。我当前的项目(Android上的Java)可以在约45秒内从SSD清洁状态,而在约40秒内从RAM磁盘进行编译(整个工具链位于RAM磁盘中,而不仅仅是源代码)。我会说这并没有急剧增加。
Haspemulator 2014年

10

其他人尚未提及的另一种技术解决方案是切换到固态驱动器而不是常规硬盘驱动器。在我之前从事的项目中,SSD将构建时间从30分钟缩短到了3分钟。

当然,它们很昂贵。对于您的老板,请根据一次性投资的价格来计算开发人员损失的时间。这笔投资可能会在几个月内收回成本。


6
那很有意思。也就是说90%的构建时间是I / O磁盘延迟。
Mike Dunlavey

我还没有看到90%的下降,但是下降幅度很大。它似乎并没有加快编译速度,但是肯定可以加快链接速度。如果您要对大型项目进行少量更改(因此更改中没有太多编译),然后重新链接,则可能会得到此结果。(这是使用C ++的Visual Studio2008。)
David Thornley,

1
这是一个好主意。另外,在文件系统上安装一部分RAM会很快,而且很便宜。
Goran Jovic

2
Ramdisk更快(更便宜)。
SK-logic

1
@John:是的,一个编写良好的编译器(IMHO)应该受I / O约束。
Mike Dunlavey 2015年


3

较长的编译时间有时是个问题,但是已经提到的模块化可以(大部分)帮助克服这一问题。

更加严重的是,您无法进行任何编译,每个代码更改都必须提交给另一个大陆的另一个部门才能应用到测试/开发环境中,而这个过程可能要花费数天才能完成。

我现在在这样的环境中工作,这个系统已经花了我一个多星期的时间(而且在预算用完之前,该项目的预算只有4周的时间),只是为了安装我们的变更的初始版本(然后他们犯了错误,导致部分文件无法被应用程序服务器接收,因此我们还要等待几天的延迟)。现在的每个微小更改(例如,我们在测试中发现需要修复的某些内容,例如错过的错误情况)都可能导致延迟一天或更长时间。

在这种情况下,您甚至在尝试编译您的代码之前,都应尽可能确定没有任何错误。感觉就像我回到大型机编程一样,在那里我们每个月有5分钟的CPU时间用于所有编译和测试工作。


1
天哪,这是一个地狱的情况。我确实记得大型机时代。我们做了很多代码的“桌面检查”。如此的惊人成就令人惊奇,例如对月球飞行的无尽模拟。
Mike Dunlavey

3

我很容易记住,构建花费了很长时间。一些缓解方法:

  • 通过组合库或dll构建系统。这样,当您修改某些代码时,唯一需要重新编译的部分就是您的部分。
  • 实现功能所需编辑的代码点数不仅会影响您必须进行的编辑量,而且还会影响您输入错误的频率,从而扩大了compile-debug-edit-compile循环。减少代码冗余的任何内容(例如DRY)都可以帮助您。
  • 如果您在调试器中,并且可以在不离开调试器的情况下进行编辑,重新编译和继续操作,那将非常有帮助。

2

10分钟以上即可进行编译?认真吗

您是否正在使用进行增量构建的IDE(例如Eclipse)?如果没有,您可能应该这样做,它将在几秒钟而不是几分钟内完成基本编译。

还是在谈论集成的东西,您需要在其中构建整个应用程序以测试您的更改?如果是这样,请在进行完整构建之前查看较小的测试,以确保主要错误不在您的代码中。


5
10分钟很小。我曾在一个项目上工作,该项目花了一个小时才能在单核计算机,PCH和所有设备上从头开始进行编译和链接。当然,除了自动发布版本外,没有人会在一个处理器核心上构建它,但是...如果您不得不更改几乎所有地方都包含的标头中的某些内容(字符串操作,错误处理),您可能会发疯。
2011年

2
几年前曾在一个系统上工作,而该系统完整编译需要48小时才能编译。当然,完整的构建只在星期五晚上才开始,希望我们星期一回到办公室时才能完成。相反,我们根据需要构建了小的模块(例如,单个DLL)。
jwenting 2011年

2
如果我可以+1到TrueDub,则对上面的所有评论-1。是的,如果您重新编译所有内容,则可能需要很长时间。但是,如果完全不考虑依赖项管理,那么整个10个小时的重新编译项目都可以在不到一分钟的时间内进行增量重新编译。你们所有人都应该为自己浪费时间浪费雇主等待您的重新编译而感到羞耻,而这会节省大量时间。
Dunk

2
而且,如果您在一家恰好位于几个MLoC项目中的小型商店工作,那么这意味着相当一部分代码是旧的,始于十年前的多个小型项目,而编译速度从来都不是问题,依赖管理非常糟糕。那么,您是否要告诉这样的公司将所有这些东西扔掉,并花十年的时间重新编写它?
2011年

2
@Dunk:这是一家小公司,只有不到十个开发人员从事多MLoC项目。这是非常从数百个开发商这样做不同的:你不能再写入任何东西从头开始,因为你需要几年这样做。尽管我讨厌这个想法,但在分布式编译上进行投资在经济上是可行的,而重写则不可行。哦,我继承了那些接口。:-x十年前,我还没想到他们。(我更改了很多代码以使用TMP,以便在编译时发现更多错误,而在现场发现的错误更少。)
sbi 2011年

2

首先,为什么首先要花这么长时间进行编译?

  • 您的环境(IDE,制造商或其他)是否支持增量构建?确保只重新编译更改,而不是整个过程。
  • 如果您有多核计算机,则您的IDE可能支持并行编译。我知道Visual Studio可以做到这一点。显然gcc也是如此。因此,请获得更好的计算机,并启用并行编译。
  • 考虑使用预编译头。
  • 如果您尝试了所有这些操作,但编译仍然很慢,请查看您的代码。寻找不必要的依赖项。您是否包含一个头文件,其中前向声明就足够了?考虑使用PIMPL习惯用法来减少对标头的依赖性。

如果毕竟您的构建时间仍然很慢,那么请解决该问题:创建许多小型测试项目,并分别处理每个项目。确保您有一个每晚自动执行的构建系统,该系统可以进行全新签出,构建所有内容并自动运行所有单元测试。

最后,如果仍然需要很长时间来测试您的更改,请多加思考。确保在版本控制系统中进行差异化测试,并在测试之前仔细查看所有更改。简而言之,这非常类似于嵌入式系统开发,在该系统中,测试的周转时间很长,并且检查系统状态的能力受到限制。

这使我想到了另一个想法:检测您的代码以使用日志记录。这样一来,您无需重新构建和重新运行多次就可以查看问题所在。


2
我不确定GCC是否支持并行编译,如果您也告诉make或类似工具会启动GCC的多个副本这一事实,我不确定。
Zachary K

1
PIMPL +1。我从事的项目的构建时间不受控制。在那个项目中,我不关心每个标题中还包含多少其他标题。在我的下一个项目中,我着重指出了通过广泛使用PIMPL来将其最小化的问题。尽管第二个项目的大小可能是第一个项目的两倍,但构建时间仍然很长。
2014年

1

您可能需要多管齐下的方法:

1)更快的构建系统。尽可能多的核心/内存/快速磁盘。对于较大的C ++项目,您会发现磁盘通常是一个限制因素,因此请确保使用快速磁盘。

2)项目的更多模块化。分解内容,以便更改不会轻易导致对所有内容进行完全重新编译。坦率地说,将尽可能多的基本内容推入单独的dll / so文件中,以便使项目的一部分与其余部分完全脱离。

3)增量构建/分布式构建/缓存,以适合您的环境。在某些系统上,distcc(分布式构建)和ccache(缓存部分构建的内容)可以节省大量的编译时间。

4)确保您的构建可以很好地并行化。尤其是在makefile环境中,不难进入意外设置Makefile使得无法并行构建的情况。


0

大量的日志记录和内部验证有助于延长周转时间。构建完成后,一次运行即可一次发现大量可能的问题。

当处理相当复杂的算法或簿记时,将一个高度简化的版本与“真实”版本同时包含会有所帮助。在任何运行中,都包含有用的参考数据。


0

@sbi和@Michael Kohne说了什么。

在构建过程本身上花费时间和精力。曾几何时,我们拥有一款庄重,成熟的产品,整个构建花费了一个多小时。花了很多时间和精力来修复构建依赖项所声称的内容,然后再修复/减少它们的实际存在。构建时间降至约30分钟。

更改构建工具后,它的下降幅度更大。对于多部分项目,“ scons”可以在进行任何链接之前进行所有编译。使用多个makefile的“ make”会在该项目的链接之前执行一个项目的编译,然后继续进行。

这使我们意识到,所有单独的编译命令都可以大规模并行完成。在慢速计算机上为'distcc',在多核计算机上为make / scons -j8。如此一来,完整的构建工作就减少了几分钟。

用另一种方式,创建一个自动的每晚构建过程。这样,如果有问题的东西提交到您的源存储库,则第一个上班的人来查看并解决问题,可能会阻止多个人(重新)进行多个失败的构建。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.