Next Up Previous Contents
Next: 4.2 The build system `interface'
Up: 4 Incorporating a package into the Starlink build system
Previous: 4 Incorporating a package into the Starlink build system
[ID index][Keyword index]

4.1 Autoconfing a library

The example here shows the autoconfing of the adam library, chosen simply because it's relatively simple.

Make a directory to hold the package, and add it to the repository


% pwd
<cvs-checkout>/libraries/pcs
% mkdir adam
% cvs add adam
Directory /cvs/libraries/pcs/adam added to the repository
% cd adam
          

Get the complete set of source files, and check them in to the repository. This means unpacking all the files in adam_source.tar, which you can find in /star/sources/pcs/adam (as it happens).

In this case, the adam_source.tar distribution tarball is a suitable set of sources. This is not always true, since some Starlink distributions -- especially some of the larger libraries and applications -- do quite elaborate processing of their sources in the process of creating this `source' tarball; in these cases, you should attempt to obtain a more fundamental set of sources from the package's developer (if that is not you).

The ideal source for new code is a CVS or RCS repository. A CVS repository is easy to import -- you just tar it up and unpack it into the correct place within the Starlink repository. An RCS repository is barely harder, with the only difference being that you have to create the Starlink repository directory structure by hand, and copy the RCS files into place within it. The only gotcha with this route is that you must make sure that the permissions are correct on the resulting repository: you must make sure that everyone who should have any access to the repository can read and write each of the directories.

CVS repository access is controlled by groups (at least when the repository is shared), and so each directory within the repository must have a suitable group ownership, with group-write permissions; each directory must also have the setgid bit set, so that any directories created within it inherit its gid. Make sure you check this as soon as you put the repository in place, or else everyone will have problems with the repository. Within the Starlink repository in particular, all participants are part of the cvs group. In short, you can set the correct permissions on an imported directory foo with the commands


