Running mono

Basic steps

To work with mono, you first have to create a C# program. Open up your favourite editor, and type in the following code:


using System;

class Hello
{
public static void Main(String[] args)
	{
	Console.WriteLine("mono:: is alive and well...");

	for (int i = 0; i < args.Length; i++)
		Console.WriteLine("Argument {0} = {1}", i, args[i]);
	}
}

Save the file as hello.cs. To compile this into a working program, type mcs hello.cs. If you get the following:


[hinne@taurus hello]$ mcs hello.cs
RESULT: 0
[hinne@taurus hello]$

you know the compile worked fine. If you see some strange error messages including the word 'parser' somewhere, you made a mistake in your program. Fix this up first.

You are now ready to execute your first mono program. To execute the code, type


[hinne@taurus hello]$ mono hello.exe arg1 arg2 arg 3

(where we have given some arguments just for fun) and you'll see the following:


mono:: is alive and well...
Argument 0 = arg1
Argument 1 = arg2
Argument 2 = arg
Argument 3 = 3
RESULT: 0

As you can see, mono printed the line "mono:: is alive and well" and printed the list of arguments. This completes the creation and execution of your first mono program.

Interpreter

But mono will allow you to do more. First of all, mono is the compiled mono execution environment which uses the Just in Time (JIT) compiler. Mono also comes with an interpreted environment, which can be accessed using the command 'mint' as follows


[hinne@taurus hello]$ mint hello.exe arg1 arg 2
mono:: is alive and well...
Argument 0 = arg1
Argument 1 = arg
Argument 2 = 2
[hinne@taurus hello]$

As you can see, it makes no difference to mono output which environment you use, but what happens under the hood is very different. If you use 'mono' as the command line tool, you call the 'production' execution environment which will read your portable executable (PE) file, and call the just in time (JIT) compiler to compile the PE code down to machine level code (in my case, an x86 architecture) after which it is executed.

If you use mint, the JIT is not used, and the PE code is interpreted into x86 instructions for execution. In fact, for our simple 'hello' mint is slightly faster. The point is that the JIT compiler will take some time to compile the code of our program and store it in some location in memory, but the subsequent execution of the code is faster with mono.

You can see what happens below (the thing to look for is the 'user' time: 0.1 seconds with mono and 0.06 seconds with mint):


[hinne@taurus hello]$ time mono hello.exe arg1 arg 2
mono:: is alive and well...
Argument 0 = arg1
Argument 1 = arg
Argument 2 = 2
RESULT: 0

real    0m0.575s
user    0m0.100s
sys     0m0.010s
[hinne@taurus hello]$ time mint hello.exe arg1 arg 2
mono:: is alive and well...
Argument 0 = arg1
Argument 1 = arg
Argument 2 = 2

real    0m0.545s
user    0m0.060s
sys     0m0.000s
[hinne@taurus hello]$

After this simple run of mono, it is time to play with some options. I won't cover these in detail since there are quite a few, and also because I assume you downloaded mono to hack it around in the first place. So I'll leave some pointers.

Statistics

It is also possible to collect some runtime statistics on your program. These will give you some idea of the resource utilisation of your program.


[hinne@taurus hello]$ mono --stats hello.exe
mono:: is alive and well...
RESULT: 0
Mono Jit statistics
Compiled methods:       58
Methods cache lookup:   15
Method trampolines:     698
Basic blocks:           188
Max basic blocks:       15
Allocated vars:         238
Analyze stack repeat:   61
Compiled CIL code size: 2450
Native code size:       10167
Max code size ratio:    7.13 (FileStream::FlushBuffer)
Biggest method:         1016 (StreamWriter::Write)
Code reallocs:          27
Allocated code size:    22073
Inlineable methods:     17
Inlined methods:        22

Created object count:   18
Initialized classes:    127
Used classes:           37
Static data size:       288
VTable data size:       8292

Inspecting IL Assembly code

Mono also provides a small tool that will let you disassemble the executable (.exe) file so you can have a peek under the hood. This tool is monodis, and is run as follows:


[hinne@taurus hello]$ monodis hello.exe
.assembly extern mscorlib
{
  .ver 0:0:0:0
}
.assembly 'hello'
{
  .hash algorithm 0x00008004
  .ver  0:0:0:0
}
  .class private auto ansi beforefieldinit Hello
        extends [mscorlib]System.Object
  {

    // method line 1
    .method public hidebysig  specialname  rtspecialname
           instance default void .ctor()  cil managed
    {
        // Method begins at RVA 0x20ec
        // Code size 7 (0x7)
        .maxstack 8
        IL_0000: ldarg.0
        IL_0001: call instance void System.Object::.ctor()
        IL_0006: ret
    } // end of method instance default void .ctor()

    // method line 2
    .method public static
           default void Main(string[] args)  cil managed
    {
        // Method begins at RVA 0x20f4
        .entrypoint
        // Code size 56 (0x38)
        .maxstack 5
        .locals init (
                int32   V_0,
                int32   V_1)
        IL_0000: ldstr "mono:: is alive and well..."
        IL_0005: call void System.Console::WriteLine(string)
        IL_000a: ldc.i4.0
        IL_000b: stloc.0
        IL_000c: ldloc.0
        IL_000d: ldarg.s 0
        IL_000f: ldlen
        IL_0010: clt
        IL_0012: brfalse IL_0037

        IL_0017: ldstr "Argument {0} = {1}"
        IL_001c: ldloc.0
        IL_001d: box [mscorlib]System.Int32
        IL_0022: ldarg.s 0
        IL_0024: ldloc.0
        IL_0025: ldelem.ref
        IL_0026: call void System.Console::WriteLine(string, object, object)
        IL_002b: nop
        IL_002c: ldloc.0
        IL_002d: ldc.i4.1
        IL_002e: add
        IL_002f: stloc.1
        IL_0030: ldloc.1
        IL_0031: stloc.0
        IL_0032: br IL_000c

        IL_0037: ret
    } // end of method default void Main(string[] args)

  } // end of type Hello

[hinne@taurus hello]$

This is the listing of the code of your program in a language called IL assembly, or Common Intermediate Language (CIL). The CIL provides the portability of the mono platform, and ensures that code compiled with Microsoft's .NET framework will work on mono and vice versa.

Man pages

Mono has man pages already installed, and generally, typing man before the command you wish to execute should help in getting a list of the options. In many cases, it's still up to you to figure out what they do.