Compile and Run a Small C# Program with Mono dmcs

You type dmcs to compile a C# file and Mono greets you with a deprecation notice before it even builds anything. This walks you through compiling a small C# source file with dmcs, running the resulting Mono executable, and producing a library instead when that is what you need. The installed command is Mono's C# compiler, but this local release prints a deprecation notice recommending mcs.

Allow about ten minutes if Mono is already installed. You need a shell, a text editor, and permission to write in your working directory.

1. Check the installed compiler

Start by checking which command will run and recording its version. These commands only read system state and do not need elevated privileges:

$ command -v dmcs
/usr/bin/dmcs
$ dmcs --version
Note: dmcs is deprecated, please use mcs instead!
Mono C# compiler version 6.8.0.105

On this machine, package mono-mcs is version 6.8.0.105+dfsg-3.6ubuntu2. The manual describes the command as the Turbo C# compiler and documents language support through C# 6, with partial C# 7 support. The executable currently accepts the same compiler options through dmcs, but new scripts should normally use mcs unless they specifically need the historical command name.

Checkpoint: if command -v dmcs prints nothing, stop here and install Mono through your normal package-management process. Do not guess a compiler path or run the build as root.

2. Create a complete source file

dmcs compiles the source files supplied on its command line. It does not provide partial compilation, so include every source file that belongs in the assembly. Save this as Hello.cs:

using System;

class Hello
{
    public static void Main()
    {
        Console.WriteLine("hello from dmcs");
    }
}

The file must have a .cs extension. This example has one class with the program entry point, Main. Keep the source in a separate directory from important build outputs while learning the command, so a failed experiment cannot overwrite unrelated files.

3. Build an executable

Compile the source into an executable with an explicit output name:

$ dmcs -target:exe -out:Hello.exe Hello.cs
Note: dmcs is deprecated, please use mcs instead!

The deprecation note is on standard error, while a successful compilation produces no ordinary success message. -target:exe selects a console executable, and -out:Hello.exe chooses the file name. The manual says exe is the plain executable target; winexe is for a Windows.Forms executable.

Check both the exit status and the output file:

$ printf '%s\n' "$?"
0
$ file Hello.exe
Hello.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

The exact file wording depends on your installed file release. The useful result is a non-empty assembly with the requested name and a zero compiler status.

4. Run the assembly with Mono

Use the Mono runtime to execute the assembly. This is an ordinary user command:

$ mono Hello.exe
hello from dmcs

Warning: do not run a newly compiled executable just because compilation succeeded. Treat C# source and the resulting assembly as code: inspect code from other people before running it, and run it with the least filesystem and network access appropriate to the task. The compiler does not make an untrusted program safe.

Checkpoint: you are ready to continue when mono Hello.exe prints the expected line and returns status 0. If Mono is missing, the compiler and runtime packages are incomplete; fix the package installation rather than changing the source first.

5. Produce a reusable library

For code that another program will reference, select the library target. The source still needs to be complete, but it does not need a Main method:

public class Greeter
{
    public static string Message()
    {
        return "hello from a library";
    }
}
$ dmcs -target:library -out:Greeter.dll Greeter.cs
Note: dmcs is deprecated, please use mcs instead!
$ file Greeter.dll
Greeter.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, 3 sections

Use -r:AssemblyName or -reference:AssemblyName when compiling another program that uses this library. If the assembly is outside the current directory, provide its path or add a search directory with -lib:PATH. The compiler already references mscorlib.dll, System.dll, and System.Xml.dll by default according to the local manual.

6. Add references and choose language compatibility

Most small programs need no extra reference. When they do, pass assemblies explicitly:

$ dmcs -r:ExtraLibrary.dll -out:App.exe Program.cs Helper.cs
Note: dmcs is deprecated, please use mcs instead!

7. Diagnose a failed build without losing a good output

Capture diagnostics and use a temporary destination when replacing an existing assembly:

$ dmcs -out:Hello.exe.new Hello.cs 2>compile-errors.txt
$ status=$?
$ if [ "$status" -eq 0 ]; then mv Hello.exe.new Hello.exe; else cat compile-errors.txt; fi
Note: dmcs is deprecated, please use mcs instead!

The mv runs only after a successful compile, so an older Hello.exe remains in place when the new build fails. If the command fails, read compile-errors.txt, correct the reported source or reference, and rerun. A missing input produces an error such as CS2001; check spelling and the current directory with pwd and ls -l. Remove the failed .new file only after checking that it is the disposable output you intended to create.

Done means