Thursday, June 09, 2011

gEDA and Guile — compiling against multiple Guile versions

This is the second in a series of blog posts on extensibility in gEDA using Guile Scheme.

  1. Finding Scheme API code in gEDA
  2. Compiling against multiple Guile versions
  3. Safe handling of non-local exits
  4. Dealing with deprecated libguile functions
  5. Checking arguments to Scheme functions in C
  6. How and when to use Scheme errors
  7. Reducing boilerplate with "snarfing macros"
  8. Opportunities to get involved

In this post, I'll explain how to set up your build environment in such a way that you can easily compile gEDA against either Guile 1.8 or Guile 2.0, since we need to support using gEDA with either version of Guile at the moment.

Firstly, you need to build and install Guile 2.0 and Guile 1.8 to their own prefixes, e.g. /opt/guile-2.0/ and /opt/guile-1.8/.

$ wget
$ tar -zxf guile-2.0.1.tar.gz
$ cd guile-2.0.1
$ ./configure --prefix=/opt/guile-2.0
$ make
$ sudo make install

$ wget
$ tar -zxf guile-1.8.8.tar.gz
$ cd guile-1.8.8
$ ./configure --prefix=/opt/guile-1.8
$ make
$ sudo make install

Next, you need to have some way of quickly adding and removing the different versions of Guile to your environment. Specifically, you need to be able to modify INFOPATH, PATH, MANPATH, LD_LIBRARY_PATH and PKG_CONFIG_PATH.

The approach I use is to use Environment Modules (henceforth referred to as modules). The idea is to be able to do something like this:

$ module load guile/1.8
$ which guile
$ module switch guile guile/2.0
$ which guile

One particularly neat thing about modules is that although I give all my examples here for POSIX sh and/or bash, the same module files can be used with other shells such as tcsh with no modification.

Installing & setting up Environment Modules

Unfortunately, modules can be a bit of a pain to install, and many distributions don't appear to package it. This is a guide to getting it working on Ubuntu 10.04; it's much easier on Fedora, since there you can just install the environment-modules package.

Due to a really obnoxious default file layout that's not at all trivial to fix, it's easiest to install modules to its own prefix, e.g. /opt/Modules. You'll need to do something like this (after downloading the source code):

$ tar -zxf modules-3.2.8a.tar.gz
$ ./configure --disable-versioning --prefix=/opt
$ make
$ sudo make install

It's then necessary to set up your ~/.bash_profile and ~/.bashrc to enable modules for your sessions. Firstly, you need to add some boilerplate to the top of ~/.bash_profile:

if [ -f /opt/Modules/init/bash ]
# Set the file to store your initial environment in
export MODULESBEGINENV=$HOME/.modules/beginenv
# Initialise environment for modules
. /opt/Modules/init/bash
# Set a directory for your personal module files (create this directory)
module use $HOME/.modules
# Load some default modules
module load guile

It's also useful add this to your ~/.bashrc, to make sure that when you start a new shell your environment is preserved:

if [ ! -z "$MODULESHOME" ]; then
module() { eval `$MODULESHOME/bin/modulecmd bash $*`; }

module update # Need to reload modules because of setuid utmp

Creating modules for Guile versions

The next step is to make the module files for the two versions of Guile. These will be called /opt/Modules/modulefiles/guile/1.8 and /opt/Modules/modulefiles/guile/2.0, and will look like this:

prepend-path PATH /scratch/opt/guile-2.0/bin
prepend-path LD_LIBRARY_PATH /scratch/opt/guile-2.0/lib
prepend-path PKG_CONFIG_PATH /scratch/opt/guile-2.0/lib/pkgconfig
prepend-path INFOPATH /scratch/opt/guile-2.0/share/info
prepend-path MANPATH /scratch/opt/guile-2.0/share/man

with 2.0 replaced by 1.8 for /opt/Modules/modulefiles/guile/1.8.

Finally, it's necessary to tell modules which version of Guile should be the default, for when a user asks for module load guile. We can do this by adding a /opt/Modules/modulefiles/guile/.modulerc file.

set ModulesVersion 2.0

Putting it all together

After re-initialising your session (probably easiest to log out and back in again), you should be able to swap between versions of Guile using module load and module switch as described above.

You should now be easily able to compile gEDA against either version of Guile without too much difficulty — simply load the appropriate environment module, and then run:

$ ./config.status --recheck && ./config.status && make

In my next post I will discuss one of the problems that's quite common in gEDA's use of Guile: unsafe behaviour on non-local exits such as Scheme exceptions.

No comments: