.Net technology weblog

Mono mkbundle - How to export stand alone UI application on Linux base on GTK#

Lot of people would like to have a multiple platform application using share code One of the best cross platform language is C# and .Net framework. With C# you able to create application on too many platforms same as Windows, Linux, Mac, iOS, Android, Tizen, Web application and so on. But the big problem around C# is huage framework and installtion by customer, this is good to know how you able to have standalone application on diffent platforms.

Must know something about License

First you must know Mono changed the license to MIT at 2016 and it's free to use whatever you want.

What is the mkbundle

mkbundle is part of the Mono project that generates an executable program that will contain static copies of the assemblies listed on the command line. You able to create executions binary for Windows, Mac and Linux.

What is the GTK+ and GTK#

GTK+, or the GIMP Toolkit, is a multi-platform toolkit for creating graphical user interfaces. Offering a complete set of widgets, GTK+ is suitable for projects ranging from small one-off tools to complete application suites.

Gtk# is a .NET language binding for the GTK+ toolkit and assorted GNOME libraries.

What is the Mono.Xwt

Xwt is a new .NET framework for creating desktop applications that run on multiple platforms from the same codebase. Xwt works by exposing one unified API across all environments that is mapped to a set of native controls on each platform.

This means that Xwt tends to focus on providing controls that will work across all platforms. However, that doesn't mean that the functionality available is a common denominator of all platforms. If a specific feature or widget is not available in the native framework of a platform, it will be emulated or implemented as a set of native widgets.

Xwt can be used as a standalone framework to power the entire application or it can be embedded into an existing host. This allows developers to develop their "shell" using native components (for example a Ribbon on Windows, toolbars on Linux) and use Xwt for specific bits of the application, like dialog boxes or cross platform surfaces.

