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
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
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 https://github.com/mono/gtk-sharp.git
cd gtk-sharp
git checkout gtk-sharp-2-12-branch
./bootstrap-2.12
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
<configuration>
<dllmap dll="i:cygwin1.dll" target="libc.so.6" os="!windows" />
<dllmap dll="libc" target="libc.so.6" os="!windows"/>
<dllmap dll="intl" target="libc.so.6" os="!windows"/>
<dllmap dll="intl" name="bind_textdomain_codeset" target="libc.so.6" os="solaris"/>
<dllmap dll="libintl" name="bind_textdomain_codeset" target="libc.so.6" os="solaris"/>
<dllmap dll="libintl" target="libc.so.6" os="!windows"/>
<dllmap dll="i:libxslt.dll" target="libxslt.so" os="!windows"/>
<dllmap dll="i:odbc32.dll" target="libodbc.so" os="!windows"/>
<dllmap dll="i:odbc32.dll" target="libiodbc.dylib" os="osx"/>
<dllmap dll="oci" target="libclntsh.so" os="!windows"/>
<dllmap dll="db2cli" target="libdb2_36.so" os="!windows"/>
<dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.so" os="!windows" />
<dllmap dll="i:msvcrt" target="libc.so.6" os="!windows"/>
<dllmap dll="i:msvcrt.dll" target="libc.so.6" os="!windows"/>
<dllmap dll="sqlite" target="libsqlite.so.0" os="!windows"/>
<dllmap dll="sqlite3" target="libsqlite3.so.0" os="!windows"/>
<dllmap dll="libX11" target="libX11.so.6" os="!windows" />
<dllmap dll="libgdk-x11-2.0" target="libgdk-x11-2.0.so.0" os="!windows"/>
<dllmap dll="libgtk-x11-2.0" target="libgtk-x11-2.0.so.0" os="!windows"/>
<dllmap dll="libXinerama" target="libXinerama.so.1" os="!windows" />
<dllmap dll="libcairo-2.dll" target="libcairo.so.2" os="!windows"/>
<dllmap dll="libcairo-2.dll" target="libcairo.2.dylib" os="osx"/>
<dllmap dll="libcups" target="libcups.so.2" 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>
<dllmap dll="gdiplus" target="libgdiplus.so" os="!windows"/>
<dllmap dll="gdiplus.dll" target="libgdiplus.so" os="!windows"/>
<dllmap dll="gdi32" target="libgdiplus.so" os="!windows"/>
<dllmap dll="gdi32.dll" target="libgdiplus.so" os="!windows"/>
<dllmap os="linux" dll="libglib-2.0-0.dll" target="libglib-2.0.so.0"/>
<dllmap os="linux" dll="libgobject-2.0-0.dll" target="libgobject-2.0.so.0"/>
<dllmap os="linux" dll="libgthread-2.0-0.dll" target="libgthread-2.0.so.0"/>
<dllmap os="linux" dll="glibsharpglue-2" target="libglibsharpglue-2.so"/>
</configuration>
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.
- WPF
- 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)
- GTK+ for windows only supporting 32bit application
- You need to instal GTK+ separately
- .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.
For test please run GtkTest directly on your Linux. You can have this test on any minimal Linux distro without Mono runtime