An introduction to the Mercury source code and tools

The source code to Mercury is freely available and may be modified by anyone. However, there's a bit of a difference between being legally allowed to modify the code, and actually being able to do it! The Mercury system is quite large, and as the compiler for Mercury is written in Mercury itself, there are a few tricks worth learning if you are going to develop with Mercury.

This document aims to help developers get started with the Mercury development environment, by explaining some of the special tools that are available for developers.

Other useful documents are in the Developers Information section of the web site. In particular you may wish to see how to access the Mercury git repository and read about the design of the Mercury compiler.

This document is a work-in-progress; if there is particular information you feel is useful, please let us know and we will write something about it.

About grades

The Mercury system uses the word "grade" to refer to a set of compilation options for the system. Some of them are for benchmarking purposes, others enable debugging or profiling, and others enable research features. Many grades are incompatible with each other.

Mixing and matching grades can be the cause of headaches. It's a good idea to `mmake realclean' build from scratch if you run into weird problems and have been changing grades. The Mercury system makes a pretty good attempt to try to stop this kind of thing resulting in a crashing program, but you will often get linker errors if you try to build different parts of the compiler in incompatible grades.

Setting the installation path

If you want to install your own compiler, you will probably want to keep it separate from a working stable compiler (or else you might make a mistake that makes it impossible to compile the compiler anymore!).

When you run configure, you can set an installation path. For example:

./configure --prefix /tmp/mercury/install
will set the installation path to /tmp/mercury/install. Make sure you set your PATH so that it includes the `bin' subdirectory of your install path -- in this example it would be /tmp/mercury/install/bin. And be sure that this is earlier in your path than any other Mercury installation (for example, one in /usr/bin or /usr/local/bin).

See the files INSTALL and INSTALL_CVS for more information on installation of Mercury.

Installing fewer grades

If you make a lot of changes to the compiler, you will find it a bit time consuming to install the entire Mercury system to run a few tests.

The first thing to realize is that when you install the compiler, you don't have to install all the grades. You can set the make variable LIBGRADES to set the list of "extra" grades to install. If you set it to empty, it will install only the default grade (probably asm_fast.gc).

A good way to do this is to create (or modify an existing) Mmake.params file in the top-level of the mercury distribution (in the same directory as README and NEWS). Mmake.params is used to set local workspace options and is very useful for overriding default mmake settings. Add the line

LIBGRADES=
and you won't have to wait for all those grades to be installed. You can also set this variable on a once off basis on the command line.
mmake install LIBGRADES=

There are some good default settings for libgrades you can set at configuration time, for example

./configure --disable-most-grades
./configure --enable-libgrades=...
Run configure with the --help option to see more options.

Again, the INSTALL file in the Mercury distribution has more detailed documentation on installing grades.

Using the local build directory

If you only need to run your version of mmc (and don't need mmake), you don't need to install at all. There is a script in the tools directory of the Mercury distribution called `lmc'. You can use this script just like mmc, but it will use the Mercury compiler, library, runtime, etc that you have in an uninstalled workspace.

You need to set the environment variable WORKSPACE to point to the workspace you are using. The easiest way to do this is to create a small script which sets WORKSPACE and runs lmc. For example if you are using $HOME/mercury as your workspace:

#!/bin/sh                                                                    
WORKSPACE=$HOME/mercury
export WORKSPACE                                   
$WORKSPACE/tools/lmc "$@"       
See the tools/lmc file for further documentation on this tool -- it can also run the compiler under gdb or compile programs suitable for C level debugging.

There is also a script in the tools directory called `lml', which is similar to `lmc' except that it runs `ml' rather than `mmc'. You can use these with mmake:

mmake MC=lmc ML=lml ...
However, this will still use the installed version of `mmake', `c2init'/`mkinit', `mgnuc', etc. So it isn't entirely foolproof. If you've made changes to the scripts, it may be best to install rather than trying to use the local build directory.

Bootchecking

If you've made changes to the compiler or library that you think are working fine, you should make sure you haven't messed up some other part of the compiler.

The bootcheck script in the tools directory of the Mercury compiler is just what you need to do this. It works in a number of stages, where each stage is the output of the compiler we built in the previous stage.

Stage 1 is to build a working Mercury compiler (just like typing mmake at the top level of the mercury distribution). We build this compiler using a known, trusted, stable Mercury compiler.

Stage 2 uses the stage 1 Mercury compiler to build a stage 2 Mercury compiler. This ensures that you can still build the compiler using your modifications.

Bootcheck then uses the stage 2 Mercury compiler to build the C files of another Mercury compiler, the stage 3 compiler, and compares them with the C files of the stage 2 compiler, which were built by the stage 1 compiler. If they differ, then the stage 2 compiler does not execute the same algorithm as the stage 1 compiler. Since the stage 1 and 2 compilers were built from the same source, the difference must have been introduced by differences in the compilers used to compile that source. Since stage 1 was compiled with a trusted compiler, the compiler used to generate the stage 2 executable (i.e. the stage 1 compiler) must be buggy. If this happens, the compiler doesn't "bootstrap" -- it cannot reliably compile itself.

Finally, if you have checked out the "tests" module from CVS, the bootcheck will use the stage 2 compiler, library and runtime to run all the tests in the testing hierarchy.

Check out the tools/bootcheck script to see further documentation on how it works. You can build only specific stages, just run the tests, omit building certain parts of the compiler, and much much more.

Bootchecking can take quite a while -- 1-3 hours is not uncommon. It's a good idea to run the bootcheck in the background and log the results to a file. For example:

./tools/bootcheck > bootchecklog.Jan21 2>&1 &
tail -f bootchecklog.Jan21
There is also a script tools/submit_patch, which can be used for testing and/or committing patches. It takes as input a file containing a CVS log message and a patch file. It checks out the Mercury sources, applies the patch file, and then tests the patch by running a couple of bootchecks in different grades. If you specified the `--commit' option, and the tests pass, it then goes ahead and commits the patch.

Debugging the declarative debugger

The browser directory contains the source code for the declarative debugger as well as the features of the procedural debugger implemented in Mercury.

By default this directory is compiled with no tracing enabled, even when a .debug or .decldebug grade is specified. This allows the declarative debugger to take advantage of optimisations such as tail recursion and reduces the size of the installed libraries.

In order to debug the code in the browser directory add the following line to your Mmake.browser.params file in the browser directory:

EXTRA_MCFLAGS=--no-force-disable-tracing

The `dd_dd' command can then be used from mdb to start the declarative debugger with interactive debugging turned on.

Since tracing turns off the tail recursion optimisation, you may also need to increase the size of the stack by setting the --detstack-size runtime option:

export MERCURY_OPTIONS="--detstack-size 8128"

Comments? See our contact page.