NAME
metaconfig - a Configure script generator
SYNOPSIS
metaconfig [ -dhkmostvwGMV ] [ -L dir ]
DESCRIPTION
Metaconfig is a program that generates Configure scripts. If you don’t
know what a Configure script is, please skip to the TUTORIAL section of
this manual page. If you want a full (formal) description of the way to
use metaconfig and its units, please look at the REFERENCE section. The
following is a quick introduction and reference for knowledgeable
users.
Metaconfig operates from set of units which define everything that
metaconfig knows about portability. Each unit is self-contained, and
does not have to be registered anywhere other than by inclusion in
either the public U directory or your private U directory. If the dist
package (of which metaconfig is a part) is installed in LIB, then the
public U directory is LIB/dist/mcon/U. On this machine, the LIB
directory is /usr/share/dist. Your private U directory, if you have
one, is in the top level directory of your package. Before you can run
metaconfig you must do a several things:
· Create a .package file in the package’s top level directory by
running packinit. This program will ask you about your package
and remember what you tell it so that all the dist programs can be
smart.
· Consult the Glossary (in LIB/dist/mcon) and write your shell
scripts and C programs in terms of the symbols that metaconfig
knows how to define. You don’t need to tell metaconfig which
symbols you used, since metaconfig will figure that out for you.
· Generate any .SH scripts needed to write Makefiles or shell
scripts that will depend on values defined by Configure. There is
a program called makeSH that will help you convert a plain script
into a script.SH template; some editing will still need to be
performed on the resulting .SH file to move the variable
configuration part in the top part of the script (see inline
comments generated by makeSH within your .SH file).
· Create a MANIFEST.new file in your top level directory that lists
all the files in your package. This file will remain private and
will not be part of the final distribution. (As a convenience, the
MANIFEST file will be used by metaconfig if there is no
MANIFEST.new file yet.) The filename should be the first field on
each line. After some whitespace you can add a short comment
describing your file. Only source files should be listed in
there. The special file patchlevel.h (which is handled and
maintained by the patching tools -- see pat(1)) should be part of
the MANIFEST.new file, but may be silently ignored by some tools.
As a rule of thumb, only files maintained by RCS should be listed
in there, the patchlevel.h file being one important exception.
· Optionally, you may wish to create a MANIFEST file, which will be
an exported version of your MANIFEST.new. That file must be made
part of the release, i.e. listed in both your MANIFEST.new and
MANIFEST itself. One of the metaconfig units knows about this
file and will force Configure to perform a release check, ensuring
all the files listed there are part of the distribution. The
MANIFEST and MANIFEST.new files should be distinct, not links.
· Copy any .U files that you want to modify to your private U
directory. Any .U files in your private U directory will be used
in preference to the one in the public U directory. For example,
one way to force inclusion of any unit is to copy the End.U file
to your .U directory and add the name of the unit you want as a
dependency on the end of the ?MAKE: line. Certain units can ONLY
be forced in this way, namely those of the form Warn_*.U and
Chk_*.U. You can also customize certain default Configure
variables by copying Myinit.U to your package’s private U
directory and setting the variables in that unit.
Now you are ready to run metaconfig. That will create a Configure file,
and optionally a config_h.SH file (if your sources make any use of C
symbols). The generated files will automatically be added to your
MANIFEST.new if necessary. Do not forget to update your MANIFEST file
though.
In order to create new units, do the following:
· Copy a similar unit to a new .U file. The name you choose should
be the name of a variable generated by the unit, although this is
only a convenience for you, not a requirement. It should be 12 or
less characters to prevent filename chopping. Actually, it should
probably be 10 or less so that those who want to use RCS can have
a .U,v on the end without chopping. Metaconfig uses the case of
the first letter to determine if any variable is actually produced
by this unit, so don’t Capitalize your unit name if it is supposed
to produce a shell variable.
· Edit the new .U file to do what you want. The first ?MAKE: line
indicates the dependencies; before the final list colon all the
variables this unit defines, and after the final colon all the
variables (or other units) on which this unit depends. It is very
important that these lists be accurate. If a dependency is
optional and a default value can be used, you should prefix the
dependency with a ’+’ sign. The corresponding unit will not be
loaded to compute the symbol, unless really required by another
unit.
· To the extent possible, parameterize your unit based on shell
variable defined on ?INIT: lines. This will move the variable
definitions up to the Init.U unit, where they can be overridden by
definitions in Myinit.U, which is included after Init.U.
· Add the definition of any C symbols desired as ?H: lines. A line
beginning with ?H:?%<: in the .U file will be added to the
eventual config.h file if and only if metaconfig decides that this
unit is needed. The %< stands for the unit’s name, which happens
to be the name of the file too (without .U) if you followed the
convention. Always put a comment on each ?H: line in case one of
the variable substitutions earlier on the line starts a comment
without finishing it. Any shell variable starting with d_ may do
this, so beware. If you ommit the ?%<:, then metaconfig will try
to intuit the symbol whose definition is needed prior any
inclusion in config.h.
· Add glossary definitions as ?S: lines for shell variables and ?C:
lines for C preprocessor variables. See a current unit for
examples. It is VERY important to start each entry with a left
justified symbol name, and end each entry with a ?C:. or ?S:.
line. The algorithm that translates C preprocessor symbol entries
for the Glossary into comments for config.h depends on this.
· Make sure the order of all your ? lines is right. The correct
order is:
?RCS: and ?X: basically just comments
?MAKE: metaconfig dependencies
?Y: unit layout directive
?S: glossary shell definitions
?C: glossary C definitions
?H: config.h definitions
?M: confmagic.h definitions
?W: wanted symbols
?V: visible symbols
?F: files created by this unit
?T: temporary shell symbols used
?D: optional dependencies default value
?O: used to mark obsolete units
?LINT: metalint hints
?INIT: shell symbols initializations
Here is an example to show the ordering of the lines and the various
formats allowed:
?RCS: $RCS-Id$
?RCS: Copyright information
?RCS: $RCS-Log$
?X:
?X: A contrived example
?X:
?MAKE:d_one two: three +four Five
?MAKE: -pick add $@ %<
?Y:DEFAULT
?S:d_one:
?S: First shell symbol, conditionally defines ONE.
?S:.
?S:two:
?S: Second shell symbol, value for TWO.
?S:.
?C:ONE:
?C: First C symbol.
?C:.
?C:TWO:
?C: Second C symbol.
?C:.
?H:#$d_one ONE /**/
?H:#define TWO "$two"
?H:#$d_one ONE_TWO "$two"
?H:.
?M:flip: HAS_FLIP
?M:#ifndef HAS_FLIP
?M:#define flip(x) flop(x)
?M:#endif
?M:.
?W:%<:one_two
?V:p_one p_two:p_three
?F:file ./ftest !tmp
?T:tmp var
?D:two=’undef’
?LINT:change three
?INIT:two_init=’2’
: shell code implementing the unit follows
p_one=’one’
p_two=’two’
p_three=""
Let me state it one more time: the above unit definition is a fake one
to only show the different possibilities. Such a unit would serve
little purpose anyway... Some more advanced features are not described
here. Please refer to the REFERENCE section for more complete
information.
· Put the unit into the public or private U directory as
appropriate.
· Rerun metaconfig.
· Send your unit to ram@acri.fr (Raphael Manfredi) for inclusion
in the master copy, if you think it’s of general interest.
In order to add a new program to be located:
· Edit Loc.U, and add the name of the program both to the ?MAKE:
line (between the two colons) and to either loclist or trylist
(depending on whether the program is mandatory or not).
· Rerun metaconfig.
· Send your unit to me for inclusion in the master copy, if you
think it’s of general interest.
Notes for writing .U files:
* Always use "rm -f" because there are systems where rm is
interactive by default.
* Do not use "set -- ..." because ’--’ does not work with every
shell. Use "set x ...; shift".
* Do not use "unset ENV" since unset is not fully portable. Say
"ENV=’’" instead.
* Always use echo " " (with a space) because of Eunice systems.
* Only use test with -r, -w, -f or -d since those are the only
portable switches. In particular, avoid "test -x".
* Use only programs that came with V7, so that you know everyone has
them.
* Use $contains when you want to grep conditionally, since not all
greps return a reasonable status. Be sure to redirect the output
to /dev/null, by using ’>/dev/null 2>&1’.
* Use "if test" rather than "if [...]" since not every sh knows the
latter construct.
* Use the myread script for inputs so that they can do shell escapes
and default evaluation. The general form is
case "$grimble" in
’’) dflt=452;;
*) dflt="$grimble";;
esac
rp=’How many grimbles do you have?’
. ./myread
grimble="$ans"
* Use the getfile script when asking for a file pathname in order to
have optional ~name expansion and sanity checks. See the Getfile.U
unit for a full decription.
* Always put a
$startsh
at the top of every generated script that is going to be launched
or sourced by Configure.
* Never assume common UNIX-isms like the fact that an object file
ends with a .o and that a library name ends with .a. Use the $_o
and $_a variables instead (see Unix.U).
* When doing a compile-link-execute test, always write it like this:
$cc $ccflags $ldflags try.c -o try $libs
because some systems require that linking flags be specified
before the compiled target (with the exception of trailing linking
libraries).
* Issue important messages on file descriptor #4, by using ’>&4’ to
redirect output. Only those messages will appear when the -s
switch is given to Configure on the command line (silent mode).
* Always try to determine whether a feature is present in the most
specific way--don’t say "if bsd" when you can grep libc. There
are many hybrid systems out there, and each feature should stand
or fall by itself.
* Always try to determine whether a feature is present in the most
general way, so that other packages can use your unit.
* When in doubt, set a default and ask. Don’t assume anything.
* If you think the user is wrong, allow for the fact that he may be
right. For instance, he could be running Configure on a different
system than he is going to use the final product on.
Metaconfig reserves the following names in your directory, and if you
use such a name it may get clobbered or have other unforeseen effects:
.MT/*
Configure
Wanted
Obsolete
configure
config_h.SH
confmagic.h
U/*
MANIFEST.new
Additionally, Configure may clobber these names in the directory it is
run in:
UU/*
config.sh
config.h
OPTIONS
The following options are recognized by metaconfig:
-d Turn on debug mode. Not really useful unless you are
debugging metaconfig itself.
-h Print help message and exit.
-k Keep temporary directory, so that you may examine the
working files used by metaconfig to build your Configure
script. Useful only when debugging the units.
-m Assume lots of memory and swap space. This will speed up
symbol lookup in source files by a significant amount of
time, at the expense of memory consumption...
-o Map obsolete symbols on new ones. Use this switch if you
still have some obsolete symbols in your source code and
do not want (or cannot) remove them for now. The
obsolete symbols are otherwise ignored, although that
will give you a warning from metaconfig.
-s Turn silent mode on.
-t Trace symbols as they are found.
-v Turn verbose mode on.
-w Assume Wanted file is up-to-date. This will skip the
time and memory consuming phase of source code scanning,
looking for known symbols. Use it only when you know
your source file have not changed with respect to the
pool of metaconfig symbols used.
-G Also provide a GNU configure-like front end to the
generated Configure script, to be included in the
distribution as well. This is only a wrapper around the
Configure script naturally, but it lets people familiar
with the GNU tool to not be lost when facing a new
distribution.
-L dir Override default library location. Normally only useful
for metaconfig maintainers to locally use the units
being developped instead of the publicly available ones.
The dir specified is the one containing the units U
directory.
-M Allow production of a confmagic.h file to automagically
remap some well-known symbols to some other alternative,
like bcopy() being remapped transparently to memcpy()
when not available. This option is turned on
automatically when a confmagic.h file exists in the top-
level directory. Simply remove that file if you wish to
disable this option permanently.
-V Print version number and exit.
TUTORIAL
This (long) section is an introduction to metaconfig, in which we will
learn all the basics. If you already know how to use metaconfig, you
may safely skip to the next section.
Overview
Usually when you want to get some source package to compile on a given
platform you have to edit the main Makefile (assuming there is one!),
choose a C compiler, make sure you have the proper libraries, and then
fire the make command. If the package is reasonably well written, it
will compile (without a warning being an option :-). In itself, the
last sentence is a real performance, since given the variety of UNIX
platforms available today and the diversity of flavours, that means the
author of the package has gone into deep trouble to figure out the
right choices given some standard trial, guessing and messing around
with system includes and types.
However, despite all his talent, the author cannot possibly know that
some system has a broken system call, or that some sytem structure
lacks one otherwise standard field, or simply wheter a given include
file exists or not. And I’m not considering the implicit assumptions,
like the type returned by the malloc() function or the presence of the
rename() system call to name a few. But that knowledge is necessary to
achieve real portability.
Now let’s not abuse ourselves. Using that information requires greater
skills, yet it can lead to more portable programs since it is then
written in a system-independant fashion and relies only on the fact
that some assumption is true or false on a particular system, each
assumption being unrelated with each other. That is to say, we do not
say: We’re on a BSD system or we are on a USG system. That’s too fuzzy
anyway nowadays. No, we want to say to the source code: this system
does not have the rename() system call and malloc() returns a (void *)
value.
Metaconfig is a tool that will let you do just that, with the
additional benefit of not having to hand-edit the Makefile if all goes
well. By running metaconfig, you create a shell script named Configure.
Lots of efforts have been devoted to the Configure script internals to
ensure it will run on 99% of the existing shells available as of this
writing. Configure will probe the target system, asking questions when
in doubt and gather all the answers in one single shell file, which in
turn can be used to automatically generate configured Makefiles and C
include files.
There is only a limited (but quite large) set of symbols available for
your shell scripts and C programs. They are all documented in the
Glossary file. All you need to do is learn about them and start using
them to address portability and configuration problems. Then, by
running metaconfig, a suitable Configure script will be generated for
your package.
The Configure script is built out several units (more than 300), each
unit being responsible for defining a small number of shell and/or C
symbols. Units are assembled together at the final stage, honoring the
dependency graph (one unit may need the result of several other units
which are then placed before in the script).
Symbols
Symbols are the most important thing in the metaconfig world. They are
the smallest recognized entity, usually a word, and can be granted a
value at the end of the Configure execution. For instance, the C pre-
processor symbol HAS_RENAME is a metaconfig symbol that is guranteed to
be defined if, and only if, the rename() system call is present.
Likewise, the $ranlib shell variable will be set to either ’:’ or
’ranlib’ depending on whether the call to the ranlib program is needed
to order a library file. How this works is not important for now, what
is important is to understand that those symbols are given a life (i.e.
a value) upon Configure execution.
Using symbols is relatively straightforward. In a C source file, you
simply use the symbol value, as a pre-processor directive (for instance
an: #ifdef HAS_RENAME) or, if the symbol value is a string, directly as
you would use a macro in C. And in a shell file or a Makefile, you may
reference a shell symbol directly.
Actually, I’m lying, because that’s not completely as magic as the
previous paragraph could sound. In a C file, you need to include the
Configure-produced config.h file, and you must wrap your shell script
or Makefile in a .SH file and you may reference the shell symbol only
in the variable substitution part of that .SH file. More on this later.
Source Files
Symbols may only appear in a limited set of source files, because
metaconfig will only scan those when looking for known symbols, trying
to figure out which units it will need. You may use C symbols in C
source files, i.e. files with a .c, .h, .y or .l extension, and shell
symbols are looked for only in .SH files.
In order to get the value of a symbol, a C file needs to include the
special config.h file, which is produced by Configure when C symbols
are present. And .SH files are run through a shell, producing a new
file. However, in the top section of the .SH file, the special
config.sh file (also produced by running Configure) is sourced, and
variable substitutions apply. Actually, config.h is produced by running
the metaconfig-produced config_h.SH file, again using variable
substitution. So we’re going to look at that a little more closely
since this is the heart of the whole configuration scheme...
Variable Substitution
There is shell construct called here document which enables a command
to take an input specified within the script itself. That input is
interpreted by the shell as a double-quoted string or a single quoted
string depending on the form of the here document specification.
To specify a here document, the ’<<’ token is used, followed by a
single identifier. From then on, the remaining script lines form the
input for the command, until the here document is found on a line by
itself. Shell substitution (including shell variable substitutions) is
done unless the identifier is surrounded by single quotes. For
instance:
var=’first’
tar=’second’
echo "--> first here document:"
cat <<EOM
var=’$var’
tar=’$tar’
EOM
echo "--> second here document:"
cat <<’EOM’
echo $var
echo $tar
EOM
echo "--> end."
will produce, when run through a shell:
--> first here document:
var=’first’
tar=’second’
--> second here document:
echo $var
echo $tar
--> end.
The first here document has its content interpreted whilst the second
one is output as-is. Both are useful in a .SH script, as we are about
to see.
Using .SH Scripts
A .SH script is usually produced by running the MakeSH script other an
existing file, transforming file into a file.SH. Let’s take a single
example. Here is a little script (let’s call it intsize) which prints a
single message, the size of the int datatype in C. Unfortunately, it
has the value hardwired in it, thusly:
#!/bin/sh
intsize=’4’
echo "On this machine, the int type is $intsize bytes"
Let’s run makeSH on it by typing ’makeSH intsize’. We get a single
intsize.SH file that looks like this:
case $CONFIG in
’’)
if test -f config.sh; then TOP=.;
elif test -f ../config.sh; then TOP=..;
elif test -f ../../config.sh; then TOP=../..;
elif test -f ../../../config.sh; then TOP=../../..;
elif test -f ../../../../config.sh; then TOP=../../../..;
else
echo "Can’t find config.sh."; exit 1
fi
. $TOP/config.sh
;;
esac
: This forces SH files to create target in same directory as SH file.
: This is so that make depend always knows where to find SH derivatives.
case "$0" in
*/*) cd ‘expr X$0 : ’X\(.*\)/’‘ ;;
esac
echo "Extracting intsize (with variable substitutions)"
: This section of the file will have variable substitutions done on it.
: Move anything that needs config subs from !NO!SUBS! section to !GROK!THIS!.
: Protect any dollar signs and backticks that you do not want interpreted
: by putting a backslash in front. You may delete these comments.
$spitshell >intsize <<!GROK!THIS!
$startsh
!GROK!THIS!
: In the following dollars and backticks do not need the extra backslash.
$spitshell >>intsize <<’!NO!SUBS!’
intsize=’4’
echo "On this machine, the int type is $intsize bytes"
!NO!SUBS!
chmod 755 intsize
$eunicefix intsize
The first part of this script (in the case statement) is trying to
locate the config.sh file, in order to source it. The $CONFIG variable
is false by default, by true when config.sh has been sourced already
(which would be the case if this file was executed from within
Configure itself, but let’s not confuse the issue here).
Once the config.sh file has been sources, all the shell symbols defined
by Configure are set. We know reach a second case statement, used to
change the current directory should a path be used to reach this
program (for instance if we said ’sh ../scripts/intsize.SH’, we would
first run ’cd ../scripts’ before continuing). If you do not understand
this, don’t worry about it.
Here comes the intersting stuff. This script uses the $spitshell
variable, and it’s not something we know about...yet. If you look
through the Glossary file, you will see that this is a variable known
by metaconfig. If you make this file part of your distribution (by
including it in the MANIFEST.new file, we’ll come back to that later
on) and run metaconfig, then the Configure script will determine a
suitable value for this variable and it will be set in config.sh. Same
goes for $startsh and the mysterious $eunicefix at the end. On a
reasonable system, the relevant part of config.sh would look like this:
spitshell=’cat’
startsh=’#!/bin/sh’
eunicefix=’:’
Ah! We’re getting there. Now it looks familiar. We’re facing a single
cat command whose input comes from a variable-interpolated here
document and whose output is redirected to intsize. The value will be
that of $startsh, i.e. ’#!/bin/sh’. Fine so far.
Then we reach the second here document expansion, to get the remaining
of the script. This time, the here document symbol is surrounded by
single quotes so the contents will be appended verbatim to the intsize
file. So, by running ’sh intsize.SH’, we get the following output:
Extracting intsize (with variable substitutions)
and by looking at the produced intsize file, we see:
#!/bin/sh
intsize=’4’
echo "On this machine, the int type is $intsize bytes"
which is exactly what we had at the beginning. So far, it’s a no-
operation procedure... But, how marvelous! It so happens (pure
coincidence, trust me!), that metaconfig knows about the $intsize shell
symbol. By moving the initialization of intsize to the variable-
interpolated area of the .SH script and initializing it with the
Configure-computed value, and removing the now useless comments added
by makeSH, we get:
case $CONFIG in
’’)
if test -f config.sh; then TOP=.;
elif test -f ../config.sh; then TOP=..;
elif test -f ../../config.sh; then TOP=../..;
elif test -f ../../../config.sh; then TOP=../../..;
elif test -f ../../../../config.sh; then TOP=../../../..;
else
echo "Can’t find config.sh."; exit 1
fi
. $TOP/config.sh
;;
esac
case "$0" in
*/*) cd ‘expr X$0 : ’X\(.*\)/’‘ ;;
esac
echo "Extracting intsize (with variable substitutions)"
$spitshell >intsize <<!GROK!THIS!
$startsh
intsize=’$intsize’
!GROK!THIS!
$spitshell >>intsize <<’!NO!SUBS!’
echo "On this machine, the int type is $intsize bytes"
!NO!SUBS!
chmod 755 intsize
$eunicefix intsize
Of course, running this script through a shell will again output the
same script. But if we run Configure on a machine where an int is
stored as a 64 bits quantity, config.sh will set intsize to 8 and the
intsize script will bear the right value and print:
On this machine, the int type is 8 bytes
which is correct. Congratulations! We have just configured a shell
script!!
Producing config.h
We can now have a look at the way config.h is produced out of
config_h.SH. We know that running Configure produces a config.sh script
(how exactly this is done is not strictly relevant here, but for the
curious, it’s another here document substitution within Configure
itself). The config_h.SH itself is built by metaconfig at the same time
Configure is, provided you make use of at least one C symbol within
your sources.
Let’s have a look at some random config_h.SH file to see what really
happens:
case $CONFIG in
’’)
if test -f config.sh; then TOP=.;
elif test -f ../config.sh; then TOP=..;
elif test -f ../../config.sh; then TOP=../..;
elif test -f ../../../config.sh; then TOP=../../..;
elif test -f ../../../../config.sh; then TOP=../../../..;
else
echo "Can’t find config.sh."; exit 1
fi
. $TOP/config.sh
;;
esac
case "$0" in
*/*) cd ‘expr X$0 : ’X\(.*\)/’‘ ;;
esac
echo "Extracting config.h (with variable substitutions)"
sed <<!GROK!THIS! >config.h -e ’s!^#undef!/define!’ -e ’s!^#un-def!#undef!’
/*
* This file was produced by running the config_h.SH script, which
* gets its values from config.sh, which is generally produced by
* running Configure.
*
* Feel free to modify any of this as the need arises. Note, however,
* that running config.h.SH again will wipe out any changes you’ve made.
* For a more permanent change edit config.sh and rerun config.h.SH.
*/
/* Configuration time: $cf_time
* Configured by: $cf_by
* Target system: $myuname
*/
#ifndef _config_h_
#define _config_h_
/* bcopy:
* This symbol is maped to memcpy if the bcopy() routine is not
* available to copy strings.
*/
/* HAS_BCOPY:
* This symbol is defined if the bcopy() routine is available to
* copy blocks of memory. You should not use this symbol under
* normal circumstances and use bcopy() directly instead, which
* will get mapped to memcpy() if bcopy is not available.
*/
#$d_bcopy HAS_BCOPY /**/
#ifndef HAS_BCOPY
#ifdef bcopy
#un-def bcopy
#endif
#define bcopy(s,d,l) memcpy((d),(s),(l)) /* mapped to memcpy */
#endif
/* HAS_DUP2:
* This symbol, if defined, indicates that the dup2 routine is
* available to duplicate file descriptors.
*/
#$d_dup2 HAS_DUP2 /**/
/* I_STRING:
* This symbol, if defined, indicates to the C program that it should
* include <string.h> (USG systems) instead of <strings.h> (BSD systems).
*/
#$i_string I_STRING /**/
#endif
!GROK!THIS!
At the top of the file, we recognize the standard .SH construct that we
have already studied in detail. Next comes the extraction of the file
itself, via a here document with variable substitutions. However, here
we do not use a plain cat but a sed instead, since we need to do some
further editing on-the-fly. We’ll see why later on, so let’s forget
about it right now.
We now reach the leading comment, and the file is tagged with the
configuration time, the target system, etc... (those variables coming
from the sourced config.sh file have been set up by Configure). That
comment header is followed by a ’#ifndef’ protection to guard against
multiple inclusions of this file. Then comes the heart of the file...
It helps to know that $d_* and $i_* variables are set to either
’define’ or ’undef’ by Configure, depending on wether a function or an
include file is present on the system or not. That means the:
#$d_bcopy HAS_BCOPY /**/
line will be expanded to either:
#define HAS_BCOPY /**/
if the $d_bcopy variable is set to ’define’ or:
#undef HAS_BCOPY /**/
if $d_bcopy was set to ’undef’, because the feature was not there.
However, that’s not what gets written in the config.h file because of
the sed filter we have already seen, which will transform the second
form into:
/*#define HAS_BCOPY /**/
That’s a handy form for later editing of config.h because you only need
to remove the leading ’/*’ if you want to override Configure’s choice.
Likewise, you may add a single ’/*’ at the beginning of a ’#define’
line to avoid the definition of a particular symbol. This is why each
symbol definition is protected by a trailing ’/**/’, to close the
leading comment opened by ’/*’ (comments are not nested in C).
Now transforming ’#undef’ into ’/*#define’ is nice, but if we want to
actually write a ’#undef’, we’re stuck... unless we write it as ’#un-
def’ and let sed fix that to ’#undef’ while producing config.h, which
is what is actually done here.
The same kind of reasoning applies to those two lines:
#$d_dup2 HAS_DUP2 /**/
#$i_string I_STRING /**/
and assuming config.sh defines:
d_dup2=’define’
i_string=’undef’
we’ll get in the produced config.h:
#define HAS_DUP2 /**/
/*#define I_STRING /**/
Clear as running water? Good!
Now it should be obvious that by including config.h in all your C
source files, you get to know what Configure has guessed on your
system. In effect, by using those symbols, you are writing configured C
code, since metaconfig will know that you need those symbols and will
generate a suitable config_h.SH file as well as all the necessary code
in Configure to compute a proper value for them (by assigning values to
associated shell variables).
Running Metaconfig
Let’s focus on the metaconfig program for a while to understand how it
uses its units and your source code to produce all the needed
configuration files. If you intend to write new units, you should have
a good understanding of the whole scheme.
If there is no MANIFEST.new file, metaconfig will try to use the
MANIFEST file instead, for convenience. Everywhere we mention
MANIFEST.new, it can be understood as MANIFEST provided there is no
MANIFEST.new file found at the root of your package.
Assuming your MANIFEST.new file is properly set and lists all the
source files you wish to configure, and that you have run packint in
your root source directory to create a .package file, you may run
metaconfig and you’ll get the following:
$ metaconfig
Locating units...
Extracting dependency lists from 312 units...
Extracting filenames (*.[chyl] and *.SH) from MANIFEST.new...
Building a Wanted file...
Scanning .[chyl] files for symbols...
Scanning .SH files for symbols...
Computing optimal dependency graph...
Building private make file...
Determining loadable units...
Updating make file...
Determining the correct order for the units...
Creating Configure...
Done.
The first phase looks for all the units files (ending with .U) in the
public directory first, then in your private one. If you copy a public
file in your private U directory (i.e. a directory named U at the top
level of your package), it will override the public version. Once it
has a list of all the available units, it parses them and extracts all
the ?MAKE: lines to know about the dependencies and the known shell
symbols. It also focuses on the ?H: lines to learn about the C symbols
and which shell symbols needs to be computed to get a proper value for
that C symbol (so we have another level of dependencies here).
Next, the proper filenames are extracted from the MANIFEST.new files
and a Wanted file is built: that file lists all the C symbols and the
shell symbols needed for that package. We first scan the C-type files
for C symbols, then propagate the dependencies to their associated
shell symbols (gathered from ?H: lines). Next .SH files are scanned and
finally all the shell symbols are known.
A temporary Makefile is built and metaconfig tries to make all the
shell symbols to see what commands (listed on the second ?MAKE: lines)
are executed, and thus which units are really needed. Optional units
not otherwise required are removed and a second Makefile is generated.
This time, we know about all the units and their respective orders,
optional units having been removed and default values computed for
their shell symbols. The Configure script can then be generated, along
with config_h.SH. We’re done.
Conventions
Proper conventions needs to be followed to make the whole process
sound. There is a case convention for units and a variable naming
convention.
All units should have their first letter lower-cased, unless they are
special units. By special, we mean they do not really define new shell
variables that can be used by the user in his .SH files, but rather
units producing scripts or shell variables that are to be used
internally by the Configure script. Typical examples are the Init.U
file which is the main variable initialization, or Myread.U which
produces the myread script used almost everywhere in Configure when a
question is to be asked to the user.
Non-special units then subdivise in two distinct groups: units defining
variables associated to a C symbol and units defining shell variables
of their own. The first group is further divided in variables related
to include files (their name begin with i_) and variables related to
other definitions (name starting with d_). The second group have names
standing for itself, for instance cc.U defines the $cc shell variable
whose value is the C compiler to be used.
Special units sometimes reserve themselves some pre-defined variable
and return "results" in other well-known variables. For instance, the
myread script produced by Myread.U expects the prompt in $rp, the
default answer in $dflt and places the user answer in $ans. This is not
documented in this manual page: you have to go and look at the unit
itself to understand which variables are used and how the unit is to be
used.
Using The Glossary
The Glossary file is automatically produced by the makegloss script,
which extracts the information from ?S:, ?C: and ?MAKE: lines and
reformats them into an alphabetically sorted glossary. It is important
to read the Glossary to know about the symbols you are allowed to use.
However, the Glossary will not tell you how to use them. Usually,
that’s up to you.
One day, you will probably write your own units and you will know
enough about metaconfig to do so quickly and efficiently. However,
never forget to properly document your work in the ?S: and ?C: lines,
or other people will not be able to reuse it. Remember about the time
where you had only the Glossary and this manual page to get started.
Conclusion
Now that you know the metaconfig basics, you should read the
DESCRIPTION section, then skip to the REFERENCE section to learn about
all the gory details such as the allowed syntax for unit control lines
(lines starting with a ’?’) or the distinct MAKE commands you are
allowed to use.
REFERENCE
This section documents the internals of metaconfig, basically the unit
syntax, the special units you should know about and the hint files.
General Unit Syntax
A metaconfig unit is divided into two distinct parts. The header
section (lines starting with ’?’) and a shell section (code to be
included in the Configure script). It is possible to add ’?X:’ comments
anywhere within the unit, but the other ’?’ lines (also called control
lines) have a strict ordering policy.
If a control line is too long, it is possible to use a continuation by
escaping the final new-line with a backslash and continuing on the next
line (which should then be indented by spaces or tabs).
The following is a formal description of each of the control lines.
Unless stated otherwise, the order of this presentation is the order to
be used within the unit.
?RCS: free text
To be used for RCS comments, at the top of the unit.
?X: any text
General purpose comments. May appear anywhere in the unit but must
be left justfied. For RCS comments, please use the ?RCS: comment
form.
?MAKE:symbol list: dependency list [+optional]
This is the first dependency line. The first symbol list should
list all the symbols built by this unit (i.e. whose value is
computed by the shell section of the unit). Symbols should be
space separated. If a defined symbol is for internal use only and
should not appear in the generated config.sh file, then it should
be preceded by a ’+’ (not to be confused with optional
dependencies defined hereafter). The second part of the list
(after the middle ’:’) is the unit dependency. It should list all
the needed special units, as well as all the symbols used by the
shell implementation. If a symbol is nedded but its configuration
value is not critical, it can be preceded by a ’+’, in which case
it is called a conditional dependency: its corresponding unit will
be loaded if, and only if, that symbol is otherwise really wanted;
otherwise the default value will be used.
?MAKE:tab command
There can be one or more command lines following the initial
dependency lines. Those commands will be executed when the unit
is wanted to load them into Configure. See the paragraph about
make commands for more information. Note that the leading tab
character is required before the command.
?Y:layout
Declare a layout directive for this unit. That directive may be
one of the strings top, default or bottom (case does not matter,
recommended style is to spell them out uppercased). If omitted,
default is assumed.
This directive is only required if you wish to force a unit at the
top or the bottom of the generated Configure script, as unit
dependencies permit it. Important questions may thus be forced at
the beginning. Within the same layout class, units are sorted
alphabetically with two special cases for d_* and i_* units,
forced respectively at the top and bottom of their classes (but
these should belong to the default class).
It you force at the top a unit whose dependencies require all the
other unit to precede it, you achieve nothing interesting.
Therefore, that directive should really be used to increase the
priority of some interactive units that do not depend on many
other user-visible symbols, like path-related questions.
?S:symbol_name [(obsolete symbol list)]:
Introduces a shell symbol. This first line names the symbol,
optionally followed by a list enclosed between parenthesis and
giving the obsolete equivalent. Those obsolete symbols will be
remapped to the new symbol_name if the -o option is given to
metaconfig.
?S:any text, for Glossary
Basically a comment describing the shell symbol, which will be
extracted by makegloss into the Glossary file.
?S:. Closes the shell symbol comment.
?C:symbol_name [~ alias] [(obsolete symbol list)]:
Introduces a new C symbol. The alias name is the name under which
the C symbol will be controlled, i.e. if the alias symbol is
wanted, then that C symbol will be written in the config_h.SH
file. Usually, the alias is just ’%<’ (stands for the unit’s name)
and there is also a ?W: line mapping a C symbol to the alias. Also
the relevant parts of the ?H: lines are explicitely protected by a
’?%<’ condition. See the symbol aliasing paragraph for more
details. The remaining of the line is the optional obsolete
symbol list, which lists old equivalents for the new symbol_name.
?C:any text, for Glossary and config_h.SH
Basically a comment describing the C symbol, which will be
extracted by makegloss into the Glossary file and by metaconfig
into the config_h.SH file if the symbol is wanted (or if its alias
is wanted when symbol aliasing is used).
?C:. Closes the C symbol comment.
?H:?symbol:config_h.SH stuff
This is the general inclusion request into config_h.SH. The line
is only written when the guarding symbol is really wanted. This
general form is needed when C symbol aliasing was used. Otherwise,
if you use one of the other "standard" forms, the guarding is
automatically done by metaconfig itself.
?H:#$d_var VAR "$var"
Conditionally defines the VAR C symbol into $var when is set to
’define’. Implies a ’?VAR:’ guarding condition, and metaconfig
automatically links VAR to its two shell variable dependencies
(i.e. both $d_var and $var will be flagged as wanted if VAR is
used in C sources).
?H:#define VAR [optional text]
Always defines the VAR C symbol to some value. Implies a ’?VAR:’
guarding condition. An automatic shell dependency is made to the
unit itself.
?H:#define VAR(x,y,z) $var
Always defines the macro VAR to be the value of the $var variable.
It is up to the unit to ensure $var holds a sensible value. An
automatic dependency between the C macro VAR and the shell
variable is established, and the whole line is guarded by an
implicit ’?VAR:’.
?H:#$d_var VAR
Conditionally defines VAR if $d_var is set to ’define’. Implies a
’?VAR:’ guarding condition. An automatic shell dependency is
generated towards $d_war.
?H:#define VAR "$var"
Assigns a configured value to the VAR C symbol. Implies a ’?VAR:’
gurading condition. An automatic shell dependency is generated to
link VAR and $var.
?H:. Closes the config_h.SH inclusion requests.
?M:C symbol: C dependencies
Introduces magic definition concerning the C symbol, for
confmagic.h, and defines the guarding symbol for the remaining ?M:
definitions. This line silently implies ’?W:%<:C symbol’, i.e. the
unit will be loaded into Configure if the C symbol appears within
the C sources, whether magic is used or not. The C dependencies
are activated when magic is used, in order to force their
definition in config_h.SH. However, if magic is not used but the C
symbol appears in the source without the needed C dependencies,
you will be warned every time the Wanted file is built, since it
may be a portability issue (and also because the unit is
unconditionally loaded into Configure whenever the C symbol is
used, regardless of the other ?C: lines from the unit).
?M:cpp defs
Defines the magic cpp mapping to be introduced in confmagic.h
whenever the concerned symbol is used. There is an implicit ’?sym’
guarding where sym is the symbol name defined by the leading ?M:
line.
?M:. Closes the confmagic.h inclusion request.
?W:shell symbol list:C symbol list
Ties up the destiny of the shell symbols with that of the C
symbols: if any of the C symbols listed is wanted, then all the
shell symbols are marked as wanted. Useful to force inclusion of a
unit (shell symbol list set to ’%<’) when the presence of some C
symbol is detected. The shell symbol list may be left empty, to
benefit from the side effect of C symbol location within the
builtin pre-processor (symbol being defined for that pre-processor
if located in the source). To look for patterns with a space in
them, you need to quote the C symbols within simple quotes, as in
’struct timezone’.
?V:read-only symbols:read-write symbols
This is a metalint hint and should be used only in special units
exporting some shell variables. The variables before the middle
’:’ are exported read-only (changing them will issue a warning),
while other symbols may be freely read and changed.
?F:files created
This line serves two purposes: it is a metalint hint, and also a
placeholder for future jmake use. It must list three kind of
files: the temporary one which are created for a test, the private
UU ones created in the UU directory for later perusal, and the
public ones left in the root directory of the package. Temporary
files must be listed with a preceding ’!’ character (meaning "no!
they’re not re-used later!"), private UU files should be preceded
by a ’./’ (meaning: to use them, say ./file, not just file), and
public ones should be named as-is.
?T:shell temporaries
Another metalint hint. This line lists all the shell variables
used as temporaries within the shell section of this unit.
?D:symbol=’value’
Initialization value for symbols used as conditional dependencies.
If no ?D: line is found, then a null value is used instead. The
metalint program will warn you if a symbol is used at least once
as a conditional dependency and does not have a proper ?D:
initialization. It’s a good practice to add those lines even for a
null initialization since it emphasizes on the possibly optional
nature of a symbol.
?O:any message you want
This directive indicates that this unit is obsolete as a whole.
Whenever usage of any of its symbols is made (or indirect usage
via dependencies), the message is output on the screen (on
stderr). You can put one ore more lines, in which case each line
will be printed, in order.
?LINT:metalint hints
See the metalint manual page for an explaination of the distinct
hints that can be used.
?INIT:initialization code
The initialization code specified by this line will be loaded at
the top of the Configure script provided the unit is needed.
C Symbol Aliasing
Sometimes it is not possible to rely on metaconfig’s own default
selection for config_h.SH comments and C symbol definition. That’s
where aliasing comes into play. Since it’s rather tricky to explain,
we’ll study an example to understand the underlying mechanism.
The d_const.U unit tries to determine whether or not your C compiler
known about the const keyword. If it doesn’t we want to remap that
keyword to a null string, in order to let the program compile.
Moreover, we want to automatically trigger the test when the const word
is used.
Here are the relevant parts of the d_const.U unit:
?MAKE:d_const: cat cc ccflags Setvar
?MAKE: -pick add $@ %<
?S:d_const:
?S: This variable conditionally defines the HASCONST symbol, which
?S: indicates to the C program that this C compiler knows about the
?S: const type.
?S:.
?C:HASCONST ~ %<:
?C: This symbol, if defined, indicates that this C compiler knows about
?C: the const type. There is no need to actually test for that symbol
?C: within your programs. The mere use of the "const" keyword will
?C: trigger the necessary tests.
?C:.
?H:?%<:#$d_const HASCONST /**/
?H:?%<:#ifndef HASCONST
?H:?%<:#define const
?H:?%<:#endif
?H:.
?W:%<:const
?LINT:set d_const
?LINT:known const
: check for const keyword
echo " "
echo ’Checking to see if your C compiler knows about "const"...’ >&4
/bin/cat >const.c <<’EOCP’
main()
{
const char *foo;
}
EOCP
if $cc -c $ccflags const.c >/dev/null 2>&1 ; then
val="$define"
echo "Yup, it does."
else
val="$undef"
echo "Nope, it doesn’t."
fi
set d_const
eval $setvar
First we notice the use of a ?W: line, which basically says: "This unit
is wanted when the const keyword is used in a C file.". In order to
conditionally remap const to a null string in config.h, I chose to
conditionally define HASCONST via $d_const.
However, this raises a problem, because the HASCONST symbol is not
going to be used in the sources, only the const token is. And the ?H:
line defining HASCONST is implicitely guarded by ’?HASCONST’.
Therefore, we must add the explicit ’?%<’ constraint to tell metaconfig
that those lines should be included in config_h.SH whenever the ’%<’
symbol gets wanted (%< refers to the unit’s name, here d_const).
That’s almost perfect, because the ?W: line will want d_const whenever
const is used, then the ?H: lines will get included in the config_h.SH
file. However, the leading comment (?C: lines) attached to HASCONST is
itself also guarded via HASCONST, i.e. it has an implicit ’?HASCONST’
constraint. Hence the need for aliasing the HASCONST symbol to ’%<’.
The remaining part of the unit (the shell part) is really
straightforward. It simply tries to compile a sample C program using
the const keyword. If it can, then it will define $d_const via the
$setvar fonction (defined by the Setvar.U unit). See the paragraph
about special units for more details.
Make Commands
On the ?MAKE: command line, you may write a shell command to be
executed as-is or a special -pick command which is trapped by
metaconfig and parsed to see what should be done. The leading ’-’ is
only there to prevent make from failing when the command returns a non-
zero status -- it’s not really needed since we use ’make -n’ to resolve
the dependencies, but I advise you to keep it in case it becomes
mandatory in future versions. The syntax of the pick command is:
-pick cmd $@ target_file
where $@ is the standard macro within Makefiles standing for the
current target (the name of the unit being built, with the final .U
extension stripped). The cmd part is the actual metaconfig command to
be run, and the target_file is yet another parameter, whose
interpretation depends on the cmd itself. It also has its final .U
extension stripped and normally refers to a unit file, unless it start
with ’./’ in which case it references one of the metaconfig control
files in the ’.MT directory.
The available commands are:
add Adds the target_file to Configure.
add.Config_sh
Fills in that part of Configure producing the config.sh file.
Only used variables are added, conditional ones (from
conditional dependencies) are skipped.
add.Null Adds the section initializing all the shell variables used to
an empty string.
c_h_weed Produces the config_h.SH file. Only the necessary lines are
printed.
cm_h_weed Produces the confmagic.h file. Only the necessary lines are
printed. This command is only enabled when the -M switch is
given, or when a confmagic.h file already exists.
close.Config_sh
Adds the final ’EOT’ symbol on a line by itself to end the
here document construct producing the config.sh file.
prepend Prepends the content of the target to the target_file if that
file is not empty.
weed Adds the unit to Configure like the add command, but make
some additional tests to remove the ’?symbol’ and ’%symbol’
lines from the target_file if the symbol is not wanted or
conditionally wanted. The ’%’ form is only used internally by
metaconfig while producing its own .U files in the ’.MT’
directory.
wipe Same as add really, but performs an additional macro
substitution. The available macros are described in the
Hardwired Macros paragraph.
As a side note, metaconfig generates a -cond command internally to deal
with conditional dependencies. You should not use it by yourself, but
you will see it if scanning the generated Makefile in the .MT
directory.
Hardwired Macros
The following macros are recognized by the wipe command and subsituted
before inclusion in Configure:
<BASEREV> The base revision number of the package, derived from
.package.
<DATE> The current date.
<MAINTLOC>
The e-mail address of the maintainer of this package, derived
from your .package.
<PACKAGENAME>
The name of the package, as derived from your .package file.
<PATCHLEVEL>
The patch level of the metaconfig program (deprecated in
favor of <REVISION>).
<REVISION>
The SVN revision level of the metaconfig program.
<VERSION> The version number of the metaconfig program.
Those macros are mainly used to identify the metaconfig version that
generated a particular Configure script and for which package it was
done. The e-mail address of the maintainer is hardwired in the leading
instructions that Configure prints when starting.
Recent metaconfig versions understand a much more general syntax of the
form:
<$variable>
which is replaced at Configure-generation time by the value of variable
taken from your .package file. Eventually, the old hardwired macro
format will disappear, and <$baserev> will replace <BASEREV> in all the
supplied units.
Special Units
The following special units are used to factorize code and provide
higher level functionalities. They either produce a shell script that
can be sourced or a shell variable that can be eval’ed. Parameter
passing is done via well-know variables, either named or anonymous like
$1, $2, etc... (which can be easily set via the shell set operator).
When Configure executes, it creates and goes into a UU directory, so
every produced script lies in there and does not interfere with the
files from your package.
Here are the sepcial units that you should know about, and the way to
use them.
Cppsym.U
This unit produces a shell script called Cppsym, which can be used
to determine whether any symbol in a list is defined by the C
preprocessor or C compiler you have specified. It can determine
the status of any symbol, though the symbols in (attribute list)
are more easily determined.
Csym.U
This sets the $csym shell variable, used internally by Configure
to check whether a given C symbol is defined or not. A typical use
is:
set symbol result [-fva] [previous]
eval $csym
That will set the result variable to ’true’ if the function [-f],
variable [-v] or array [-a] is defined, ’false’ otherwise. If a
previous value is given and the -r switch was provided to
Configure (see the Configure Options paragraph), then that value
is re-used without questioning.
The way this computation is done depends on the answer the user
gives to the question Configure will ask about whether it should
perform an nm extraction or not. If the exctraction was performed,
the unit simply looks through the symbol list, otherwise it
performs a compile-link test, unless -r was given to reuse the
previously computed value, naturally...
End.U
By copying this unit into your private U directory and appending
dependencies on the ?MAKE: line, you can force a given unit to be
loaded into Configure even if it is not otherwise wanted. Some
units may only be forced into Configure that way.
Filexp.U
This unit produces a shell script filexp which will expand
filenames beginning with tildes. A typical use is:
exp_name=‘./filexp $name‘
to assign the expanded file name in exp_name.
Findhdr.U
This unit produces a findhdr script which is used to locate the
header files in $usrinc or other stranger places using cpp
capabilities. The script is given an include file base name like
’stdio.h’ or ’sys/file.h’ and it returns the full path of the
inlcude file and a zero status if found, or an empty string and a
non-zero status if the file could not be located.
Getfile.U
This unit produces a bit of shell code that must be sourced in
order to get a file name and make some sanity checks. Optionally,
a ~name expansion is performed.
To use this unit, $rp and $dflt must hold the question and the
default answer, which will be passed as-is to the myread script
(see forthcoming Myread.U). The $fn variable controls the
operation and the result is returned into $ans.
To locate a file or directory, put ’f’ or ’d’ in f~/. If a ’~’
appears, then ~name substitution is allowed. If a ’/’ appears,
only absolute pathnames are accepted and ~name subsitutions are
always expanded before returning. If ’+’ is specified, existence
checks are skipped. If ’n’ appears within $fn, then the user is
allowed to answer ’none’.
Usually, unless you asked for portability, ~name substitution
occurs when requested. However, there are some times you wish to
bypass portability and force the substitution. You may use the ’e’
letter (expand) to do that.
If the special ’l’ (locate) type is used, then the $fn variable
must end with a ’:’, followed by a file basename. If the answer is
a directory, the file basename will be appended before testing for
file existence. This is useful in locate-style questions like
this:
dflt=’~news/lib’
: no need to specify ’d’ or ’f’ when ’l’ is used
fn=’l~:active’
rp=’Where is the active file?’
. ./getfile
active="$ans"
Additionally, the ’p’ (path) letter may be used in conjunction
with ’l’ to tell getfile that an answer without a ’/’ in it should
be accepted, assuming that it will be in everyone’s PATH at the
time this value will be needed.
Also useful is the possibility to specify a list of answers that
should be accepted verbatim, bypassing all the checks. This list
must be within parenthesis and items must be comma separated, with
no interleaving spaces. Don’t forget to quote the resulting
string since parenthesis are meaningful to the shell. For
instance:
dflt=’/bin/install’
fn=’/fe~(install,./install)’
rp=’Use which install program?’
. ./getfile
install="$ans"
would let the user only specify fully qualified paths referring to
existing files, but still allow the special "install" and
"./install" answers as-is (assuming of course something will deal
with them specially later on in the chain since they do not
conform with the general expected frame).
If the answer to the question is ’none’, then the existence checks
are skipped and the empty string is returned. Note that since
getfile calls myread internally, all the features available with
myread apply here to.
If a completely expanded value is needed (for instance in a
Makefile), you may use the $ansexp variable which is always set up
properly by getfile as the expanded version of $ans. Of course, it
will not expand ~name if you did not allow that in the first place
in the $fn variable.
Inhdr.U
This unit produces the $inhdr shell variable, used internally by
Configure to check whether a set of headers exist or not. A
typical use is:
set header i_header [ header2 i_header2 ... ]
eval $inhdr
That will print a message, saying whether the header was found or
not and set the i_header variable accordingly. If more than one
header is specified and the first header is not found, we try the
next one, until the list is empty or one is found.
Inlibc.U
This unit produces the $inlibc shell variable, used internally by
Configure to check whether a given C function is defined or not.
A typical use is:
set function d_func
eval $inlibc
That will print a message, saying whether the function was found
or not and set $d_func accordingly. Internally, it used the $csym
routine.
Loc.U
This important unit produces a shell script loc which can be used
to find out where in a list of directories a given file lies. The
first argument specifies the file to be located, the second
argument is what will be returned if the search fails, and the
reamining arguments are a list of directories where the file is to
be searched. For instance:
dflt=‘./loc sendmail.cf X /usr/lib /var/adm/sendmail /lib‘
would set $dflt to X if no sendmail.cf file was found under the
listed directories, or something like /usr/lib/sendmail.cf on some
systems. See also Getfile.U.
MailAuthor.U
This unit needs to be included on the ?MAKE: line of your own
private End.U to make it into Configure. It offers the user to
register himself to the author, optionally being notified when new
patches arrive or receiving them automatically when issued. You
need to install mailagent to do this (at least version 3.0).
MailList.U
This unit needs to be included on the ?MAKE: line of your own
private End.U to make it into Configure. It offers the user to
subscribe or unsubscribe to a mailing list where discussion
related to the package are taking place. You need to run packinit
and answer the mailing list related questions to set up the proper
variables in your .package before this unit may become
operational.
Myinit.U
Copy this unit into your private U directory to add your own
default values to some internal variables. This unit is loaded
into Configure after all the default initializations have been
done.
Myread.U
This unit produces the myread shell script that must be sourced in
order to do a read. It allows shell escapes, default assignment
and parameter evaluation, as documented in the Instruct.U unit. It
also allows dynamic setting of the -d option, which will be used
for the remaining of the script execution.
To use this unit, $rp must hold the question and $dflt should
contain the default answer. The question will be printed by the
script itself, and the result is returned in the $ans variable.
Here is a typical usage:
dflt=’y’
rp=’Question?’
. ./myread
value="$ans"
See the unit itself for more information.
Oldconfig.U
This unit must be part of your dependency ?MAKE: line when some of
your units tries to reuse an old symbol value. This unit is
responsible for getting the old answers from config.sh or
providing useful hints when running on a given platform for the
first time. See the Configure Hints paragraph for more information
about hints.
Prefixit.U
The purpose of this unit is to detect changes in the installation
prefix directory to recompute automatically suitable defaults from
previous answers. It relies on the value of the $oldprefix
variable which holds the previous prefix directory when it
changed, and is empty otherwise. For instance, if the prefix was
changed from /opt to /usr/local, then the previous binary
installation directory will be changed from /opt/bin to
/usr/local/bin, or will remain unchanged if it was, say, /bin.
You need to call set before issuing an eval on $prefixit, such as:
set dflt var [dir]
eval $prefixit
which would set $dflt to $var or $prefix/dir depending on whether
the prefix remained the same or not. If dir is the string none, a
single space value in $dflt is kept as-is, even when the prefix
changes. If dir is omitted, then $dflt is set to an empty string
if the prefix changed, to $var otherwise.
Prefixup.U
The intent of thit unit is similar to that of Prefixit.U, i.e. it
helps fixing the default string to accomodate prefix changes.
However, the shell variable $prefixup, when evaluated, will only
restore ~name expansions, should prefix use such an escape
mechanism. Use it as:
set dflt
eval $prefixup
before prompting via getfile for instance. If the prefix does not
make use of ~name expanstion, then the above will be a no-op on
the y variable, naturally.
Typedef.U
This unit produces the $typedef shell variable, used internally by
Configure to check whether a typedef exists or not. A typical use
is:
set typedef val_t default [ includes ]
eval $typedef
This will set the variable val_t to the value of default if the
typedef was not found among the listed include files, or to
typedef if found. If no include files are specified, the unit
looks in <sys/types.h> only. If you specifiy some includes, only
those are looked at.
Unix.U
The purpose of this unit is to define some of the most common
UNIX-isms via variables which can be altered from the command line
or via proper hint files. In particular, $_exe, $_o and $_a are
set. All the units should refer to $_o and not to .o directly. The
’.’ is part of these variables.
Setvar.U
This unit produces the variable, which is used internally by
Configure to set a define/undef value to a given symbol, emitting
a warning when it suddenly changes from a previous value. For
instance:
val="$define"
set d_variable
eval $setvar
If the previous $d_variable value was non-null and $val is
different, a "whoa" warning is issued.
Whoa.U
This unit produces the whoa script, which emits a warning when the
value in variable whose name is $var is not the same as its old
previous value held in $was. Upon return, $td and $tu hold the
proper value to define or undef the variable. See examples in
Inlibc.U.
Builtin Pre-processor
Each unit to be included in Configure is ran through a built-in pre-
processor. Pre-processor statements are introduced by the ’@’ character
(’#’ is the shell comment character). It functions merely as the C pre-
processor does but allows for shell and perl escapes. Here are the
available functions:
@if expression
If expression is true, continue loading code until @end,
@elsif or @else.
@elsif expression
Alternative choice. If expression is true, continue loading
code until @end, another @elsif or @else.
@else Default code to be loaded if the @if expression was false and
none of the optional @elsif matched. Load until @end.
@end Close the conditional loading statement opened by @if.
@define symbol
Tells the pre-processor that symbol is defined from now on.
The conditional expression can include symbol names (value is true if
symbol is wanted or defined via @define or shell/perl escapes. Those
atoms can be combined using the traditional boolean operators ’!’ for
negation, ’&&’ for logical and, and ’||’ for logical or.
Text enclosed within single brackets is a shell test, while text
between double brakets is a perl test. Namely the expressions:
{ shell text }
{{ perl text }}
are translated into:
if shell text >/dev/null 2>&1; then exit 0; else exit 1; fi
if (perl text) {exit 0;} else {exit 1;}
and the exit status is used in the standard way to get a boolean value,
i.e. 0 is true and everything else is false. Note that only simple
conditions can be expressed in perl, until some complex code can be
loaded within metaconfig and executed.
The built-in pre-processor can be used to finely tune some units (see
d_gethname.U for a complex example) depending on the symbols actually
used by the program or the files present in the distribution. For
instance, the Oldconfig.U uses a test like:
@if {test -d ../hints}
and Configure will contain hint-dependent code only if there is a hints
directory in the package’s top level directory. Note that tests are ran
from within the ’.MT’ directory, hence the needed ’../’ in the test.
The pre-processor can also be used to avoid putting useless code when a
symbol is not defined. Units defining more than one symbol can be
protected that way (since the unit is loaded as a whole) by gathering
symbol-dependent code within an @if/@end pair. For instance:
@if I_TIME || I_SYS_TIME || I_SYS_TIME_KERNEL
need_time_h=’true’
@else
need_time_h=’false’
@end
will test whether the source code makes any use of one of the three
symbols that control the time.h or sys/time.h inclusion and define the
shell symbol accordingly. That gives Configure a feedback on what the
sources need and avoid the drawback of having fixed frozen units.
Via the ’?W:’ lines, you can get intersting combinations. For instance,
the i_time.U unit needs to know whether the C sources make any use of
the struct timezone type. Therefore, the line:
?W::timezone
is used for its side-effect of defining the symbol timezone for the
pre-processor. The unit code can then say:
@if timezone
for s_timezone in ’-DS_TIMEZONE’ ’’; do
@else
s_timezone=’’
@end
... code using s_timezone ...
@if timezone
done
@end
and have an extra loop trying two successive values for the s_timezone
variable, but only if needed.
Obsolete Symbols
Obsolete symbols are preserved to ease the transition with older
metaconfig units. Unless the -o switch is passed to metaconfig they
will be ignored. However, an Obsolete file will be generated, telling
you which files are making use of those obsolete symbols and what are
the new symbols to be used.
The lifetime for obsolete symbols is one full revision, i.e. they will
be removed when the next base revision is issued (patch upgrades do not
count of course). Therefore, it is wise to translate your sources and
start using the new symbols as soon as possible.
Configure Hints
It may happen that the internal configuration logic makes the wrong
choices. For instance, on some platform, the vfork() system call is
present but broken, so it should not be used. It is not possible to
include that knowledge in the units themselves, because that might be a
temporary problem which the vendor will eventually fix, or something
that was introduced by a new OS upgrade.
Anyway, for all those tiny little problems that are too system-
specific, metaconfig provides hint files support. To use it, you need
to create a hints directory in the package’s top level directory, and
have it when you run metaconfig. That will load the hint-related part
from Oldconfig.U.
From then on, you may pre-set some of the shell variables Configure
uses in an OS-specific .sh file. There is code in Oldconfig.U that
tries to guess which hint files are needed by computing a standard name
based on the system OS name, the kernel name, the release number,
etc... Since this information is likely to change rapidly, I’m not
documenting it here. You have to reverse engineer the code from
Oldconfig.U.
When you first release your package, your hints file directory should
be empty. If the users of your package complain that they have problem
with Configure defaults on a particular system, you have to see whether
this is a platform-specific problem or a general one. In the former
case, it’s time to introduce a new hint file, while in the latter, the
corresponding unit should be revised.
For instance, SGI systems are known to have a broken vfork() system
call, as of this writing. And the corresponding hint file name is
sgi.sh. So all you need to do is create a hints/sgi.sh file in which
you write:
d_vfork="$define"
which will always remap vfork on fork (see d_vfork.U). When running on
SGI systems for the first time, Configure will detect that there is an
hints/sgi.sh file, and that we are on an IRIX machine (the kernel name
is often /irix), therefore it will propose sgi as a possible hint. If
the user accepts it, and since the $d_vfork value is modified via the
$setvar call, a whoa! will be emitted to warn that we are about to
override the value computed by Configure.
Note that you don’t have to provide all the hints known by Oldconfig.U.
If a hint file is missing, it will not be proposed as a possible
choice. The heuristic tests ran to compute the possible hint candidates
are flaky. If you have new values or different tests, please send them
to me...
Overriding Choices
If you create a config.over file in the top level directory, Configure
will ask you if you wish to load it to override the default values.
This is done prior creation of the config.sh file, so it gives you a
chance to patch the values stored in there.
This is distinct from the hints approach in that it is a local file,
which the user is free to create for his own usage. You should not
provide such a file yourself, but let the user know about this
possibility.
Configure Options
The Configure script may be called with some options specified on the
command line, to slightly modify its behaviour. Here are the allowed
options:
-d Use defaults for all answers.
-e Go on without questioning past the production of config.sh.
-f file Use the specified file as a default configuration. If this
switch is not used, the configuration is taken from
config.sh, when present.
-h Print help message and exit.
-r Reuse C symbols value if possible. This will skip the costly
nm symbol extraction. If used the first time (with no
previous configuration file), Configure will try to compile
and link a small program in order to know about the presence
of a symbol, or absence thereof.
-s Silent mode. Only strings printed on file descriptor #4 will
be seen on the screen (that’s the important messages). It’s
not possible to completely turn off any output, but you may
use ’Configure -ders >/dev/null 2>&1’ to have a full batch
run with no output and no user interaction required.
-D symbol=value
Pre-defines symbol to bear the specified value. It is also
possible to use ’-D symbol’ which will use a default value of
’define’.
-E Stop at the end of the configuration questions, after having
produced a config.sh. This will not perform any ’make depend’
or .SH files extraction.
-K Knowledgeable user. When you use this option, you know what
you are doing and therefore the config.sh file will always be
handled as if it was intended to be re-used, even though it
might have been generated on an alien system. It also
prevents aborting when Configure detects an unusable C
compiler or a wrong set of C flags. Further shortcuts might
be turned on by this option as well in the future. This
option is documented in the Configure usage message, to
remind us about its existence, but the given description is
hoped to be cryptic enough. :-)
-O Allow values specified via a -D or -U to override settings
from any loaded configuration file. This is not the default
behaviour since the overriding will not be propagated to
variables derived from those you are presently altering.
Naturally, without -O, the setting is only done when no
configuration file is loaded, which is safe since derivative
variables have not been computed yet...
-S Perform variable substitution on all the .SH files. You can
combine it with the -f switch to propagate any configuration
you like.
-U symbol=
Pre-sets symbol to bear an empty value. It is also possible
to use ’-U symbol’ which will set symbol to ’undef’.
-V Print the version number of the metaconfig that generated
this Configure script and exit.
Running Environment
Upon starting, Configure creates a local UU directory and runs from
there. The directory is removed when Configure ends, but this means you
must run the script from a place where you can write, i.e. not from a
read-only file system.
You can run Configure remotely though, as in:
../package/Configure
to configure sources that are not present locally. All the generated
files will be put in the directory where you’re running the script
from. This magic is done thanks to the src.U unit, which is setting the
$src and $rsrc variables to point to the package sources. That path is
full or relative, depending on whether Configure was invoked via a full
or relative path.
From within the UU subdirectory, you can use $rsrc to access the source
files (units referring to source files link hints shall always use this
mechanism and not assume the file is present in the parent directory).
All the Makefiles should use the $src variable as a pointer to the
sources from the top of the build directory (where Configure is run),
either directly or via a VPATH setting.
When running Configure remotely, the .SH files are extracted in the
build directory, not in the source tree. However, it requires some kind
of a make support to be able to compile things in a build directory
whilst the sources lie elsewhere.
Using Magic Redefinitions
By making use of the -M switch, some magic remappings may take place
within a confmagic.h file. That file needs to be included after
config.h, of course, but also after all the other needed include files.
Namely:
#include "config.h"
...
... other inclusions ...
...
#include "confmagic.h"
Typically, confmagic.h will attempt to remap bcopy() on memcpy() if no
bcopy() is available locally, or transform vfork into fork when
necessary, hence making it useless to bother about the HAS_VFORK
symbol.
This configuration magic is documented in the Glossary file.
Unit Templates
There is a set of unit templates in the metaconfig source directory,
which are intended to be used by a (not yet written) program to quickly
produce new units for various kind of situations. No documentation for
this unfinished project, but I thought I would mention it in the manual
page in case you wish to do it yourself and then contribute it...
AUTHORS
Larry Wall <lwall@netlabs.com> for version 2.0.
Harlan Stenn <harlan@mumps.pfcs.com> for important unit extensions.
Raphael Manfredi <ram@hptnos02.grenoble.hp.com>.
Many other contributors for the metaconfig units. See the credit file
for a list.
FILES
LIB/dist/mcon/U/*.U
Public unit files
U/*.U Private unit files
LIB/dist/mcon/Glossary
Glossary file, describing all the metaconfig symbols.
Obsolete Lists all the obsolete symbols used by the sources.
Wanted Lists all the wanted symbols.
where LIB is /usr/share/dist.
BUGS
Units are sometimes included unnecessarily if one of its symbols is
accidentally mentioned, e.g. in a comment. Better too many units than
too few, however.
SEE ALSO
pat(1), makeSH(1), makedist(1), metalint(1)
Version 3.5 PL0