Incremental compilation with DMD

Robert Jacques sandford at jhu.edu
Fri Sep 11 05:53:38 PDT 2009


On Fri, 11 Sep 2009 07:47:11 -0400, Tom S  
<h3r3tic at remove.mat.uni.torun.pl> wrote:
> Short story: DMD probably needs an option to output template instances  
> to all object files that need them.
>
> Long story:
>
> I've been trying to make incremental compilation in xfBuild reliable,  
> but it turns out that it's really tricky with DMD. Consider the  
> following example:
>
> * module A instantiates template T from module C
> * module B instantiates the same template T from module C (with the same  
> arguments)
> * compile all modules at the same time in the order: A, B, C
> * now A.obj contains the instantiation of T
> * remove the instantiation from the A module
> * perform an incremental compilation - 'A' was changed, so only it has  
> to be recompiled
> * linking of A.obj, B.obj and C.obj fails because no module has the  
> instantiation of T for B.obj
>
> What happens is that the optimization in DMD to only emit templates to  
> the first module that needs it creates implicit inter-module  
> dependencies. I've tried tracking them by modifying DMD, but still  
> wouldn't find them all - it seems that one would have to dig deep in the  
> codegen, my attempts at hacking the frontend (mostly template.c) weren't  
> enough.
>
> Yet, I still managed to get some of these implicit dependencies figured  
> and attempted using this extra info in xfBuild when deciding what to  
> compile incrementally. I've tossed it on a project of mine with > 350  
> modules and no circular imports. The result was that even a trivial  
> change caused most of the project to be pulled into compilation.
>
> When doing regular incremental compilation, all modules that import the  
> modified ones must be recompiled as well. And all modules that import  
> these, and so on, up to the root of the project. This is because the  
> incremental build tool must assume that the modules that import module  
> 'A' could have code of the form 'static if (A.something) { ... } else {  
> ... }' or another form of it. As far as I know, it's not trivial to  
> detect whether this is really the case or whether the change is isolated  
> to 'A'.
>
> When trying to cope with the implicit dependencies caused by template  
> instantiations and references, one also has to recompile all modules  
> that contain template references to a module/object file which gets the  
> instance. In the first example, it would mean recompiling module 'B'  
> whenever 'A' changes. The graph of dependencies here doesn't depend very  
> much on the structure of imports in a project, but rather in the order  
> that DMD decides to run semantic() on template instances.
>
> Add up these two conservative mechanisms and it turns out that tweaking  
> a simple function causes half of your project to be rebuilt. This is not  
> acceptable. Even if it was feasible - getting these implicit  
> dependencies is probably a matter of either hacking the backend or  
> dumping object files and matching unresolved symbols with comdats.  
> Neither would be very fast or portable.
>
> Compiling modules one-at-a-time is not a solution because it's too slow.
>
> Thus my suggestion of adding an option to DMD so it may emit template  
> instances to all object files that use them. If anyone has alternative  
> ideas, I'd be glad to hear them, because I'm running out of options. The  
> approach I'm currently using in an experimental version of xfBuild is:
>
> * get a fixed order of modules to be compiled determined by the order  
> DMD calls semantic() on them with the root modules at the end
> * when a module is modified, additionally recompile all modules that  
> occur after it in the list
>
> This quite obviously ends up compiling way too many modules, but seems  
> to work reliably (except when OPTLINK decides to crash) without  
> requiring full rebuilds all the time. Still, I fear there might be  
> corner cases where it will fail as well. DMD sometimes places  
> initializers in weird places, e.g.:
>
> .objs\xf-nucleus-model-ILinkedKernel.obj(xf-nucleus-model-ILinkedKernel)
>   Error 42: Symbol Undefined  
> _D61TypeInfo_S2xf7nucleus9particles13BasicParticle13BasicParticle6__initZ
>
> The two modules (xf.nucleus.model.ILinkedKernel and  
> xf.nucleus.particles.BasicParticle) are unrelated. This error occured  
> once, somewhere deep into an automated attempt to break the experimental  
> xfBuild by touching random modules and performing incremental builds.
>
>

On the other hand, one-at-a-time builds can be done in parallel if you  
have multi-cores. Of course, still not a net win on my system, so vote++



More information about the Digitalmars-d mailing list