Compiling C# code from the command line

It”s well known that the C# compiler is the csc.exe and that you can find it on the installation folder of the .NET platform. What i”ve seen in these last days (specially since i”ve started my in-depth study of the C# language and have started discussing it with some collegues and friends) is that many people use the C# compiler and really don”t know what it does or what are the available options you can use when you compile a C# app.

For instance, i was astonished with the number of people who don”t know what the following line does:

Maybe this is a classical example of why VS rottens the mind (and no, i won”t stop using VS – specially now, that I”m a proud owner of a resharper”s lic:),,)?

Even among those that know what it does (btw, it”s compiling the HelloWorld.cs file into an exe called HelloWorld.exe and saying that it needs the “all mighty” mscordlib.dll to do that), many don”t really understand why you can reduce it simply to this (besides saying that it”s magical):

csc HelloWorld.cs

So i thought I should write something about this (even though that i”m positive that there”s already lots and lots of info out there). Ok, so why do the previous 2 instructions produce similar results? Easy:

by default, the csc.exe will always generate an executable. since i was trying to built an exe, then i can just remove the /target:exe from the command;

mscorlib.dll is a special assembly since it contains several of the basic (or primitive) types that you use when you build a C# program. The C# compiler knows this and will always add a reference to this assembly. Notice that this might not be what you want (for instance, when you”re building a silverlight application, you need to compile your cs files agains Silverlight”s mscorlib.dll and not against the one that is installed with the full .NET version). In these scenarios, you can cancel the default behavior of the compiler by passing the /nostdlib parameter;

since i wanted the assembly to have the same name as the file that i was compiling, then it”s safe to discard the /out parameter. When you do that (ie, when there”s no /out parameter), the compiler will name the final assembly with the name of the file that has the Main method (exe) or the name of the first cs file you”re compiling (dll).

Not too complicated, right? More dificult is understanding why you can compile an app that uses a type defined inside the System.Data.dll assembly without passing a reference to that assembly during compilation. well, it happens that the csc.exe can also receive a response file. A response file is simply a text file where you define a switch per line. For instance, if i wanted, i could transform my first example in a helloworld.rsp (notice the extension) file that would look like this:

/target:exe/referente:mscorlib.dll/out:HelloWorld.exe

You can make the compiler to use these settings by using the /@ switch:

csc @helloworld.rsp helloworld.cs

If you want, you can have several response files. One important thing: the C# compiler will always load any csc.rsp response files it finds. This means that you can simply rename the previous file to csc.rsp and the compiler will pick it up automatically, making the @ switch disposable(do keep in mind that in my example you really don”t need a response file since the parameters i”m passing are also automatically used by the compiler, as explained in the previous paragraphs).

Ok, interesting right? but still doesn”t answer my last question. It happens that the compiler currently searches for rsp files in two places: current working folder and the installation folder of the compiler. If you open that folder, then you”ll see that it has a csc.rsp file with references to several of the assemblies installed by the .NET (including the assembly i mentioned in the previous example). This file is special and is always picked up by the compiler. That”s why you can do what i was saying 2 or 3 paragraphs above…

One important gotcha: the csc.rsp file will always be loaded by the compiler. If you don”t want that, then pass the /noconfig switch to the C# compiler.

btw, do notice that you can add or remove assemblies, though i see no reason for removing any of the list. Some people think that by removing assemblies they”re improving the performance of the new compiled assembly. This is not true because the compiler is smart enough to only add references to types that are used in your C# code files.

Finally, another question that pops up quite frequently, is where do those assemblies come from? for instance, what happens when you have several versions of the .NET platform installed. To answer this, we must know the places where the C# compiler searches for the dll:

working directory

directory that contains the csc file (notice that inside this directory you”ll find copies of the dlls that exist on the GAC.)

folders passed through the /lib switch

folders defined on the LIB ambient variable

As always (or should i say, as amost always?) msdn has a good reference on the parameters you can pass to the compiler. Reading them garantees that you”re aware of all the options you can use when you compile your program. Don”t stop using VS (or another cool editor). However, do know what you”re doing!

I am using Visual Studio Express 2008 when I save to a .cs I get 2 other files (3 Total) Example.cs Example.Designer.cs Example.resx. Which one am I compiling? Everytime I try to compile Example.cs I get some error The name or namespace “Linq” does not exist in the name space ”System” (Are you missing an assembly reference?)

Jon, you”re probably adding a new form item. that”s why you get 3 items. you”re supposed to compile the cs files and you do need to pass a reference to the dll that has the linq namespace. btw, if you”re using VS express, you can build your project from within the environment. You should use it whenever possible. I only wrote this post to show some basic concepts which many still don”t know…