New Mono 2.0 Package Layout
Why?
Because a simple application like tomboy still needs 49.9MB, which is too much to be included in the default debian install for example [ 0 ].
Aren't the Mono packages very split already?
Yes they are but not enough to get small enough installs. This is caused by:
- indirect native dependencies (e.g. sqlite, libgdiplus, gtk+, etc)
- 2 different runtime profiles (1.0 vs 2.0)
So how to solve this mess?
With Lenny+1 (Squeeze) we will make the 1.0 runtime deprecated and compile all CLI libraries and CLI applications for only the 2.0 runtime. We will still ship the 1.0 runtime libs of Mono but they will only work for applications that do not require other Debian CLI library packages (such as GTK#).
Doesn't this require a transition?
Yes it does, all Debian CLI library and application packages need to be rebuild using gmcs instead of mcs (if they are not using gmcs by default already!). To get an idea of how many packages are built against the 1.0 runtime:
apt-cache rdepends libmono-corlib1.0-cil | grep -v libmono- | grep -v mono- | wc -l 84
So 84 binary packages are built using the 1.0 compiler (mcs) for targeting the 1.0 runtime. (btw libmono-* and mono-* packages don't count, as they will still be shipped for the 1.0 runtime for compatibility with external (as in non-debian) applications)
OK, so all this work for exactly what gain now?
As said a tomboy install needs 49.9MB of additional harddisk space when installed on a default debian/lenny system.
Tomboy is using the 2.0 runtime of Mono but uses libraries that was compiled for the 1.0 runtime and thus it pulls in 1.0 runtime libs + 2.0 runtime libs. If all libraries would use the 2.0 runtime it would reduce the tomboy install by over 10MB (and that just by recompiling the libs using gmcs).
Alright, just 10MB, that's all you got?
Nope, with this 1.0 -> 2.0 transition we will also split the Mono packages to further reduce dependency chains.Tomboy for example only use the Mono.Posix.dll library from the libmono2.0-cil package or the libmono0 which is only needed by C applications that do calls into Mono. So we would put the Mono.Posix library into an extra package as it's used almost by all Mono based GUI applications, this gives us 4.8MB back of the harddisk, and with libmono0 we get 2.3MB back.
So now we are at 10MB + 4.8MB + 2.3MB = 17.1MB
Tomboy itself is 10MB in size, this is mainly because it contains graphics with texts that need to be translated in many languages:
du -sh /usr/share/gnome/help/tomboy 5.7M /usr/share/gnome/help/tomboy
Instructions for packagers
There are three things that need to be changed to take advantage of the changes above (and, indeed, to allow building of any packages after the transition takes place). For this, we'll look at a simple 1.0-based package: Cowbell.
Build-dep changes
Currently, the package has the following build dependencies
Build-Depends: debhelper (>= 5), cdbs, cli-common-dev (>= 0.4.4), mono-mcs (>= 1.0) | c-sharp-compiler, mono-1.0-devel, libmono-corlib1.0-cil, libmono-system1.0-cil, libmono-system-web1.0-cil, libtag1-dev (>= 1.3.0), libtagc0-dev (>= 1.3.0), libgtk2.0-cil (>= 2.6), libglib2.0-cil (>= 2.6), libglade2.0-cil (>= 2.6), pkg-config, intltool, xsltproc, docbook-xsl, docbook-xml (>= 4.4)
Firstly, replace all the 1.0 versions of libmono packages with 2.0 versions - pay extra close attention to non-obvious packages like sharpzip, whose version number isn't obviously 1.0/2.0
Secondly, replace any dependencies on mono-mcs, mono-X-devel, mono-gac, and so on, with a simple new dependency: "mono-devel". mono-devel will pull in the default build version (mono-2.0-devel), and includes 'unversioned' scripts (more in the next section). Now our Cowbell looks like this:
Build-Depends: debhelper (>= 5), cdbs, cli-common-dev (>= 0.4.4), mono-devel (>= 2.0), libmono-corlib2.0-cil, libmono-system2.0-cil, libmono-system-web2.0-cil, libtag1-dev (>= 1.3.0), libtagc0-dev (>= 1.3.0), libgtk2.0-cil (>= 2.6), libglib2.0-cil (>= 2.6), libglade2.0-cil (>= 2.6), pkg-config, intltool, xsltproc, docbook-xsl, docbook-xml (>= 4.4)
Patching the build system
Ideally, you should patch your application's build system to use unversioned tools - those included in the mono-devel package - which will be those from the default Mono runtime on the system. 'al' is an example here - instead of 'al' for 1.0 and 'al2' for 2.0, we have 'al1' for 1.0, 'al2' for 2.0, and 'al' for the system default.
The most important one to patch here is the compiler - you should alter your configure scripts to look for 'csc' instead of 'mcs' or 'gmcs' - csc is the default compiler on the system, which currently means gmcs2.
The easiest solution, which should work for the majority of packages, is to pass a value for CSC to ./configure in your debian.rules file, i.e.
CSC=/usr/bin/csc ./confgure
Or, in theory, this would also work:
./confgure CSC=/usr/bin/csc
To achieve this with the CDBS debian/rules helper, use the DEB_CONFIGURE_USER_FLAGS flag, as follows:
DEB_CONFIGURE_EXTRA_FLAGS += CSC=/usr/bin/csc
A second method is to patch the build system - with luck this should be needed less often, but a few packages may demand it. For an Autotools-based build system, you would patch configure.in like this:
AC_PATH_PROG(CSC, mcs, no) if test "x$CSC" = "xno" ; then AC_MSG_ERROR(['No c-sharp compiler found']) fi
becomes:
AC_PATH_PROG(CSC, csc, no) if test "x$CSC" = "xno" ; then AC_MSG_ERROR(['No c-sharp compiler found']) fi
Obviously, autoconf is needed again here. And really, using a patchsys is better than editing files directly.
Depending on which debian/rules helper your package is using, one approach might be easier than the other. This is up to packager discretion, however, obviously adding a few letters to debian/rules is preferable to patching configure files from a simplicity standpoint.
Different packages use different build systems, and neither of the approaches above might be applicable to a given package. Generally though, the change should be small and easily made, regardless of the build system used.
Also note that you don't always want to set "CSC" - some packages you need to set "MCS", some you need to set "MCS2", some you need to set "GMCS". Generally, grep for 'mcs' in configure.in in the package's source code:
directhex@mortos:/tmp/gbrainy-1.00$ grep mcs configure.in dnl --- Check for mono and gmcs AC_PATH_PROG(MCS, gmcs) CSC=gmcs
Testing, testing, testing!
Does it build?
directhex@despair:~$ dpkg-deb -I cowbell_0.2.7.1-2_amd64.deb | grep Depend Depends: libc6 (>= 2.2.5), libc6 (>= 2.7-1) | libc6.1 (>= 2.7-1) | libc0.1 (>= 2.7-1), libgcc1, libglade2.0-cil (>= 2.12.0-2ubuntu3), libglib2.0-0 (>= 2.16.0), libglib2.0-cil (>= 2.12.0-2ubuntu3), libgtk2.0-cil (>= 2.12.0-2ubuntu3), libmono-corlib2.0-cil (>= 1.2.2.1), libmono-system-web2.0-cil (>= 1.9.1), libmono-system2.0-cil (>= 2.0), libstdc++6 (>= 4.1.1-21), libtag1c2a (>= 1.4), libtagc0 (>= 1.4), mono-runtime (>= 1.1.8.1)
You bet! Sometimes your package might require some mild patching - for example, System.Web.Mail became System.Net.Mail in the 2.0 CLR. But as you can see from the five minute example above, the amount of work needed to migrate to the 2.0 runtime is minimal.