
Portable code versus unix specific build procedures
I still do a lot of programming on OpenVMS and one thing that has really
been driving me batty lately has been the demise of packages that build
from a simple "Makefile". Although we never could use those directly, it
was easy enough to modify a Makefile and end up with build instructions for
OpenVMS. These days I rarely see a Makefile, but instead find packages
which either use "configure" or their own custom scripts full of sed, awk,
etc. They also tend to make considerable use of "ln -s" for "moving" files
around. Sometimes these build procedures are almost pathological in their
nonportability - consider this line from the interbase distribution:
ls sfx.* | awk '{split( $1, f, "."); print "cat prefix.$(BASE) " $1 " >make." f [2]}' > tmp2.ksh
Try that on a Mac!
Naturally, this is all done in the name of portability, but I really must
protest. The methods which are being widely adopted within the Unix
programming community may facilitate the movement of code from one Unix
variant to another, but they make building the code on nonUnix platforms a
nightmare. (ln -s is particularly nonportable - and I've yet to see a
build procedure where it was really needed and "-I" couldn't do the same
job.)
I especially lay the bulk of the blame for this on the gnu automake/
autoconf utilities and the people who designed them. "configure" is a
shell script and typically uses numerous Unix specific (or at least, gnu
specific) programs. There is no reason whatsoever that it could not be
written in ANSI C, and process a requirements file, and a capabilities
file, to generate a (set of) (platform specific) "Makefiles". The
"Discovery" phase of configure, where it pokes the platform to see what the
compiler(s) will do, could easily enough be replaced by a static
description file on most platforms (and could still be a sh script on Unix.)
Even on Unix, if the discovery phase been run once the results could be
stored in something like /etc/compiler_capabilities and only regenerated
when the compiler or OS is updated. That is, if a computer doesn't have
"memcpy" today, it won't have it tomorrow either, unless the compiler or OS
has been upgraded in between.
But getting a portable version of "configure" is a long term project, and
one that the Gnu folks may choose not to take on. So, in the meantime, the
next time _you_ build a package which you want to be portable, please have
a little consideration for people who may try at some point to build it on
a nonUnix platform, and at least do the following:
1. Generate Makefiles (not just Makefile.in) for some reference platform,
even if it will normally be overwritten by "configure".
2. Explicitly break out all the dependencies into a file, and indicate
prominently in the documenation what that file is called. (This
information is often sufficient to create a build procedure de novo.)
3. List somewhere all the command line "-D" arguments your program can use
and what each one does.
and if you're feeling especially generous towards nonUnix programmers:
4. Eliminate relative includes from your code
5. Keep all static file and pathname information in a single
header file (not scattered throughout the code)
6. Manipulate file and pathnames with a named set of functions so that
they may be more easily replaced on other platfroms.
That is, instead of:
(void) strcpy(fullname,path);
(void) strcat(fullname,"/");
(void) strcat(fullname,filename);
(void) strcat(fullname,".gz");
use something like
(void) make_full_filename(fullname,path,filename);
(void) append_suffix(fullname,"gz")
7. Force the compiler into a mode which checks the code for language
conformance. The closer you can get to a clean build using something
like "-ansi -pedantic -Wall" the more likely it is that the code
will work unchanged on another platform.
Thank you,
David Mathog
Manager, sequence analysis facility, biology division, Caltech