METACONFIG(1) | General Commands Manual | METACONFIG(1) |
metaconfig - a Configure script generator
metaconfig [ -dhkmostvwGMV ] [ -L dir ]
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:
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:
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.
In order to add a new program to be located:
Notes for writing .U files:
case "$grimble" in '') dflt=452;; *) dflt="$grimble";; esac rp='How many grimbles do you have?' . ./myread grimble="$ans"
$startshat the top of every generated script that is going to be launched or sourced by Configure.
$cc $ccflags $ldflags try.c -o try $libsbecause some systems require that linking flags be specified before the compiled target (with the exception of trailing linking libraries).
Metaconfig reserves the following names in your directory, and if you use such a name it may get clobbered or have other unforeseen effects:
Additionally, Configure may clobber these names in the directory it is run in:
.MT/* Configure Wanted Obsolete configure config_h.SH confmagic.h U/* MANIFEST.new
UU/* config.sh config.h
The following options are recognized by metaconfig:
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.
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 system structure lacks one otherwise standard field, or simply whether 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 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.
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...
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.
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 intsizeThe 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 intsizeOf 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 byteswhich is correct. Congratulations! We have just configured a shell script!!
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!' /*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.
* 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!
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 whether 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).
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...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).
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.
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.
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.
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.
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.
This section documents the internals of metaconfig, basically the unit syntax, the special units you should know about and the hint files.
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.
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.
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 $setvarFirst 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.
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_filewhere $@ 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:
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.
The following macros are recognized by the wipe command and subsituted before inclusion in Configure:
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.
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.
set symbol result [-fva] [previous] eval $csymThat 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...
exp_name=`./filexp $name`to assign the expanded file name in exp_name.
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.
set header i_header [ header2 i_header2 ... ] eval $inhdrThat 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.
set function d_func eval $inlibcThat will print a message, saying whether the function was found or not and set $d_func accordingly. Internally, it used the $csym routine.
dflt=`./loc sendmail.cf X /usr/lib /var/lib/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.
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.
You need to call set before issuing an eval on $prefixit, such as:
set dflt var [dir] eval $prefixitwhich 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.
set dflt eval $prefixupbefore 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.
set typedef val_t default [ includes ] eval $typedefThis 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.
val="$define" set d_variable eval $setvarIf the previous $d_variable value was non-null and $val is different, a "whoa" warning is issued.
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:
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' @endwill 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::timezoneis 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 @endand have an extra loop trying two successive values for the s_timezone variable, but only if needed.
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.
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...
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.
The Configure script may be called with some options specified on the command line, to slightly modify its behaviour. Here are the allowed options:
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/Configureto 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.
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.
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...
Larry Wall <lwall@netlabs.com> for version 2.0.
Harlan Stenn <harlan@mumps.pfcs.com> for important unit extensions.
Raphael Manfredi <Raphael.Manfredi@pobox.com>.
Many other contributors for the metaconfig units. See the credit file
for a list.
where LIB is /usr/share/dist.
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.
Version 3.5 PL0 |