The Dumpster Fire That Is MonoDevelop in Gentoo


Per a request from Freenode IRC user daedreth, I attempted to install MonoDevelop on my Gentoo system and was both surprised and amused by the difficulty of doing so. To a certain point, I can understand why. Mono, and subsequently MonoDevlop, isn’t at the head of the pack of bleeding-edge technology anymore. I’m surprised it’s even still maintained. But that hardly excuses the disaster that currently sits in the Portage tree.

Right off the bat, emerge -a monodevelop slams me with a circular dependency.

(dev-lang/mono-4.4.1.0:0/0::gentoo, ebuild scheduled for merge) depends on
 (dev-dotnet/libgdiplus-4.2-r2:0/0::gentoo, ebuild scheduled for merge) (buildtime)
  (dev-lang/mono-4.4.1.0:0/0::gentoo, ebuild scheduled for merge) (buildtime)

It might be possible to break this cycle
by applying the following change:
- dev-lang/mono-4.4.1.0 (Change USE: +minimal)

This is not unheard of. If you’ve ever built a Linux From Scratch system, then you’ve likely run into the problem where pkg-config depends on glib which depends on pkg-config. The solution is to build a special version of pkg-config that has it’s own internal copy of glib, thus eliminating the external dependency on glib. We can do something similar here. We have the +minimal use flag available which builds a version of dev-lang/mono that doesn’t depend on dev-dotnet/libgdiplus.

3aa5b22919f7 / # USE="${USE} minimal" emerge --oneshot dev-lang/mono

<sarcasm>But no worries, it still doesn’t succeed</sarcasm>. The build errors out on dev-dotnet/xsp.

checking for gmcs... no
configure: error: You need to install 'gmcs'

I have no idea what this is, but according to the dotnet overlay’s github, the problem is in some kind of confusion between mcs and gmcs and where those binaries are located in the filesystem. There is even some ugly workaround using symlink trickery provided in the issue. Believe it or not, the ugly symlink trickery works.

ln -s mcs /usr/bin/gmcs
ebuild /usr/portage/dev-dotnet/xsp/xsp-2.10.2-r2.ebuild fetch
ebuild /usr/portage/dev-dotnet/xsp/xsp-2.10.2-r2.ebuild unpack
cd /var/tmp/portage/dev-dotnet/xsp-2.10.2-r2/work/xsp-2.10.2
sed -i 's|\(/mono/2.0\)|\1-api|' configure
sed -i 's|\(/mono/4.0\)|\1-api|' configure
ebuild /usr/portage/dev-dotnet/xsp/xsp-2.10.2-r2.ebuild compile
ebuild /usr/portage/dev-dotnet/xsp/xsp-2.10.2-r2.ebuild install
ebuild /usr/portage/dev-dotnet/xsp/xsp-2.10.2-r2.ebuild qmerge

This is always a bad thing in Gentoo. I rarely say this but: Never do this. It just causes problems down the road. Nevertheless, I did it anyway just for kicks. Things then proceed but…

