October 19, 2004

Deploy me please

To preface this, I know I am picking on the iFolder guys here, and I know there are lots of other mono apps that probably do this as well, but to me, Novell should be setting the 'gold standard' for how to properly develop and deploy a mono app, and to see them set the bar this low for deployment is just not good.

Recently, talking with James Wilcox (a.k.a. Mr. S. Norpopolis, of YAMP and red-carpet fame) I discovered that ifolder and another app (which we will call YAMP#) were conflicting with eachother because both tried to put a log4net.dll into /usr/lib.

What? I said. Why would anyone put a dll in /usr/lib? Apparently both the iFolder and YAMP# teams are taking advantage of what is (imo) a bug that needs to be (again, imo) fixed in mono. Back before Mono had a GAC (right up until beta1 in early may), we used to load libraries out of MONO_ASSEMBLIES which was a compile time define to $prefix/lib. Now that we have a GAC, that bug(/feature/whatever) is still around. However, there is no longer *any* reason for mono to be loading anything from $prefix/lib. In HEAD and 1.1.1, even mscorlib.dll has been moved, so there should be no dlls ever in $prefix/lib.

So, the answer seems to be that iFolder should install log4net into the gac, and use it that way. *BZZT* Wrong. iFolder should never install anything into the gac that it expects other applications to use that it isn't 'responsible' for. Imagine this. iFolder installs log4net into the gac. YAMP# also installs log4net into the gac. There you get the RPM conflicts again. So the YAMP# guys could go ahead and make YAMP# depend on iFolder, which seems an insane way of getting log4net, but sure, it would work.

However, the real solution is a lot nicer, and far more maintainable. mono, when looking to load assemblies required by your application, will first look in what is called AppBase. That is the folder your app lives in. I explained this to Mr. S. Norpoplis, who then blurted out 'But a dll in /usr/bin is pretty weird'. What? Excuse me again? iFolder is putting ifolder.exe into /usr/bin?! Please, stop. dont.

Putting that executable into /usr/bin may seem like a cute thing, but it really is harmful in the long term. First, you are now limited in what is considered your AppBase to a location that you really shouldnt be tossing a lot of stuff into. Second, it is just wrong. It is like clubbing a baby seal. Don't do it.

Rarely will I ever point towards MonoDevelop as 'the proper way' of doing anything. However, we deploy ourselves very well. We create a directory, /usr/lib/monodevelop/ and start throwing stuff in there. We even go a step further than most applications would have to, and we create /usr/lib/monodevelop/bin/ to hold the executable and supporting libraries. Most applications won't need that kind of insanity. iFolder should be installing itself into /usr/lib/ifolder/, which would give you a /usr/lib/ifolder/ifolder.exe and a /usr/lib/ifolder/log4net.dll. Then you drop in a 2 line shell script at /usr/bin/ifolder to call mono /usr/lib/ifolder/ifolder.exe. Problem solved. Now YAMP# and iFolder don't conflict, and they dont get in each other's ways at all. As well, we no longer are leaving little assemblies sitting around int /usr/bin or /usr/lib.

But wait. Suppose that no one likes the idea of keeping multiple seperate copies of log4net.dll around for every app. Isn't that what the GAC is for? Yes. It is. However, iFolder (or YAMP#) should never install anything into the GAC that it isn't responsible for. You don't have log4net installing iFolder, or iFolder installing YAMP#, they are seperate applications. Anything put into the GAC really needs to be its own package. That way packagers can say 'I need the log4net package installed' instead of saying 'Well, since this app needs log4net, I guess we have to pull in X, Y and Z as a dependency'.

So it seems that the proper way out of this for iFolder, and YAMP#, is to take the day or so (tops) that it would take to give log4net a real linux auto* build, and create a log4net RPM to depend on. Then everyone benefits, log4net gets to be a first class citizen of the linux/mono world, and we can all do a ls /usr/lib/*.dll and not see anything. Which is exactly how it should be.

Posted by tberman at October 19, 2004 03:22 AM