Revision: 0.3
Last Revised: Monday Aug 27, 2007
Glossary
- AOT: Ahead Of Time. This usually refers to the ELF .so file that is the result of ahead of time compiling an assembly. AOTs are dependent on the assemblies they were generated from for certain data (unlike their equivalents in python and java). AOTs are created explicitly, not automatically.
- Assembly: An assembly is the EXE or DLL file created by compiling a mono application. These are not the same as EXE's or DLL's created by compiling a C or C++ program on Windows. An assembly contains CIL code rather than machine code.
- CIL: CIL stands for Common Intermediate Language. It is roughly equivalent to java bytecode and is generally portable across architectures. Some programming practices (calling out to native system libraries) can lead to CIL code that will not run on all architectures.
- Glue Libraries: Libraries which bridge a system library written in C or C++ with Mono. These wrappers are separate different than AOTs.
Packaging Tips
File Locations
Mono packages should install assemblies to %{_libdir} rather than /usr/lib or %{_datadir}. In most cases the preference is for %{_libdir}/PACKAGENAME. We use %{_libdir} because we do not consider mono packages to be noarch.
The main reason for this is that mono can ahead-of-time compile its assemblies into ELF shared objects. These AOTs have to exist in the same directory as their DLL/EXE counterparts otherwise mono cannot use them. Even if we, as packagers, choose not to create the AOT files when we build the mono rpms, the system administrator can choose to create them after install. Since there's no way to place the mono assemblies into an arch independent directory and the AOTs into arch dependent directories, the whole thing has to go into an arch dependent tree.
gacutil in a spec file
gacutil is used to register dlls with mono (think of it as installing a library - which it is!).
When packaging *any* mono application which generates libraries which gacutil then registers (say mysql-connector-net), you need something like the following in the spec file
%install %{__rm} -rf %{buildroot} %{__mkdir_p} %{buildroot}%{_libdir}/mono/gac/ gacutil -i bin/mono-1.0/release/MySql.Data.dll -f -package mysql-connector-net -root %{buildroot}%{_libdir} %files %{_libdir}/mono/gac/MySql.Data %{_libdir}/mono/mysql-connector-net/MySql.Data.dll
gacutil format
-i = input dll -f = check references -package = package name -root = build root
RPMS and source
Don't build RPMS against built from source versions of mono. It will work for you but probably not for other users!
While you may get away with recompiling the source for part of the overall package (such as gnome-panel is part of gnome or evolution-data-server is part of evolution) for other programs, you should not attempt this with Mono.
If you're going to use the source, you MUST remove the RPMS first.
Compiling mono is not a trivial matter and may not even work (when you download the source, you must also make get-monolite-latest which grabs a version of the corelib and mcs which are need for compiling the main C# compilers - the monolite-latest does not always work and you end up without a working copy of Mono.
Reporting Mono bugs
Upstream Mono's bugtracker is located at Ximian: [1]
rpmlint and mono packages
rpmlint is a program that checks packages for common problems. For mono packages, some of the rpmlint messages can be disregarded.
Mono installs binaries in %{_libdir}/<package>/bin with symlinks back to /usr/bin. rpmlint is not happy with this and generates an error (which is the correct behaviour). It will also not recognise that mono libraries are not ELF format and may generate errors on this as well.
rpmlint will also pick up on any .pc file installed in the rpm (see below).
-devel packages
Mono packages must package .pc files in a -devel package, even if that is the only file that will be included. If we were to permit .pc files in non-devel packages, then we'll have non-devel packages that depend on -devel packages, inflating the install needlessly.
Building Mono Packages Using mock with SELinux Enabled
Empty debuginfo
Sometimes building mono packages results in an empty debuginfo sub package, one without any files to install. See Packaging/Debuginfo
Incorrect Behaviours
Distributing Prebuilt Assemblies
Because mono .dlls are generally architecture independent, upstream may ship tarballs which install precompiled .dlls and .exes. All packages must build from source so the packager needs to watch out for these tarballs and be certain not to use them. (This can sneak in during upgrades as well, so the packager has to make sure they're building from source every time the tarball is changed.)
Distributing .DLLs from other projects
The Mono project's website makes this suggestion
Sometimes developers might want to distribute a library to other developers but they might not have a library that is API stable or has not matured enough over time to guarantee the backwards-compatibility of their libraries or they are not willing to maintain multiple packages of the various versions for users. [...] To solve this problem, we recommend that: * The library developer ships a properly configured pkg-config file. * The library consumers include an "update-libraries" target on their Makefile that will import the latest version of a library from a system directory into their application source code distribution. * The library consumers ship this library as part of their package.
This suggestion may make it easier for applications targetting unstable library APIs but it is extremely poor practice. Using libraries in this manner has all the same problems as linking with static libraries, most notably that the application can suffer from security holes in the library long after it is fixed upstream. Mono applications in Fedora cannot include upstream DLLs (even if they are compiled from source). This is a blocker issue and must be fixed.
There are several techniques for detecting the presence of these libraries, none of them fool proof. If you know of a better method, please add it:
1. Upstream tarball contains .dlls that were not rebuilt from source contained in the package. 2. Look through the installed .dlls for any that have the same name as system .dlls or are suspiciously out of place (Package is myDiary and contains mysql.dll, sqlite.dll, and gtk-sharp.dll) 3. Source directories look odd:
PKGNAME/ src/ data/ libs/ gtk-sharp/ atk-sharp/
Redefining _libdir
Packagers should avoid redefining _libdir in their spec file. Redefinition of this macro will cover up problems instead of helping fix them. Packagers should:
1. Identify which directories the files should install into according to the Packaging Guidelines . 2. Patch the packages build scripts to install to those locations. 3. Identify places where the package has hardcoded the old locations instead of the new ones and fix those. 4. Either report the issues to upstream or submit patches. Note that upstream projects are generally receptive to patches that allow package builders to redefine install locations at build time -- less receptive to patches which change upstream's hardcoded defaults to our hardcoded defaults.
Defining target
Was done for a brief period when we attempted to package mono apps as noarch. It was not necessary then (the actual fix was to stop using AC_CANONICAL_* in the configure.ac file) and it is definitely not needed now that we are no longer building noarch mono packages.