Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is C# compile/build an incremental process?

Our solution contains lots of C# projects. There are complicated dependency relationship between them, eg. project A/B/C, A dependents on B, B dependents on C. If I change one file in project C, then rebuild the solution, project A,B,C will be rebuild together.

In C++, build contains two process, compile and link. If I change one file in project C, then I build the solution, the relevant file in A and B will be compiled(other's files won't be compiled, their .obj will be reused in link process), then do link.

In java, just the changed file in project C will be recompiled, others file will be kept then package to .jar. It reuse previous work output(not changed file's .class).

In a word, C# doesn't reuse any previous work output. It doesn't have any middle file just like Java's .class and C++'s .obj. So in this point, I feel C# doesn't do incremental build process. Some little change will cause a big build process. I don't understand why C# doesn't use previous work output to accelerate the build process.

I am not sure whether my understanding of C# compile/build process is right. Could you please help to explain more? Thanks a lot.

like image 475
Lei Xiao Avatar asked Jan 04 '16 06:01

Lei Xiao


4 Answers

The C# compiler does incremental compilations, I'm not sure where you got the idea that it doesn't. Maybe, due to the complexity of your solution, you are not understanding the dependencies correctly and projects that you assumed would not need to be recompiled are in fact necessary.

The best way to check the compiler's behavior is to create a simple dummy solution and play around with it:

Setup:

  1. Create an empty Visual Studio C# solution.
  2. Add any two projects, A and B.
  3. Make project B a reference in project A.
  4. Implement a class FooInB in B and use it in another class in A BarInA.

Now lets play around a bit with this setup:

  1. Compile the solution. You will see that both projects compile.
  2. Compile the solution again. You will see that none of the projects compile, both are up to date.
  3. Change the implementation in BarInA and compile again. You will see that only one project compiles, A. There is no need to compile B again as there are no changes.
  4. Change the implementation in FooInB and compile one last time. You will see that both projects compile. This behaviour is correct, A depends on B so any change in B will necessarily need that A recompile again to make sure it is pointing to the latest version of B. In a theoretical world where the C# compiler could detect if the changes in B have no consequences in A and could therefore "optimize" away building A again, would be a nightmare scenario where each project could be referencing different and outdated assembly versions.

That said, I'd like to point out that, AFAIK, the C# compiler will only perform incremental compilations at project level. I am not aware of any incremental compilation optimizations at class level inside any given assembly. Someone with much more insight in the inner workings of the compiler might be able to clarify this behavior.

like image 133
InBetween Avatar answered Sep 30 '22 13:09

InBetween


Ok.. you are actually on the right track.. if there are 3 projects in the solution, you can give reference of one project to the other. It means that project A dependent on project B dependent on project C..

When you build a project, all the built files and dlls (from the post build events ) end up in the bin folder of that project.

So when you build project A, project C will build first (because A->B->C). Project B uses the built components of project C and creates its own components. and project A uses components of B and C and creates its own components.

Because of this, if you only build project A, if the referencing is correct, you will see all build files of B and C in the bin folder on project A.

like image 24
Jay Nirgudkar Avatar answered Sep 30 '22 14:09

Jay Nirgudkar


I have a solution with many projects and even more cross-project references.

For simplicity lets say I have project A B and C.

  • A is my main desktop exe which reffers B and C
  • B contains windows forms and reffers C
  • C contains buisness and database logic.

My main problem is: B takes about fourty five seconds to compile. Now let's say I only change a small line of code in C, the compiler will compile C and after that it will compile B, than A Since I mostly change code in C which compiles very fast I always have to wait for B to compile.

I discovered .NET Daemon from redgate. This is a tool which changes the build process and will only rebuild B if the public API from C changes. This can have a massive impact on your build process. I would say, it saves about 80% of the time spent building over a day based on my personal experience..

However, I just looked and they aren't selling it anymore: https://www.red-gate.com/products/dotnet-development/dotnet-demon/

Visual Studio 2015 will introduce Microsoft's new Roslyn compiler, with improvements which we believe make .NET Demon redundant.

I am still on Visual Studio 2013 but I think initial observation of the build process and the other answers about the NET build may not be true anymore for Visual Studio 2015 with Roslyn. Maybe it behaves more like the dotnet-deamon build.

On a side note: My newer projects use IOC containers, everything is wired up in the main project without much cross project references. This will also improve the build process since almost everything can be build in parallel.

like image 42
Jürgen Steinblock Avatar answered Sep 30 '22 13:09

Jürgen Steinblock


You are kind of right.

If project A depends on project B. A change in dependent project B, does make a recompile of project A necessary.

If project B depends on project C. A change in project B, does not make project C recompile.

In Java, one class/file is compiled to a single .class file. Therefor the whole project does not to be recompiled when a single file changes.

Before distribution these .class files are combined into a .jar. If a single .class file changes, the whole .jar also needs to be reassembled.

In .Net you immediately compile a project to an assembly (.dll or .exe), so a single file change, needs a recompile of the whole assembly.

The same behavior is seen on Java environments where the .jar (or dependencies like .apk) is used to run/debug the application. The whole .jar is also needed during development. And the whole project is recompiled when a single file changes.

You can always place projects, outside of your solution. And only add a reference the .dll they produce. This will minimize compile times.

like image 44
GvS Avatar answered Sep 30 '22 12:09

GvS