Review request: kdesrc-build login session script

One of the long-standing desirable improvements that I’ve wanted for kdesrc-build is to automatically make it easy to login to the newly-built-from-source desktop. In fact, this is item 5 on my current ROADMAP included with the kdesrc-build source.

The issue, of course, is that it is often nowhere near good enough to compile and install a recently-compiled KDE if your distribution can’t be bothered to actually use it!

Why It’s Difficult:

Unfortunately there are many different environment variables that need to be set (e.g. PATHLD_LIBRARY_PATH (on Linux and perhaps some BSDs?), XDG_DATA_DIRS, etc.), in order to inform the shell, operating system, utilities, and even KDE itself that you want to use programs and libraries installed to alternate locations instead of places like /usr and /bin.

Additionally, there are environment variables that should be set on top of that to support the development of further KDE software to automatically use the KDE libraries that were just installed, which needs environment variables like PKG_CONFIG_PATH (and even things like MANPATH).

There are a surprising number of issues that go into solving this problem:

  • Alternative shell users. I’m not talking about taking advantage of advanced Oh My ZSH hackery, but it’s a fact that some distros use “lite” shells like ASH as /bin/sh (and Busybox’s /bin/sh is even more restrictive), so we need to be careful about what shell features are used.
  • Different shell types. In other words, how do we support all of: Login shells, “interactive” non-login shells, and non-login shell scripts that should have the same KDE environment variable settings?
  • Different login managers. How do we support users using LightDM, KDM, GDM, etc.?
  • Are we using system-provided Qt, or self-compiled Qt?
  • How does the user customize the result? All too often you see config files with large “THIS IS AUTO-GENERATED, DO NOT EDIT” warnings, how do we allow for user customization?
  • Data flow direction. Normally kdesrc-build feeds build parameters into CMake (or whatever the build system is) and not the other way around. But to setup session support right we need to know (or assume…) where the software was installed. Sometimes it is difficult to assume, for example do you know how to determine which path is correct between $prefix/lib, $prefix/lib32, $prefix/lib64 on any given system? CMake normally figures this out, not kdesrc-build! ;)

Development Work

I was discussing this some months ago with Michael Jansen, developer of the wonderful Ruby script build-tool, and he graciously provided me with some sample login-support files which I started working in earnest on a couple of weeks ago. By last week I had a solution which I think will meet the requirements of most without tripping over too many of the issues I mentioned. This solution is being developed in kdesrc-build’s xsession-support branch.

The Design

What I’ve chosen to do is to handle the “common case”… that is, a user logging in from a graphical login manager and installing their kdesrc-build KDE to a given user account (if I’m doing it right this can in theory even be the same user account used with a system KDE installation, but you shouldn’t assume I’m doing it right! ;).

There are many ways to support a login manager. One of the ancient, time-honored methods is for the login manager to detect the presence of a shell script called .xsession in the user’s home directory, and to allow the user to run this script to setup the rest of the login session. In KDM, this is what the “Custom” session setting does. In GDM it seems to be called “Default System Session”, at least on Ubuntu (although that description’s not quite accurate). Also, Fedora at least requires you to install an additional package for GDM (and who knows, maybe KDM too) to obey ~/.xsession scripts.

So as you can tell from the end of that last paragraph, ~/.xsession doesn’t seem to be the preferred mode of operation for modern login managers. Instead, they search for Desktop Entry files describing a session in the data directory share/xsessions (e.g. /usr/share/xsessions). Unfortunately this directory is obviously only accessible to root, so it would require special permissions to add a session type. But in any event, you still end up running a custom script, the Desktop Entry simply adds a layer of indirection (and allows you to set a custom name, description, etc. in the login manager).

So, the big picture objective I’ve decided on so far is to make the ~/.xsession approach work… if it works, it works without needing root permissions. And even if it doesn’t work immediately, we can simply make our new entry in share/xsessions point back to the ~/.xsession without having to duplicate the hard work (and in some distros “making it work” is as sample as installing an additional package).

Making xsession work

Of course this merely punts the problem down the road a little bit… how do we make ~/.xsession work?

