Compiling .Net (C#) on Red Hat Enterprise Linux without Mono installed

Our super computing cluster at the VLSCI is currently running Red Hat Enterprise Linux.  While we can simply send the helpdesk a request to get pretty much any free applications / libraries installed on the cluster, asking them to install Mono seemed embarrassing.  So I set about making a simple .Net assembly work on the cluster.

Mono includes a tool called "mkbundle" which allows for the bundling of .Net assemblies into single executables with no dependencies on mono.

I run Linux Mint for my normal Linux development, which doesn't seem to be fully compatible with RHEL, due to differences in glibc versions and countless other things.  Therefore, running the usual mkbundle run on my executable "mono-mem.exe" (which was compiled by VS2010 on windows):

mkbundle mono-mem.exe  -o mono-mem.broken  --deps --static -z

(where "mono-mem.broken" is our output and "-z" tells it to zip the libraries)

Will not result in an executable that will run on RHEL, instead you'll end up with output like:

 

[terences@merri mono-mem]$ ./mono-mem.broken 
./mono-mem.broken: /lib64/libc.so.6: version `GLIBC_2.9' not found (required by ./mono-mem.broken)
./mono-mem.broken: /lib64/libc.so.6: version `GLIBC_2.11' not found (required by ./mono-mem.broken)
./mono-mem.broken: /lib64/libc.so.6: version `GLIBC_2.8' not found (required by ./mono-mem.broken)

Which is not helpful at all.

Rather, what we need to do is to use mkbundle to generate a library with all the required mono stuff in it, and a c file containing our entry point to the app such that the c file can be compiled on our server (and thus get its dynamic libraries all sorted out).

Turns out this is a bit tricky, but doable.

Firstly, we use mkbundle to generate the c file and the bundle of libraries with this command:

/mkbundle -c -o mono-mem.c -oo bundle.o --deps mono-mem.exe reference_library.dll
(Where "-c" tells it to build the c file but not the final assembly "-oo" builds the bundle library and "reference_library.dll" is a dll that my app needs).

From this, we copy mono-mem.c to our cluster along with bundle.o.

But, we also need the header files and library files from mono for the RHEL / CentOS platform.  To get access to these, I needed to create a CentOS install with mono and then copied the contents of "lib64" and "include" from the mono directory.  For your convenience I have extracted these and created an archive that you can download here:

With those files extracted to your working directory, compiling is as simple as:

cc mono-mem.c bundles.o /PATH_TO_LIBS/mono-2.10/lib64/libMonoPosixHelper.so /PATH_TO_LIBS/mono-2.10/lib64/libmono-2.0.a -I/PATH_TO_LIBS/mono-2.10/include -L/PATH_TO_LIBS/mono-2.10/lib64 -lpthread -lc -lrt -lm -ldl -lz -omono-mem.o
(Where PATH_TO_LIBS is the path to where you extracted the libraries).

Then it is just a matter of updating your LD_LIBRARY_PATH to include your mono libs:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/vlsci/VR0002/terences/build/mono-2.10/lib64/

And the app should run perfectly.