gmcs -keyfile:../mono-addins.snk -noconfig -codepage:utf8 -warn:4 -debug -d:DEBUG -out:../bin/Mono.Addins.MSBuild.dll -target:library ./AssemblyInfo.cs ./ResolveAddinReferences.cs  -r:Microsoft.Build.Framework -r:Microsoft.Build.Utilities -r:System   -r:../bin/Mono.Addins.dll  -r:../bin/Mono.Addins.Setup.dll
error CS0006: Metadata file `Microsoft.Build.Utilities' could not be found
Compilation failed: 1 error(s), 0 warnings
Makefile:425: recipe for target '../bin/Mono.Addins.MSBuild.dll' failed
make[1]: *** [../bin/Mono.Addins.MSBuild.dll] Error 1
make[1]: Leaving directory '/var/tmp/portage/dev-dotnet/mono-addins-0.6.2/work/mono-addins-0.6.2/Mono.Addins.MSBuild'
Makefile:211: recipe for target 'all-recursive' failed
make: *** [all-recursive] Error 1

Oh joy, it gets worse. Now dev-dotnet/mono-addins is broken. And now we pause for a moment of truth…

At this point I’m panicking.

I can debug Linux code. I can also debug Microsoft code. But when you start mixing the two I get lost. I don’t know what Microsoft.Build.Utilities is, nor do I care. A Google search provides little more than confirmation that I’m traveling a well worn path. Here’s where I begin to give up on the stable channel and move to unstable (See my post Stop Calling It Stable and Unstable! for why you should, too). Let’s see if we can find an easy out by adding ~amd64 to dev-dotnet/mono-addins.

!!! Multiple package instances within a single package slot have been pulled
!!! into the dependency graph, resulting in a slot conflict:

dev-dotnet/gtk-sharp:2

  (dev-dotnet/gtk-sharp-2.12.10:2/2::gentoo, installed) pulled in by
    ~dev-dotnet/gtk-sharp-2.12.10 required by (dev-dotnet/glade-sharp-2.12.10:2/2::gentoo, installed)
    ^                     ^^^^^^^                                                                                                                           

  (dev-dotnet/gtk-sharp-2.12.21:2/2::gentoo, ebuild scheduled for merge) pulled in by
    >=dev-dotnet/gtk-sharp-2.12.21:2 required by (dev-dotnet/mono-addins-1.0-r1:0/0::gentoo, ebuild scheduled for merge)
    ^^                     ^^^^^^^^^                                                                                                                                                              


It may be possible to solve this problem by using package.mask to
prevent one of those packages from being selected. However, it is also
possible that conflicting dependencies exist such that they are
impossible to satisfy simultaneously.  If such a conflict exists in
the dependencies of two different packages, then those packages can
not be installed simultaneously. You may want to try a larger value of
the --backtrack option, such as --backtrack=30, in order to see if
that will solve this conflict automatically.

For more information, see MASKED PACKAGES section in the emerge man
page or refer to the Gentoo Handbook.


The following keyword changes are necessary to proceed:
 (see "package.accept_keywords" in the portage(5) man page for more details)
# required by dev-dotnet/gnomevfs-sharp-2.24.2::gentoo
# required by dev-dotnet/gnome-sharp-2.24.2::gentoo
# required by dev-dotnet/gconf-sharp-2.24.2::gentoo
# required by dev-util/monodevelop-3.0.2-r1::gentoo
# required by monodevelop (argument)
=dev-dotnet/gtk-sharp-2.12.21 ~amd64

Oh geez. Things just got real.

No, seriously, what just happened?!

Bumping dev-dotnet/mono-addins pulled in version 2.12.21 of dev-dotnet/gtk-sharp, but dev-dotnet/glade-sharp pulls in 2.12.10 of dev-dotnet/gtk-sharp because 2.12.21 of dev-dotnet/glade-sharp doesn’t exist!

Alright, alright, alright, let’s add the dotnet overlay because surely they bumped glade-sharp in the overlay.

Nope.

Same error.

This is where I go into hacker mode. I’m going to grab the source URI out of the ebuild and see if there is a newer upstream version of dev-dotnet/glade-sharp. Maybe I just need to make a new ebuild for the newer version?

# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

EAPI=2

inherit gtk-sharp-module

SLOT="2"
KEYWORDS="amd64 ppc x86 ~x86-fbsd"
IUSE=""

RESTRICT="test"

Contents of /usr/portage/dev-dotnet/glade-sharp-2.12.10.ebuild

Whaaaat?!

From where does this thing pull its source tarball and how does it determine the version to pull from? Good grief, judging from that inherit line, I have to dig into the eclass now. It has to be getting this information from somewhere.

# Default value: mirror://gnome/sources/${TARBALL}/${PV_MAJOR}/${TARBALL}-${PV}.tar.bz2
if [[ ${TARBALL} == "gtk-sharp" ]]; then
    SRC_URI="${SRC_URI}
        http://download.mono-project.com/sources/gtk-sharp212/${TARBALL}-${PV}.tar.bz2"
else
    SRC_URI="${SRC_URI}
        mirror://gnome/sources/${TARBALL}/${PV_MAJOR}/${TARBALL}-${PV}.tar.bz2"
fi

Partial contents of /usr/portage/eclass/gtk-sharp-module.eclass

Ooooooh, all of these packages come from the same gtk-sharp tarball, and the file’s version is lifted straight from the version string portion of the ebuild’s filename. Note that upstream changed their tarball archive type from .bz2 to .gz after version 2.12.11. This is an indicator of things to come, which we will get into.

At this point I’m thinking I just need to create ghost ebuild shells for the 2.12.21 version of packages that are missing that verison. I added a condition to the eclass to pull down the correct file:

@@ -286,8 +286,13 @@
 # @DESCRIPTION:
 # Default value: mirror://gnome/sources/${TARBALL}/${PV_MAJOR}/${TARBALL}-${PV}.tar.bz2
 if [[ ${TARBALL} == "gtk-sharp" ]]; then
-       SRC_URI="${SRC_URI}
-               http://download.mono-project.com/sources/gtk-sharp212/${TARBALL}-${PV}.tar.bz2"
+    if [[ ${PV} == "2.12.10" ]]; then
+           SRC_URI="${SRC_URI}
+                   http://download.mono-project.com/sources/gtk-sharp212/${TARBALL}-${PV}.tar.bz2"
+       else
+           SRC_URI="${SRC_URI}
+               http://download.mono-project.com/sources/gtk-sharp212/${TARBALL}-${PV}.tar.gz"
+       fi
 else
        SRC_URI="${SRC_URI}
                mirror://gnome/sources/${TARBALL}/${PV_MAJOR}/${TARBALL}-${PV}.tar.bz2"

Then made a new ebuild for the 2.12.21 version:

3aa5b22919f7 ~ # cp /usr/portage/dev-dotnet/glade-sharp/glade-sharp-2.12.10.ebuild /usr/portage/dev-dotnet/glade-sharp/glade-sharp-2.12.21.ebuild 
3aa5b22919f7 ~ # ebuild /usr/portage/dev-dotnet/glade-sharp/glade-sharp-2.12.21.ebuild manifest
>>> Creating Manifest for /usr/portage/dev-dotnet/glade-sharp

This also needs to be done for the rest of the stack…

  • dev-dotnet/gtk-sharp-gapi
  • dev-dotnet/glib-sharp
  • dev-dotnet/atk-sharp
  • dev-dotnet/gdk-sharp
  • dev-dotnet/pango-sharp

Aaaaaand still a problem…

Calculating dependencies... done!
[ebuild  NS    ] sys-devel/automake-1.11.6-r1 [1.10.3-r1, 1.14.1, 1.15]
[ebuild     U  ] dev-dotnet/gtk-sharp-gapi-2.12.21 [2.12.10]
[ebuild     U  ] dev-dotnet/glib-sharp-2.12.21 [2.12.10]
[ebuild     U  ] dev-dotnet/atk-sharp-2.12.21 [2.12.10]
[ebuild     U  ] dev-dotnet/pango-sharp-2.12.21 [2.12.10]
[ebuild     U  ] dev-dotnet/gdk-sharp-2.12.21 [2.12.10]
[ebuild     U  ] dev-dotnet/gtk-sharp-2.12.21-r1 [2.12.10] USE="-developer%" 
[ebuild     U  ] dev-dotnet/glade-sharp-2.12.21 [2.12.10]
[blocks B      ] dev-dotnet/glib-sharp ("dev-dotnet/glib-sharp" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)
[blocks B      ] dev-dotnet/atk-sharp ("dev-dotnet/atk-sharp" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)
[blocks B      ] dev-dotnet/pango-sharp ("dev-dotnet/pango-sharp" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)
[blocks B      ] dev-dotnet/gdk-sharp ("dev-dotnet/gdk-sharp" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)
[blocks B      ] dev-dotnet/glade-sharp ("dev-dotnet/glade-sharp" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)
[blocks B      ] dev-dotnet/gtk-sharp-gapi ("dev-dotnet/gtk-sharp-gapi" is blocking dev-dotnet/gtk-sharp-2.12.21-r1)

 * Error: The above package list contains packages which cannot be
 * installed at the same time on the same system.

  (dev-dotnet/glade-sharp-2.12.21:2/2::gentoo, ebuild scheduled for merge) pulled in by
    =dev-dotnet/glade-sharp-2.12.21

Huh?

Everything I just did got blocked because the gtk-sharp ebuild blocks them excplicitly.

Okay, okay, okay, let’s take a step back. Remember when I pointed out that upstream renamed their archives? That’s probably when they combined all of these separate libraries into one, thus giving the distro package maintainers fits and breaking compatibility with previous versions. I’m speculating here, of course, but regardless, those packages have definitely been combined now. Also, the stable MonoDevelop ebuild explicitly specifies them separated. This creates a Catch-22.

So what now?

I guess I have no choice but to bump the MonoDevelop version to ~amd64. But before that, I do an emerge --sync to clear out those custom ebuilds I made earlier from my portage tree.

Then attempting, once again, to emerge MonoDevelop causes www-servers/xsp to puke all over my screen due to file collisions, so let’s bump that one, too. But this isn’t straight forward seeing as the version in the dotnet overlay follows a completely different naming scheme, causing Portage to think the one in the main Gentoo tree is the more recent one. In order get past this, the main tree version needs to be masked, so add =www-servers/xsp-2014.12-r2014120900 to /etc/portage/package.mask.

Oh, and by the way, this will happen afterward:

F: mkdir
S: deny
P: /usr/share/.mono/keypairs
A: /usr/share/.mono/keypairs
R: /usr/share/.mono/keypairs
C: mono /usr/lib/mono/NuGet/4.5/NuGet.exe restore 

F: mkdir
S: deny
P: /usr * --------------------------------------------------------------------------------

>>> Failed to emerge dev-util/monodevelop-6.0.0.4761, Log file:

>>>  '/var/tmp/portage/dev-util/monodevelop-6.0.0.4761/temp/build.log'

Good lord, this is like a circus that just won’t end!

At this point I just make a wild guess. See the line that has NuGet in it? It references version 4.5. I’m wondering if, since I bumped versions of some packages up to unstable, they silently require .NET 4.5. Fantastcally, dev-dotnet/nuget has a net45 use flag.

3aa5b22919f7 / # equery u nuget
[ Legend : U - final flag setting for installation]
[        : I - package is installed with flag     ]
[ Colors : set, unset                             ]
 * Found these USE flags for dev-dotnet/nuget-2.8.7-r2:
 U I
 - - debug      : Enable extra debug codepaths, like asserts and extra output. If you want to get
                  meaningful backtraces see
                  https://wiki.gentoo.org/wiki/Project:Quality_Assurance/Backtraces
 - - developer  : <unknown>
 + + gac        : <unknown>
 - - net45      : <unknown>
 + + pkg-config : <unknown>
 + + symlink    : Force kernel ebuilds to automatically update the /usr/src/linux symlink

Setting the net45 use flag then doing an emerge --oneshot dev-dotnet/nuget finally allows dev-util/monodevelop to install!

MonoDevelop Splash

This is the single biggest mess I’ve ever seen in Gentoo, but sadly more and more packages are beginning to look like this in the “stable” Portage tree. Do we really have that many abandoned/unmaintained projects sitting around? Are we that short on Gentoo developers? Do the developers just not care?

Regardless, installing a package in a distro, any distro, should never be this difficult!


Leave a Reply