% find foo -type d | xargs chgrp cvs
% find foo -type d | xargs chmod g+sw
This sets the group-owner of each directory to be cvs, and sets the group-write and set-group-id bits in the permissions mask (don't tinker with file permissions, since these affect the permissions of the checked out files). You need not worry about file or directory ownership, since this always ends up being the last person who committed a file. Note: The instructions here are based on observation of CVS repositories; the actual requirements don't seem to be formally documented anywhere.

Add all of the source files, including files like the mk script and the old makefile, which we are about to remove. Tag this initial import with a tag <component>-initial-import, so that it is possible to recover this old-style distribution if necessary. As mentioned above, it is not always completely clear what constitutes the old-style source set: so don't do this step mechanically, use your judgement, and above all avoid losing information. Note also that some of the infrastructure libraries were added before we settled on this particular tagging practice, and so lack such an initial tag.

In this present case, the adam_source.tar file includes a Fortran include file containing error codes, adam_err; there are two problems with this.

Firstly, the filename should be uppercase: the file is generally specified within the program in uppercase, and it should appear thus on the filesystem. The traditional makefile works around this by creating a link from adam_err to ADAM_ERR, but this won't work (and indeed will fail messily) on a case-insensitive filesystem like HFS+, used on OS X.

The second problem is that this is a generated file, though the source is not distributed, is probably misplaced, and in any case the generation was probably done on a VAX a decade ago. All is not lost, however. The functionality of the VAX `message' utility is duplicated in the application messgen, in a component of the same name, along with an application cremsg which constructs a source file from this message file. Thus it is neither adam_err nor ADAM_ERR which we should check in, but the source file adam_err.msg which we reconstruct using cremsg. Thus with error files, it is the (probably reconstructed) .msg file which should be checked in to the repository, and not the _err, _err.h or fac_xxx_err files which you may have found in the old-style distribution.

The file adam_defns is similar, but this is genuinely a source file, so we need do nothing more elaborate than rename it to ADAM_DEFNS, then add it to the repository and remove the original lowercased version. Many packages have one or two xxx_par files, and these should be similarly renamed to XXX_PAR.


% tar xf /star/sources/pcs/adam/adam_source.tar
% chmod +x adam_link_adam
% cremsg adam_err
% cvs add *.f mk makefile adam_link_adam adam_defns.h adam_defns adam_err.msg
...
cvs server: scheduling file `adam_err.msg' for addition
cvs server: use 'cvs commit' to add these files permanently
% cvs commit -m "Initial import"
% cvs tag adam-initial-import
% mv adam_defns ADAM_DEFNS
% cvs remove adam_defns
% cvs add ADAM_DEFNS
% rm mk makefile
% cvs remove mk makefile
          

Note that CVS preserves access modes when it stores files, so we should make sure that the script adam_link_adam is executable before checking it in, and we need not bother to make it executable as part of the build process. On the other hand, scripts which are substituted by configure do need to be made executable explicitly, which you do by a variant of the AC_CONFIG_FILES macro. The macro invocation


AC_CONFIG_FILES(foo, [chmod +x foo])
substitutes foo from source file foo.in and then makes it executable. Note that the sequence

AC_CONFIG_FILES(foo)
chmod +x foo
would not work, since this is one of the cases where autoconf macros do not simply expand inline to shell code. For further discussion, see the section Performing Configuration Actions in the autoconf manual.

Create files configure.ac, Makefile.am and component.xml.in by copying the templates in the starconf buildsupport directory (starconf --show buildsupportdata); the fields in the component.xml.in file are discussed in Section 2.2.4. If you have an editor that can use it, you might also want to create a link to the DTD used for the component.xml file, which is in the same directory. Edit these files as appropriate, using information in the original Starlink makefile for guidance (so it's useful to keep a copy of the original makefile handy, rather than simply deleting it as illustrated above). Then check the files in.

What edits should you make?

The adam Makefile.am file looks as follows:


bin_SCRIPTS = adam_link_adam
lib_LTLIBRARIES = libadam_adam.la
libadam_adam_la_SOURCES = $(PUBLIC_INCLUDES) $(F_ROUTINES)
include_HEADERS = $(PUBLIC_INCLUDES)
PUBLIC_INCLUDES = ADAM_ERR ADAM_DEFNS adam_defns.h
F_ROUTINES = \
        adm_acknow.f adm_getreply.f adm_getreplyt.f adm_path.f \
        adm_prcnam.f adm_receive.f adm_reply.f adm_send.f \
        adm_sendonly.f adm_sendt.f adm_trigger.f
Four out of six of these variable declarations are variables meaningful to automake (see Section 2.1.2), and the other two are simply copied from the original makefile.

The adam configure.ac looks like this:


AC_INIT(adam, 3.0, ussc@star.rl.ac.uk)
AC_PREREQ(2.50)
AM_INIT_AUTOMAKE(1.8.2-starlink)
AC_CONFIG_SRCDIR([ADAM_DEFNS])
STAR_DEFAULTS

AC_PROG_FC
AC_PROG_LIBTOOL
STAR_CNF_COMPATIBLE_SYMBOLS

STAR_DECLARE_DEPENDENCIES(build, [sae messys])
STAR_DECLARE_DEPENDENCIES(link,  [chr psx ems messys])

dnl    There is no .msg file in this directory.  The ADAM_ERR file 
dnl    contains only a single definition, of the parameter ADAM__OK.

AC_CONFIG_FILES(Makefile component.xml)
AC_OUTPUT
The first five lines are straightforward boilerplate (see Section 2.1.1). The next three find a Fortran compiler, declare that we want to use libtool to build our libraries, and finally that we wish the symbols in that library to be of the sort that the CNF package is able to handle (see Appendix A.15). The `FC' autoconf macros will search for a Fortran compiler by looking for a f95 compiler before looking for a f77 compiler; if you know or discover this is inappropriate, then you can constrain the Fortran dialect that AC_PROG_FC will look for by giving a value for its optional dialect argument. Macro AC_PROG_FC is not yet documented in the autoconf manual, but see Appendix B.

After that, we declare the dependencies. The dependencies you work out by any and all means you can. For a library, the set of `build' dependencies is determined by the set of components which supply files which the code here includes. Grepping for all the Fortran INCLUDE statements and all the C #include directives is a good start. For link dependencies, grepping for CALL lines is useful for Fortran, and grepping for


= *\([A-Za-z][A-Za-z]*__*[A-Za-z][A-Za-z]*\) *(.*
will probably be handy. In fact, the script

#! /bin/sh -
sed -n \
        -e 's/^ *\(INCLUDE\|include\) *'\(.*\)'.*/_ \2/p' \
        -e 's/^ *\(CALL\|call\) *\([A-Za-z]*_[A-Za-z]*\).*/\2/p' \
        -e 's/.*= *\([A-Za-z][A-Za-z]*__*[A-Za-z][A-Za-z]*\) *(.*/\1/p' \
        ${1+"$@"} | \
    sort | \
    uniq
should give you the raw material for most of the dependencies you need. It doesn't really matter too much if you get this wrong -- you might cause something to be built slightly later than it might be in the top-level bootstrap, might cause some eventual user to have to download one package more than they have to, or might create a circular dependency and break the nightly build, in which case you'll find out soon enough.

See Appendix A.16 for the description of the various types of dependencies you can specify here.

By the way, remember (because everyone forgets) that there are no components err and msg: all of the err_ and msg_ functions are in the mers component.

The next couple of lines tells you that we lied outrageously, above, when we were talking about .msg files. Though the remarks there are true enough in general, the ADAM_ERR file is special, and doesn't come from any .msg file. This is surprising enough that it's worth making a remark to this effect in the configure.ac file.

Finally, we list the files that should be configured. Essentially all starconf-style configure files should have at least these two files mentioned here.

Now run starconf. As described in Section 2.2, this adds some required files, and checks that the directory looks right. It will look something like this:


% starconf
starconf-validate: the following files are required but do not exist:
        bootstrap
starconf-validate: the following files should be checked in, but aren't
        Makefile.am configure.ac bootstrap component.xml.in component.xml
Configuring with STARCONF_DEFAULT_STARLINK=/export3/sun
Configuring with STARCONF_DEFAULT_PREFIX=/export3/sun
Creating bootstrap
          

That complained that the file bootstrap wasn't present, and then went on to install one for you; it listed a number of files which should be checked in; and it added a bootstrap script. The starconf application actually does the checking by running the starconf-validate script, which you can run yourself independently if you wish.

Now you have a bootstrap file, so run it:


% ./bootstrap 
starconf-validate: the following files should be checked in, but aren't
        Makefile.am configure.ac bootstrap component.xml.in component.xml
Configuring with STARCONF_DEFAULT_STARLINK=/export3/sun
Configuring with STARCONF_DEFAULT_PREFIX=/export3/sun
File bootstrap already exists, not overwriting
autoreconf --install --symlink
configure.ac: installing `./install-sh'
configure.ac: installing `./missing'
          
The bootstrap script always re-runs starconf if it can, so this reminds you that you still haven't checked those files in. It also runs autoreconf (Section 2.1.4) for you, installing the helper files that requires, and constructing configure from configure.ac and Makefile.in from configure.ac and Makefile.am.

Now, finally, you can try ./configure and make. That might just work.

Iterate until success.

When the code is working, you will might want to add it to the set of components which are explicitly built. To do this, add it to the ALL_TARGETS variable in the top-level Makefile.in. Next, go to the parent directory of the directory you have just added: the configure.ac file there will almost certainly have a skeleton configure.ac which includes a AC_CONFIG_SUBDIRS line, to which you should add your newly working directory.


Next Up Previous Contents
Next: 4.2 The build system `interface'
Up: 4 Incorporating a package into the Starlink build system
Previous: 4 Incorporating a package into the Starlink build system
[ID index][Keyword index]
The Starlink Build System
Starlink System Note 78
Norman Gray, Peter W Draper, Mark B Taylor, Steven E Rankin
11 April 2005. Release snapshot: $Revision: 1.116 $. Last updated 28 May 2006