The problem essentially comes down to, figure out what is “custom” about the installed KDE (e.g. what was its install prefix, what prefix are we using for Qt), use that to set the needed environment variables to the right value, and then kick off the KDE startup script (startkde) with the environment already set. Oh, and do all this while allowing for user customizations.

My first attempt had this all as a single .xsession file, but this isn’t ideal (as pointed out by the indomitable David Faure). The reason it is not ideal is because all of our environment variable settings will also be needed for non-login shells within the logged-in desktop, and those shells can’t source ~/.xsession again without trying to start a KDE-within-a-KDE. Additionally, the .xsession would have to change any time the user wanted to edit a setting, which introduces the difficult problem of how to allow kdesrc-build to update auto-generated parts of the file while retaining user changes.

So, the next round split the .xsession into 2 auto-generated files, ~/.kde-env-master.sh and ~/.xsession. Now the profile setup for interactive non-login shells could use ~/.kde-env-master.sh without worrying about accidentally trying to start another session. Unfortunately, this didn’t solve the problem of user customizations.

So, my more recent try split the ~/.kde-env-master.sh further, into a “user’s playground” and “kdesrc-build owned” bisection. kdesrc-build will install a sample user-settings file to ~/.kde-env-user.sh and will not touch it again from there. ~/.xsession and ~/.kde-env-master.sh will continue to be tracked by kdesrc-build (using MD5 sums) which allows for kdesrc-build to easily be able to install bugfixed versions of those two (e.g. as new environment variables become required, such as QML_IMPORT_PATH).

Obviously I try to take pains to ensure that existing .xsession and .kde-env-master.sh files ($DEITY forbid) are not overwritten, (but this leads to complaining in the xsession-support version of kdesrc-build if existing files are in the way).

Solving the other problems

Of course, I mentioned other problems. How did I work-around or solve them?

  • Alternative shell users. I use Busybox /bin/sh and Ash for testing. As it turns out, “source” is a complete Bash-ism, and you really shouldn’t use the “function” keyword in portable shell either. It’s also more well-known that you should export environment variables as a separate step in portable shell. I also have included testing support in the test suite to syntax-check the shell code (and I also try to manually run those tests with the alternate shells I mentioned earlier). Another difficulty was making a “path_add” function that works in portable shell.
  • Different shell types. Already covered, we split the different functions (environment setup, user customization, session login) into different scripts.
  • Different login managers. As long as the login manager supports ~/.xsession (the “traditional” way) you’re already set. More work is needed to support login managers that only support share/xsessions Desktop Entries.
  • Are we using system-provided Qt, or self-compiled Qt? The shell code is setup so that if the Qt directory is not set by kdesrc-build, it will automatically try to find a system Qt and ensure it’s added to the PATH and rest of environment if necessary (in fact this is probably overkill since it should be all rights already be in the system environment).
  • How does the user customize the result? The aforementioned ~/.kde-env-user.sh. My late draft work on this also supported user-custom scripts run just before session start and just after session end, but KDE supports that natively so I will remove that capability to avoid (even more) debugging insanity.
  • Data flow direction. The sample script tries to figure out the library directory “bit suffix” (if any) if the user doesn’t set it, by asking the installed kde4-config. kdesrc-build only needs to fill in where Qt and/or KDE were installed to.

Help I need

At this stage, I essentially need people to actually test being able to login using this scheme. This would be helpful even if you don’t use kdesrc-build (but you’d need to fill in the KDE prefix and Qt prefix yourself in that case). Don’t forget to make ~/.xsession executable if you decide to install it manually, otherwise the session won’t work at all (Yep, it caught me… ;)

Any advice on how to setup current login managers for “user-custom” sessions without having to trawl around in /usr/share/xsessions would be appreciated as well.

Also, for those who like writing documentation (or might like it), I wouldn’t mind someone donating rewritten documention for the “Setting the Environment” section… :)

You can find kdesrc-build by checking it out from KDE’s git repository (git clone git://anongit.kde.org/kdesrc-build)… the code I’m talking about is in the xsession-support branch.