Xwt works by creating an engine at runtime that will map to the underlying platform. These are the engines that are supported on each platform:

  • Windows: WPF engine, Gtk engine (using Gtk#)
  • MacOS X: Cocoa engine (using Xamarin.Mac) and Gtk engine (using Gtk#)
  • Linux: Gtk engine (using Gtk#)

This means for example that you can write code for Xwt on Windows that can be hosted on an existing WPF application (like Visual Studio) or an existing Gtk# application (like MonoDevelop). Or on Mac, you can host Xwt on an existing Cocoa/Xamarin.Mac application or you can host it in our own MonoDevelop IDE.

Linux requirements

  1. Install the gtk-2 development headers first. On Debian, this can be done using: apt-get install libgtk2.0-dev libpango1.0-dev libglade2-dev

  2. Install zlib-devel version from the package manager if you want to compress your binary

NOTE: Better to do it because already you have lot of dependency and better to minimal your code

Download GTK# 2 source code and compile using the code at below:

git clone
cd gtk-sharp
git checkout gtk-sharp-2-12-branch

After you success compile progress take a copy of all the .so files

find . -name "*.so"

You must have 5 so files. those file should be copy into the final distribute package.

Create config file for your application

Here we need to map all dll usage in our application to Linux version files for example all the native .dll was used in GTK# should be convert to Linux .so files for example if you have GtkTest.exe you need to create config file GtkTest.exe.config and edit it using vim or text editor

	<dllmap dll="i:cygwin1.dll" target="" os="!windows" />
	<dllmap dll="libc" target="" os="!windows"/>
	<dllmap dll="intl" target="" os="!windows"/>
	<dllmap dll="intl" name="bind_textdomain_codeset" target="" os="solaris"/>
	<dllmap dll="libintl" name="bind_textdomain_codeset" target="" os="solaris"/>
	<dllmap dll="libintl" target="" os="!windows"/>
	<dllmap dll="i:libxslt.dll" target="" os="!windows"/>
	<dllmap dll="i:odbc32.dll" target="" os="!windows"/>
	<dllmap dll="i:odbc32.dll" target="libiodbc.dylib" os="osx"/>
	<dllmap dll="oci" target="" os="!windows"/>
	<dllmap dll="db2cli" target="" os="!windows"/>
	<dllmap dll="MonoPosixHelper" target="" os="!windows" />
	<dllmap dll="i:msvcrt" target="" os="!windows"/>
	<dllmap dll="i:msvcrt.dll" target="" os="!windows"/>
	<dllmap dll="sqlite" target="" os="!windows"/>
	<dllmap dll="sqlite3" target="" os="!windows"/>
	<dllmap dll="libX11" target="" os="!windows" />
	<dllmap dll="libgdk-x11-2.0" target="" os="!windows"/>
	<dllmap dll="libgtk-x11-2.0" target="" os="!windows"/>
	<dllmap dll="libXinerama" target="" os="!windows" />
	<dllmap dll="libcairo-2.dll" target="" os="!windows"/>
	<dllmap dll="libcairo-2.dll" target="libcairo.2.dylib" os="osx"/>
	<dllmap dll="libcups" target="" os="!windows"/>
	<dllmap dll="libcups" target="libcups.dylib" os="osx"/>
	<dllmap dll="i:kernel32.dll">
		<dllentry dll="__Internal" name="CopyMemory" target="mono_win32_compat_CopyMemory"/>
		<dllentry dll="__Internal" name="FillMemory" target="mono_win32_compat_FillMemory"/>
		<dllentry dll="__Internal" name="MoveMemory" target="mono_win32_compat_MoveMemory"/>
		<dllentry dll="__Internal" name="ZeroMemory" target="mono_win32_compat_ZeroMemory"/>
	<dllmap dll="gdiplus" target="" os="!windows"/>
	<dllmap dll="gdiplus.dll" target=""  os="!windows"/>
	<dllmap dll="gdi32" target="" os="!windows"/>
	<dllmap dll="gdi32.dll" target="" os="!windows"/>

	<dllmap os="linux" dll="libglib-2.0-0.dll" target=""/>
	<dllmap os="linux" dll="libgobject-2.0-0.dll" target=""/>
	<dllmap os="linux" dll="libgthread-2.0-0.dll" target=""/>
	<dllmap os="linux" dll="glibsharpglue-2" target=""/>

Take a copy of GTK# files to the Release folder

They must be in gac directory /usr/lib/mono/gac/* for example you can find /usr/lib/mono/gac/gtk-sharp/[VERSION]/gtk-sharp.dll From here you need to take a copy for both .dll and .config files. IMPORTANT: you must take a copy of .config files too because they contains dllmap config inside for Linux

Compile and make bundle file

After you compile and test your project successfully you must make a bundle file to be able to run standalone using mkbundle

mkbundle --static GtkTest.exe Xwt.Gtk.dll Xwt.dll atk-sharp.dll gdk-sharp.dll glib-sharp.dll gtk-dotnet.dll gtk-sharp.dll pango-sharp.dll -o GtkTest --deps -z -L /usr/lib/mono/4.5 --config GtkTest.exe.config

Than take a copy of all the config files + .so files together + output files to a same directory and run in another Linux for test.

Done, Now you have a package to run it most linux distro. I had created a binary using Centos and I was able to run on Ubuntu.

How about other OS (Windows, Mac)

For Mac you can simply use Xamarin.Mac and you able to take make a bundle by VisualStudio for Mac And for Windows there is 2 cases.

  1. WPF
  2. GTK+

If you want to use WPF you must install .Net framework on Windows if you use specific .Net framework. But you have automatic system for install Or use GTK+ and Mono with mkbundle, but you end up to some problem(s)

  1. GTK+ for windows only supporting 32bit application
  2. You need to instal GTK+ separately
  3. .Net have better performance on Windows.

So it's much better to use normal .Net framework and WPF for Windows

Prepared files

Already I had compiled GTK2 and GTK# also I had uploaded Compiled version of Xwt Test application for linux.

Prepared files for donwload

For test please run GtkTest directly on your Linux. You can have this test on any minimal Linux distro without Mono runtime