


       



       .














                                   Cook

                         A File Construction Tool




                                User Guide







                               Peter Miller

                         _m_i_l_l_e_r_p_@_c_a_n_b_._a_u_u_g_._o_r_g_._a_u

































       .












       This document describes Cook version 2.32
       and was prepared 25 April 2009.






       This  document  describing  the  Cook  program, and the Cook
       program itself, are
       Copyright (C) 1988, 1989,  1990,  1991,  1992,  1993,  1994,
       1995,  1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
       2005, 2006, 2007, 2008 Peter Miller

       This program is  free  software;  you  can  redistribute  it
       and/or  modify  it under the terms of the GNU General Public
       License as published by the Free Software Foundation; either
       version  3  of  the  License,  or (at your option) any later
       version.

       This program is distributed in the  hope  that  it  will  be
       useful,  but  WITHOUT ANY WARRANTY; without even the implied
       warranty of MERCHANTABILITY  or  FITNESS  FOR  A  PARTICULAR
       PURPOSE.   See  the  GNU  General  Public  License  for more
       details.

       You should have received a copy of the  GNU  General  Public
       License    along    with   this   program.   If   not,   see
       <http://www.gnu.org/licenses/>.




















       Cook                                              User Guide



       _1_.  _I_n_t_r_o_d_u_c_t_i_o_n

       This document describes ccooookk, a maintenance tool designed to
       construct  files.   CCooookk may be used to maintain consistency
       between executable files and  the  associated  source  files
       that   are  used  to  generate  them.   The  consistency  is
       designated by the relative last-modified times of files  and
       is  thus  automatically adjusted each time a file is edited,
       compiled  or  otherwise  modified.    CCooookk   validates   the
       consistency  of  a system of files and executes all commands
       necessary to maintain that consistency.

       CCooookk is a tool for constructing files.  It is given a set of
       files to create, and instructions detailing how to construct
       them.   In   any   non-trivial   program   there   will   be
       prerequisites   to   performing  the  actions  necessary  to
       creating any file, such as extraction from a  source-control
       system.  CCooookk provides a mechanism to define these.

       When  a  program  is  being  developed  or  maintained,  the
       programmer will typically change one file of  several  which
       comprise the program.  CCooookk examines the last-modified times
       of the files to see when the prerequisites of  a  file  have
       changed,  implying that the file needs to be recreated as it
       is logically out of date.

       CCooookk also provides a facility for implicit recipes, allowing
       users to specify how to form a file with a given suffix from
       a file with a different  suffix.   For  example,  to  create
       _f_i_l_e_n_a_m_e..oo from _f_i_l_e_n_a_m_e..cc

       _1_._1  _W_h_y _Y_o_u _W_a_n_t _T_o _U_s_e _C_o_o_k



          +o Cook is a replacement for the traditional _m_a_k_e(1) tool.

          +o There  is  a  _m_a_k_e_2_c_o_o_k   utility   included   in   the
            distribution  to help convert makefiles into cookbooks.

          +o Cook is more powerful than the traditional _m_a_k_e tool.

          +o Cook has true variables, not simple macros.

          +o Cook has a simple but powerful string-based description
            language  with  many  built-in  functions.  This allows
            sophisticated filename specification  and  manipulation
            without loss of readability or performance.

          +o Cook has user defined functions.

          +o Cook can build in parallel.




       Peter Miller                                          Page 1





       Cook                                              User Guide



          +o Cook can distribute builds across your LAN.

          +o Cook  is  able  to  build  your  project  with multiple
            parallel threads, with support for rules which must  be
            single threaded.  It is possible to distribute parallel
            builds over your LAN, allowing you to turn your network
            into a virtual parallel build engine.

          +o Cook  is  able  to  use fingerprints to supplement file
            modification times.   This  allows  build  optimization
            without contorted rules.

          +o Cook can be configured with an explicit list of primary
            source files.  This allow the dependency  graph  to  be
            constructed  faster  by  not  going down dead ends, and
            also allows better error messages when the graph  can't
            be  constructed.  This requires an accurate source file
            manifest.

          +o In addition to walking the dependency graph,  Cook  can
            turn  the  input  rules  into  a shell script, or a web
            page.

          +o Cook  has  special   _c_a_s_c_a_d_e   dependencies,   allowing
            powerful   include  dependency  specification,  amongst
            other things.

          +o And Cook doesn't interpret tab differently to  8  space
            characters!

       If  you  are putting together a source-code distribution and
       planning to write a makefile, consider  writing  a  cookbook
       instead.   Although  Cook takes a day or two to learn, it is
       much more  powerful  and  a  bit  more  intuitive  than  the
       traditional _m_a_k_e(1) tool.

       _1_._2  _H_o_w _t_o _U_s_e _t_h_i_s _M_a_n_u_a_l

       This manual is divided into two parts.

       The  first part is tutorial introduction to ccooookk.  This part
       runs from chapter 4 to chapter 5.

       The second part is for reference and details  precisely  how
       ccooookk works.  This part runs from chapter 6 to chapter 14.

       Users  familiar  with  other  programs  similar  to ccooookk are
       advised to skim the tutorial part  before  diving  into  the
       reference part.

       _1_._3  _A_n_c_i_e_n_t _H_i_s_t_o_r_y

       CCooookk  was  originally developed because I was marooned on an
       operating system without anything  even  vaguely  resembling


       Peter Miller                                          Page 2





       Cook                                              User Guide



       _m_a_k_e(1).   This was in 1988.  Since I had to write my own, I
       added a few improvements.  When I finally  escaped  back  to
       UNIX,  in  1990,  it  took  only  two  days  to port ccooookk to
       SystemV.  I have since deleted all code  for  that  original
       operating  system,  although clues to its identity are still
       present.

       After I had ccooookk up on UNIX, the progress the world had made
       caught  up  with  me.   It  was  gratifying that many of the
       features other make-oid authors had thought  necessary  were
       either already present, or easily and seamlessly added.

       CCooookk  was  written  with portability in mind.  This does not
       means it is entirely portable, but it comes close.  CCooookk has
       been  tested  on  numerous UNIX flavors.  This was made much
       simpler in 1994  when  I  started  using  the  GNU  Autoconf
       utility.   This  means  that when you obtain the sources for
       Cook, all you  have  to  do  is  run  the  _c_o_n_f_i_g_u_r_e  script
       included in the distribution and Cook will be configured for
       your  system.   See  the  BUILDING  file   in   the   source
       distribution for more information.

       In 1996 Cook had internationalization support added, so that
       users could  have  error  messages  and  other  warning  and
       informational  messages  printed  in  their native language.
       This was made possible by the GNU Gettext utilities.

       In 1997 Cook had a major re-write of significant portions of
       its inference engine.  This enabled the addition of parallel
       processing  support,  and  simplified  adding   user-defined
       functions to the cookbook language.

























       Peter Miller                                          Page 3





       Cook                                              User Guide



       _2_.  _C_o_o_k _f_r_o_m _t_h_e _O_u_t_s_i_d_e

       This  chapter is part of the tutorial on how to use the ccooookk
       program.  It focuses on how to use ccooookk, without needing  to
       know how ccooookk works internally.

       _2_._1  _W_h_a_t _c_a_n _c_o_o_k _d_o _f_o_r _m_e_?

       By far the most common use of cook, by experts and beginners
       alike, is to issue the command
            cook
       and cook will consult its cookbook to see what needs  to  be
       done.

       In  general, ccooookk is used to take a set of files and chew on
       them in some way to produce another set of  files;  such  as
       the  source  files  for a program, and how to turn them into
       the executable program  file.   In  order  for  ccooookk  to  do
       anything  useful, it needs to know what to do.  "What to do"
       is contained  in  a  file  called  _H_o_w_t_o_._c_o_o_k  in  the  same
       directory  as the files it is going to work on.  You need to
       execute the  cook command in the same directory  as  all  of
       the files.

       _2_._2  _W_h_a_t _i_s _c_o_o_k _d_o_i_n_g_?

       The _H_o_w_t_o_._c_o_o_k file was written by the same person who wrote
       the source files.  It contains a set  of  recipes;  each  of
       which,  among  other  things,  contain  commands  for how to
       manipulate the files.  The ccooookk program echos  each  of  the
       commands  it is about to execute, so that you can watch what
       it is doing as it goes.

       If the _H_o_w_t_o_._c_o_o_k file contained only commands, you would be
       better  off  using  a  shell  script.   In  addition  to the
       commands is information telling ccooookk which files need to  be
       constructed  before  other  files  can  be,  and  from  this
       information ccooookk determines the order in  which  to  execute
       the  commands.   Also,  ccooookk  examines  other information to
       determine  which  commands  it  need  not  do,  because  the
       associated files are already up-to-date.

       _2_._3  _W_h_a_t _c_a_n _c_o_o_k _a_l_w_a_y_s _d_o_?

       If  you  are  in a directory with a _H_o_w_t_o_._c_o_o_k file, you can
       expect a few common requests to work

       cook clobber   This command can be expected  to  remove  any
                      files  from  the directory which ccooookk is able
                      to reconstruct.

       cook all       This is the default action,  and  so  can  be
                      obtained by a simple cook request.  It causes
                      ccooookk to construct some specific file  or  set


       Peter Miller                                          Page 4





       Cook                                              User Guide



                      of files.

       cook clean     This  is similar to "cook clobber" above, but
                      it only removes intermediate files,  and  not
                      not  the final file or files which "cook all"
                      constructs.

       In addition to the above, many _H_o_w_t_o_._c_o_o_k  files  will  also
       define

       cook install   If  a  program  or  library  or  document  is
                      constructed  in  the  directory,   the   this
                      command  will  install  it  into  the correct
                      place in the system.

       cook uninstall The  reverse  of  the   above,   it   removes
                      something from the system.

       _2_._4  _I_f _s_o_m_e_t_h_i_n_g _g_o_e_s _w_r_o_n_g

       Most  errors  while  ccooookk is constructing file are caused by
       errors in the source files, and not the _H_o_w_t_o_._c_o_o_k file.  In
       general,  you  can fix the problems in the source files, and
       execute the ccooookk command again, and ccooookk  will  resume  from
       the command which incurred the error.

       To  help  you  while editing the files with the errors, ccooookk
       keeps a listing file of all the commands  it  executed,  and
       any output of those commands, in a file called _H_o_w_t_o_._l_i_s_t in
       the current directory.

       You may want ccooookk to find all the errors it can  before  you
       do any editing, do do this, use the --CCoonnttiinnuuee option (it may
       be abbreviated to --cc for convenience).

       _2_._5  _T_h_e _R_e_f_e_r_e_n_c_e _M_a_n_u_a_l

       For more information about the command  line  arguments  and
       options  of  the  various  commands  mentioned,  you  should
       consult the on-line manual pages.  The Cook Reference Manual
       is  also a good source of this information, and is available
       from the same place as you obtained this manual.














       Peter Miller                                          Page 5





       Cook                                              User Guide



       _3_.  _C_o_o_k _f_r_o_m _a _C_o_o_k_b_o_o_k

       This  chapter  describes  the  contents  and  meaning  of  a
       cookbook, a file which contains information ccooookk needs to do
       its job.  It focuses on what  a  cookbook  looks  like,  and
       touches on a few areas of how ccooookk works does its job.

       _3_._1  _W_h_a_t _d_o_e_s _C_o_o_k _d_o_?

       The  basic  building  block  for  ccooookk  is  the concept of a
       _r_e_c_i_p_e.  A recipe has three parts:

         1.  one or more files which the recipe  constructs,  known
             as the _t_a_r_g_e_t_s of the recipe

         2.  zero  or  more  files  which are used by the recipe to
             construct the target, known as the _i_n_g_r_e_d_i_e_n_t_s of  the
             recipe

         3.  one  or  more  commands to execute which construct the
             targets from the ingredients, known as the _b_o_d_y of the
             recipe.

       When  a  number  of  recipes  are  given,  some  recipes may
       describe how to cook the ingredients of other recipes.  When
       ccooookk   is   asked   to  construct  a  particular  target  it
       automatically determines the correct order  to  perform  the
       recipe bodies to cook the requested target.

       CCooookk  would  not  be  especially  useful  if you had to give
       explicit recipes for how to cook every little thing.   As  a
       result,  ccooookk  has  the  concept  of an _i_m_p_l_i_c_i_t recipe.  An
       implicit recipe is  very  similar  to  an  explicit  recipe,
       except  that  the  targets and ingredients of the recipe are
       _p_a_t_t_e_r_n_s to be matched to file names, rather  than  explicit
       file  names.   This  means it is possible to write a recipe,
       for example which constructs a files with a name  ending  in
       `..oo' from a file of the same name, but ending in `..cc' rather
       than `..oo'.

       In addition to recipes, ccooookk needs to know _w_h_e_n to construct
       targets from ingredients.  CCooookk has been designed to cook as
       little as possible.  "As little as possible"  is  determined
       by  examining  when  each  file  was last modified, and only
       constructing targets when that are  out  of  date  with  the
       ingredients.


       _3_._1_._1  _W_h_e_n _i_s _C_o_o_k _u_s_e_f_u_l_?
       From  the above description, ccooookk may be described as a tool
       for maintaining consistency of sets of files.





       Peter Miller                                          Page 6





       Cook                                              User Guide



       _3_._1_._2  _W_h_e_n _i_s _C_o_o_k _n_o_t _u_s_e_f_u_l_?
       Cook is not useful for maintaining consistency  of  sets  of
       things  which  are  _w_i_t_h_i_n  files and thus ccooookk is unable to
       determine when they were modified.  For example, ccooookk is not
       useful for maintaining consistency of sets of records within
       a database.


       _3_._2  _H_o_w _d_o _I _t_e_l_l _C_o_o_k _w_h_a_t _t_o _d_o_?

       Sets of recipes are gathered together into cookbooks.   When
       ccooookk  is  executed  it  looks  for  a  cookbook  of the name
       _H_o_w_t_o_._c_o_o_k in the current directory.  If you did not name  a
       file to be constructed on the command line, the first target
       in the cookbook will be constructed.

       The best way to  understand  how  to  write  recipes  is  an
       example.   In this example, a  program, _p_r_o_g, is composed of
       three files: _f_o_o_._c, _b_a_r_._c and  _b_a_z_._c.   To  inform  ccooookk  of
       this, the cookbook
            #include "c"

            prog: foo.o bar.o baz.o
            {
                    cc -o prog foo.o bar.o baz.o;
            }
       is sufficient for _p_r_o_g to be constructed.

       This cookbook has two parts.  The line
            #include "c"
       tells  ccooookk  to  refer  to a system cookbook which tells it,
       among other things, how to construct a _s_o_m_e_t_h_i_n_g..oo file from
       a _s_o_m_e_t_h_i_n_g..cc file.

       The second part is a recipe.  The first line of this recipe
            prog: foo.o bar.o baz.o
                ...
       names  the  target,  _p_r_o_g, and the ingredients, _f_o_o_._o, _b_a_r_._o
       and _b_a_z_._o.

       The next three lines
            ...
            {
                    cc -o prog foo.o bar.o baz.o;
            }
       are the recipe  body,  which  consists  of  a  single  _c_c(1)
       command  to  be executed.  Recipe bodies are always within {{
       curly braces }}, and commands always  end  with  a  semicolon
       (;;).

       Thus, to update _p_r_o_g after any of the source files have been
       edited, it is only necessary to issue the command
            cook prog
       This could be simplified further, because ccooookk will cook the


       Peter Miller                                          Page 7





       Cook                                              User Guide



       targets  of the first recipe by default; in this case, _p_r_o_g.

       The power of cook becomes more apparent when  include  files
       are  considered.   If  the files _f_o_o_._c and _b_a_z_._c include the
       file _d_e_f_s_._h, this would automatically be detected  by  ccooookk.
       If  _d_e_f_s_._h  were  to  be  edited, and ccooookk re-executed, this
       would cause ccooookk to recompile  both  _f_o_o_._c  and  _b_a_z_._c,  and
       relink  _p_r_o_g_.   The  information  about how to turn ..cc files
       into ..oo files came from the  ``#include  "c"''  line,  which
       read in the C recipes distributed with Cook.

       _3_._2_._1  _T_h_e _c_o_m_m_o_n _p_r_o_g_r_a_m _c_a_s_e
       The  above  example  may be simplified even further.  If the
       four files _f_o_o_._c, _b_a_r_._c, _b_a_z_._c and _d_e_f_s_._h all resided  in  a
       directory   with   a  path  of  _/_s_o_m_e_/_w_h_e_r_e_/_p_r_o_g,  then  the
       _H_o_w_t_o_._c_o_o_k file in that directory need only contain
            #include "c"
            #include "program"
       for _p_r_o_g to  be  cooked.   This  is  because  the  "program"
       cookbook  looks  for  all  of  the  _s_o_m_e_t_h_i_n_g..cc files in the
       current directory, compiles them all, and links them into  a
       program named after the current directory.

       The  default target in the "program" cookbook is called _a_l_l.
       The ingredient of _a_l_l is the program named after the current
       directory.  Two other targets are supplied by this cookbook:

       clean removes all of the _s_o_m_e_t_h_i_n_g..oo files from the  current
            directory.

       clobber removes   the   program   named  after  the  current
            directory, and also  removes  all  of  the  _s_o_m_e_t_h_i_n_g..oo
            files from the current directory.

       _3_._3  _C_r_e_a_t_i_n_g _a _C_o_o_k_b_o_o_k

       To  use  ccooookk you will usually need to define a cookbook, by
       creating a file, usually called _H_o_w_t_o_._c_o_o_k  in  the  current
       directory, with your favorite text editor.

       This  file  has  a  specific  format.   The  format has been
       designed to be easy to learn,  even  for  the  casual  user.
       Much  of  the  power  of  ccooookk is contained in how it works,
       without complicating the format of the cookbook.












       Peter Miller                                          Page 8





       Cook                                              User Guide



       Example  of  what  a  cookbook  looks  like  are   scattered
       throughout  this  document.   The  following  example is the
       entire cookbook for many programs, some quite large:
            #include "c"
            #include "yacc"
            #include "usr.local"
            #include "program"
       As you can see, even for many complex programs, the cookbook
       is remarkably simple.















































       Peter Miller                                          Page 9





       Cook                                              User Guide



       _4_.  _C_o_o_k_i_n_g _i_n _P_a_r_a_l_l_e_l

       Cook  is  able  to  use  the  dependency  information in the
       cookbook to schedule more than  one  recipe  body  at  once,
       where  they  are  independent.   In  large  projects this is
       almost always possible.

       Parallel  processing  is  of  most  use  on  multi-processor
       systems.  There are cases, however, when running two jobs at
       once on a workstation can take advantage of disk or  network
       latencies.

       Parallel  processing requires more resources than the simple
       case.  Because  more  commands  are  running,  more  CPU  is
       required,  but  also  more virtual memory and more temporary
       file space.  You need to be sure that cooking in parallel is
       a sensible thing to be doing.

       _4_._1  _C_o_m_m_a_n_d _L_i_n_e _O_p_t_i_o_n

       The  -PARallel option is used to tell Cook to run the recipe
       bodies in parallel.  By default, 4  jobs  run  in  parallel.
       You  may  specify  the number of jobs after the option (_e_._g_.
       --par=2) if you wish.

       _4_._2  _C_o_o_k_b_o_o_k _V_a_r_i_a_b_l_e

       It is also possible to set the number of  jobs  from  within
       the  cookbook by using the parallel_jobs variable.  This can
       be used to automate the selection of  the  number  of  jobs,
       based on the current host name:
            if [not [defined parallel_jobs]] then
            {
                    host = [os node];
                    if [in [host] cerberus] then
                            parallel_jobs = 3;
                    else if [in [host] zaphod] then
                            parallel_jobs = 2;
                    else if [in [host] hydra] then
                            parallel_jobs = 8;
            }
       In  this  way,  the number of jobs will be set appropriately
       for each machine,  provided  the  number  of  jobs  was  not
       already set by the command line option.

       _4_._3  _R_e_c_i_p_e _W_r_i_t_i_n_g

       Most  recipes  run  in  parallel without difficulty, however
       some will require special  treatment.   The  problems  arise
       from conflict for resources - usually temporary files.






       Peter Miller                                         Page 10





       Cook                                              User Guide



       The  simplest  example  of  this  is  _y_a_c_c(1).   The  output
       filenames are hard-coded, even when you write a more general
       recipe:
            %.c: %.y
                    single-thread yy.tab.c
            {
                    [yacc] [yacc_flags] %.y;
                    sed "'s/[yY][yY]/%_/g'" yy.tab.c > [target];
                    rm yy.tab.c;
            }
       Replacing  the  YY  is a common method for getting more than
       one yacc grammar into a program.  We run into  trouble  with
       the  yy.tab.c  file  because  every one of the yacc grammars
       will need to use the same temporary file name.

       The single-thread clause tells cook to find  something  else
       to  do  if it discovers that it wants do two of these at the
       same time.

       The temporary file name may not be so evident as in the yacc
       case.   The GNU Autoconf utilities use a number of temporary
       files in the current directory, but none of them  appear  in
       the text of the recipes.
            %: %.in: config.status
                    single-thread conftest.subs
            {
                    CONFIG_FILES\=[target] CONFIG_HEADERS\= config.status;
            }
       It is common, if your project uses GNU Autoconf, to generate
       several files in this way.  Once the config.status script is
       produced,  all  of  these  files will then be candidates for
       cook to generate - but they can only be done one at a  time.

       Other  resources, such as tape drives, can also be described
       in the single-thread clause.  You can do this by device name
       (_e_._g_. /dev/rmt/0) or by some descriptive string.  The single
       threading is performed by mutually  exclusive  string  sets,
       not by inode.

       _4_._3_._1  _C_o_n_c_u_r_r_e_n_t _E_x_e_c_u_t_i_o_n _T_h_r_e_a_d_s
       Each  recipe,  when  its  actions  are executed, is executed
       within an execution thread.  Execution threads share  almost
       everything  in  common;  this includes all of the variables,
       the state of the ``set'' statement, the stat cache, _e_t_c.

       If you need to create  variable  names,  or  temporary  file
       names,  which  are  unique  to a thread, use the [thread-id]
       variable.  This variable has a unique value for the life  of
       a  thread.   No  other  concurrent thread will have the same
       value.

       Note, however, that  the  [thread-id]  values  of  completed
       threads  will  be re-used; this ensures that when it is used
       to construct variable names, the variables will be  re-used.


       Peter Miller                                         Page 11





       Cook                                              User Guide



       This prevents memory bloat when cooking large projects.

       _4_._4  _F_i_l_e _L_o_c_k_i_n_g

       The  above  discussion applies to utilities which perform no
       file locking, and thus cannot detect  or  sequence  multiple
       accesses to a resource.  Other programs, such as those which
       access  databases,  may  have  quite  capable  file  locking
       mechanisms  and are able to manage multiple parallel updates
       on their own,  obviating  the  need  for  the  single-thread
       clause.

       _4_._5  _V_i_r_t_u_a_l _M_a_c_h_i_n_e

       It  is possible to simulate a parallel machine if you are on
       a network.  Cook is able to distribute tasks to computers on
       a network, if it is given sufficient information.

       The first information Cook requires is the list of machines.
       This is done using the parallel_hosts variable.   NNoottee::  The
       tasks will be distributed amongst these machines independent
       of the setting of the parallel_jobs variable.  _i_._e_. even  if
       you are not doing parallel processing.
            parallel_hosts = larry curly moe;
       If  you  want  to  give  one machine more weighting than the
       others (say, because it is twice as fast) you simply name it
       more  than  once.   Cook will use these names in round-robin
       fashion.

       _4_._5_._1  _R_e_m_o_t_e _S_h_e_l_l _C_o_m_m_a_n_d
       Cook uses the Berkeley _r_s_h(1) command to invoke  the  remote
       command.   You  can set the command, or the command and some
       options, using the parallel_rsh variable.  The default value
       is
            parallel_rsh = rsh;
       In   order  to  work  in  a  useful  way,  Cook  makes  some
       assumptions about your environment and your account:

          +o That your system administrators allow _r_s_h(1) to be used
            on your network.

          +o That  your  account  name  is  the same on _a_l_l machines
            (otherwise not even the rsh -l _l_o_g_i_n_-_n_a_m_e  option  will
            help).

          +o That the /etc/hosts.equiv file, or your ~/.rhosts file,
            is set on _a_l_l machines so that you don't need to give a
            password.

          +o That  all  of  the  necessary files and directories are
            mounted in  exactly  the  same  place  on  all  of  the
            machines;  and  that  they  are  _t_h_e  _s_a_m_e _f_i_l_e_s on all
            machines, via NFS or similar.   Automounters  can  make
            this especially messy.


       Peter Miller                                         Page 12





       Cook                                              User Guide



          +o That  your  account  start-up scripts set the necessary
            environment settings, _e_._g_. command search PATH, without
            any intervention required.

          +o That  all of the machines are of the same architecture,
            or that the architecture doesn't matter.

          +o That the system time is synchronized on  all  machines,
            using  _r_d_a_t_e(1) from _c_r_o_n(8), or using NTP, or similar.

       _4_._5_._2  _L_i_m_i_t_a_t_i_o_n_s
       There are some inherent limitations in the _r_s_h(1)  protocol.

          +o Your  current  environment  variable  settings  are not
            transferred across.  Neither are _u_l_i_m_i_t settings,  _e_t_c.
            If any are important, you need to write the cookbook to
            explicitly replicate them.

          +o The exit status of the remote command is  not  reported
            in  the  exit status of the _r_s_h(1) command1.  There are
            internal contortions used by Cook to  obtain  the  exit
            status;  error  about  mysteriously named files usually
            indicate that one or more of the above  assumptions  is
            being broken.

       _4_._5_._3  _S_e_c_u_r_e _S_h_e_l_l
       It  is  possible  to  use  the Secure Shell (ssh) instead of
       Remote Shell (rsh).  This  gives  you  fully  authenticated,
       fully  encrypted  sessions, both over your intranet and even
       over  the  Internet.   Once  you  have  it   installed   and
       configured  correctly, you simply replace the _r_s_h command in
       the above examples with the _s_s_h command.

       This is accomplished by setting
            parallel_rsh = "ssh";
       Somewhere near the top of your cookbook.

       _4_._5_._4  _H_o_s_t _B_i_n_d_i_n_g
       In some cases, such as licensing conditions,  some  commands
       will  only  run  on  a  limited  set  of hosts.  Rather than
       perform all commands on those hosts, it is possible to  bind
       recipes  to  specific  hosts.   This  binding  overrides the
       parallel_hosts variable.
            %.c: %.esql
                    host-binding shylock
            {
                    esql %.esql > [target];
            }
       This example says that the embedded SQL preprocessor is only

       ____________________

       1. The  Berkeley  sources certainly don't contain code to do
          this.   Do  any  other  vendors  have   a   more   useful
          implementation?

       Peter Miller                                         Page 13





       Cook                                              User Guide



       to  be  run  on  the  database  server  called  ``shylock'',
       probably due to usurious licensing fees.  However,  you  may
       want  to  perform  your other development activities on more
       lightly loaded machines; this clause only  applies  to  this
       one recipe, other recipes behave as normal.

       The  host-binding  clause may have more than one host named,
       and they will be used in round-robin  fashion.   This  is  a
       recipe-level variant of the parallel_hosts variable.

       The  host-binding  clause  will  apply  independent  of  the
       setting of the  settings  parallel_jobs  and  parallel_hosts
       variables.

       The  recipe  level host-binding overrides the cookbook level
       parallel_hosts when determining which remote hosts should be
       used.

       If  the  list  of  hosts given to the host-binding clause is
       empty, the local host will be used (normal recipe  execution
       will occur).

       If  you  need  to include the local host in the round robin,
       use localhost or [os node], however this will behave exactly
       the  same  as  for  a remote host.  You should also consider
       hard coding the name, that way you get the same behavior  no
       mater  which  of  the  machines  in the round robin the Cook
       command is executed on.

       _4_._5_._5  _L_o_a_d _B_a_l_a_n_c_i_n_g
       It  is  possible  to  use  _h_o_s_t_-_b_i_n_d_i_n_g  to   perform   load
       balancing.  This is accomplished by using _r_u_p(1) to discover
       which hosts are least busy, and then using this  information
       to invoke the system's _r_s_h(1).

       This may be accomplished by using
            parallel_rsh = "cook_rsh";
       somewhere  near the top of your cookbook (or _c_o_o_k___r_s_h _-_s for
       secure shell).  You then give classes of hosts to the  _h_o_s_t_-
       _b_i_n_d_i_n_g  clause  of  the  recipes, rather than specific host
       names.  See _c_o_o_k___r_s_h(1) for more information  about  setting
       up classes of hosts.

       If  you  still  need  to  give  specific  host names to some
       recipes, _c_o_o_k___r_s_h(1) will cope with this, too.

       _4_._6  _V_i_r_t_u_a_l _M_a_c_h_i_n_e_, _R_e_v_i_s_i_t_e_d

       It is also possible to have Cook run multiple  processes  in
       parallel without having to know what machines are available.
       This method puts control of the  network  resources  in  the
       hands  of  an  external  program,  one  example  of which is
       cook_rsh, distributed with Cook.



       Peter Miller                                         Page 14





       Cook                                              User Guide



       Once you have such a virtual network defined it becomes very
       easy   to   build   projects   for   multiple  platforms  or
       architectures in the same  build.   It  also  allows  easily
       adding  new machines, or disabling machines for maintenance.
       The virtual network can  be  changed  at  any  time  without
       disturbing ongoing development.

       The  following examples will have the form allowing multiple
       architecture builds, but of course they will work for single
       architecture as well.

       _4_._6_._1  _c_o_o_k___r_s_h
       The  cook_rsh  system  is  just  one  way  of  defining  the
       capabilities of a given network  in  a  way  that  a  single
       program can make the best choice of machine for a given job.
       It does so in a way that is reliable and does a  decent  job
       of  balancing  loads  across  available  machines, even with
       multiple developers doing builds at the same time.

       Each job that requested via cook_rsh picks  the  appropriate
       machine  from  those  able  to do the job at that instant in
       time.  In contrast to parallel_hosts or  host-binding  hostA
       hostB etc, it does not work from a list which was current at
       the time a cook  process  was  started.   Thus  it  is  less
       vulnerable to machines going off line or becoming overloaded
       as time passes.

       Currently cook_rsh uses rsh to actually execute the job,  so
       requires  the  same network setup.  The next version may use
       multicast instead for even finer control and reliability.

       There are minor differences in the  setup  to  use  cook_rsh
       control.   The  first is that Cook no longer requires a list
       of machines.  It is not necessary to set the  parallel_hosts
       variable.  The parallel_rsh variable is set as:
            parallel_rsh = cook_rsh -v;
       The  -v  option  produces information as to what machine was
       actually picked for each job.

       _4_._6_._2  _H_o_s_t _B_i_n_d_i_n_g
       All recipe bodies which should run in parallel need a  host-
       binding  setting.   Rather than list the hosts to be used we
       form  a  name  which  is  used  by  cook_rsh  to  select  an
       appropriate  machine.  This name may include an architecture
       component and a operation component.
            %1/%.o: %.c
                    host-binding %1_C
            {
                    [%1_cc] -o [target] -c [resolve %.c];
            }

            %1/%2: [addprefix %1/ [%2_objs]]
                    host-binding %1_L
            {


       Peter Miller                                         Page 15





       Cook                                              User Guide



                    [%1_ld] -o [target] [resolve [need]];
            }
       This  example  says  that  the  compiles   for   a   certain
       architecture  should take place on any machine designated as
       a compile host for  that  architecture.   And  linking  jobs
       should  go  to  machines  designated as a link host for that
       architecture.  Of course the same machine could probably  do
       both  jobs,  but  you  get  to define it as you see fit, and
       change the designations  from  moment  to  moment.   Current
       designations per architecture are:

       _C   Compile   (Compile source code)
       _L   Link      (link binary programs)
       _T   Test      (run automatic tests)
       _B   Build     (including cooking, or generic jobs)
       And others may be added if necessary by simple extension.

       _4_._6_._3  _A_d_m_i_n_i_s_t_r_a_t_i_o_n _o_f _c_o_o_k___r_s_h
       The  definition  of  the virtual network used by cook_rsh is
       contained in just a two configuration files.  One file lists
       designations,   and   lists   machines   belonging  to  each
       designation.  The other is  an  eexxcclluuddee  file,  which  lists
       machines which should not be used for whatever reason.

       The  designations file may be created by hand if desired but
       a utility called rate_hosts is provided  that  can  generate
       the  host_lists.pl file, possibly after being customized for
       the particular requirements of a given environment.

       The exclusion file  lists  machines  that  should  never  be
       selected.   The exclusion file can be edited at any time and
       adding a machine will prevent any further  jobs  from  going
       its  way.   Removing  the name will again allow selection of
       that machine.  How soon a job actually  goes  there  depends
       greatly  on the network utilization.  The exclude_hosts file
       contains machine names and optional  comments.   An  example
       exclude_hosts file might contain:
            # list of hosts to exclude from arch_hosts lists
            # for whatever reason.
            monolith        # not a development machine - the FTP host
            namshub         # developer test station
            tiamat          # unreliable configuration
            locutus         # Being upgraded
       This  is handy for maintenance on machines.  If a particular
       machine needs to be brought down you simply add its name  to
       the  exclusion  file.   Checking  its process list will tell
       when any currently running remove jobs are done.  After that
       it  can  safely be brought down without affecting any active
       builds.







       Peter Miller                                         Page 16





       Cook                                              User Guide



       _5_.  _I_n_c_l_u_d_e _F_i_l_e _D_e_p_e_n_d_e_n_c_i_e_s

       A significant factor in a cookbook accurately describing the
       dependencies in a program are the include file dependencies.
       There are three methods for doing this in Cook.   The  first
       is  easily  understandable  but  is too slow to use on large
       projects, the second is a little harder to  understand,  but
       works  well  for large projects.  The third method is rather
       convoluted, but works well for projects with many  thousands
       of  source  files  and  multiple  simultaneous architectures
       built within the same source tree.

       The recipes here are merely examples  and  starting  points;
       you  will  almost certainly need to enhance them to suit the
       needs of your projects.  Areas  you  will  need  to  address
       include  (a) the existence of cc -I_p_a_t_h options, (b) the use
       of search_list variable and the [resolve] function, and  (c)
       heterogeneous  development.   The  techniques  also apply to
       other languages, such as Fortran, Pascal and Roff, but  each
       requires a language-specific include scanning program2.

       _5_._1  _T_h_e _M_a_n_u_a_l _M_e_t_h_o_d

       Well,  actually  there  are  four  methods,  if  you   count
       maintaining the dependencies manually.  This has the serious
       defect that humans tend to _f_o_r_g_e_t to  update  the  cookbook.
       On  a large project not all developers are familiar with the
       workings of Cook, and so they shy  away  from  updating  the
       cookbook.   By  finding  ways to automate include dependency
       processing, we reduce the risk that a developer will  forget
       to  update  the  cookbook,  and  we reduce the risk that the
       cookbook's dependency information is out-of-date.

       Automatic include dependency methods  described  below  have
       flaws,  and  can  never  replace a human for flexibility and
       domain knowledge.  On the other  hand,  humans  have  better
       things  to  do  with their time than grope files for include
       file dependencies (like write neat software).

       _5_._2  _D_e_b_u_g_g_i_n_g _C_o_o_k_b_o_o_k_s

       Before we proceed further, it is worth  spending  some  time
       covering  some  of  the methods for debugging your cookbook,
       because small mistakes in implementing the methods below can
       become quite difficult to locate.

       _5_._2_._1  _C_o_m_m_a_n_d _L_o_c_a_t_i_o_n_s
       Usually  Cook  will  echo all the commands it executes, just
       before executing them.  If you add the line
            set tell-position;

       ____________________

       2. The _c___i_n_c_l program understands Roff, you just need to use
          the -r option.

       Peter Miller                                         Page 17





       Cook                                              User Guide



       near the top of your cookbook, Cook will  add  the  filename
       and  line  number  within  the  cookbook  to each command it
       echoes.  This can be useful in  figuring  out  which  recipe
       Cook actually chose to execute.

       _5_._2_._2  _P_r_i_n_t_i_n_g _S_t_u_f_f
       Often  you  will  want  to have Cook print various pieces of
       information.  The wrong way to do it  is  with  the  shell's
       "echo" command
            echo variable "=" [variable];
       because   this  invokes  another  process  (which  can  make
       debugging parallel cookbooks  harder)  and  because  of  the
       optional _d_a_t_a _._._. _d_a_t_a_e_n_d which can follow commands (see the
       command statement in the language definition,  below).   The
       correct method is to call the "print" function, like this
            function print [__FILE__]: [__LINE__]: variable "=" [variable];
       Note  the  use  of the __FILE__ and __LINE__ builtins, which
       provide you with cookbook position information.

       _5_._2_._3  _T_r_i_g_g_e_r _I_n_g_r_e_d_i_e_n_t_s
       Another useful piece of information is the ingredients which
       caused  Cook  to  invoke  a  particular  recipe  body.   The
       following function
            function say-why =
            {
                    if [count [@1]] then
                            @1 = [@1];
                    if [count [@2]] then
                            @2 = [@2];
                    local tt = [target];
                    if [defined targets] then
                            tt = [targets];
                    local t = ;
                    if [in [count [younger]] 0 1 2 3] then
                    {
                            function print [@1] [@2]
                                    Building [target]
                                    because of [younger];
                    }
                    else
                    {
                            function print [@1] [@2]
                                    Building [target] because of
                                    [wordlist 1 3 [younger]] et al;
                    }
            }
       can be inserted at the beginning of a recipe
            %.o: %.c
            {
                    function say-why [__FILE__] [__LINE__];
                    cc -c %.c;
            }
       to say why the recipe was invoked.  This will  even  include
       dependencies  automatically determined by all of the methods


       Peter Miller                                         Page 18





       Cook                                              User Guide



       which follow, not just those named on the right-hand-side of
       the recipe itself.

       _5_._3  _T_o_o_l_s

       All   of  the  automated  include  file  dependency  methods
       described below use the _c___i_n_c_l(1) program  included  in  the
       Cook  distribution.  It has a number of options tailored for
       use with Cook.   For  exact  information  about  the  _c___i_n_c_l
       command,  consult  the on-line _m_a_n(1) system (it should have
       been installed) or the Cook Reference Manual.

       Other tools are available.  The  commonest  is  to  use  the
       gcc-M  option, which produces a list of include files on the
       standard output.  Because the gcc-M output is aimed  at  GNU
       Make,  you  will  need an _a_w_k(1) or _s_e_d(1) script to massage
       the output into a format suitable for Cook.

       _5_._4  _T_h_e _S_m_a_l_l _M_e_t_h_o_d

       The easiest way to determine a file's  include  dependencies
       is within the recipe's ingredients.
            %.o: %.c: [collect c_incl -api %.c]
            {
                    cc -c %.c;
            }

       Note  the  second colon - the _s_e_c_o_n_d set of dependencies are
       only evaluated after Cook has chosen to activate the  recipe
       (based  on the first set).  This does not guarantee that the
       file exists yet (it may have  to  be  generated  by  _l_e_x  or
       _y_a_c_c),  which  is  why the --Absent-Program-Ignore option is
       required.

       This method has the advantage  of  simplicity.   It  uses  a
       single  recipe which reads the way recipes usually read, and
       does not contain any unusual constructs.

       There are two problems with this method.  The first is  that
       it  doesn't  scale  well.   When there are only a few source
       files, the processing burden of running _c___i_n_c_l for every  ..cc
       file  every  time Cook is invoked is hardly noticeable.  The
       _c___i_n_c_l program caches the results of its scans, so  that  is
       can  minimize the length of time taken, and this does help a
       little.  However projects  with  hundreds  or  thousands  of
       files  find  even  the  cached  performance  an unreasonable
       burden; it is constantly re-calculating something which  has
       not changed from one run to the next.

       The  second  problem  is that the _c___i_n_c_l program is run when
       the dependency graph is being built, not when  it  is  being
       walked.   This  means  that the ..cc file (or a subordinate ..hh
       file) may have been out-of-date at the time.  When the graph
       is  walked,  it will have been regenerated, and the two sets


       Peter Miller                                         Page 19





       Cook                                              User Guide



       of include  files,  those  determined  by  _c___i_n_c_l  at  graph
       building  time,  and those seen by _c_c at graph walking time,
       may not agree - which may result in compile-time errors.

       _5_._5  _T_h_e _L_a_r_g_e _M_e_t_h_o_d

       For projects with large numbers of files, hundreds  or  even
       thousands,  it is necessary to re-calculate the include file
       dependencies only when a ..cc file changes, or  a  subordinate
       ..hh  file.   Ideally,  Cook  should  access  this information
       directly, rather than running a program to determine  it  or
       to fetch it.

       The  first  task  is  to  move  the information which _c___i_n_c_l
       caches into a format that Cook can access directly; Cook can
       then  read in this information as it scans the cookbook.  By
       making a separate ``dependency'' file for each ..cc  file,  we
       can  use  existing  Cook  mechanisms to describe how to keep
       this file up-to-date.

       The dependency file is generated and maintained as follows:
            %.c.d: %.c
            {
                    c_incl --no-cache %.c
                            "--prefix='%.o "[target]": %.c'"
                            "--suffix='set nodefault;'"
                            -o [target];
            }

       This recipe generates a file which contains a  mini-cookbook
       describing   the   ingredients  of  the  _o_b_j_e_c_t  file.   The
       dependencies are in terms of the object file because if  any
       of  the ..hh files change, it is the object file which is out-
       of-date, not the ..cc file.  The mini-cookbook itself is  also
       described,  so  that  if any of the source files change, the
       mini-cookbook can be brought up-to-date again.

       The recipe for the object file is less complicated  than  in
       the  previous section, because the mini-cookbooks supplement
       it:
            %.o: %.c
            {
                    cc -c %.c;
            }

       The only thing missing is how to get the information in  the
       mini-cookbooks into the main cookbook.  This is done with an
       include directive in the cookbook itself, but a special form
       of  it.   The  names of the mini-cookbooks can be determined
       the same way as the names of  the  object  files,  and  this
       allows  the  cookbook  fragments such as the following to be
       written:
            object_files = [fromto %.c %.o [source_files]];
            dependency_files = [fromto %.c %.c.d [source_files]];


       Peter Miller                                         Page 20





       Cook                                              User Guide



            #include-cooked [dependency_files]

       The #include-cooked directive  says  to  include  the  named
       files  (there may be more than one) if the file exist.  Once
       the cookbook (and its includes) have been read in, the files
       included  with this directive are checked to see if they are
       up-to-date.  If they are not, then they are  re-cooked,  and
       then  Cook  starts  over  again;  this  time with up-to-date
       include dependencies.

       The advantage of the method is  that  if  the  source  files
       don't    change,   the   dependency   information   is   not
       recalculated, this can result in significant savings.  Also,
       no  processes are invoked if nothing has changed, Cook reads
       the  information   directly.    Because   file   opens   are
       significantly cheaper than process invocations, this results
       in a significant performance improvement.

       The disadvantage of this method is  that  it  is  harder  to
       describe  and  harder  to implement.  To the uninitiated the
       cookbook looks incomplete and overly complex.

       Another problem is that if you delete an include file,  Cook
       will  complain  that  it  is unable to derive the dependency
       file because the include file is not present.  Simply delete
       the  dependency file and start again.  To avoid the problem,
       remove references to include  files,  and  re-build,  before
       deleting  the include files.  This problem is seen from time
       to time, but does not  present  a  huge  problem  in  normal
       practice.

       _5_._6  _T_h_e _C_a_s_c_a_d_e _M_e_t_h_o_d

       When  large  numbers of files are involved, it becomes clear
       that the  more  popular  include  files  are  being  scanned
       repeatedly.   This can be un-necessarily time-consuming when
       a popular include file is touched, as the  dependency  files
       of all .c files which reference it, even indirectly, must be
       re-calculated.

       There is also a problem when you are attempting  to  perform
       heterogeneous  builds  for multiple architectures out of the
       same sources.  This  is  typically  done  by  inserting  the
       architecture  name into the object file path as a directory.
       This  presents  another  problem:  nominating  all  of   the
       architectures  on  the  left-hand-side  of  the  regenerated
       dependency recipes.  Especially if you add another one after
       the  fact  -  now  all the existing dependency files must be
       recalculated, merely to add the new architecture.

       An alternative is to scan  each  of  the  source  files  and
       include  files  once,  and  request  cook  to  combine  them
       together at build time, rather than at dependence scan time.
       This  is done using cascade recipes.  These recipes nominate


       Peter Miller                                         Page 21





       Cook                                              User Guide



       additional ingredients (on their right-hand-size) if any  of
       the  files on their left-hand-size appears in an ingredients
       list.
            cascade foo.c = bar.h;
       This recipe says that any recipe  which  has  _f_o_o_._c  for  an
       ingredient, also has _b_a_r_._h for an ingredient.

       This takes care of the heterogeneous case, because while the
       recipes remain specified in a simple manner, _v_i_z_:
            %1/%0%.o: %0%.c
            {
                    %1-gcc -o [target] -c %0%.c;
            }
       Any and all of them which compile _f_o_o_._c will depend on _b_a_r_._h
       from the cascade recipe.  (This example assumes that you are
       using _g_c_c(1) in the usual way, and  that  your  architecture
       names match the GNU target names.)

       The  dependency  files  are generated and maintained in much
       the same way as before, except that you need two: one for .c
       files and one for .h files:
            %0%.c.d: %0%.c
                    set no-cascade
            {
                    c_incl --no-cache --no-recurs %0%.c
                            "--prefix='cascade %0%.c ='"
                            "--suffix=';'"
                            -o [target];
            }
            %0%.h.d: %0%.h
                    set no-cascade
            {
                    c_incl --no-cache --no-recurs %0%.h
                            "--prefix='cascade %0%.h ='"
                            "--suffix=';'"
                            -o [target];
            }
       You  will  also  need to add the .h.d files to the #include-
       cooked lines, to ensure they are generated.   If  there  are
       any  generated  .c  or  .h  files,  you will need to mention
       these, too.

       _5_._7  _D_e_p_e_n_d_e_n_c_i_e_s _o_n _D_e_r_i_v_e_d _F_i_l_e_s

       If  the  relationship  between  a  target  and   a   derived
       ingredient  appears only in a derived cookbook, it is likely
       that a clean build (solely from primary source  files)  will
       fail.   It is recommended that relationships such as this be
       placed in a primary source cookbook.  Cook  looks  for  such
       dependencies, and will warn you about them.

       An example of this is commonly seen when using the -d option
       with _y_a_c_c(1).  If you have a separate lexical analyzer  (the
       usual  reason  for  using  -d)  it  will need to include the


       Peter Miller                                         Page 22





       Cook                                              User Guide



       generated token definition file.

       When you first add the _y_a_c_c(1) grammar definition, Cook will
       generate  both  the  .c  and  .h  file  from  the usual yacc
       recipes.  It is only later, when you have  cleaned  out  all
       derived  files (including the dependency files) that you may
       have problems.  Where is it  recorded  that  Cook  needs  to
       regenerate the token definition file before it can determine
       the include dependencies of  the  lexical  analyzer?   (They
       were in a .d file which was ``cleaned'' away.)

       Cook  will  detect  this  situation  at  the  first possible
       moment, and warn you.  But placing the dependency in a  non-
       derived  cookbook  (_e_._g_.   Howto.cook)  the  warning will go
       away, and you will be able to do reliable clean builds.

       If you are convinced that Cook is _a_l_w_a_y_s wrong in your case,
       it is possible to suppress this warning.  Place the line
            set no-include-cooked-warning;
       in your main cookbook, and the warning will not be issued.

       Suppressing the warning could lead to problems.  It is often
       better to add the ingredients recipe given in the warning to
       the  cookbook,  even  if  you  think  it is redundant.  This
       disables a single instance of the warning, rather  than  all
       of them - subsequent _v_a_l_i_d instances will still be reported.
       (Implicit ingredients recipes, rather  than  explicit  ones,
       are  a useful alternative if you have a consistent pattern.)

       _5_._8  _R_e_n_a_m_i_n_g _I_n_c_l_u_d_e _F_i_l_e_s

       A consistent problem when you have  automatically  generated
       include  dependencies is that when you move an include file,
       Cook complains that a required ingredient does not exist.

       The easiest way to avoid this is to do a few  things  before
       you build again after moving the include file.

          +o Move the include file to the new name.

          +o Where  the include file was _f_r_o_m, put a file containing
            the line
                 #error "I'm not here"
            to make Cook happy (the  ingredient  will  exist),  but
            also  have the compiler generate an error if you miss a
            reference to it.

          +o Edit all the references to the old include file name to
            reference the new name.  Don't worry if you miss one or
            two, the previous step will catch it.

          +o Rebuild  the  program.   Cook  will  automatically  re-
            calculate  all  of  the  include  dependences  and then
            recompile.


       Peter Miller                                         Page 23





       Cook                                              User Guide



          +o If you missed one of the include file references,  Cook
            will  not  complain,  but  the  compiler  will.   (This
            assumes  you  are  using   whole-project   builds,   as
            described in the _L_a_r_g_e _P_r_o_j_e_c_t_s chapter.)

          +o Once  the  program  builds cleanly, remove the fake old
            include file, because you know for certain  that  there
            are no longer any references.
















































       Peter Miller                                         Page 24





       Cook                                              User Guide



       _6_.  _B_u_i_l_d_i_n_g _L_a_r_g_e _P_r_o_j_e_c_t_s

       This  chapter covers some of the  issues you may come across
       in building large projects.  It gives a skeleton for how you
       could use Cook to build a medium-to-large projects, and even
       covers some heterogeneous build issues.  It is expected that
       you  will  use  this  chapter  as  a guide; your development
       environment, and the shape of each individual project,  mean
       that you will probably change this to suit your own needs.

       The  material  in  this  chapter uses many, many features of
       Cook.  If you are not familiar with Cook, you  may  want  to
       read  the  rest  of  this  User  Guide to get a good idea of
       Cook's features and capabilities.  Even if you are  familiar
       with  Cook,  you may need to refer to the language guide and
       built-in function descriptions from time to time.

       _6_._1  _W_h_o_l_e _P_r_o_j_e_c_t _B_u_i_l_d

       The skeleton given here builds the whole project as a single
       Cook  invocation,  even  when  the  project consists of tens
       thousands of individual source files.  This is distinct from
       a  build  process which has Cook recursively invoking itself
       in deeper directories, or a  shell  script  doing  much  the
       same.   Some of the advantages of doing whole project builds
       will be discussed  in  a  later  section.   For  now  it  is
       sufficient  to say that experience has shown repeatedly that
       this method does scale to significant projects.

       The first thing about a single build pass is that it happens
       relative  to a single fixed place.  The logical place is the
       top  of  the project source tree3.  This works well with the
       _s_e_a_r_c_h___l_i_s_t functionality, mentioned below, which simplifies
       the structure of private work areas.

       _6_._1_._1  _P_r_o_j_e_c_t _D_i_r_e_c_t_o_r_y _S_t_r_u_c_t_u_r_e
       In the examples use in this chapter, the following directory
       structure is assumed:













       ____________________

       3. If  you  ever  want  to  use  Aegis   for   configuration
          management, this is what Aegis expects.

       Peter Miller                                         Page 25





       Cook                                              User Guide



                             +++
                             ++_P+_r|_o_j_e_c_t
                              ++++Hloiwbtroa.rcyook
                              |++ +|_s_o_u_r_c_e_1.c
                              | + +|_s_o_u_r_c_e_2.c
                              | + +|_e_t_c_._._.
                              ++++i+nclude
                              | + +|_a_p_i_1.h
                              | + +|_a_p_i_2.h
                              | + +|_e_t_c_._._.
                              ++++_p+_r_o_g_r_a_m_1
                              | + +|_s_o_u_r_c_e_3.c
                              | + +|_s_o_u_r_c_e_4.c
                              |+++-_e_t_c_._._.
                              +++_p+_r|_o_g_r_a_m_2
                                + +|_s_o_u_r_c_e_5.c
                                + +|_s_e_o_t_u_c_r_._c_._e_._6.c
                                  -

       Below the project directory is a  library  directory,  which
       contains  functions  common  to  all  of  the programs.  All
       source files in this  directory  are  to  be  compiled,  and
       linked  into  a library.  When the programs are linked, they
       will all reference this library.

       Next to the library  directory  is  the  include  directory.
       This  describes  interfaces  and data shared by the project.
       Information which is private to the internals of the library
       or  a  programs  belongs  there,  not  in the shared include
       space.

       The rest of the directories below the project directory  are
       programs  to  be built.  The sources files in each are to be
       compiled and linked, together with the  common  library,  to
       form  the  programs.   The name of the program will be taken
       from the directory.

       This is a common enough picture, repeated for many projects.
       Your  individual  projects  may vary in the details; you may
       have more directory levels below the library  directory,  or
       all   of  your  programs  may  be  below  a  single  command
       directory.  With simple changes to  the  examples  given  in
       this  chapter,  you will be able to cope with just about any
       project structure.

       _6_._1_._2  _F_i_l_e _M_a_n_i_f_e_s_t
       There are many ways of discovering the source files you  are
       working  with.   Many  configuration  management systems are
       able to give you a list of them.  For example, if  you  were
       using Aegis, you would say
            change_files =
                    [collect aegis -l cf -terse -p [project] -c [change]];
            project_files =
                    [collect aegis -l pf -terse -p [project] -c [change]];


       Peter Miller                                         Page 26





       Cook                                              User Guide



            manifest =
                    [sort [change_files] [project_files]];

       If  you were using RCS, you could find all of the RCS files,
       and reconstruct the original filenames from them, _v_i_z_:
            manifest =
                    [fromto ./%0RCS/%,v %0%
                            [collect find .  -path "*/RCS/*,v" -print]
                    ];

       Or you could simply scan the directory tree:
            manifest =
                    [fromto ./%0% %0%
                            [collect find .  ! -type d -print]
                    ];
       This is will find too much, but what  follows  will  not  be
       altered by this.  If you want to get more advanced, however,
       it helps to have an accurate primary source file manifest.

       _6_._1_._3  _C_o_m_p_i_l_i_n_g _C _S_o_u_r_c_e_s
       Recalling that the build will take place from the top of the
       source tree, this means that there it is going to have to be
       directory  components  in  the  filenames  in  the   command
       executed by Cook, and in the recipes Cook is to use.

       This  chapter  uses C examples, but the same techniques work
       just as will with Fortran or Groff, or anything else.   Most
       of  it  maps  directly;  you  may  need  to  adjust for your
       specific compiler behavior.

       This chapter starts with the  lowest  level  of  building  a
       project,  the  individual  source  files,  and works its way
       upwards, building on the examples until the  whole  project,
       including  the  library  and  all  programs  are linked in a
       single pass.

       So, when cooking C sources, you need recipes of the form
            cc = gcc;
            cc_flags = -g -Wall -O;

            %0%.o: %0%.c
            {
                    [cc] [cc_flags] -c %0%.c
                            -o [target];
            }
       The ``%0''  part  of  the  patterns  matches  zero  or  more
       directory  parts.   If  your compiler insists on putting the
       output (.o) file into the current directory (the  top  level
       one) you will need to move it, after:
            %0%.o: %0%.c
            {
                    [cc] [cc_flags] -c %0%.c;
                    mv %.o [target];
            }


       Peter Miller                                         Page 27





       Cook                                              User Guide



       But,  most  existing  sources  will be assuming that most of
       their include files are in the same directory as the  source
       files.   We  need include options to indicate this.  This is
       most easily done by using more pattern elements
            %1/%0%.o: %1/%0%.c
            {
                    [cc] [cc_flags] -I%1 -c %0%.c
                            -o [target];
            }
       Or by using the dirname of the source file
            %0%.o: %0%.c
            {
                    [cc] [cc_flags] -I[dirname %0%.c] -c %0%.c
                            -o [target];
            }
       For structures more  than  2  directories  deep,  these  two
       produce   different  options.   Depending  on  your  project
       structure, if you have deep directories, one  will  probably
       be more suitable than the other.  One elegant use for deeper
       directory structures  is  to  reflect  the  C++  inheritance
       hierarchy directly in the directory hierarchy.

       The  simple  [cc_flags]  variable  is  often not sufficient.
       Instead, you may want to replace it  with  [variable_by_path
       "cc_flags" %0%.c] which will look for several variables (all
       prefixed with "cc_flags") based on the name  of  the  source
       file.   See  the _F_u_n_c_t_i_o_n_s _L_i_b_r_a_r_y chapter for a description
       of this function.

       The common include file  will  also  need  to  be  searched.
       Because  of where the command is issued, it is rather simple
       to add the include directory, _v_i_z_:
            %0%.o: %0%.c
            {
                    [cc] [cc_flags]
                            -I[dirname %0%.c] -Iinclude
                            -c %0%.c -o [target];
            }
       It is important to note that all of these recipes,  and  the
       commands  they  execute,  are independent of the location of
       the source file.  It is possible to customize  the  cc-flags
       used,  based  on  the  target  file,  or  even the directory
       containing the file, without compromising the generality  of
       the recipe4.

       _6_._1_._4  _T_r_a_c_k_i_n_g _I_n_c_l_u_d_e _D_e_p_e_n_d_e_n_c_i_e_s
       When it comes to tracking include dependencies using _c___i_n_c_l,
       you  need  to  remember, again, that the Cook happens from a
       single place.  All of the recipes that _c___i_n_c_l writes for you
       must be _r_e_l_a_t_i_v_e _t_o _t_h_a_t _p_l_a_c_e.


       ____________________

       4. Hint:  use a function, and pass [target] as the argument.

       Peter Miller                                         Page 28





       Cook                                              User Guide



       Continuing  our  example,  and  assuming  we  are  using the
       cascade include method described in the previous chapter, we
       need include dependency files which look similar to
            cascade _p_r_o_g_r_a_m_1/_s_o_u_r_c_e_3.c =
            include/_a_p_i_1.h
            ;
       Working  backwards,  we  need  to create the dependency file
       using the following recipe:
            %0%.c.d: %0%.c
                    set nocascade
            {
                    c_incl -nc -ns -nrec
                            -I[dirname %0%.c] -Iinclude
                            %0%.c
                            -prefix "'cascade %0%.c ='"
                            -suffix "';'"
                            -o [target];
            }
       For other source languages, you will need to use the  _c___i_n_c_l
       _-_-_l_a_n_g_u_a_g_e option.

       The dependency files need to be included in the magic way so
       that Cook will build them again if they  are  out  of  date.
       This  method  needs  the  source file manifest to know their
       names.
            dep-files =
                    [addsuffix .d
                            [match_mask %0%.c [manifest] ]
                            [match_mask %0%.h [manifest] ]
                    ];
            #include-cooked [dep-files]
       These files will only be re-calculated if they  are  out  of
       date;  they  are  small  and  often  zero-length, and so are
       usually very quick to read, adding little  to  the  time  it
       takes to read the cookbook.

       Notice  that  adding  a  new  source file will automatically
       cause it to be scanned  for  include  dependencies,  without
       modification to the cookbook.

       _6_._1_._5  _L_i_n_k_i_n_g _L_i_b_r_a_r_i_e_s
       To  link  libraries  with  a  generic  recipe,  you  need  a
       generalized way of  specifying  their  contents.   A  little
       trickery with constructed variable names does the job:
            %/lib%.a: [[target]_obj]
                    set unlink
            {
                    ar cq [target] [[target]_obj];
            }
       The  right-hand-side of recipes has late binding, and we use
       the name of the target to tell us the name of  the  variable
       which  holds  all  of  the  object  files.   Assigning  this
       variable looks bizarre, but it looks  more  logical  as  you
       have more and more of them...


       Peter Miller                                         Page 29





       Cook                                              User Guide



            library/liblibrary.a_obj =
                    [fromto %0%.c %0%.o
                            [match_mask "library/%0%.c" [manifest] ]
                    ];
       The great thing about this construct is that you can build a
       loop, using Cook's loop statement, that assigns  a  variable
       for each of your libraries, if you have more than one.

       Notice   that   adding   a  new  library  source  file  will
       automatically cause it to  be  compiled  into  the  library,
       without modification to the cookbook.

       _6_._1_._6  _L_i_n_k_i_n_g _C_o_m_m_a_n_d_s
       We'll  use a similar trick for each of the programs you want
       to link...  First the link line
            bin/%: [[target]_obj]
                    set mkdir
            {
                    [cc] -o [target] [[target]_obj];
            }
       Then the objects  variable.   Note  how  we  add  a  library
       _f_i_l_e_n_a_m_e here, this will still only use the library portions
       actually referenced, not the  whole  library,  so  it  won't
       bloat your programs.
            bin/_p_r_o_g_r_a_m_obj =
                    [fromto %0%.c %0%.o
                            [match_mask _p_r_o_g_r_a_m/%0%.c [manifest] ]
                    ]
                    library/liblibrary.a
                    ;

       Notice   that   adding   a  new  program  source  file  will
       automatically cause it to be compiled and  linked  into  the
       program, without modification to the cookbook.

       The loop construct tends to obscure things, which is why the
       essential assignment was given first.   This  next  fragment
       shows the whole loop.
            programs =
                    [fromto %/main.c %
                            [match_mask %/main.c [manifest] ]
                    ];
            program_list = [programs];
            loop
            {
                    program = [head [program_list]];
                    if [not [count [program]]] then
                            loopstop;
                    program_list = [tail [program_list]];

                    bin/[program]_obj =
                            [fromto %0%.c %0%.o
                                    [match_mask [program]/%0%.c
                                            [manifest]


       Peter Miller                                         Page 30





       Cook                                              User Guide



                                    ]
                            ]
                            library/liblibrary.a
                            ;
            }
       And now tell Cook you actually want it to do something, like
       build all of the programs...
            all: [addprefix bin/ [programs]];

       Notice they way the commands variable is  constructed:  just
       adding   a   new   command   (and   its  main.c  file)  will
       automatically cause it to be built, without modification  to
       the cookbook.


       _6_._2  _P_r_i_v_a_t_e _W_o_r_k _A_r_e_a_s

       This  chapter  is  about  large projects, but large projects
       usually means large numbers of  developers.   The  directory
       structure and cookbook presented so far does not immediately
       lend itself to use by multiple developers.

       _6_._2_._1  _D_i_r_e_c_t_o_r_y _S_t_r_u_c_t_u_r_e
       The  method   suggested   here   uses   Cook's   _s_e_a_r_c_h___l_i_s_t
       functionality,  which nominates a search list of directories
       that Cook looks in to find the files named in  the  recipes.
       This  can be used to overlay a private work area on top of a
       master repository.
                       ++          +
                      ++ _R_e_p_o_s_i_t_o+_r+_y
                     +     main.+c+        _C_o_m_b_i_n_e_d _V_i_e_w
                   ++     part1+.c            main.c
                    _W_o_r_k _A_r_e_a      +         part1.c
                      main.c      ++         part2.c
                                ++
                     part2.c   +


       When recipes are run, the results are written into the  work
       area,  which  means  that  the  repository can be completely
       read-only.

       It follows from this, that the directory  structure  of  the
       work  area  exactly parallels the directory structure of the
       repository.  _E_x_c_e_p_t you only check out files into your  work
       area that you actually need to change.

       _6_._2_._2  _F_i_n_d_i_n_g _t_h_e _C_o_o_k_b_o_o_k
       Setting  the  search  list is done with a simple assignment.
       In  your  work  area,  create  a  simple  Howto.cook   file,
       containing only 3 lines:
            set mkdir;
            search_list = . /project/repository ;
            #include /project/repository/Howto.cook

       
       Peter Miller                                         Page 31





       Cook                                              User Guide



       You  only  use  this  file  if  you don't need to modify the
       cookbook itself.  You can make it work always, even  if  you
       are  modifying  the  cookbook,  by  giving  the  cookbook  a
       different  name  (main.cook),  and  changing  Howto.cook  to
       always read
            set mkdir;
            search_list = . /project/repository ;
            #include [resolve main.cook]
       The  [resolve]  function  walks the search list, looking for
       the  file5.  This gives you access to Cook's internal search
       mechanism.  However, we also need  to  modify  each  of  the
       recipes to take the search list into account.

       The   unexplained   mkdir  flag  is  used  to  request  that
       directories be automatically created  before  recipe  bodies
       are  run.   This  is  common  for  large projects, where the
       source files are structured  into  several  sub-directories,
       rather  than all lumped together in the one place.  This may
       be necessary, for example, if a .c file  in  the  repository
       needs  to  be  recompiled because a .h file in the work area
       has been changed.

       _6_._2_._3  _F_i_l_e _M_a_n_i_f_e_s_t
       The files could be in either of two  places.   You  need  to
       merge them.  Most configuration management tools do this for
       you; in this example we'll scan the directory  trees  again.
       Fortunately,  Cook comes with a tool to do this efficiently.
            all_files_in_. = ;
            #include manifest.cook
            manifest = [all_files_in_.];

            /* This reduces re-scanning to a minimum. */
            set fingerprint;

            %0manifest.cook: ["if" [in "%0" ""] "then" "." "else" "%0"]
                    set mkdir
            {
                    cook_bom /* Bill Of Materials */
                            [addprefix '--dir=' [search_list]]
                            [need] [target] ;
            }
       At the end of this fragment, the manifest variable  contains
       a complete list of all files in the directory tree(s).  This
       variable  may  then  be  taken  apart  with  the  match_mask
       function to build ingredients lists.

       The if function is different to the _i_f statement.  It allows
       you to select one of two values (the then part or  the  else
       part)  without  creating a dummy variable.  In this example,
       it would be impossible to create a dummy variable.  Remember

       ____________________

       5. The  search  list  defaults  to  just  dot  (the  current
          directory) if not set.

       Peter Miller                                         Page 32





       Cook                                              User Guide



       to  quote the if, then and else strings, otherwise Cook will
       think they are _i_f, _t_h_e_n and _e_l_s_e keywords, and  give  you  a
       syntax error.

       The  constructed  _m_a_n_i_f_e_s_t_._c_o_o_k files work for both the top-
       level directory and individual sub-directories.

       _6_._2_._4  _C_o_m_p_i_l_i_n_g _C _S_o_u_r_c_e_s
       The C compilation recipe needs to be changed to read...
            %0%.o: %0%.c
            {
                    [cc] [cc_flags]
                            [prepost "-I" /[dirname %0%.c] [search_list]]
                            [prepost "-I" "/include" [search_list]]
                            -c [resolve %0%.c]
                            -o [target];
            }
       This ensures that the rights places are searched for include
       files.

       The prepost function is used to add a prefix and a suffix to
       each of the remaining strings.  This  is  very  useful  when
       constructing  filenames,  as are the addprefix and addsuffix
       functions.

       _6_._2_._5  _T_r_a_c_k_i_n_g _I_n_c_l_u_d_e _D_e_p_e_n_d_e_n_c_i_e_s
       A  similar  change  needs  to  be  made   to   the   include
       dependencies recipe...
            %0%.c.d: %0%.c
                    set nocascade
            {
                    c_incl -nc -ns -nrec
                            [prepost "-I" /[dirname %0%.c] [search_list]]
                            [prepost "-I" "/include" [search_list]]
                            [resolve %0%.c]
                            -prefix "'cascade %0%.c ='"
                            -suffix "';'"
                            [addsuffix "-rp=" [search_list]]
                            -o [target];
            }
       Note  that  the  form  of the output of this recipe _d_o_e_s _n_o_t
       change.  This means that the recipes it writes work even  if
       you subsequently copy a file from the repository to the work
       area, or uncopy one.

       _6_._2_._6  _L_i_n_k_i_n_g _L_i_b_r_a_r_i_e_s
       The library recipe needs few modifications.
            %/lib%.a: [[target]_obj]
                    set unlink
            {
                    ar cq [target] [resolve [[target]_obj]];
            }
       The   variable   assignment   given   above   requires    no
       modifications.

       
       Peter Miller                                         Page 33





       Cook                                              User Guide



       _6_._2_._7  _L_i_n_k_i_n_g _C_o_m_m_a_n_d_s
       The command linking recipe requires few modifications.
            bin/%: [[target]_obj]
                    set mkdir
            {
                    [cc] -o [target] [resolve [[target]_obj]];
            }
       The variable assignment needs no modifications.

       _6_._3  _W_h_o_l_e _P_r_o_j_e_c_t _B_u_i_l_d _A_d_v_a_n_t_a_g_e_s

       The  advantage  of  using  a whole project build is that the
       dependency graph is complete, and the order of traversal may
       be  freely  determined  by  Cook.   Breaking  the build into
       fractured segments denies Cook access to  the  whole  graph,
       and  dictates  the  order  of traversal to one which, in the
       light of the entire graph, would be incorrect.

       It  greatly  simplifies  the  creating  of  work  areas  for
       developers, by using Cook's _s_e_a_r_c_h___l_i_s_t functionality.

       A whole project build also permits the _c_o_o_k _-_c_o_n_t_i_n_u_e option
       to work in the presence of a wider range of errors.

       The whole project build  also  permits  the  _c_o_o_k  _-_p_a_r_a_l_l_e_l
       option to parallelize more operations.

       _6_._4  _H_e_t_e_r_o_g_e_n_e_o_u_s _B_u_i_l_d

       Large    projects   frequently   involve   numerous   target
       architectures.  This may be in the form  a  multiple  native
       compilations,  performed  in  suitable hosts, or it may take
       the form of cross-compilation.

       In this example, we assume that the GNU C Compiler (GCC)  is
       being  used.  When GCC is installed as a cross compiler, the
       command names (cc, as,  ld,  _e_t_c)  are  installed  with  the
       architecture  name as a prefix.  For consistency, the native
       compiler is installed with its own architecture names  as  a
       prefix,  in  addition to the more commonly used gcc command.
       This example will exploit this normal installation practice.

       _6_._4_._1  _C_r_o_s_s _C_o_m_p_i_l_i_n_g _C _S_o_u_r_c_e_s
       In  order  to  support  cross  compiling,  the C compilation
       recipe needs to be changed to read...
            %1/%0%.o: %0%.c
                    host-binding [defined-or-null %1-hosts]
            {
                    %1-gcc [cc_flags]
                            [prepost "-I" /[dirname %0%.c] [search_list]]
                            [prepost "-I" "/include" [search_list]]
                            -c [resolve %0%.c]
                            -o [target];
            }

       
       Peter Miller                                         Page 34





       Cook                                              User Guide



       This uses the first directory element of the  _t_a_r_g_e_t  to  be
       the  architecture  name.  This allows multiple architectures
       to be compiled in the same source tree, simultaneously.

       Because of the practice of installing a duplicate GCC in the
       same form as the cross compilers, this same recipe continues
       to work for native builds.

       The _h_o_s_t_-_b_i_n_d_i_n_g line tells Cook to run the command  on  one
       of   the  hosts  nominated  in  a  variable  named  for  the
       architecture (or as  a  native  cross-compiler  of  no  such
       variable   exists).    (The   defined-or-null   function  is
       available in  the  ``functions''  library  distributed  with
       Cook.)

       Remembering  these  architectures follow the GNU convention,
       these lines could read
            i386-linux-hosts = fast faster fastest ;
       This will do two things  for  you:  first,  it  will  always
       execute  linux compiles on linux hosts even when Cook is not
       executed on one; second, it will use more than one  of  them
       when you use the --parallel option.

       It  is  possible  to use implicit ingredients recipes to say
       that all object of a given architecture depend  on  a  magic
       include file, _e_._g_.
            i386-linux/%0%.o: include/linux-special.h;
       could  be  used to say that all Linux object files depend on
       this include file.  (This is a sledge-hammer approach, and a
       more  subtle  method  is  preferable,  but  it  is sometimes
       required.)

       _6_._4_._2  _T_r_a_c_k_i_n_g _I_n_c_l_u_d_e _D_e_p_e_n_d_e_n_c_i_e_s
       Because of the cascade form of include dependency, there  is
       no  need  to do anything different for include dependencies,
       even if you  add  another  architecture  some  time  in  the
       future.

       _6_._4_._3  _L_i_n_k_i_n_g _L_i_b_r_a_r_i_e_s
       The library recipe needs few modifications.
            %1/%/lib%.a: [%/lib%.a_obj]
                    set unlink
            {
                    %1-ar cq [target] [resolve [%/lib%.a_obj]];
            }
       The    variable   assignment   given   above   requires   no
       modifications.

       _6_._4_._4  _L_i_n_k_i_n_g _C_o_m_m_a_n_d_s
       The command linking recipe requires few modifications.
            %1/bin/%: [bin/%_obj]
                    set mkdir
            {
                    %1-gcc -o [target] [resolve [bin/%_obj]];

       
       Peter Miller                                         Page 35





       Cook                                              User Guide



            }
       The variable assignment needs no modifications.

       _6_._4_._5  _W_h_a_t _t_o _B_u_i_l_d
       The list of what to build becomes more interesting.  You can
       nominate  any and all architectures for which you have cross
       compilers, or native compilers and native hosts.
            all:
                    [addprefix i386-linux/bin/ [commands]]
                    [addprefix sparc-linux/bin/ [commands]]
                    [addprefix sparc-solaris2.0/bin/ [commands]]
                    [addprefix m68k-sunos4.1.3/bin/ [commands]]
                    ;

       All of these architectures will be built in  a  single  Cook
       invocation,  on  appropriate machines if necessary.  The use
       of --continue and --parallel work over the entire  scope  of
       the build.

       _6_._5  _I_n_s_t_a_l_l_i_n_g _T_h_i_n_g_s

       The  biggest  hassle  is  that the _i_n_s_t_a_l_l(1) command, which
       should  know  how  to  do  most  installation   tasks,   has
       completely incompatible interfaces on the various platforms.
       This is why the GNU Autoconf system comes with an _i_n_s_t_a_l_l_-_s_h
       script, which faithfully emulates the BSD options.  Once you
       have a reliable command  line  interface  to  an  _i_n_s_t_a_l_l(1)
       program  (be  it  Perl or shell) you can then write sensible
       installation cookbooks.

       If we have a list of commands, we would install as follows:
            prefix = /usr/local;
            bindir = [prefix]/bin;
            install = install;

            install: [addprefix [bindir]/ [commands]];
            [bindir]/%0%: bin/%0% bin/%0.mkdir
            {
                    [install] -m 755 bin/%0% [bindir]/%0%;
            }
       That magic bin/%0.mkdir file is  used  to  record  that  the
       destination  directory  exists.   While you can often assume
       this, it is not always true when  you  are  building  things
       like RPM packages.
            bin/%0.mkdir:
            {
                    [install] -d [bindir]/%0
                            set errok;
                    touch [target];
            }
       The alternative is to use
            set mkdir;
       at  the  top of your cookbook.  This creates directories for
       targets before rules are run.  The install recipe then reads

       
       Peter Miller                                         Page 36





       Cook                                              User Guide



            set mkdir;

            [bindir]/%0%: bin/%0%
            {
                    [install] -m 755 bin/%0% [bindir]/%0%;
            }
       because  there  is no need for the ``.mkdir'' recipe.  This,
       however  gives  you  less  control  over   the   directories
       permission  modes,  and  it  doesn't  help  when you want to
       create empty directories as part of the  install.   Use  the
       appropriate technique for your needs.

       _6_._6  _M_i_s_c_e_l_l_a_n_e_o_u_s

       This  section  contains  assorted  material  that  covers  a
       variety of topics.  (As the manual expands, it will probably
       be moved somewhere else.)

       _6_._6_._1  _L_o_t_s _o_f _D_e_p_e_n_d_e_n_c_i_e_s
       There  are  cases  where  you  may  want to nominate a whole
       category of files  as  depending  on  something  else.   For
       example,  you  may  want to say that all your fubar-language
       sources  depend  on  your  fubar  compiler  You  could   say
       something such as
            cascade [match_mask %0%.fubar [manifest]] = fubarcompiler;
       but  recall  that  _e_v_e_r_y_t_h_i_n_g  which has a .fubar file as an
       ingredient will also have fubarcompiler  as  an  ingredient.
       This may not be what you wanted.

       Recall,   also,   that   compiler   recipes  carry  specific
       information.   You  could  more  specifically  nominate  the
       compiler by saying
            %0%.o: %0%.fubar: fubarcompiler
            {
                    fubarcompiler -c %0%.fubar -o [target];
            }
       which  would  be  much  more  selective  about which uses of
       .fubar files also depend on fubarcompiler.

       There are times when writing cross-compilation recipes  when
       you  want  to  nominate an operating-system-specific include
       file for all of the object files:
            %1/%0%.o: %0%.c
            {
                    /* general cross compiler recipe */
                    %1-gcc -c %0%.c -o [target];
            }
            /* All windows NT objects depend on this include file */
            i386-NT/%0%.o: winnt.h;

       You can also use _g_a_t_e_s to make you recipes  more  selective.
       The  gating  expression  may  be just about anything, but is
       often a pattern match or simple set membership.
            %.o: %.c

       
       Peter Miller                                         Page 37





       Cook                                              User Guide



                    if [in [target] foo.o bar.o]
            {
                    /* foo.o and bar.o are magic */
                    cc -DMAGIC [cc_flags] -c %.c;
            }
       The gate is most easily read as ``if  _(_t_h_i_s  _c_o_n_d_i_t_i_o_n_)  use
       this recipe''.

       _6_._6_._2  _E_r_r_o_r _P_r_o_c_e_s_s_i_n_g
       Cook  stops  processing a recipe at the first error.  If the
       error occurs when constructing a command to be executed, the
       command  is  _n_o_t  executed.   If a recipe body contains more
       than one command, and one of them gets an error (and doesn't
       have the _e_r_r_o_k flag set) the rest of the command will _n_o_t be
       executed.

       In addition, if an error occurs  while  executing  a  recipe
       body,  the  targets  of  the  recipe will be deleted (on the
       assumption that they are probably only partially  completed,
       or otherwise defective).  To override this behavior, use the
       _p_r_e_c_i_o_u_s flag.

       _6_._6_._3  _N_F_S
       A perennial problem for building projects over  networks  is
       that  the  clocks  don't  match.  If you use the _t_i_m_e_-_a_d_j_u_s_t
       flag, this problem is largely solved.  The  simplest  method
       is to put
            set time-adjust;
       at the top of your cookbook.

       File  fingerprints,  while not directly relevant to NFS, can
       offer significant  performance  improvements,  as  they  can
       eliminate many cases of unnecessary re-compilation.  To turn
       them on, use
            set fingerprint;
       at the top of your cookbook.  See below for more  discussion
       of fingerprints.

       _6_._6_._4  _S_y_m_b_o_l_i_c _L_i_n_k_s
       Symbolic  links  are  followed  to  the  actual  file,  when
       determining file modification times.  The modification  time
       of  the  symbolic  link itself is not used.  This means that
       ``symlink farms'' can be used when constructing work  areas,
       particularly  when  you want functionality more complex than
       search_list can provide.

       _6_._7  _F_i_l_e _F_i_n_g_e_r_p_r_i_n_t_s

       Cook has the ability to supplement the  last-modified  time-
       stamps  the  operating  system supplies for each file with a
       ``fingerprint''.   This  is   a   cryptographically   strong
       checksum,  with  an mind-bogglingly low probability that two
       different files will have the same fingerprint.


       
       Peter Miller                                         Page 38





       Cook                                              User Guide



       When Cook needs to know if a file has changed, it  looks  at
       the  last-modified  time-stamp.  If it has changed since the
       last time the fingerprint was calculated, the fingerprint is
       re-calculated.   If  the  fingerprints match, Cook knows the
       file contents are unchanged, and uses  the  old  time-stamp,
       and  also  suppress any recipe actions which would otherwise
       happen if the file contents  had  actually  changed.   (Cook
       remembers  the  both the new and old time-stamps, so that it
       can be efficient about re-calculating  checksums  and  still
       use the old time stamp for out-of-date calculations.)

       When  recipe  bodies  are run, Cook knows that the target(s)
       have been modified, so it doesn't  need  to  re-examine  the
       operating  system's idea of the last-modified time-stamp, it
       simply re-fingerprints.

       It is tempting  to  try  to  achieve  something  similar  by
       writing recipe bodies which only over-write their targets if
       they actually changed.  _E_._g_.
            %.o: %.c
            {
                    if [exists [target]] then
                    {
                            [CC] -o %.tmp -c %.c;
                            if cmp %.tmp %.o\;
                            then mv %.tmp %.o\;
                            else rm %.tmp;
                    }
                    else
                            [CC] -o %.o -c %.c;
            }
       However, this  will  not  work  (whether  or  not  you  have
       fingerprints  turned  on).  Largely as a defense against NFS
       time synchronization problems and stupid systems  with  very
       coarse  file  time-stamps,  Cook  ``knows'' that because the
       recipe body was run the target ``changed'', causing all down
       stream dependencies to be considered out-of-date.

       In addition, this recipe would leave the last-modified time-
       stamp out-of-date if the file was unchanged.  This means the
       recipe  would  trigger  again  in  the  next Cook execution,
       negating many of the intended savings.

       Fingerprints are intended for this  purpose,  but  have  the
       advantage  of leaving the last-modified time-stamps correct,
       and they need to do half the I/O  that  the  _c_m_p(1)  command
       does.  Also, all down stream dependent files are touched, to
       ensure their last-modified time-stamps are also  consistent.
       Naturally,  if  they  needed  to  be re-built for some other
       reason, then they would be re-built, not simply touched.

       While there is some overhead in  initially  calculating  the
       fingerprints  for  a new work area, they repay that overhead
       many times over.  This is especially true if your system has

       
       Peter Miller                                         Page 39





       Cook                                              User Guide



       generated  code in it, particularly generated include files,
       but there are also savings for simpler, smaller projects.

       _6_._7_._1  _T_u_r_n_i_n_g _F_i_n_g_e_r_p_r_i_n_t_s _O_n
       To turn fingerprints on, you need to add the lines
            set fingerprint;
            set time-adjust;
       to your cookbook.  That second line is no essential, but  it
       corrects    last-modified    time-stamps   when   NFS   time
       synchronization problems would otherwise cause  inconsistent
       behavior.

       While it is possible to turn fingerprints on for a subset of
       the files in your project, it is not as  straightforward  as
       it  may  seem.   There  is  no  way  to bind the fingerprint
       request to a single file, only to recipes, so  you  need  to
       use  the  ``set  fingerprint''  recipe  flag  on all recipes
       between the relevant source file and  the  ultimate  target.
       This tends to be messy.

       _6_._7_._2  _V_a_n_i_s_h_i_n_g _D_e_p_e_n_d_e_n_c_i_e_s
       It  is  quite common that you need to re-build a file if one
       of the dependencies is removed.  Usually, this is quite hard
       to  detect,  because  Cook has trouble seeing something that
       isn't there, compared to the previous execution.  However an
       ingenious  method  has  been  described  by  Gilles  Lamiral
       <lamiral@mail.dotcom.fr> which ``remembers'' though a file:
            function contents-remember =
            {
                    /* @1 = name of contents file */
                    /* @2..N = the value of [need] */
                    [write [args]];
            }
            function contents-changed =
            {
                    /* @1 = name of contents file *
                    /* @2..N = the value of [need] */
                    if [not [exists [resolve [@1]]]] then
                            return 0;
                    local old-contents = [collect_lines cat [resolve [@1]]];
                    /* return 0 if nothing disappeared, >0 if did disappear */
                    return [count [stringset [old-contents] - [tail [arg]]]];
            }
            libfred.a libfred.contents: [fred_obj]
                    set ["if" [contents-changed libfred.contents [fred_obj]]
                            "then" forced]
                        unlink
            {
                    ar cq [target] [resolve [fred_obj]];
                    [contents-remember libfred.contents [fred_obj]];
            }

       Note: because the set clause is evaluated when the target is
       evaluated,  the  [need]  variable is not available.  In this

       
       Peter Miller                                         Page 40





       Cook                                              User Guide



       example,  you  must  have  calculated  the  final  value  of
       [fred_obj]  before  the recipe appears in the cookbook.  The
       evaluation of the set clause also limits the application  of
       this  technique  to  explicit  recipes; it will not work for
       implicit (pattern) recipes, because the value of the pattern
       elements  is  not  known  at  the  time  the  set  clause is
       evaluated.

       _6_._8  _C_o_p_i_n_g _w_i_t_h _L_i_n_k_s

       You will notice that the default  operation  of  Cook  copes
       with  links  (hard  links and symbolic links) rather poorly.
       For example, the recipe
            two: one
            {
                    ln one two;
            }
       will always conclude that file _t_w_o is out-of-date.  This  is
       because  files _o_n_e and _t_w_o have exactly the same time stamp.

       If you specify a weaker time  constraint,  Cook  will  allow
       this  kind  of  recipe  to  be written, and _n_o_t conclude the
       files is always out of date:
            two: one(weak)
            {
                    ln one two;
            }
       The ``(weak)'' on the end of the ingredient name tells  Cook
       to use the weak edge type, rather than the strict edge type.

       This technique is useful for symbolic links, too.

       One other thing which can  be  very  useful  for  both  link
       types,  but  particularly  symbolic links to directories, is
       the ``set unlink'' recipe flag.
            two: one(weak)
                    set unlink
            {
                    ln -s one two;
            }
       This removes the target (if  necessary)  before  the  recipe
       body is run.

       _6_._9  _C_o_p_i_n_g _w_i_t_h _V_e_r_s_i_o_n _S_t_a_m_p_s

       In  some systems, the version stamp is regenerated for every
       build, but you don't want to relink zillions of  executables
       just because the version stamp has changed, but nothing else
       has.

       By using the ``(exists)'' edge type, you can tell Cook  that
       an  ingredient  is  needed  for  a given target, but that it
       should never be considered to make the  target  out-of-date.
       For example:

       
       Peter Miller                                         Page 41





       Cook                                              User Guide



            #include "c"
            all: prog1 prog2;
            version.c:
                    set forced
            {
                    date "'+#define VERSION \"%C\"'" > [target];
            }
            prog1: prog1.o mylib.a version.o(exists)
            {
                    gcc -o [target] [need];
            }
            prog2: prog2.o mylib.a version.o(exists)
            {
                    gcc -o [target] [need];
            }
       This  cookbook will generate a new _v_e_r_s_i_o_n_._c file every time
       that Cook is run, and thus a new _v_e_r_s_i_o_n_._o  file.   However,
       the  _p_r_o_g_1  and  _p_r_o_g_2  files  will  not be re-linked unless
       something else changed as well.




































       
       Peter Miller                                         Page 42





       Cook                                              User Guide



       _7_.  _C_o_o_k_b_o_o_k _L_a_n_g_u_a_g_e _D_e_f_i_n_i_t_i_o_n

       This chapter  defines  that  language  which  cookbooks  are
       written  in.  While some of its properties are similar to C,
       do not be misled.

       A number of sections appear within this chapter.

         1.  The _L_e_x_i_c_a_l _A_n_a_l_y_s_i_s section describes what the  words
             of the cookbook language look like.

         2.  The   _P_r_e_p_r_o_c_e_s_s_o_r   section   describes  the  include
             mechanism and the conditional compilation mechanism.

         3.  The _S_y_n_t_a_x _a_n_d _S_e_m_a_n_t_i_c_s section describes  how  words
             in   the  cookbook  may  be  combined  to  form  valid
             constructs (the _s_y_n_t_a_x),  and  what  these  constructs
             mean (the _s_e_m_a_n_t_i_c_s).

       The  sections are laid out in the recommended reading order.

       _7_._1  _L_e_x_i_c_a_l _A_n_a_l_y_s_i_s

       The cookbook is made of a number of recipes,  which  are  in
       turn made of words.  This section describes what constitutes
       a word, and what does not.

       _7_._1_._1  _W_o_r_d_s _a_n_d _K_e_y_w_o_r_d_s
       Words are made of sequences of almost any character, and are
       separated  by  white  space  (including  end-of-line) or the
       special symbols.  CCooookk is always case sensitive when reading
       cookbooks.

       The  characters  ::;;=={{}}[[]]  are  the  special symbols, and are
       words in themselves, needing no delimiting.

       In addition to the special symbols,  some  words,  known  as
       _k_e_y_w_o_r_d_s, have special meaning to ccooookk.  The keywords are:

           else        host-binding      loopstop      single-thread
           fail             if            return           then
         function          loop             set          unsetenv
       You will meet the keywords in later sections.

       _7_._1_._2  _E_s_c_a_p_e _S_e_q_u_e_n_c_e_s
       The  character \\ is the _e_s_c_a_p_e character.  If a character is
       preceded by a \\ any specialness, if  it  had  any,  will  be
       removed.  If it had no specialness it may have some added.

       This  means  that,  if  you want to use iiff as a word, rather
       than a keyword, at least one of its characters needs  to  be
       escaped, for example \\iiff.

       The escape sequences which are special are as follows.

       
       Peter Miller                                         Page 43





       Cook                                              User Guide



                  \\bb    The backspace character
                  \\ff    The form feed character
                  \\nn    The newline or linefeed character
                  \\rr    The carriage return character
                  \\tt    The horizontal tab character
                 \\_n_n_n   A  character with a value of _n_n_n,
                        where _n_n_n is an octal  number  of
                        at most 3 digits.
       An  escaped  end-of-line  is  totally ignored.  It should be
       noted that a cookbook may not have  any  non-printing  ASCII
       characters in it other than space, tab and end-of-line.

       _7_._1_._3  _Q_u_o_t_i_n_g
       Words, and sections of words, may be quoted.  If any part of
       a word is quoted it cannot be a keyword.

       This means that, if you want to use iiff  as  a  word,  rather
       than  a  keyword, at least one of its characters needs to be
       quoted, for example ''iiff''.

       Both single ('') and double  ("")  quotes  are  understood  by
       ccooookk,  and one may enclose the other.  If a quote is escaped
       it does not open or close a quote as it usually would.

       CCooookk does not  like  newlines  within  quotes.   This  is  a
       generally good heuristic for catching unbalanced quotes.  If
       you really want a  newline  within  a  string,  use  the  \n
       escape.

       _7_._1_._4  _C_o_m_m_e_n_t_s
       Comments  are  delimited on the left by //**, and on the right
       by **//.  If the // character has been escaped  or  quoted,  it
       doesn't  introduce  a  comment.   Comments  may  be  nested.
       Comments may span multiple lines.  Comments are replaced  by
       one logical space.

       _7_._2  _P_r_e_p_r_o_c_e_s_s_o_r

       The  preprocessor  may  be thought of as doing a little work
       before the _S_y_n_t_a_x _a_n_d _S_e_m_a_n_t_i_c_s section has its turn.

       The preprocessor is driven by  _p_r_e_p_r_o_c_e_s_s_o_r  _d_i_r_e_c_t_i_v_e_s.   A
       preprocessor  directive  is  a line which starts with a hash
       (##) character.   Each  of  the  preprocessor  directives  is
       described below.

       _7_._2_._1  _i_n_c_l_u_d_e
       The most common preprocessor directive is
            #include "_f_i_l_e_n_a_m_e"

       This  preprocessor directive is processed as if the contents
       of the named file had appeared in the cookbook, rather  than
       the preprocessor include directive.


       
       Peter Miller                                         Page 44





       Cook                                              User Guide



       The  most common use of the #include directive is to include
       system cookbooks.  For example, many small programs  can  be
       developed using the following simple cookbook:
            #include "c"
            #include "program"

       The  standard  places to search are first any path specified
       with the --IInncclluuddee command line option, and then  _$_H_O_M_E_/_._c_o_o_k
       and then _/_u_s_r_/_s_h_a_r_e_/_c_o_o_k in that order.

       _7_._2_._2  _i_n_c_l_u_d_e_-_c_o_o_k_e_d
       This directive looks similar to the one above, but do not be
       deceived.
            #include-cooked _f_i_l_e_n_a_m_e...
       You may name several filenames on the line, and they may  be
       expressions.

       The  search  path  used  for these files is the same as that
       used for other cooked files, see  the  _s_e_a_r_c_h___l_i_s_t  variable
       and the _r_e_s_o_l_v_e built-in function for more information.  The
       order in which you set the  _s_e_a_r_c_h___l_i_s_t  and  the  _#_i_n_c_l_u_d_e_-
       _c_o_o_k_e_d  directives is important.  Always set the _s_e_a_r_c_h___l_i_s_t
       variable first, if you are going to use it.

       Files included in this way are checked, after they have been
       read,  to  make  sure they are up-to-date.  If they are not,
       ccooookk brings them up-to-date and then re-reads  the  cookbook
       and starts over.

       You  will  only  get  a  warning if the files are not found.
       Usually, ccooookk will either succeed in constructing  them,  in
       which case they will be present the second time around, or a
       fatal error will result from attempting to  construct  them.
       Note that it is possible to go into an infinite loop, if the
       files are constantly out-of-date.

       The commonest use of this construct is  maintaining  include
       file dependency lists for source files.
            obj = [fromto %.c %.o [glob *.c]];

            %.o: %.c
            {
                    [cc] [cc_flags] -c %.c;
            }

            %.c.d: %.c
            {
                    c_incl -prefix "'%.o "[target]": %.c'" -suffix "';'"
                            -no-cache %.c > [target];
            }

            #include-cooked [fromto %.o %.c.d [obj]]
       This  cookbook  fragment shows how include file dependencies
       are maintained.  Notice how the _._d files have  a  recipe  to

       
       Peter Miller                                         Page 45





       Cook                                              User Guide



       construct  them, and that they are also included.  CCooookk will
       bring them up-to-date if necessary,  and  then  re-read  the
       cookbook,  so  that  it  is  always working with the current
       include dependencies.  (The  doubly  nested  quotes  are  to
       insulate  the  spaces  and special characters from both ccooookk
       and the shell.)

       You could use _g_c_c _-_M_M if you  prefer  (you  will  need  some
       extra  shell script).  The _c___i_n_c_l program understands absent
       files better but doesn't understand conditional compilation,
       and  _g_c_c understands conditional compilation but gives fatal
       errors for absent include files.  Warning: If you are  using
       _s_e_a_r_c_h___l_i_s_t  you  mmuusstt  use  _c___i_n_c_l.   Gcc  returns complete
       paths, which will result in ccooookk failing to notice  when  an
       include  file  is  copied  from  later in the search list to
       earlier, and then modified.

       There are times when  you  don't  want  the  #include-cooked
       directives to be acted upon.  You can over-ride it using the
       --no-include-cooked command line option,  but  it  is  often
       easier  to  use  the  [command-line-goals] variable, and say
       something like
            #if [not [match %1clean%2 [command-line-goals]]]
            #include-cooked [fromto %.o %.c.d [obj]]
            #endif
       This construct means that  whenever  an  explicit  ``clean''
       goal  (or  similar)  is requested, the #include-cooked lines
       will not be performed.  This is sensible,  because  cleaning
       actions  usually  remove dependency files; there is no point
       making sure they are up-to-date first.

       _7_._2_._3  _i_n_c_l_u_d_e_-_c_o_o_k_e_d_-_n_o_w_a_r_n
       This directive is almost identical to the one above, but  no
       warning is issued for absent files.
            #include-cooked-nowarn _f_i_l_e_n_a_m_e...
       You  may name several filenames on the line, and they may be
       expressions.

       _7_._2_._4  _i_f
       The #if directive may be used to conditionally  pass  tokens
       to the syntax and semantics processing.  Directives take the
       form
            #if _e_x_p_r_e_s_s_i_o_n_1
            _s_o_m_e_t_h_i_n_g_1
            #elif _e_x_p_r_e_s_s_i_o_n_2
            _s_o_m_e_t_h_i_n_g_2
            #else
            _s_o_m_e_t_h_i_n_g_3
            #endif
       There may be any number of elif clauses, and the else clause
       is  optional.   Only  one  of  the _s_o_m_e_t_h_i_n_g_s will be passed
       through.



       
       Peter Miller                                         Page 46





       Cook                                              User Guide



       _7_._2_._5  _i_f_d_e_f
       This directive takes a similar form to the if directive, but
       with a different first line:
            #ifdef _v_a_r_i_a_b_l_e
       This is syntactic sugar for
            #if [defined _v_a_r_i_a_b_l_e]
       This is of most use in bracketing #include directives.

       _7_._2_._6  _i_f_n_d_e_f
       This directive takes a similar form to the if directive, but
       with a different first line:
            #ifndef _v_a_r_i_a_b_l_e
       This is syntactic sugar for
            #if [not [defined _v_a_r_i_a_b_l_e]]
       This is of most use in bracketing #include directives.

       _7_._2_._7  _p_r_a_g_m_a
       This is for the addition of extensions.

       _7_._2_._7_._1  _o_n_c_e
       This directive is to ensure that include files in  which  it
       appears are included exactly once.

       This directive has the form
            #pragma once

       _7_._2_._7_._2  _u_n_k_n_o_w_n _e_x_t_e_n_s_i_o_n_s
       Any pragma extensions not recognized will be ignored.



























       
       Peter Miller                                         Page 47





       Cook                                              User Guide



       _7_._3  _S_y_n_t_a_x _a_n_d _S_e_m_a_n_t_i_c_s

       The syntax is described using ``train track'' diagrams, with
       prose descriptions of the related semantics.

       _7_._3_._1  _O_v_e_r_a_l_l _S_t_r_u_c_t_u_r_e
       The general form of the cookbook is defined as
        -c-o-o-k-b-o-o-k--------------------------------------------------
                        |     -----------------------     |
                             +                       +
                         -------------+-----+-------------
                                  +   --s-t-m-t-    +
                                     +--------
                                   ---function+--
                                     ---------

       A cookbook is defined as a  sequence  of  statements.   Each
       statement  statement  is executed.  For a definition of what
       it means when a statement is executed,  see  the  individual
       statement definitions.

       The  nonterminal  symbol  _s_t_a_t_e_m_e_n_t  will  be defined in the
       sections below.

       Please note that a statement is not always evaluated when is
       is read, but at specific, well defined times.

       _7_._3_._2  _T_h_e _C_o_m_p_o_u_n_d _S_t_a_t_e_m_e_n_t
       A  nonterminal symbol which will be referred to below is the
       _c_o_m_p_o_u_n_d___s_t_a_t_e_m_e_n_t symbol, defined as follows:
        cstmt            -                              -
        ---------------- -{ ---------------------------- -} --------
                              |      ---------      |
                                   +  |-----+  +
                                --------s-t-m-t---------

       The compound statement may be used anywhere a statement  may
       be, and in particular
        stmt                          +-----+
        --------------------------------c-s-t-m-t----------------------


       _7_._3_._3  _V_a_r_i_a_b_l_e_s _a_n_d _E_x_p_r_e_s_s_i_o_n_s
       CCooookk provides variables to the user to simplify things.

       _7_._3_._3_._1  _T_h_e _A_s_s_i_g_n_m_e_n_t _S_t_a_t_e_m_e_n_t
       It  is  possible  to  assign to variables with the following
       statement.
        stmt                  +----+  -   +-----+  +
        ------------------------e-x-p-r-- -= ---e-x-p-r-s-- +; --------------

       When this statement is executed, the variable whose name the
       left hand expression evaluates to will be assigned the value
       that the right hand expression list evaluates to.

       
       Peter Miller                                         Page 48





       Cook                                              User Guide



       For example:
            program_obj = foo.o bar.o baz.o;

       NNoottee:: It is possible to  over-ride  the  value  of  built-in
       functions  and variables with this statement.  This will not
       produce  an  error  message,  however  it  is  usually   not
       desirable  as it will change the meaning of the rest of your
       cookbook.

       _7_._3_._3_._2  _T_h_e _A_s_s_i_g_n_-_A_p_p_e_n_d _S_t_a_t_e_m_e_n_t
       It is possible to append to the value of variables with  the
       following statement.
        stmt                  +----+  -   +-----+  +
        ------------------------e-x-p-r-- -+=---e-x-p-r-s-- +; --------------

       When this statement is executed, the variable whose name the
       left hand  expression  evaluates  to  will  have  its  value
       appended  by  the  value that the right hand expression list
       evaluates  to.   Expression  values  are  lists  of   words,
       appending means to append to the word list; it does _n_o_t mean
       appending to the last string of the value.

       For example:
            program_obj += [glob "deeper/*.o" ];

       NNoottee:: It is possible to  over-ride  the  value  of  built-in
       functions  and variables with this statement.  This will not
       produce an error message (unless  evaluating  them  with  no
       arguments  is an error), however it is usually not desirable
       as it will change the meaning of the rest of your  cookbook.

       _7_._3_._3_._3  _T_h_e _S_e_t_e_n_v _S_t_a_t_e_m_e_n_t
       It  is  possible to assign to environment variables with the
       following statement.
         stmt             -----  +----+  -   +-----+  +
         ------- ---------s-e-t-e-n-v ---e-x-p-r-- -= ---e-x-p-r-s-- +; ----------

       When this statement is executed,  the  environment  variable
       whose  name  the  left  hand expression evaluates to will be
       assigned the value  that  the  right  hand  expression  list
       evaluates  to.   It  is  an  error  if the variable does not
       already exist.

       For example:
            setenv PATH = [getenv PATH]":"[getenv HOME]/more-bin;

       _7_._3_._3_._4  _T_h_e _S_e_t_e_n_v_-_A_p_p_e_n_d _S_t_a_t_e_m_e_n_t
       It is possible to append to  the  value  of  an  environment
       variables with the following statement.
         stmt             -----  +----+  -   +-----+  +
         ------- ---------s-e-t-e-n-v ---e-x-p-r-- -+=---e-x-p-r-s-- +; ----------

       When  this  statement  is executed, the environment variable
       whose name the left hand expression evaluates to  will  have

       
       Peter Miller                                         Page 49





       Cook                                              User Guide



       its  value  appended  by  the  value  that  the  right  hand
       expression list evaluates to.  Evaluation  is  analogous  to
       the assign-append statement.

       For example:
            setenv FRED += nurk;

       _7_._3_._3_._5  _E_x_p_r_e_s_s_i_o_n_s
       Many definitions make reference to the _e_x_p_r_, _e_l_i_s_t and _e_x_p_r_s
       nonterminal symbols.  These are defined as follows.

       The _e_l_i_s_t is a list of at least one expression,
                                     ---------
                                   +  |------  +
        -e-l-i-s-t--------------------------expr +---------------------
                                      ------

       whereas the _e_x_p_r_s is a list of zero or more expressions.
        -e-x-p-r-s-----------------------------------------------------
                                   +           +
                                     --+----+--
                                       -e-l-i-s-t-


       An expression is composed  of  words,  variable  references,
       function  invocations, or concatenation of expressions.  The
       concatenation is implied by abutting the two  parts  of  the
       expression  together, _e_._g_._: "[fred]>thing" is an indirection
       on _f_r_e_d concatenated with the literal word ">thing".
        expr                           ------
        ------------------------------ -_w-_o-_r-_d-----------------------
                             +     -   +----- -       +
                             |-----[ --elist+ ] ----- |
                             |     -   ------ -       |
                              --+----+- -----+----+--
                                --e-x-p-r-  -_c-_a-_t  --e-x-p-r-


       When an  [[_e_l_i_s_t]]  expression  is  evaluated,  the  _e_l_i_s_t  is
       evaluated  first.   If  the  result is a single word, then a
       variable of that name is searched for.  If found  the  value
       of  an expression of this form is the value of the variable.

       If there is no variable of the  given  name,  or  the  _e_l_i_s_t
       evaluated  to more than one word, the first word is taken to
       be a built-in function name.  If there  is  no  function  of
       this name it is an error.

       The _c_a_t operator works as one would expect, joining the last
       word of the left expression and the first word of the  right
       expression  together, and otherwise leaving the order of the
       expressions alone.  One usually uses  the  trivial  case  of
       single  word  expressions.  For more complex concatenations,
       see the [catenate] and [join] built-in functions.

       
       Peter Miller                                         Page 50





       Cook                                              User Guide



       _7_._3_._4  _R_e_c_i_p_e_s
       A number of forms of _s_t_a_t_e_m_e_n_t are  concerned  with  telling
       ccooookk  how  to  cook  things.   There  are  three  forms, the
       _e_x_p_l_i_c_i_t recipe, the _i_m_p_l_i_c_i_t recipe,  and  the  _i_n_g_r_e_d_i_e_n_t_s
       recipe.

       _7_._3_._5  _T_h_e _E_x_p_l_i_c_i_t _R_e_c_i_p_e _S_t_a_t_e_m_e_n_t
       The explicit recipe has the form
        stmt       +----+  +  +-----++-----+ +----++-----+-+---+
        ------------e-l-i-s-t--:+---e-x-p-r-s----f-l-a-g-s---g-a-t-e----c-s-t-m-t---u-s-e----

       The  target(s)  of  the recipe are to the left of the colon,
       and  the  ingredients,  if  any,  are  to  the  right.   The
       statements,  usually  commands, which are to be performed to
       (re)construct the target(s) are contained  in  the  compound
       statement.   The  expressions  are only evaluated into words
       when the recipe is executed.  Recipe bodies may  have  local
       variables.

       For example:
            program: [program_obj]
            {
                    /* use [need] rather than [program_obj] in case
                       there are additional ingredients recipes
                       (see below).  */
                    cc -o program [need];
            }

       The  target  expressions and recipe flags are evaluated when
       the recipe is instantiated.  The ingredients expressions and
       the  recipe  gate are evaluated at graph building time.  The
       body and use statements are executed at graph walking  time.

       The recipes also take a ``_h_o_s_t_-_b_i_n_d_i_n_g'' attribute.  See the
       chapter on Cooking in Parallel for how this is attribute  is
       written  and used.  If the host binding flag is given, it is
       always used, even when not cooking in parallel.   If  it  is
       not  given  _a_n_d you are cooking in parallel, it will default
       to the contents of the [parallel_hosts] variable.

       _7_._3_._5_._1  _R_e_c_i_p_e _F_l_a_g_s
       The _f_l_a_g_s are defined as follows.
        -f-l-a-g-s-----------------------------------------------------
                                +                 +
                                  ----- -+-----+--
                                    -s-e-t  -e-x-p-r-s--

       Recipe flags are  evaluated  when  the  recipe  targets  are
       evaluated.   At  this time, _n_o_n_e of the [target], [targets],
       [need] or [younger] variables are set, and neither  are  any
       of the pattern matches (%, %1, _e_t_c) available.

       A number of flags may be used


       
       Peter Miller                                         Page 51





       Cook                                              User Guide



       clearstat The  last-modified  time  of  the  files  named in
                 executed commands will be removed from  the  last-
                 modified   time  cache.   This  is  essential  for
                 commands such as _r_m(1) and _m_v(1).

       noclearstat Do not clear entries from the last-modified time
                 cache.  This is usually the default.

       ctime     Use  the  ctime of files as well as the mtime when
                 determining the  last-modified  time  of  a  file.
                 This is the default.

       no-ctime  Do  not  supplement  st_mtime with st_ctime.  This
                 can be important if you version control tool often
                 hard links files for efficiency.

       default   If  no  targets are specified on the command line,
                 the first recipe with the  _d_e_f_a_u_l_t  flag  will  be
                 used.  Not meaningful for implicit recipes.

       nodefault If  no  targets are specified on the command line,
                 and there are no recipes  with  the  _d_e_f_a_u_l_t  flag
                 set,  the  first recipe wwiitthhoouutt the _n_o_d_e_f_a_u_l_t flag
                 will  be  used.   Not  meaningful   for   implicit
                 recipes.

       errok     Exit status from commands will be ignored.

       noerrok   If  the  _n_o_e_r_r_o_k  flag  is specified, the commands
                 within the actions bound to the recipe must always
                 be successful.  This is usually the default.

       fingerprint File  fingerprints  are used to supplement last-
                 modified time information about  files,  which  is
                 how  _c_o_o_k  determines if a file is out-of-date and
                 needs to be cooked.  If a  file  appears  to  have
                 changed,   from  the  last-modified  time,  it  is
                 fingerprinted, and the fingerprint  compared  with
                 what  it was in the past.  The file has changed if
                 and only if the fingerprint has also  changed.   A
                 cryptographically  strong  hash  is  used,  so the
                 chance of  a  file  edit  producing  an  identical
                 fingerprint    is   less   than   1   in   2**200.
                 Fingerprinting is disabled by default.

       nofingerprint Do  not  use  file  fingerprinting.   This  is
                 usually the default.

       forced    If the _f_o_r_c_e_d flag is specified, the actions bound
                 to the recipe will always be evaluated.

       noforced  If the _n_o_f_o_r_c_e_d flag  is  specified,  the  actions
                 bound  to  the  recipe  will be evaluated when the
                 recipe is logically out-of-date.  This is  usually

       
       Peter Miller                                         Page 52





       Cook                                              User Guide



                 the default.

       gate-after-ingredients This  flags causes the recipe gate to
                 be  evaluated  after  the  ingredients  have  been
                 evaluated  and determined to be cookable.  This is
                 usually the default.

       gate-before-ingredients This flag causes the recipe gate  to
                 be  applied  before  the ingredients are evaluated
                 and determined to be cookable.  This is useful  if
                 the  ingredients  evaluation  itself  needs  to be
                 conditional.

       implicit-ingredients
                 This flag may be used to specify that  a  recipe's
                 ingredients  may be satisfied by implicit recipes.
                 This is usually the default.

       no-implicit-ingredients
                 This flag may be used to specify that  a  recipe's
                 ingredients  may  not  be  satisfied  by  implicit
                 recipes; this is of most use with  utilities  such
                 as  RCS  where  the  recipe  writer knows that the
                 ingredients cannot be constructed.

       include-cooked-warning This  flag  may  be  used  to  enable
                 warnings  when  the  relationship between a target
                 and a derived ingredient appears only in a derived
                 cookbook.  This is usually the default.  This flag
                 is only meaningful at the cookbook  level,  it  is
                 not meaningful for individual recipes or commands.

       no-include-cooked-warning This flag may be used  to  disable
                 warnings  when  the  relationship between a target
                 and a derived ingredient appears only in a derived
                 cookbook.   This  flag  is  only meaningful at the
                 cookbook  level,  it   is   not   meaningful   for
                 individual recipes or commands.

       ingredients-fingerprint This  flag  may  be  used  to  cause
                 recipes to re-trigger when their ingredients  list
                 changes  in  any  way.  This is especially useful,
                 for example, in causing libraries  to  be  rebuilt
                 when a content source file is removed.

       no-ingredients-fingerprint Cancel  any  active  _i_n_g_r_e_d_i_e_n_t_s_-
                 _f_i_n_g_e_r_p_r_i_n_t setting.

       match-mode-cook Use native Cook pattern matching.

       match-mode-regex Use  POSIX   regular   expression   pattern
                 matching.



       
       Peter Miller                                         Page 53





       Cook                                              User Guide



       meter     If  the  _m_e_t_e_r flag is specified, a summary of the
                 CPU usage by the commands within this recipe  will
                 be printed after each command.  The silent options
                 override this option.

       nometer   Do  not  meter  commands.   This  is  usually  the
                 default.

       mkdir     If the _m_k_d_i_r flag is specified, the directories of
                 any targets will be  created  before  the  actions
                 bound to the recipe are evaluated.

       nomkdir   If  the _n_o_m_k_d_i_r flag is specified, the directories
                 of any targets will need  to  be  created  by  the
                 actions  bound to the recipe.  This is usually the
                 default.

       precious  If the _p_r_e_c_i_o_u_s flag is specified, if the  actions
                 bound  to  the  recipe  fail,  the  targets of the
                 recipe will not be deleted.

       noprecious If the  _n_o_p_r_e_c_i_o_u_s  flag  is  specified,  if  the
                 actions  bound  to the recipe fail, the targets of
                 the recipe will be deleted.  This is  usually  the
                 default,  so  that  erroneous  targets will be re-
                 cooked.

       recurse   If this flag is specified,  recipes  will  recurse
                 upon   themselves  if  one  of  their  ingredients
                 matches one of  their  targets.   This  can  cause
                 problems, and so it is not the default.

       norecurse If  this  flag  is  specified, the recipe will not
                 recurse if one of its ingredients matches  one  of
                 its targets.  This is the default.

       silent    If  the  _s_i_l_e_n_t  flag  is  specified, the commands
                 within the actions bound to the recipe will not be
                 echoed.

       nosilent  Commands  will  be  echoed.   This  is usually the
                 default.

       stripdot  This option causes ccooookk  to  remove  leading  "./"
                 prefixes  from  filenames.   This  is  usually the
                 default.

       nostripdot This option causes ccooookk  to  leave  leading  "./"
                 prefixes on filenames.

       symlink-ingredients When   using   a   search  path,  of  an
                 ingredient exists, but is not in the top level  of
                 the  search  path,  this  option  request  that  a
                 symbolic link to the actual file be created in the

       
       Peter Miller                                         Page 54





       Cook                                              User Guide



                 top  level  directory.   This  option is typically
                 used on a per-recipe  basis  for  for  brain  dead
                 tools,  like GNU Automake, which don't grok search
                 paths.

       no-symlink-ingredients Reverse of the above.   Never  create
                 symbolic links for ingredients.

       tell-position This  option  causes  the  filename  and  line
                 number to be printed when  echoing  commands  just
                 before  they  are  executed,  in  addition  to the
                 command itself.

       no-tell-position This option suppresses the printing of  the
                 filename  and  line  number  when echoing commands
                 just before they are executed.   This  is  usually
                 the default.

       time-adjust This  option  causes  ccooookk  to  check  the last-
                 modified time  of  the  targets  of  recipes,  and
                 adjust  them  if  necessary, to make sure they are
                 consistent with (younger than)  the  last-modified
                 times  of  the  ingredients.  This usually adjusts
                 the file time into the (near) future.   A  warning
                 message  will  be  printed,  telling  you how many
                 seconds the file was adjusted.   This  results  in
                 more  system  calls,  and  can slow things down on
                 some systems6.

       no-time-adjust Do not adjust the  file  last-modified  times
                 after  performing  the  body of a recipe.  This is
                 usually the default.

       time-adjust-back This option causes ccooookk to force the  last-
                 modified  time  of  the  targets  of recipes to be
                 exactly one (1) second younger than their youngest
                 ingredient.   This  usually  adjusts the file time
                 into the (recent) past.  A warning message will be
                 printed, telling you how many seconds the file was
                 adjusted.  This results in more system calls,  and
                 can  slow  things  down  on some systems.  This is
                 primarily useful when some later process is  going
                 to compress file modification times; this provides
                 smarter compression.

       unlink    If the _u_n_l_i_n_k flag is specified,  of  any  targets
                 will  be  unlinked before the actions bound to the
                 recipe are performed.


       ____________________

       6. This flag was once named the ``update'' flag.   The  name
          was  changed  to  more closely reflect its function.  The
          old name continues to work.

       Peter Miller                                         Page 55





       Cook                                              User Guide



       nounlink  If the _n_o_u_n_l_i_n_k  flag  is  specified,  the  recipe
                 targets  are  not removed before the actions bound
                 to the recipe are performed.  This is usually  the
                 default.

       Each flag may also be specified in the negative, by adding a
       "no" prefix,  to  override  any  existing  positive  default
       setting.   There  is  a  strict  precedence  defined for the
       various levels of flag setting, see the end of the "How Cook
       Works" chapter for details.

       _7_._3_._5_._2  _R_e_c_i_p_e _G_a_t_e
       Each  recipe  may  have  a  _g_a_t_e.   The  gate  is  a  way of
       specifying a conditional recipe; if  the  condition  is  not
       true,  the recipe is not used.  The condition is in addition
       to the condition that the ingredients are cookable.
        -g-a-t-e------------------------------------------------------
                                 +                +
                                  ---- --+----+--
                                     -if  --e-x-p-r-


       For example:
            program: [program_obj]
                    if [not [in horrible.o [program_obj]]]
            {
                    cc -o program [program_obj];
            }

       _7_._3_._5_._3  _T_h_e_n _C_l_a_u_s_e
       There are times when it is necessary to know that  a  recipe
       has been applied, but because the recipe was up-to-date, the
       recipe body was not run.
        -u-s-e-------------------------------------------------------
                               +                   +
                                 --------+-----+--
                                   t-h-e-n- --c-s-t-m-t-

       The then-clause is run every time  the  recipe  is  applied,
       even  if the recipe is up-to-date.  It will be run after the
       recipe body, if the recipe body is run.  All  of  the  usual
       percent  (%)  substitutions  and  automatic  variables  will
       apply.  Recipe then-clauses may have local variables.

       For example:
            program: [program_obj]
            {
                    cc -o program [program_obj];
            }
            then
            {
                    install-set += program;
            }


       
       Peter Miller                                         Page 56





       Cook                                              User Guide



       _7_._3_._5_._4  _D_o_u_b_l_e _C_o_l_o_n
       Most cookbooks are constructed  so  that  if  ccooookk  finds  a
       suitable recipe for the target it is currently constructing,
       it will apply the recipe  and  then  conclude  that  it  has
       finished  constructing  the  target.  In some rare cases you
       will want ccooookk to keep going after applying  a  recipe.   To
       specify this use a ``double colon'' construction:
        stmt       +----+  +  +-----++-----+ +----++-----+-+---+
        ------------e-l-i-s-t--:+:---e-x-p-r-s----f-l-a-g-s---g-a-t-e----c-s-t-m-t---u-s-e----

       This  operates  like a normal explicit recipe, but ccooookk will
       continue on looking for recipes after applying this one.  As
       soon  as  an applicable ``single colon'' recipe is found and
       applied,  ccooookk  will   conclude   that   it   has   finished
       constructing the target.

       For example:
            all:: programs
            {
                    [print "all programs done"];
            }
            all:: libraries
            {
                    [print "all libraries done"];
            }

       _7_._3_._6  _T_h_e _I_m_p_l_i_c_i_t _R_e_c_i_p_e _S_t_a_t_e_m_e_n_t
       Implicit  recipes are distinguished from explicit recipes in
       that and implicit recipe has a target with a  '%%'  character
       in it.

       _7_._3_._6_._1  _S_i_m_p_l_e _F_o_r_m


       In  general  the  user  will rarely need to use the implicit
       recipe form, as there are a huge range of  implicit  recipes
       already defined in the system default recipes.

       An example of this recipe form is
            %: %.gz
            {
                    gzcat %.gz > %;
            }
       This recipe tells ccooookk how to use the _g_z_c_a_t(1) program.

       _7_._3_._6_._2  _C_o_m_p_l_e_x _F_o_r_m
       The implicit recipe recipe has a second form where there are
       two sets of ingredients, separated  by  another  colon.   In
       this   form,   the   ingredients   specified  in  the  first
       ingredients list are used to determine the applicability  of
       the  recipe;  if these are all constructible then the recipe
       will be applied, if  any  are  not  constructible  then  the
       recipe  will  not be applied.  If the recipe is applied, the
       ingredients specified in the  second  ingredients  list  are

       
       Peter Miller                                         Page 57





       Cook                                              User Guide



       required  to  be  constructible.  The the second ingredients
       list section is known as the _f_o_r_c_e_d _i_n_g_r_e_d_i_e_n_t_s section.

       NNoottee:: if you want the first ingredients list to be empty you
       _m_u_s_t  separate  the  two colons with a space, otherwise ccooookk
       will think this is a ``double colon'' recipe.

       An example of this is the C recipe
            %.o: %.c: [collect c_incl -api %.c]
            {
                    cc -c %.c;
            }
       This recipe is applied if the _%_._c file can  be  constructed,
       and is not applied if it cannot be constructed.  The include
       dependencies are only expressed if the recipe is going to be
       applied;   but   if   they   are  expressed,  they  _m_u_s_t  be
       constructible.   This  means  that  absent   include   files
       generate an error7.

       The naive form of this recipe
            %.o: %.c [collect c_incl -api %.c]
            {
                    cc -c %.c;
            }
       will attempt to apply the _c___i_n_c_l command before the _%_._c file
       is guaranteed to exist.   This  is  because  the  _e_x_p_r_s_2  is
       performed  after  the  _e_x_p_r_s_1  all  exist  (because they are
       constructible, they have been constructed).  In  this  naive
       form,  absent  include  files result in the recipe not being
       applied.

       _7_._3_._6_._3  _D_o_u_b_l_e _C_o_l_o_n
       Just as explicit recipes have a ``double colon'' form, so do
       both   types   of   implicit  recipes.   The  semantics  are
       identical, with ccooookk looking for more  than  one  applicable
       implicit  recipe,  but  stopping  if  it finds an applicable
       ``single colon'' implicit recipe.

       As stated earlier in  this  manual,  ccooookk  first  scans  for
       explicit  recipes  before scanning for implicit recipes.  If
       an explicit recipe has been applied, ccooookk will not also look
       for  applicable implicit recipes, even if all the applicable
       explicit recipes were double colon recipes.

       _7_._3_._7  _T_h_e _I_n_g_r_e_d_i_e_n_t_s _R_e_c_i_p_e _S_t_a_t_e_m_e_n_t
       The ingredients recipe has the form
        stmt            +----+  +  +-----++-----++----+   +
        -----------------e-l-i-s-t- +: ---e-x-p-r-s---f-l-a-g-s----g-a-t-e-- +; -------


       ____________________

       7. This  is not the recommended way of determining C include
          dependencies, see the  ``Include  Dependencies''  chapter
          for more information.

       Peter Miller                                         Page 58





       Cook                                              User Guide



       The target(s) of the recipe are to the left  of  the  colon,
       and  the  prerequisites  are  to  the  right.   There are no
       statements to perform to cook the targets of this recipe, it
       is  simply  supplementary  to  any  other recipe, usually an
       implicit recipe.

       For example:
            program: batman.o robin.o;

       The right-hand-side  expressions  are  only  evaluated  into
       words when the recipe is instantiated.

       Ingredients  recipes  are  usually  explicit, but it is also
       valid to use implicit ingredients recipes.

       For example:
            some-%-program: %.o;

       _7_._3_._8  _T_h_e _C_a_s_c_a_d_e _R_e_c_i_p_e _S_t_a_t_e_m_e_n_t
       The cascade recipe statement has the form
          stmt            ------  +----+  -   +----+  +
         ------- ---------c-a-s-c-a-d-e --e-l-i-s-t-- -= ---e-l-i-s-t- +; ----------

       This recipe  specifies  on  its  right-hand-side  additional
       ingredients  for  any recipe which has ingredients mentioned
       on the left-hand-side of this cascade recipe.

       Unlike all other recipe forms, both the  left-hand-side  _a_n_d
       the   right-hand-side  are  evaluated  when  the  recipe  is
       instantiated.

       For example:
            cascade batman.c = robin.h;
            cascade somelib.a = some-deeper-lib.a;

       _7_._3_._9  _C_o_m_m_a_n_d_s
       Commands may take several forms in ccooookk.  They all have  one
       thing in common; they execute a command.

       _7_._3_._1_0  _T_h_e _S_i_m_p_l_e _C_o_m_m_a_n_d _S_t_a_t_e_m_e_n_t
       The simplest command form is
        stmt                     +----++-----+  +
        --------------------------e-l-i-s-t---f-l-a-g-s-- +;-----------------

       When  executed,  the _e_l_i_s_t is evaluated into a word list and
       used as a command to be passed to the operating system.   On
       UNIX  this  usually means that a shell is invoked to run the
       command,  unless  the  string  contains   no   shell   meta-
       characters.

       The  _f_l_a_g_s  are those which may be specified in the explicit
       recipe statement.  They have a higher precedence than either
       the _s_e_t statement or the recipe flags.


       
       Peter Miller                                         Page 59





       Cook                                              User Guide



       Some  characters  in  commands are special both to the shell
       and to cook.   You  will  need  to  quote  or  escape  these
       characters.  Each command is executed in a separate process,
       so the cd command will not work, you will need to combine it
       with  the  relevant  commands,  not forgetting to escape the
       semicolon (;) characters.

       When Cook needs to invoke a shell to execute a  command,  it
       uses  the shell named in the SHELL environment variable.  If
       the cookbook is to be used by a variety of users, each  with
       a different shell setting, it may be useful to add a
            setenv SHELL = /bin/sh;
       line at the top of your cookbook.

       It  is also important to note that unless the _e_r_r_o_k flag has
       been specified, the shell will be given the -e option, which
       will  cause  it  to exit immediately after the first command
       which returns a non-zero exit status.  This can be important
       when  commands  in the _._p_r_o_f_i_l_e or _._b_a_s_h_r_c (or similar) file
       fails.

       _7_._3_._1_1  _T_h_e _D_a_t_a _C_o_m_m_a_n_d _S_t_a_t_e_m_e_n_t
       For programs which require _s_t_d_i_n to be supplied by  ccooookk  to
       perform their functions, the data command statement has been
       provided.
        stmt         |-----++-----+  +   ---- |-----+  ------
        ---------------e-l-i-s-t--f-l-a-g-s-- +; --d-a-t-a----e-x-p-r--d-a-t-a-e-n-d -----

       In this form, the _e_x_p_r is evaluated and used as input to the
       command.    Between   the  ddaattaa  and  ddaattaaeenndd  keywords  the
       definition of the special  symbols  and  whitespace  change.
       There  are  only  two  special  symbols,  [[  and ]], to allow
       functions  and  variable  references  to   appear   in   the
       expression.   In  addition,  whitespace  ceases  to have its
       usual specialness; it is handed to the command, instead.

       For those of you familiar with writing shell  scripts,  this
       is  analogous to _h_e_r_e documents.  It allows you to create an
       input file without creating an explicit temporary file.   It
       also  allows  you  to create files that you could not create
       using _e_c_h_o redirected into the file8.

       The  ddaattaa  keyword  must  be  the last on a line, whitespace
       after the ddaattaa keyword up to and including end-of-line, will
       _n_o_t be given to the command.

       The  ddaattaaeenndd keyword must appear alone on a line, optionally
       surrounded by whitespace; if it is not alone, it  is  not  a
       ddaattaaeenndd keyword and will not terminate the expression.


       ____________________

       8. For example, Windows NT has a ludicrously  small  command
          line length limit.

       Peter Miller                                         Page 60





       Cook                                              User Guide



       An example of this may be useful.
            /usr/fred/%: %
            {
                    newgrp fred;
            data
            cp % /usr/fred/%
            dataend
            }
       The _n_e_w_g_r_p(1) command is used to change the default group of
       a process, and then throw a shell; so the ``cp'' is executed
       by  this sub-shell when it reads its standard input.  If the
       directory _/_u_s_r_/_f_r_e_d has read-only  permissions  for  others,
       and group write permissions, and belonged to group _f_r_e_d, and
       you were a member of group _f_r_e_d, the above  implicit  recipe
       could be used to copy the file.

       Here  is  an  example  of how to cope with stupidly short NT
       command lines:
            %.LIB: [%_obj]
            {
                    cat > %.contents;
            data
            [unsplit "\n" [unix-to-dos [need]]]
            dataend
                    link -lib "/out:"[unix-to-dos [target]] @%.contents;
                    rm %.contents;
            }
       The ``@_s_o_m_e_t_h_i_n_g'' means the linker should read  file  names
       from the _s_o_m_e_t_h_i_n_g file.

       This  technique  will  also  work with Unix if you have more
       then 5MB of  command  line  arguments  _a_n_d  the  program  is
       written  to  have an option something like this (many have a
       --ff option).

       _7_._3_._1_2  _T_h_e _S_e_t _S_t_a_t_e_m_e_n_t
       It is possible to override the defaults used by ccooookk or even
       those  specified  by the _C_O_O_K environment variable, by using
       the _s_e_t statement.
       stmt                       ---  +-----+  +
       ----------------------------s-e-t---e-x-p-r-s-- +; ------------------

       The flag values are those mentioned in the _f_l_a_g_s  clause  of
       the  explicit  recipe  statement.  Many command-line options
       have  equivalent  flag  settings.   There  is  no  ``unset''
       statement,  to  restore  the  default  settings,  but  it is
       possible to set flags the other way, by adding  or  removing
       the ``no'' prefix.

       To set flags for individual recipes, use the _f_l_a_g_s clause of
       the recipe statements.

       To set flags for individual commands, use the  _f_l_a_g_s  clause
       of the command statements.

       
       Peter Miller                                         Page 61





       Cook                                              User Guide



       _7_._3_._1_2_._1  _E_x_a_m_p_l_e_s
       Fingerprinting  is not used by default, because it can cause
       a few surprises, and takes a little  more  CPU.   To  enable
       fingerprinting for you project, place the statement
            set fingerprint;
       somewhere  near  the  start  of  your  _H_o_w_t_o_._c_o_o_k file.  The
       --NNoo__FFiinnggeerrPPrriinntt command line option can still override this,
       but the default behavior will be to use fingerprints.

       To prevent echoing of commands as they are executed, place
            set silent;
       somewhere  in  your  _H_o_w_t_o_._c_o_o_k file.  The --NNooSSiilleenntt command
       line  option  can  still  override  this,  but  the  default
       behavior will be not to echo commands.

       _7_._3_._1_3  _T_h_e _F_a_i_l _S_t_a_t_e_m_e_n_t
       CCooookk  can be forced to think that a recipe has failed by the
       uses of the ffaaiill statement.
        stmt                      ---  +-----+  +
        -------------------------f-a-i-l --e-x-p-r-s---;+-----------------

       This is hugely useful when programs do not return  a  useful
       exit  status,  but  _d_o  fail.  If they have printed an error
       message, but not produced the output file, you could use the
       Fail statement without arguments:
            fred: other stuff
                    set unlink
            {
                    brain-dead [need] -o [target];
                    if [not [exists [target]]] then
                            fail;
            }

       If  you  give the Fail statement any arguments, they will be
       printed as an error message before the recipe fails:
            fred: other stuff
                    set unlink
            {
                    brain-dead [need] -o [target];
                    if [not [exists [target]]] then
                            fail Did not produce [target] file.;
            }

       _7_._3_._1_4  _T_h_e _I_f _S_t_a_t_e_m_e_n_t
       The if statement has one of two forms.
         stmt    -   +----+  ---- |-----+
         -------i-f ---e-x-p-r---t-h-e-n----s-t-m-t-------------------------
                                           +   ----  +----+  +
                                            ----e-l-s-e---s-t-m-t----


       In nested if statements, the eellssee will bind to  the  closest
       _e_l_s_e-less  _i_f.  An expression is false if and only if all of
       its words are null or it has no words.

       
       Peter Miller                                         Page 62





       Cook                                              User Guide



       Note that one or both of the subordinate statements  may  be
       compound  statements,  should you need to say something more
       complex than a single statement.

       _7_._3_._1_5  _T_h_e _L_o_o_p _a_n_d _L_o_o_p_e_n_d _S_t_a_t_e_m_e_n_t_s
       Looping is provided for in ccooookk by the generic infinite loop
       construct defined below.
        stmt                        ----  +----+
        -----------------------------l-o-o-p----s-t-m-t-------------------

       A  facility is provided to break out of a loop at any point.
        stmt                        -------   +
        ---------------------------l-o-o-p-s-t-o-p--;+-------------------

       The statement  following  the  lloooopp  directive  is  executed
       repeatedly   forever.    The   llooooppssttoopp  statement  is  only
       semantically valid within the scope of a lloooopp statement.

       Here is an example of how to use the loop statement:
            dirs = a b c d;
            src = ;

            tmp = [dirs];
            loop
            {
                    tmp_dir = [head [tmp]];
                    if [not [tmp_dir]] then
                            loopstop;
                    tmp = [tail [tmp]];
                    src = [src] [glob [tmp_dir]"/*.c"];
            }

       There is also a ``for each'' loop variant, allowing  a  more
       terse expression of exactly the same thing
            dirs = a b c d;
            src = ;

            loop tmp_dir = [dirs]
            {
                    src = [src] [glob [tmp_dir]"/*.c"];
            }
       You can use loopstop within such a loop.  Note that the loop
       body _m_u_s_t be a compound statement.

       _7_._3_._1_6  _F_u_n_c_t_i_o_n_s
       It is possible to define your own functions.

       _7_._3_._1_6_._1  _F_u_n_c_t_i_o_n _D_e_f_i_n_i_t_i_o_n
       User-defined functions are specified using something similar
       to an assignment.
        function           -------   ------   -   +-----+
        -------------------fu-n-c-t-i-o-n-- --_w-_o-_r-_d--- -= ---c-s-t-m-t-----------

       Functions must be defined before they are used.

       
       Peter Miller                                         Page 63





       Cook                                              User Guide



       You  need  to  make  sure  you  do not re-define a built-in-
       function as this may have dire consequences.

       _7_._3_._1_6_._2  _T_h_e _R_e_t_u_r_n _S_t_a_t_e_m_e_n_t


       You return values  from  a  function  by  using  the  return
       statement:
        stmt                     -----  +-----+  +
        -------------------------r-e-t-u-r-n---e-x-p-r-s---;+----------------

       Note  that  return  statements  are not meaningful outside a
       function definition.

       _7_._3_._1_6_._3  _F_u_n_c_t_i_o_n _A_r_g_u_m_e_n_t_s
       The arguments to the function  are  passed  in  the  ``arg''
       variable.   Each  argument is also separately defined in the
       ``@1'' to ``@9'' variables for direct access.  (If there are
       more  than  9,  you  will need to use ``[word _n [arg]]'' for
       argument 10 and later).  These variables are unique for each
       function invocation, even if they are nested.

       You  can  use  the  ``@1''  to  ``@9''  variables  as  local
       variables if you have no need of their values.

       All of these special names are  thread  safe  and  recursion
       safe.   Every  function  invocation  receives its own set of
       them.

       _7_._3_._1_6_._4  _E_x_a_m_p_l_e
       An example of a  function  definition  is  a  ``capitalize''
       function:
            function capitalize =
            {
                    @1 = ;
                    loop @2 = [downcase [arg]]
                    {
                            @1 += [upcase [substr 1 1 [@2]]][substr 2 99 [@2]];
                    }
                    return [@1];
            }
       This  function  capitalizes  the first letter of each of its
       arguments.

       User-defined functions are invoked in the same way a  built-
       in functions.
            host = [os node];
            Host = [capitalize [host]];

       See the ``Function Library'' section for additional function
       examples which are distributed with Cook.




       
       Peter Miller                                         Page 64





       Cook                                              User Guide



       _7_._3_._1_6_._5  _F_u_n_c_t_i_o_n _C_a_l_l _S_t_a_t_e_m_e_n_t
       User defined functions may be invoked in  the  same  way  as
       built-in functions, but they may also be invoked in the same
       way as commands, providing a form of subroutine.
        stmt                 --------  +-----+  +
        -------------------- -f-u-n-c-t-i-o-n --e-l-i-s-t---;+-----------------


       If the function return value is not zero, it  is  considered
       to fail, just as a command would fail.  The commonest use of
       this is to invoke the built-in print function for  debugging
       cookbooks.
            function print [__FILE__] [__LINE__] hello [getenv USER];

       These function calls may be used in recipe bodies, or in the
       general cookbook.

       _7_._3_._1_6_._6  _L_o_c_a_l _V_a_r_i_a_b_l_e_s
       Functions can have local variables simply by using the  word
       local  on  the left-hand-side of the assignment.  Care needs
       to be taken with the loop statement and the  +=  assignment,
       as  the variable needs to be established as a local variable
       _f_i_r_s_t.
            function capitalize =
            {
                    local result = ;
                    local tmp = ;
                    loop tmp = [downcase [arg]]
                    {
                            result += [upcase [substr 1 1 [tmp]]][substr 2 99 [tmp]];
                    }
                    return [result];
            }
       Functions may have as many local variables as they like.

       Local variables are  reentrant.   You  can  write  recursive
       functions,  and  each  invocation  of  the  function  has an
       independent set of local variables.

       Local variables are thread-safe.  You can use the same user-
       defined  function  in  two parallel threads, and their local
       variables are completely independent.

       The ``arg'' and ``@1'' to ``@9''  variables  are  implicitly
       local.










       
       Peter Miller                                         Page 65





       Cook                                              User Guide



       _8_.  _B_u_i_l_t_-_I_n _F_u_n_c_t_i_o_n_s

       This chapter defines each of the built-in functions of _c_o_o_k.

       A built-in function is invoked by using an expression of the
       form
            [[_f_u_n_c_-_n_a_m_e _a_r_g _a_r_g ...]]
       in most places where a literal word is valid.

       _8_._1  _a_d_d_p_r_e_f_i_x

       The  _a_d_d_p_r_e_f_i_x function is used to add a prefix to a list or
       words.  This function requires at least one  argument.   The
       first  argument  is  a  prefix to be added to the second and
       subsequent arguments.

       _8_._1_._1  _S_e_e _A_l_s_o
       addsuffix, patsubst, prepost, subst

       _8_._2  _a_d_d_s_u_f_f_i_x

       The _a_d_d_s_u_f_f_i_x function is used to add a suffix to a list  or
       words.   This  function requires at least one argument.  The
       first argument is a suffix to be added  to  the  second  and
       subsequent arguments.

       _8_._2_._1  _S_e_e _A_l_s_o
       addprefix, patsubst, prepost, subst

       _8_._3  _a_n_d

       This function requires at least two arguments, upon which it
       forms a logical conjunction.   The  value  returned  is  "1"
       (true) if none of the arguments are "" (false), otherwise ""
       (false) is returned.

       _8_._3_._1  _E_x_a_m_p_l_e
       The following cookbook fragment shows how to use  the  [and]
       function in conditional recipes.
            #if [and [defined change] [defined baseline]]
            _._._._d_o _s_o_m_e_t_h_i_n_g_._._.
            #endif
       This  fragment will only _d_o _s_o_m_e_t_h_i_n_g if both the _c_h_a_n_g_e and
       _b_a_s_e_l_i_n_e variables are defined.

       _8_._3_._2  _C_a_v_e_a_t
       This function is rather clumsy, and  probably  needs  to  be
       replaced  by  a  better  syntax  within  the cokbook grammar
       itself.

       This function does not short-circuit evaluation.




       
       Peter Miller                                         Page 66





       Cook                                              User Guide



       _8_._3_._3  _S_e_e _A_l_s_o
       or, not

       _8_._4  _b_a_s_e_n_a_m_e

       The _b_a_s_e_n_a_m_e treats each argument as filenames, and extracts
       all  but  the  suffix  of  each  filename.   If the filename
       contains a period, the basename is everything up to (but not
       including)  the  period.   Otherwise,  the  basename  is the
       entire filename.

       Please note: this is not  the  same  behavior  as  the  Unix
       _b_a_s_e_n_a_m_e(1)  utility.  For this, [basename [notdir _a_r_g_s]] or
       [fromto %0%.c %0% _a_r_g_s] may be more appropriate.

       _8_._4_._1  _E_x_a_m_p_l_e


                   Expression               Result
                   -------------------------------------
                   [basename foo.c]         foo
                   [basename foo/bar.c]     foo/bar
                   [basename baz]           baz
                   [basename foo/bar/baz]   foo/bar/baz

       _8_._4_._2  _S_e_e _A_l_s_o
       addsuffix, dirname, entryname, fromto, notdir, suffix

       _8_._4_._3  _C_a_v_e_a_t
       This function is almost nothing like the Unix command of the
       same  name.   It  operates  in this manner for compatibility
       with other packages.

       _8_._5  _c_a_n_d_o

       This function is used to test whether Cook knows how to cook
       the  given  targets.   It  returns  all of the arguments for
       which derivations can be found, or nothing if none can.

       _8_._5_._1  _C_a_v_e_a_t
       This will use as much of the cookbook as has been read in up
       to  the  point  where  this function is used.  This can mean
       that crucial recipes have yet to be parsed and instantiated.

       _8_._5_._2  _S_e_e _A_l_s_o
       cook, uptodate









       
       Peter Miller                                         Page 67





       Cook                                              User Guide



       _8_._6  _c_a_t_e_n_a_t_e

       This  function  requires  zero  or  more  arguments.   If no
       arguments are supplied, the result is an  empty  word  list.
       If  one or more arguments are supplied, the result is a word
       list of  one  word  being  the  catenation  of  all  of  the
       arguments.

       _8_._6_._1  _E_x_a_m_p_l_e


                    Expression      Result
                    ----------------------------------
                    [catenate a]    a
                    [catenate a b]  ab
                    [catenate a " " b]      "a b"
       Quotes used in the results for clarity.

       _8_._6_._2  _S_e_e _A_l_s_o
       split, unsplit, prepost, join

       _8_._7  _c_o_l_l_e_c_t___l_i_n_e_s

       The  arguments  are interpreted as a command to be passed to
       the operating system.  The result is  one  "word"  for  each
       line of the output of the command.

       _8_._7_._1  _E_x_a_m_p_l_e
       To read each line of a file into a variable:
            files = [collect_lines cat file];
       Spaces  and tabs in the input lines will be preserved in the
       "words" of the result.

       _8_._7_._2  _S_e_e _A_l_s_o
       collect, execute, glob, read, read_lines, write

       _8_._7_._3  _C_a_v_e_a_t
       You will probably get better performance using the #include-
       cooked  directive, and a recipe to create the included file.
















       
       Peter Miller                                         Page 68





       Cook                                              User Guide



       _8_._8  _c_o_l_l_e_c_t

       The arguments are interpreted as a command to be  passed  to
       the  operating  system.   The  result  is  one word for each
       white-space separated word of the output of the command.

       The command will not be echoed unless the -No_Silent  option
       is specified on the command line.

       _8_._8_._1  _E_x_a_m_p_l_e
       Read the date and time and assign it to a variable:
            now = [collect date];
       Do  not  use  the  collect  function  to  expand  a filename
       wildcard, used the [glob] function instead.

       _8_._8_._2  _S_e_e _A_l_s_o
       collect_lines, execute, glob, read, read_lines, write

       _8_._8_._3  _A_l_s_o _K_n_o_w_n _A_s
       shell

       _8_._9  _c_o_o_k

       This function requires one or more arguments,  filenames  to
       be  tested to see if they are up-to-date, and be brought up-
       to-date if they are not.  The result are true ("1")  if  the
       files  are (now) up-to-date, or false ("") if they could not
       be built.

       _8_._9_._1  _C_a_v_e_a_t
       This will use as much of the cookbook as has been read in up
       to  the  point  where  this function is used.  This can mean
       that crucial recipes have yet to be parsed and instantiated.

       This  function works one argument at a time.  This is slower
       than the  main  cookbook,  which  will  pursue  all  targets
       simultaneously.

       _8_._9_._2  _S_e_e _A_l_s_o
       cando, uptodate















       
       Peter Miller                                         Page 69





       Cook                                              User Guide



       _8_._1_0  _c_o_u_n_t

       This  function  requires zero or more arguments.  The result
       is a word list of one word containing the  (decimal)  length
       of the argument word list.

       _8_._1_0_._1  _E_x_a_m_p_l_e
       This  cookbook fragment echoes the number of files, and then
       the name of the last file:
            echo There are [count [files]] files.;
            echo The last file is [word [count [files]] [files]].;

       _8_._1_0_._2  _S_e_e _A_l_s_o
       head, tail, word

       _8_._1_0_._3  _A_l_s_o _K_n_o_w_n _A_s
       words

       _8_._1_1  _d_e_f_i_n_e_d

       This function requires a single  argument,  the  name  of  a
       variable  to be tested for existence.  It returns "1" (true)
       if the named variable is defined and ""  (false)  if  it  is
       not.

       _8_._1_1_._1  _E_x_a_m_p_l_e
       This  function is most often seen in conditional portions of
       cookbooks:
            if [defined baseline] then
                    cc_flags = [cc_flags] -I[baseline];

       _8_._1_2  _d_i_r_n_a_m_e

       This function requires one or more arguments, the  names  of
       files which will have their directory parts extracted.

       _8_._1_2_._1  _E_x_a_m_p_l_e


                        Expression      Result
                        ---------------------------
                        [dirname a]     _`_p_w_d_`
                        [dirname a/b]   a
                        [dirname a/b/c] a/b
       When  the answer would be ``.'' (the current directory), the
       result  is  instead  the  absolute  path  of   the   current
       directory.   This  allows repeated [dirname] applications to
       climb the directory tree, no matter where  you  start.   See
       _r_e_l_a_t_i_v_e___d_i_r_n_a_m_e for one which returns ``.'' instead.

       _8_._1_2_._2  _S_e_e _A_l_s_o
       basename,  entryname,  notdir,  pathname,  relative_dirname,
       suffix


       
       Peter Miller                                         Page 70





       Cook                                              User Guide



       _8_._1_2_._3  _A_l_s_o _K_n_o_w_n _A_s
       dir

       _8_._1_3  _d_i_r

       This function requires one or more arguments, the  names  of
       files which will have their directory parts extracted.

       _8_._1_3_._1  _E_x_a_m_p_l_e


                        Expression      Result
                        ---------------------------
                        [dir a] .
                        [dir a/b]       a
                        [dir a/b/c]     a/b

       _8_._1_3_._2  _S_e_e _A_l_s_o
       basename,  entryname,  notdir,  pathname,  relative_dirname,
       suffix

       _8_._1_3_._3  _A_l_s_o _K_n_o_w_n _A_s
       dirname

       _8_._1_4  _d_o_s_-_p_a_t_h

       This function requires one or more arguments, which will  be
       converted from a UNIX path into a DOS path.  This is of most
       use under Windows-NT, to convert Cook's  internal  pathnames
       into  DOS  pathnames.  (The UNIX porting layer usually hides
       this from Cook.)

       _8_._1_4_._1  _E_x_a_m_p_l_e


                Expression                  Result
                -------------------------------------------
                [dos-path a/b/c]            a\b\c
                [dos-path //c/temp]         c:\temp
                [dos-path //server/stuff]   \\server\stuff

       _8_._1_4_._2  _S_e_e _A_l_s_o
       un-dos-path












       
       Peter Miller                                         Page 71





       Cook                                              User Guide



       _8_._1_5  _d_o_w_n_c_a_s_e

       This function requires one or more arguments,  words  to  be
       forced into lower case.

       _8_._1_5_._1  _E_x_a_m_p_l_e


                        Expression      Result
                        ---------------------------
                        [downcase FOO]  foo
                        [downcase Bar]  bar
                        [downcase baz]  baz

       _8_._1_5_._2  _S_e_e _A_l_s_o
       upcase

       _8_._1_6  _e_n_t_r_y_n_a_m_e

       This  function  requires one or more arguments, the names of
       files which will have their entry name parts extracted.

       _8_._1_6_._1  _E_x_a_m_p_l_e


                    Expression      Result
                    ----------------------------------
                    [entryname foo.c]       foo.c
                    [entryname foo/bar.c]   bar.c
                    [entryname baz] baz

       _8_._1_6_._2  _S_e_e _A_l_s_o
       basename, dir, suffix

       _8_._1_6_._3  _A_l_s_o _K_n_o_w_n _A_s
       notdir

       _8_._1_7  _e_x_e_c_u_t_e

       This function requires at least one argument,  and  executes
       the command given by the arguments.  If the executed command
       returns non-zero exit  status  the  resulting  value  is  ""
       (false), otherwise it is "1" (true).

       The  command will not be echoed unless the -No_Silent option
       is specified on the command line.

       _8_._1_7_._1  _C_a_v_e_a_t
       This function is not often required as its functionality  is
       available in a more useful form as recipe bodies.

       _8_._1_7_._2  _E_x_a_m_p_l_e
       To  get  access  to  a  wide  range of Unix command, such as
       _t_e_s_t(1), you can use this function in conditionals

       
       Peter Miller                                         Page 72





       Cook                                              User Guide



            if [not [test -d fubar]] then
            {
                    rm -f fubar;
                    mkdir fubar;
            }

       _8_._1_7_._3  _S_e_e _A_l_s_o
       collect

       _8_._1_8  _e_x_i_s_t_s

       This function requires one argument, being  the  name  of  a
       file  to  test for existence.  The resulting word list is ""
       (false) if the file does not exist, and "1"  (true)  if  the
       file does exist.

       _8_._1_8_._1  _E_x_a_m_p_l_e
       To remove the target of a recipe before building it again:
            %.a: [%_obj]
            {
                    if [exists [target]] then
                            rm [target]
                                    set clearstat;
                    [ar] qc [target] [%_obj];
            }
       Note:  you  _m_u_s_t use the clearstat, because otherwise cook's
       "stat cache" will be incorrect.

       This is only an example.   It  is  better  to  perform  this
       particular  activity  using  the  ``unlink''  flag.  See the
       [find_command] function, below, for an example.

       _8_._1_8_._2  _S_e_e _A_l_s_o
       cando, find_command, uptodate

       _8_._1_9  _e_x_i_s_t_s_-_s_y_m_l_i_n_k

       This function requires one argument, being  the  name  of  a
       file  to  test  for  existence.   The  test  will _n_o_t follow
       symbolic links, so it may be used to test for the  existence
       of symbolic links themselves.  The resulting word list is ""
       (false) if the file does not exist, and "1"  (true)  if  the
       file does exist.

       _8_._1_9_._1  _S_e_e _A_l_s_o
       exists, readlink









       
       Peter Miller                                         Page 73





       Cook                                              User Guide



       _8_._2_0  _e_x_p_r

       This  function  may  be  used  to  calculate  simple integer
       arithmetic expressions.  The numbers and the  operators  are
       expected  to  each  be a separate argument.  The result is a
       string containing the value of the evaluated expression.

       _8_._2_0_._1  _O_p_e_r_a_t_o_r_s
       The following operators are understood.  They have the  same
       precedence as the equivalent C operators.

                        Operator    Associativity
                        --------------------------
                        ( )              ->
                        ! ~ -            <-
                        * / %            ->
                        + -              ->
                        << >>            ->
                        < <= > >=        ->
                        == !=            ->
                        &                ->
                        ^                ->
                        |                ->
                        &&               ->
                        ||               ->
                        ?:               <-
       Please note that there is no short-circuit evaluation of the
       ?: or && or || operators.

       You may need to quote some of  the  operators,  to  insulate
       them  from their usual Cook interpretation (colon and equals
       characters in particular).

       Numbers may be given in decimal, octal (with a 0 prefix), or
       hexadecimal  (with  a  0x  prefix).   The  result  is always
       decimal.

       _8_._2_0_._2  _S_e_e _A_l_s_o
       count
















       
       Peter Miller                                         Page 74





       Cook                                              User Guide



       _8_._2_1  _f_i_l_t_e_r___o_u_t

       This function requires one or  more  arguments.   The  first
       argument  is  a  pattern, the second and later arguments are
       strings  to  match  against  this  pattern.   The  resulting
       wordlist  contains  those  arguments which did not match the
       pattern given as the first argument.

       _8_._2_1_._1  _E_x_a_m_p_l_e


                   Expression                  Result
                   ------------------------------------
                   [filter_out %.c a.c a.o]    a.o
                   [filter_out %.cc a.c a.o]   a.c a.o

       _8_._2_1_._2  _M_a_t_c_h _M_o_d_e
       This function is affected by the selected match  mode.   See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.

       _8_._2_1_._3  _S_e_e _A_l_s_o
       filter, stringset

       _8_._2_2  _f_i_l_t_e_r

       This  function  requires  one  or more arguments.  The first
       argument is a pattern, the second and  later  arguments  are
       strings  to  match  against  this  pattern.   The  resulting
       wordlist contains those arguments which matched the  pattern
       given as the first argument.

       _8_._2_2_._1  _E_x_a_m_p_l_e


                      Expression              Result
                      -------------------------------
                      [filter %.c a.c a.o]    a.c
                      [filter %.cc a.c a.o]

       _8_._2_2_._2  _M_a_t_c_h _M_o_d_e
       This  function  is affected by the selected match mode.  See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.

       _8_._2_2_._3  _S_e_e _A_l_s_o
       filter_out, stringset

       _8_._2_2_._4  _A_l_s_o _K_n_o_w_n _A_s
       match_mask







       
       Peter Miller                                         Page 75





       Cook                                              User Guide



       _8_._2_3  _f_i_n_d___c_o_m_m_a_n_d

       This function requires at  least  one  argument,  being  the
       names  of  commands  to  search for in $PATH.  The resulting
       word list contains either "" (false) or  a  fully  qualified
       path name for each command given.

       _8_._2_3_._1  _E_x_a_m_p_l_e
       Some  systems  require  _r_a_n_l_i_b(1) to be run on archives, and
       some do not.  Here is a simple way to test:
            ranlib = [find_command ranlib];

            %.a: [%_obj]
                    set unlink
            {
                    ar qc [target] [%_obj];
                    if [ranlib] then
                            [ranlib] [target];
            }

       _8_._2_3_._2  _S_e_e _A_l_s_o
       cando, exists, uptodate

       _8_._2_4  _f_i_n_d_s_t_r_i_n_g

       The findstring function is used  to  match  a  fixed  string
       against  a set of strings.  This function takes at least one
       argument.  The first  argument  is  the  fixed  string,  the
       second  and  subsequent  arguments  are  matched against the
       first.  The result contains one word for each of the  second
       and  subsequent  arguments,  each  will  either be the empty
       string (false) or the string to be matched, if a  match  was
       found.

       _8_._2_4_._1  _E_x_a_m_p_l_e


                      Expression             Result
                      -------------------------------
                      [findstring a a b c]   a "" ""
                      [findstring a b c]     "" ""
       Quotes  are  for  clarity,  to  emphasize the empty strings.
       Because the empty string is "false", this can be used in  an
       _i_f statement:
            if [findstring fish [sources]] then
                    sources = [sources] hook.c;

       _8_._2_4_._2  _S_e_e _A_l_s_o
       filter-out, match, match_mask, patsubst, stringset, subst






       
       Peter Miller                                         Page 76





       Cook                                              User Guide



       _8_._2_5  _f_i_r_s_t_w_o_r_d

       This function requires zero or more arguments.  The wordlist
       returned is empty if there were no arguments, or  the  first
       argument if there were arguments.

       _8_._2_5_._1  _E_x_a_m_p_l_e
       You  can  iterate  along  a  list  using  the _l_o_o_p statement
       combined with the _f_i_r_s_t_w_o_r_d and _t_a_i_l functions:
            dirs = a b c d;
            src = ;

            tmp = [dirs];
            loop
            {
                    tmp_dir = [firstword [tmp]];
                    if [not [tmp_dir]] then
                            loopstop;
                    tmp = [tail [tmp]];
                    src = [src] [glob [tmp_dir]"/*.c"];
            }
       More efficient ways exist to do this, this an example  only.

       _8_._2_5_._2  _S_e_e _A_l_s_o
       count, glob, fromto, prepost, tail, word

       _8_._2_5_._3  _A_l_s_o _K_n_o_w_n _A_s
       head

       _8_._2_6  _f_r_o_m_t_o

       This function requires at least two arguments.  Fromto gives
       the user access to the pattern transformations available  to
       ccooookk.   The  first  argument  is the "from" form, the second
       argument is the "to" form.  All other arguments  are  mapped
       from one to the other.

       _8_._2_6_._1  _E_x_a_m_p_l_e
       Given  a  list  of C source files, generate a list of object
       files as follows:
            obj = [fromto %.c %.o [src]];

       _8_._2_6_._2  _S_e_e _A_l_s_o
       filter, filter_out, subst

       See the pattern matching chapter for more information  about
       patterns.

       _8_._2_6_._3  _M_a_t_c_h _M_o_d_e
       This  function  is affected by the selected match mode.  See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.




       
       Peter Miller                                         Page 77





       Cook                                              User Guide



       _8_._2_6_._4  _A_l_s_o _K_n_o_w_n _A_s
       patsubst

       _8_._2_7  _g_e_t_e_n_v

       Each argument is treated  as  the  name  of  an  environment
       variable.    The  result  is  the  value  of  each  argument
       variable, or ""  if  it  does  not  exist  (consistent  with
       command shell behaviour).

       _8_._2_7_._1  _E_x_a_m_p_l_e
       To read the value of the TERM environment variable:
            term = [getenv TERM];

       Values  of  variables  are  not  automagically  set from the
       environment, you must set each one explicitly:
            cc = [getenv CC];
            if [not [cc]] then
                    cc = gcc;

       _8_._2_7_._2  _S_e_e _A_l_s_o
       find_command, home

       _8_._2_8  _g_l_o_b

       Each argument is treated as a _s_h(1) file name  pattern,  and
       expanded  accordingly.   The  resulting list of filenames is
       sorted lexicographically.

       You may  need  to  quote  the  pattern,  to  protect  square
       brackets from the meaning cook attaches to them.

       NNoottee:: The character sequence /* is a comment introducer, and
       is a frequent source of problems when combined with the _g_l_o_b
       function.   Remember to quote _g_l_o_b arguments which need this
       character sequence.  See the [head] function, below, for  an
       example of this.

       _8_._2_8_._1  _E_x_a_m_p_l_e
       To find the sources in the current directory:
            src = [glob *.c];
            obj = [fromto %.c %.o [src]];

       _8_._2_8_._2  _S_e_e _A_l_s_o
       filter, filter_out, shell

       _8_._2_8_._3  _A_l_s_o _K_n_o_w_n _A_s
       wildcard







       
       Peter Miller                                         Page 78





       Cook                                              User Guide



       _8_._2_9  _h_e_a_d

       This function requires zero or more arguments.  The wordlist
       returned is empty if there were no arguments, or  the  first
       argument if there were arguments.

       _8_._2_9_._1  _E_x_a_m_p_l_e
       You  can  iterate  along  a  list  using  the _l_o_o_p statement
       combined with the _h_e_a_d and _t_a_i_l functions:
            dirs = a b c d;
            src = ;

            tmp = [dirs];
            loop
            {
                    tmp_dir = [head [tmp]];
                    if [not [tmp_dir]] then
                            loopstop;
                    tmp = [tail [tmp]];
                    src = [src] [glob [tmp_dir]"/*.c"];
            }
       More efficient ways exist to do this, this an example  only.

       _8_._2_9_._2  _S_e_e _A_l_s_o
       count, glob, fromto, prepost, tail, word

       _8_._2_9_._3  _A_l_s_o _K_n_o_w_n _A_s
       firstword

       _8_._3_0  _h_o_m_e

       The  _h_o_m_e function is used to find the home directory of the
       named users.  You may name more than one user.  If no  users
       are  named,  it  returns  the  home directory of the current
       user.

       _8_._3_1  _i_f

       This function requires one or more arguments, the  arguments
       before  the  "then"  word  are  used as a condition.  If the
       condition is true the words between the "then" word and  the
       "else"  word  are  the result, otherwise the words after the
       "else" word are the value.  The "else" clause  is  optional.
       There is no way to escape the "then" and "else" words.

       _8_._3_1_._1  _E_x_a_m_p_l_e
       Here is an example of the ``if'' function.  Please note that
       ``if'', ``then'' and ``else'' are  reserved  words,  so  you
       need  to  quote  them  before they will be recognised on the
       function context.
            %: %_obj
                    set ["if" [defined all_shallow] "then" shallow]
            {
                    [cc] -o [target] [%_obj];

       
       Peter Miller                                         Page 79





       Cook                                              User Guide



            }

       _8_._3_1_._2  _C_a_v_e_a_t
       It is often clearer  to  use  the  _i_f  _s_t_a_t_e_m_e_n_t  than  this
       function.

       The  recipe  flags  are  evaluated  at  the same time as the
       recipe targets.  None of the  [target],  [targets],  [need],
       [younger]  variables or pattern matches (%, %1, _e_t_c) are set
       at this time.

       _8_._3_2  _i_n

       This function requires one or more arguments.  The  wordlist
       returned is a single word: the index of the matching word (1
       based) if the first argument is equal to any  of  the  later
       ones; or "" (false) if not.

       This  function  can  also be used for equality testing, just
       use a single element in the set.

       Because it returns the index, the return valus can  be  used
       with the _[_w_o_r_d_] or _[_w_o_r_d_s_] functions.

       _8_._3_2_._1  _E_x_a_m_p_l_e
       Frequently seen in conditional parts of recipes:
            %: [%_obj]
            {
                    [cc] -o [target] [%_obj];
                    if [in [target] [private]] then
                            chmod og-rwx [target];
            }

       _8_._3_2_._2  _S_e_e _A_l_s_o
       stringset, word, words

       _8_._3_3  _i_n_t_e_r_i_o_r___f_i_l_e_s

       This  function  requires  zero arguments.  The result is the
       list of files which are interior to  the  dependency  graph.
       (Files which are constructed by a recipe.)  This function is
       only meaningful within a recipe body.

       _8_._3_3_._1  _S_e_e _A_l_s_o
       leaf_files    function,    graph_interior_file     variable,
       graph_interior_pattern variable









       
       Peter Miller                                         Page 80





       Cook                                              User Guide



       _8_._3_4  _j_o_i_n

       The  _j_o_i_n  function  is  used  to  join  two sets of strings
       together,  element  by  element.   The  argument  list  must
       contain  an  even  number  of arguments, with the first half
       joined pair-wise with the last half.  There is no marker  of
       any kind between the lists, so the user needs to ensure they
       are both the same length.

       _8_._3_4_._1  _E_x_a_m_p_l_e


                         Expression       Result
                         ------------------------
                         [join a b c d]   ac bd
                         [join a b]       ab

       _8_._3_4_._2  _S_e_e _A_l_s_o
       basename, catenate, suffix

       _8_._3_5  _l_e_a_f___f_i_l_e_s

       This function requires zero arguments.  The  result  is  the
       list  of  files  which  are  leaves of the dependency graph.
       (Files  which  are  not  constructed  by  a  recipe.)   This
       function is only meaningful within a recipe body.

       _8_._3_5_._1  _S_e_e _A_l_s_o
       interior_files     function,    graph_leaf_file    variable,
       graph_leaf_pattern variable

       _8_._3_6  _m_a_t_c_h_e_s

       This function requires one or  more  arguments.   The  first
       argument  is  a  pattern, the second and later arguments are
       strings  to  match  against  the  pattern.   The   resulting
       wordlist  contains  ""  (false)  if  did  not  match and the
       1-based list index (true) if it did.

       The returned list index may be used in combination with  the
       [words] function.

       _8_._3_6_._1  _E_x_a_m_p_l_e
       This  function  may be used to test for strings which have a
       particular form:
            if [matches %1C%2 [version]] then
                    cc_flags = [cc_flags] -DDEBUG
       If the version contains a Capital-C character, then turn  on
       debugging.

       _8_._3_6_._2  _M_a_t_c_h _M_o_d_e
       This  function  is affected by the selected match mode.  See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.


       
       Peter Miller                                         Page 81





       Cook                                              User Guide



       _8_._3_6_._3  _S_e_e _A_l_s_o
       filter, filter-out, words

       _8_._3_7  _m_a_t_c_h___m_a_s_k

       This function requires one or  more  arguments.   The  first
       argument  is  a  pattern, the second and later arguments are
       strings  to  match  against  this  pattern.   The  resulting
       wordlist  contains those arguments which matched the pattern
       given as the first argument.

       _8_._3_7_._1  _E_x_a_m_p_l_e


                    Expression                  Result
                    -----------------------------------
                    [match_mask %.c a.c a.o]    a.c
                    [match_mask %.cc a.c a.o]

       _8_._3_7_._2  _M_a_t_c_h _M_o_d_e
       This function is affected by the selected match  mode.   See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.

       _8_._3_7_._3  _S_e_e _A_l_s_o
       filter-out, findstring, stringset

       _8_._3_7_._4  _A_l_s_o _K_n_o_w_n _A_s
       filter

       _8_._3_8  _m_t_i_m_e

       This  function  requires one argument, the name of a file to
       fetch the last-modified time of.  The resulting wordlist  is
       ""  (false)  is  the  file  does  not  exist,  or  a  string
       containing a (sortable) representation of the date and  time
       the files were last modified.

       _8_._3_8_._1  _S_e_e _A_l_s_o
       exists, mtime-seconds, sort_newest

       _8_._3_9  _m_t_i_m_e_-_s_e_c_o_n_d_s

       This  function  requires one argument, the name of a file to
       fetch the last-modified time of.  The resulting wordlist  is
       ""  (false)  is  the  file  does  not  exist,  or  a  string
       containing number of seconds since the epoch that the  files
       were  last  modified.   This is more useful than [mtime] for
       doing arithmetic on.

       _8_._3_9_._1  _S_e_e _A_l_s_o
       exists, expr, mtime, sort_newest




       
       Peter Miller                                         Page 82





       Cook                                              User Guide



       _8_._4_0  _n_o_t_d_i_r

       This function requires one or more arguments, the  names  of
       files which will have their entry name parts extracted.

       _8_._4_0_._1  _E_x_a_m_p_l_e


                    Expression      Result
                    ----------------------------------
                    [notdir foo.c]  foo.c
                    [notdir foo/bar.c]      bar.c
                    [notdir baz]    baz

       _8_._4_0_._2  _S_e_e _A_l_s_o
       basename, dirname, relative_dirname, suffix

       _8_._4_0_._3  _A_l_s_o _K_n_o_w_n _A_s
       entryname

       _8_._4_1  _n_o_t

       This  function requires zero or more arguments, the value to
       be logically negated.  It returns "1" (true) if all  of  the
       arguments  are  ""  (false),  or there are no arguments; and
       returns "" (false) otherwise.  This is  symmetric  with  the
       definition of true and false for iiff.

       _8_._4_1_._1  _E_x_a_m_p_l_e
       This is often seen in recipes:
            %1/%0%2.o: %1/%0%2.c
                    single-thread %2.o
            {
                    if [not [exists [dirname [target]]]] then
                            mkdir -p [dirname [target]]
                                    set clearstat;
                    [cc] [cc_flags] -I%1 %1/%0%2.c;
                    mv %2.o [target];
            }
       Note that "%0" matches zero or more whole filename portions,
       including the trailing slash.  See the  chapter  on  pattern
       matching for more information.

       This  is an example only.  The ``mkdir'' recipe flag creates
       the directory more efficiently.

       _8_._4_1_._2  _S_e_e _A_l_s_o
       and, or







       
       Peter Miller                                         Page 83





       Cook                                              User Guide



       _8_._4_2  _o_p_e_r_a_t_i_n_g___s_y_s_t_e_m

       This  function  requires  zero  or  more   arguments.    The
       resulting wordlist contains the values of various attributes
       of the operating system, as named in the arguments.   If  no
       attributes  are named, "system" is assumed.  Below is a list
       of attributes:

       node      The name of the computer ccooookk is presently running
                 on.

       system    The name of the operating system ccooookk is presently
                 being run under.  For example: if you were running
                 on SunOS 4.1.3, this would return "SunOS".

       release   The  specific  release of operating system, within
                 name, ccooookk is  presently  being  run  under.   For
                 example:  if you were running on SunOS 4.1.3, this
                 would return "4.1.3".

       version   Version information.  For SunOS 4.1.3, this  would
                 return  the kernel build number, for other systems
                 it is often the kernel patch release number.

       machine   The name of the hardware ccooookk is presently running
                 on.   For  example:  If  you were running on SunOS
                 4.1.3 this would return "sun4" or similar.

       This function may be abbreviated to "os".

       _8_._4_2_._1  _E_x_a_m_p_l_e
       This function is usually used to determine the  architecture
       (either system or machine):
            arch=[os system]-[os release]-[os machine];
            if [matches SunOS-4.1%1-sun4%2 [arch]] then
                    arch = sun4;
            else if [matches SunOS-5.%1-sun4%2 [arch]] then
                    arch = sun5;
            else if [matches SunOS-5.%1-i86pc [arch]] then
                    arch = sun5pc;
            else if [matches ConvexOS-%1-%2 [arch]] then
                    arch = convex;
            else
                    arch = unknown;

       _8_._4_2_._2  _C_a_v_e_a_t
       This function is implemented using the _u_n_a_m_e(2) system call.
       Some systems do not implement this correctly, and  therefore
       this  function  is  less useful than it should be, and needs
       the pattern match appropach used above.

       _8_._4_2_._3  _S_e_e _A_l_s_o
       collect


       
       Peter Miller                                         Page 84





       Cook                                              User Guide



       _8_._4_2_._4  _A_l_s_o _K_n_o_w_n _A_s
       os

       _8_._4_3  _o_p_t_i_o_n_s

       This  functions  takes  no  arguments.   The  results  is  a
       complete  list  of  _c_o_o_k  options,  exactly  describing  the
       current  options  settings.   This  intended  for   use   in
       constructing recursive _c_o_o_k invocations.

       The  option  setting  generated  are  a  combination  of the
       command line options used to invoke _c_o_o_k_,  the  contents  of
       the  COOK  environment  variable, the results of the ``set''
       command and the various ``set'' clauses.

       _8_._4_3_._1  _E_x_a_m_p_l_e
       The top level cookbook for a recursive project structure can
       be as follows:
            %:
            {
                    dirlist = [dirname [glob '*/Howto.cook' ]];
                    loop
                    {
                            dir = [head [dirlist]];
                            if [not [dir]] then
                                    loopstop;
                            dirlist = [tail [dirlist]];

                            cd [dir]\; cook [options] %;
                    }
            }

            /*
             * This recipe sets the default.
             * It doesn't actually do anything.
             */
            all:;
       Please  note  the  %  hiding  on  the end of the nested _c_o_o_k
       command, this is how  the  target  is  communicated  to  the
       nested ccooookk invocation.

       _8_._4_3_._2  _C_a_v_e_a_t
       Recursive  Cook  is not recommended, because it segments the
       dependency graph and  forces  Cook  to  walk  the  graph  in
       (potentially)  the wrong order.  This introduces a number of
       significant  problems.   A  single  top-level  cookbook   is
       recommended.

       _8_._4_3_._3  _S_e_e _A_l_s_o
       The  supplied  ``recursive'' cookbook does exactly this.  In
       order to use it, you need a _H_o_w_t_o_._c_o_o_k file  containing  the
       single line
            #include "recursive"


       
       Peter Miller                                         Page 85





       Cook                                              User Guide



       _8_._4_4  _o_r

       This function requires at least two arguments, upon which it
       forms a logical disjunction.   The  value  returned  is  "1"
       (true)  if  any  one  of  the  arguments  is not "" (false),
       otherwise "" (false) is returned.

       _8_._4_4_._1  _S_e_e _A_l_s_o
       and, not

       _8_._4_5  _p_a_t_h_n_a_m_e

       The function requires one or  more  arguments,  being  files
       names to be replaced with their full path names.

       _8_._4_5_._1  _E_x_a_m_p_l_e
       Relative  names are made absolute, and redundant slashes and
       dots are removed:
            pwd = [pathname .];

       _8_._4_5_._2  _S_e_e _A_l_s_o
       basename, dirname, entryname

       _8_._4_6  _p_a_t_s_u_b_s_t

       This function requires at  least  two  arguments.   Patsubst
       gives   the  user  access  to  the  pattern  transformations
       available to ccooookk.  The first argument is the  "from"  form,
       the  second  argument is the "to" form.  All other arguments
       are mapped from one to the other.

       _8_._4_6_._1  _E_x_a_m_p_l_e
       Given a list of C source files, generate a  list  of  object
       files as follows:
            obj = [patsubst %.c %.o [src]];

       _8_._4_6_._2  _M_a_t_c_h _M_o_d_e
       This  function  is affected by the selected match mode.  See
       the _F_i_l_e _N_a_m_e _P_a_t_t_e_r_n_s chapter for details.

       _8_._4_6_._3  _S_e_e _A_l_s_o
       filter, filter_out, subst

       _8_._4_6_._4  _A_l_s_o _K_n_o_w_n _A_s
       fromto










       
       Peter Miller                                         Page 86





       Cook                                              User Guide



       _8_._4_7  _p_r_e_p_o_s_t

       This function must have at least two arguments.   The  first
       argument  is  a  prefix and the second argument is a suffix.
       The resulting word list is the  third  and  later  arguments
       each given the prefix and suffix as defined by the first and
       second arguments.

       _8_._4_7_._1  _E_x_a_m_p_l_e


                Expression               Result
                -------------------------------------------
                [prepost sun4/ .o a b]   sun4/a.o sun4/b.o
                [prepost -I "" . bl]     -I. -Ibl

       _8_._4_7_._2  _S_e_e _A_l_s_o
       addprefix, addsuffix, patsubst, subst

       _8_._4_8  _p_r_i_n_t

       The arguments are printed as an  informative  message.   The
       usual  output  wrapping  is performed.  The function returns
       the empty list as a result.

       This function is frequently use to debug cookbooks.

       _8_._4_9  _q_u_o_t_e

       Each argument  is  quoted  by  double  quotes,  with  shell9
       special characters escaped as necessary.

       _8_._4_9_._1  _S_e_e _A_l_s_o
       collect, execute


















       ____________________

       9. See _s_h (1) and _c_s_h(1) for more information.

       Peter Miller                                         Page 87





       Cook                                              User Guide



       _8_._5_0  _r_e_a_d___l_i_n_e_s

       The argument is interpreted as the name of a text file to be
       read.  The result is one word for each line of the file.

       _8_._5_0_._1  _E_x_a_m_p_l_e
       Read a the _e_x_a_m_p_l_e file and assign it to a variable:
            example = [read_lines example];

       _8_._5_0_._2  _S_e_e _A_l_s_o
       collect, collect_lines, read, write

       _8_._5_1  _r_e_a_d_l_i_n_k

       The arguments are assumed to be symbolic  links,  and  their
       values are read.  It is a fatal error if the files named are
       not symbolic links.

       _8_._5_1_._1  _S_e_e _A_l_s_o
       collect, exists-symlink

       _8_._5_2  _r_e_a_d

       The argument is interpreted as the name of a text file to be
       read.  The result is one word for each white-space separated
       word of the file.

       _8_._5_2_._1  _E_x_a_m_p_l_e
       Read a the _e_x_a_m_p_l_e file and assign it to a variable:
            example = [read example];

       _8_._5_2_._2  _S_e_e _A_l_s_o
       collect, collect_lines, read_lines, write

       _8_._5_3  _r_e_l_a_t_i_v_e___d_i_r_n_a_m_e

       This function requires one or more arguments, the  names  of
       files which will have their directory parts extracted.

       _8_._5_3_._1  _E_x_a_m_p_l_e


                 Expression      Result
                 ----------------------------------------
                 [relative_dirname a]    .
                 [relative_dirname a/b]  a
                 [relative_dirname a/b/c]        a/b
       See  _d_i_r_n_a_m_e  if  you  want to climb the directory tree with
       repeated applications,  _r_e_l_a_t_i_v_e___d_i_r_n_a_m_e  will  continue  to
       return ``.'' once the current directory is reached.

       _8_._5_3_._2  _S_e_e _A_l_s_o
       basename, dirname, entryname, notdir, pathname, suffix


       
       Peter Miller                                         Page 88





       Cook                                              User Guide



       _8_._5_3_._3  _A_l_s_o _K_n_o_w_n _A_s
       reldir

       _8_._5_4  _r_e_s_o_l_v_e

       This  builtin  function  is  used to resolve file names when
       using  the  _s_e_a_r_c_h___l_i_s_t  variable  to  locate  files.   This
       builtin  function  produces  resolved  file names as output.
       This is useful when taking partial copies  of  a  source  to
       perform  controlled  updates.   The  targets  of recipes are
       always cooked into the current directory.

       _8_._5_4_._1  _E_x_a_m_p_l_e
       This  function  is  used  in  cookbooks   which    use   the
       _s_e_a_r_c_h___l_i_s_t functionality:
            search_list = . baseline;

            %.o: %.c
            {
                    [cc] [cc_flags] [addprefix -I [search_list]] [resolve %.c];
            }

       The cookbooks distributed with Cook contain full support for
       the search_list functionality.  They are a  good  source  of
       examples  of  how  to  write  recipes  which  take this into
       account.

       _8_._5_5  _s_h_e_l_l

       The arguments are interpreted as a command to be  passed  to
       the  operating  system.   The  result  is  one word for each
       white-space separated word of the output of the command.

       The command will not be echoed unless the -No_Silent  option
       is specified on the command line.

       _8_._5_5_._1  _E_x_a_m_p_l_e
       Read the date and time and assign it to a variable:
            now = [shell date];
       Do not use the shell function to expand a filename wildcard,
       used the [wildcard] function instead.

       _8_._5_5_._2  _S_e_e _A_l_s_o
       collect_lines, execute, wildcard

       _8_._5_5_._3  _A_l_s_o _K_n_o_w_n _A_s
       collect








       
       Peter Miller                                         Page 89





       Cook                                              User Guide



       _8_._5_6  _s_o_r_t___n_e_w_e_s_t

       The  arguments  are  sorted  by  file  last-modified   time,
       youngest  to oldest.  File names are resolved first (see the
       resolve function, below).  Absent files will  be  sorted  to
       the start of the list.

       _8_._5_6_._1  _E_x_a_m_p_l_e
       This  function  is  often  used  to  "shorten the wait" when
       building large project, so that the  file  you  edited  most
       recently is recompiled almost immediately:
            src = [glob *.c];
            obj = [sort_newest [fromto %.c %.o [src]]];

       This  trick  does  not always work as expected, and can take
       significant time for little result.

       _8_._5_6_._2  _S_e_e _A_l_s_o
       fromto, glob, sort

       _8_._5_7  _s_o_r_t

       The arguments are sorted lexicographically.

       NNoottee::  Duplicates  are  _n_o_t  removed.   Use  the   _s_t_r_i_n_g_s_e_t
       function if you want to do this.

       _8_._5_7_._1  _S_e_e _A_l_s_o
       sort_newest, stringset

       _8_._5_8  _s_p_l_i_t

       The  _s_p_l_i_t  function  is used to split strings into multiple
       strings, given the separator.   This  function  requires  at
       least  one  argument.   The  first argument is the separator
       character, the second and subsequent  arguments  are  to  be
       separated.   The  result is the separated strings, each as a
       separate word.

       _8_._5_8_._1  _E_x_a_m_p_l_e


                 Expression                  Result
                 ----------------------------------------
                 [split ":" "foo:bar:baz"]   foo bar baz
                 [split " " "New York"]      New York
       Each of the words in the result is a separate string.

       This can be useful in splitting an environment variable into
       separate words.  For example:
            path = [split ":" [getenv PATH]];




       
       Peter Miller                                         Page 90





       Cook                                              User Guide



       _8_._5_8_._2  _S_e_e _A_l_s_o
       unsplit, join, catenate, strip

       _8_._5_9  _s_t_r_i_n_g_s_e_t

       Logical  operations are performed on sets of strings.  These
       include conjunction (++) or  implicit,  disjunction  (**)  and
       difference (--).

       _8_._5_9_._1  _E_x_a_m_p_l_e


                     Expression                Result
                     ---------------------------------
                     [stringset a b a]         a b
                     [stringset a b c * a]     a
                     [stringset a b c - a]     b c
                     [stringset a b - c + d]   a b d

       The  can  be  very  useful  in  constructing lists of source
       files:
            src = [stringset [glob "*.[cyl]" ] - y.tab.c lex.yy.c];

       _8_._5_9_._2  _S_e_e _A_l_s_o
       filter, filter_out, glob, in, patsubst, subst

       _8_._6_0  _s_t_r_i_p_d_o_t

       The _s_t_r_i_p_d_o_t function  is  used  to  remove  leading  ``.\''
       directories from each of the path name arguments.

       _8_._6_0_._1  _E_x_a_m_p_l_e


                       Expression           Result
                       ----------------------------
                       [stripdot ./foo.c]    foo.c
                       [stripdot bar.o]     bar.o
                       [stripdot /fubar]    /fubar

       _8_._6_0_._2  _S_e_e _A_l_s_o
       set stripdot













       
       Peter Miller                                         Page 91





       Cook                                              User Guide



       _8_._6_1  _s_t_r_i_p

       The  _s_t_r_i_p  function  is used to remove leading and trailing
       white space from words.  Internal sequences of  white  space
       are replaced by a single space.

       _8_._6_1_._1  _E_x_a_m_p_l_e


                 Expression                  Result
                 -----------------------------------------
                 [strip " " "foo " " bar"]   "" foo bar
                 [strip " really   big  "]   "really big"
       Quotes are used here for clarity, and are not present in the
       internal representation of strings.

       _8_._6_1_._2  _S_e_e _A_l_s_o
       split

       _8_._6_2  _s_u_b_s_t_r

       The _s_u_b_s_t_r function is used to perform substring  extracton.
       The  first  argument is the starting position in the string,
       starting from one.  The second argument  is  the  number  of
       characters to extract.  Thirst and subsequent arguments will
       be processed to extract sub-strings.

       _8_._6_2_._1  _E_x_a_m_p_l_e


                      Expression             Result
                      ------------------------------
                      [substr 1 1 Peter]     P
                      [substr 3 99 Miller]   ller

       _8_._6_2_._2  _S_e_e _A_l_s_o
       subst, patsubst


















       
       Peter Miller                                         Page 92





       Cook                                              User Guide



       _8_._6_3  _s_u_b_s_t

       The _s_u_b_s_t function is used to perform  string  substitutions
       on  its  arguments.   This  function  requires  at least two
       arguments.  The first argument is  the  "from"  string,  the
       second  argument  is  the  "to" string.  All occurreneces of
       "from" are replaced with "to" in the  third  and  subsequent
       arguments.

       _8_._6_3_._1  _E_x_a_m_p_l_e
       This is a literal replacement, not a pattern replacement:

            Expression                            Result
            ---------------------------------------------------
            [subst buffalo cress water.buffalo]   water.cress
            [subst .c .o test.c]                  test.o
            [subst .c .o stat.cache.c]            stat.oache.o
       Note that last case: it is not selective.

       _8_._6_3_._2  _S_e_e _A_l_s_o
       filter, filter_out, patsubst

       _8_._6_4  _s_u_f_f_i_x

       The  _s_u_f_f_i_x function treats each argument as a filename, and
       extracts the suffix from each.  If the filename  contains  a
       period,  the  suffix  is  everything  starting with the last
       period.  Otherwise, the  suffix  is  the  empty  string  (as
       opposed to nothing at all).

       _8_._6_4_._1  _E_x_a_m_p_l_e


                     Expression              Result
                     ---------------------------------
                     [suffix a.c foo b.y]    .c "" .y
                     [suffix stat.cache.c]   .c
                     [suffix .eric]          ""
       Quotes are used here for clarity, and are not present in the
       internal representation of strings.

       The _s_u_f_f_i_x functions in this way to allow  sensible  results
       when   using   the   _j_o_i_n  function  to  re-unite  filenames
       dismembered by the _b_a_s_e_n_a_m_e and _s_u_f_f_i_x functions.

       _8_._6_4_._2  _S_e_e _A_l_s_o
       basename, dirname, entryname, join, patsubst








       
       Peter Miller                                         Page 93





       Cook                                              User Guide



       _8_._6_5  _t_a_i_l

       This function requires zero or  more  arguments.   The  word
       list  returned  will  be  empty  if  there  is less than two
       arguments, otherwise it will consist of the second and later
       arguments.

       _8_._6_5_._1  _S_e_e _A_l_s_o
       count, head, word

       _8_._6_6  _u_n_-_d_o_s_-_p_a_t_h

       This  function requires one or more arguments, which will be
       converted from a DOS path into a UNIX path.  This is of most
       use  under  Windows-NT, to convert DOS pathnames into Cook's
       internal pathnames.  (The UNIX porting layer  usually  hides
       this from Cook.)

       _8_._6_6_._1  _E_x_a_m_p_l_e


              Expression                     Result
              ----------------------------------------------
              [un-dos-path a\b\c]            a/b/c
              [un-dos-path c:\temp]          //c/temp
              [un-dos-path \\server\stuff]   //server/stuff

       _8_._6_6_._2  _S_e_e _A_l_s_o
       dos-path

       _8_._6_7  _u_n_s_p_l_i_t

       The _u_n_s_p_l_i_t function is used to glue strings together, using
       the specified glue.  The first argument is the  text  to  go
       between each of the second and subsequent arguments.

       _8_._6_7_._1  _E_x_a_m_p_l_e


              Expression                    Result
              ----------------------------------------------
              [unsplit ":" one two three]   "one:two:three"
              [unsplit " " four five six]   "four five six"
       The quotes are necessary to isolate characters such as colon
       and space which cook would normally treat differently.

       _8_._6_7_._2  _S_e_e _A_l_s_o
       catenate, prepost, split







       
       Peter Miller                                         Page 94





       Cook                                              User Guide



       _8_._6_8  _u_p_c_a_s_e

       This function requires one or more arguments,  words  to  be
       forced into upper case.

       _8_._6_8_._1  _E_x_a_m_p_l_e


                          Expression     Result
                          ----------------------
                          [upcase FOO]   FOO
                          [upcase Bar]   BAR
                          [upcase baz]   BAZ

       _8_._6_8_._2  _S_e_e _A_l_s_o
       downcase

       _8_._6_9  _u_p_t_o_d_a_t_e

       This  function  may be used to determine if files are up-to-
       date.  It returns a word list containing the  names  of  the
       up-to-date  files,  or empty if none of them are up-to-date.
       They are _n_o_t brought up to date if  they  are  not  already.
       This function requires one or more arguments.

       _8_._6_9_._1  _C_a_v_e_a_t
       This will use as much of the cookbook as has been read in up
       to the point where this function is  used.   This  can  mean
       that crucial recipes have yet to be parsed and instanciated.

       _8_._6_9_._2  _S_e_e _A_l_s_o
       cando, cook

       _8_._7_0  _w_i_l_d_c_a_r_d

       Each argument is treated as a _s_h(1) file name  pattern,  and
       expanded  accordingly.   The  resulting list of filenames is
       sorted lexicographically.

       You may  need  to  quote  the  pattern,  to  protect  square
       brackets from the meaning cook attaches to them.

       NNoottee:: The character sequence /* is a comment introducer, and
       is a frequent source of  problems  when  combined  with  the
       _w_i_l_d_c_a_r_d  function.   Remember  to  quote _w_i_l_d_c_a_r_d arguments
       which need this character sequence.

       _8_._7_0_._1  _E_x_a_m_p_l_e
       To find the sources in the current directory:
            src = [wildcard *.c];
            obj = [patsubst %.c %.o [src]];




       
       Peter Miller                                         Page 95





       Cook                                              User Guide



       _8_._7_0_._2  _S_e_e _A_l_s_o
       filter, filter_out, patsubst

       _8_._7_0_._3  _A_l_s_o _K_n_o_w_n _A_s
       glob

       _8_._7_0_._4  _W_o_r_d_l_i_s_t
       This function may be used to extract a list of words from  a
       larger  list.   The first argument is the starting position,
       and the second argument is the ending  poistion,  inclusive.
       The  third  and  subsequent  arguments  are  the  list to be
       extracted from.  Positions are numbered starting from 1.  If
       the  start  is  bigger  than  the  end, they will be quietly
       swapped.  If the start is bigger than the list,  the  result
       will be empty.

       _8_._7_0_._4_._1  _E_x_a_m_p_l_e


                   Expression                   Result
                   -------------------------------------
                   [wordlist 2 3 foo bar baz]   bar baz
                   [wordlist 1 1 foo bar baz]   foo
                   [wordlist 7 3 foo bar baz]   baz

       There are a number of functions which are similar

                  Expression               Similar to
                  ---------------------------------------
                  [wordlist 1 1 _l_i_s_t]      [head _l_i_s_t]
                  [wordlist 2 9999 _l_i_s_t]   [tail _l_i_s_t]
                  [wordlist _N _N _l_i_s_t]      [word _N _l_i_s_t]

       _8_._7_0_._4_._2  _S_e_e _A_l_s_o
       firstword head, tail, word, words

       _8_._7_1  _w_o_r_d

       The  _w_o_r_d function is used to extract a specific word from a
       list of words.  The function requires at least one argument.
       The first argument is the number of the word to extract from
       the wordlist.  The wordlist is  the  second  and  subsequent
       arguments.  An empty list will be returned if you ask for an
       element off the end of the list.

       _8_._7_1_._1  _E_x_a_m_p_l_e


                     Expression               Result
                     --------------------------------
                     [word 1 one two three]   one
                     [word 2 one two three]   two
                     [word 3 one two three]   three


       
       Peter Miller                                         Page 96





       Cook                                              User Guide



                     [word 5 one two three]

       The last element of a list of words may be extracted as:
            last = [word [count [list]] [list]];

       _8_._7_1_._2  _S_e_e _A_l_s_o
       count, head

       _8_._7_2  _w_o_r_d_s

       This function requires zero or more arguments.   The  result
       is  a  word list of one word containing the (decimal) length
       of the argument word list.

       _8_._7_2_._1  _E_x_a_m_p_l_e
       This cookbook fragment echoes the number of files, and  then
       the name of the last file:
            echo There are [words [files]] files.;
            echo The last file is [word [words [files]] [files]].;

       _8_._7_2_._2  _S_e_e _A_l_s_o
       head, tail, word

       _8_._7_2_._3  _A_l_s_o _K_n_o_w_n _A_s
       count

       _8_._7_3  _w_r_i_t_e

       This  function  requires  one  or more arguments.  The first
       argument is the name of the file to  write,  the  second  an
       later  arguments are lines to be written to the file.  (This
       is specifically a text file.)  The result is an  empty  word
       list.

       This  function  is  very useful in writing command line file
       for Windows-NT, due  to  its  absurdly  short  command  line
       interface.

       _8_._7_3_._1  _S_e_e _A_l_s_o
       read, read_lines















       
       Peter Miller                                         Page 97





       Cook                                              User Guide



       _9_.  _P_r_e_d_e_f_i_n_e_d _V_a_r_i_a_b_l_e_s

       A number of variables are defined by ccooookk at run-time.

       _9_._1  _a_r_g

       This  is  the  arguments  list  for  user-defined functions.
       Individual arguments are split out into  ``@1''  to  ``@9''.
       These can also be used at automatic variables.  Caution: _a_r_g
       and  the  automatic  variables  are  _s_h_a_r_e_d   for   parallel
       execution,  causing  weird  interactions  if  you  execute a
       command within the function.

       _9_._2  _c_o_m_m_a_n_d_-_l_i_n_e_-_g_o_a_l_s

       The value of this variable is the  goals  specified  on  the
       command  line,  if  any.   If  none  were specified, and the
       default goal is in effect, the value will be empty.

       _9_._3  _____F_I_L_E____

       The value of this variable is the logical name of  the  file
       which  contains  it.   In the case of #include-cooked files,
       the physical  name  may  be  obtained  using  the  [resolve]
       function.   The  logical  name  may  be  set using the #line
       directive.

       _9_._4  _____F_U_N_C_T_I_O_N____

       The value of this variable is the name of the function which
       executes it.  It is not set for the global cookbook scope or
       the recipe body scope.

       _9_._5  _g_r_a_p_h___l_e_a_f___f_i_l_e

       File names which are listed in this variable could  be  leaf
       files  of  the  dependency  graph.  (See also the _l_e_a_f___f_i_l_e_s
       function, for Cook's idea of the leaf files.)

       _9_._6  _g_r_a_p_h___e_x_t_e_r_i_o_r___f_i_l_e

       File names which are  listed  in  this  variable  cannot  be
       present in any way in the dependency graph.

       _9_._7  _g_r_a_p_h___i_n_t_e_r_i_o_r___f_i_l_e

       File  names  which  are  listed  in  this  variable could be
       interior files of  the  dependency  graph.   (See  also  the
       _i_n_t_e_r_i_o_r___f_i_l_e_s  function,  for  Cook's  idea of the interior
       files.)

       _9_._8  _g_r_a_p_h___l_e_a_f___p_a_t_t_e_r_n

       File names which match the patterns in this  variable  could

       
       Peter Miller                                         Page 98





       Cook                                              User Guide



       be  leaf  files  of  the  dependency  graph.   (See also the
       _l_e_a_f___f_i_l_e_s function, for Cook's idea of the leaf files.)

       _9_._9  _g_r_a_p_h___e_x_t_e_r_i_o_r___p_a_t_t_e_r_n

       File names which match the patterns in this variable  cannot
       be present in any way in the dependency graph.

       _9_._1_0  _g_r_a_p_h___i_n_t_e_r_i_o_r___p_a_t_t_e_r_n

       File  names  which match the patterns in this variable could
       be interior files of the dependency graph.   (See  also  the
       _i_n_t_e_r_i_o_r___f_i_l_e_s  function,  for  Cook's  idea of the interior
       files.)

       _9_._1_1  _____L_I_N_E____

       The value of this variable is the line number within of  the
       file  which  contains  it.  The line number may be set using
       the #line directive.

       _9_._1_2  _n_e_e_d

       The ingredients of the recipe currently being cooked.

       _9_._1_3  _p_a_r_a_l_l_e_l___h_o_s_t_s

       This variable may be set to indicate a list of hosts to  use
       to distribute the execution of recipe bodies.

       _9_._1_4  _p_a_r_a_l_l_e_l___j_o_b_s

       This variable may be set to the number of parallel execution
       threads to perform simultaneously.  Defaults  to  1  if  not
       set.

       _9_._1_5  _p_a_r_a_l_l_e_l___r_s_h

       This  variable  may  be  set  to the command used to execute
       commands on remote machines.  Assumes to  take  argument  in
       the  same  form  as  the  BSD  _r_s_h(1)  command.  Defaults to
       ``_r_s_h'' if not set.

       _9_._1_6  _s_e_a_r_c_h___l_i_s_t

       This variable may be set to a  list  of  directories  to  be
       searched   for   targets  and  ingredients.   This  list  is
       initially the current directory (.)  and  will  always  have
       the  current directory prepended if it is not present.  This
       is useful when taking partial copies of a source to  perform
       controlled  updates.   Use  the _r_e_s_o_l_v_e built-in function to
       determine what file name cook actually found.   The  targets
       of recipes are always cooked into the current directory.


       
       Peter Miller                                         Page 99





       Cook                                              User Guide



       The cookbooks distributed with Cook contain full support for
       the search_list functionality.  They are a  good  source  of
       examples  of  how  to  write  recipes  which  take this into
       account.

       _9_._1_7  _s_e_l_f

       The name ccooookk was invoked as, usually  "cook".   Be  careful
       what  you call cook, because anything with the string "cook"
       in it will be changed, including (but not limited  to)  file
       suffixes and environment variable names.

       _9_._1_8  _t_a_r_g_e_t

       The  target  of  the  recipe  currently being cooked, or the
       first target if there is more than one.

       _9_._1_9  _t_a_r_g_e_t_s

       The targets of the  recipe  currently  being  cooked.   This
       includes  all  targets  of  the recipe, should there be more
       than one.

       _9_._2_0  _t_h_r_e_a_d_-_i_d

       This variable has a unique value for each execution  thread,
       for  the lifetime of that thread.  This value may be used to
       construct  thread-unique   variable   names,   thread-unique
       temporary  file  names,  or  anything  else that needs to be
       unique to each execution thread.  The  thread  IDs  are  re-
       used,  and  so several threads in sequence may have the same
       thread ID; it is only guaranteed that no other  simultaneous
       thread  will  have  the  same thread ID.  By re-using thread
       IDs, generated variable names  are  also  re-used,  avoiding
       memory bloat.

       _9_._2_1  _t_i_m_e_s_t_a_m_p___g_r_a_n_u_l_a_r_i_t_y

       This   variable  may  be  set  to  the  granularity  of  the
       filesystem's modtime in seconds.  Defaults to  1  second  if
       not  set  (a  suitable  value for most systems). Recommended
       non-default values include 2 seconds for Cygwin on FAT32 and
       4 seconds for PrimeOS.

       _9_._2_2  _y_o_u_n_g_e_r

       The  subset of the ingredients of the recipe currently being
       cooked which are younger than the target.

       _9_._2_3  _v_e_r_s_i_o_n

       The version of ccooookk currently executing.



       
       Peter Miller                                        Page 100





       Cook                                              User Guide



       _1_0_.  _F_u_n_c_t_i_o_n_s _L_i_b_r_a_r_y

       There is a file of functions available to you by using a
            #include "functions"
       line in your cookbook.  The file defines a number of  useful
       functions.

       The  functions in the file also serve as examples of how you
       can write your own functions.

       _1_0_._1  _c_a_p_i_t_a_l_i_z_e

       The _c_a_p_i_t_a_l_i_z_e function maps all of its arguments into lower
       case,  and  then the first letter of each argument is mapped
       to upper case.  Zero, one or more arguments may be given.

       _1_0_._2  _d_e_f_i_n_e_d_-_o_r_-_n_u_l_l

       The _d_e_f_i_n_e_d_-_o_r_-_n_u_l_l function may be used to determine  if  a
       variable has been set (on the command line, for example) and
       return its value if so, otherwise return the empty list.

       This function should only be given one argument -  the  name
       of  the  variable to look for.  Additional arguments will be
       ignored.  Too few arguments will produce a  complaint  about
       the "" variable being undefined.

       _1_0_._3  _d_e_f_i_n_e_d_-_o_r_-_d_e_f_a_u_l_t

       The  _d_e_f_i_n_e_d_-_o_r_-_d_e_f_a_u_l_t function may be used to determine if
       a variable has been set (on the command line,  for  example)
       and  return  its  value  if  so,  otherwise return the given
       default value.

       The first argument is the name of the variable to look  for.

       The  second and later arguments (if present) are the default
       value to be used if  the  named  variable  is  not  defined.
       Optional.

       _1_0_._4  _r_e_p_e_a_t

       The  _r_e_p_e_a_t  function  is  used  to  repeatedly call another
       function, once for each of the specified arguments.  The can
       be   useful   when  dealing  with  functions  which  do  not
       automatically accept argument lists in the form you require.

       There  are  many instances where the repeat function call be
       used to elegantly avoid used to the ``loop  {  loopstop  }''
       construct.

       The  first  argument  is  the  name of the function you want
       called.  This function must accept a single argument.


       
       Peter Miller                                        Page 101





       Cook                                              User Guide



       The second and subsequent arguments are argument  values  to
       be passed to the named function, one at a time.

       The   results   of  the  invocations  of  the  function  are
       accumulated in the order in which they were calculated.  The
       accumulated results are returned.

       _1_0_._5  _v_a_r_i_a_b_l_e___b_y___p_a_t_h

       The  _v_a_r_i_a_b_l_e___b_y___p_a_t_h  function is used to extract the union
       of option settings relevant to a particular  compilation  or
       link.  By using a variable prefix, this function may be used
       to obtain the setting of  a  wide  variety  of  options  and
       commands.

       Global  variables  are searched in a no particular order for
       the necessary information.  All are searched, all found  are
       used.

       For  example,  the  function call [variable_by_path cc_flags
       foo/bar/baz.c] will hunt for variables  with  the  following
       names:   cc_flags_foo/bar/baz.c   and  cc_flags_foo/bar  and
       cc_flags_foo and cc_flags.  It is  expected  that  the  vast
       majority of these variables will not be set.  Duplicates are
       removed.






























       
       Peter Miller                                        Page 102





       Cook                                              User Guide



       _1_1_.  _A_c_t_i_o_n_s _w_h_e_n _C_o_o_k_i_n_g

       This section describes what ccooookk does when  you  ask  it  to
       cook something.

       CCooookk performs the following actions in the order stated.

       _1_1_._1  _S_c_a_n _t_h_e _C_O_O_K _E_n_v_i_r_o_n_m_e_n_t _V_a_r_i_a_b_l_e

       The  CCOOOOKK  environment  variable  is  looked  for.  If it is
       found, it is treated as if it consisted of ccooookk command line
       arguments.   Only  the  --HHeellpp option is illegal.  This could
       result is very strange behavior if used incorrectly.

       This feature is supplied to  override  ccooookk's  default  with
       your own preferences.

       _1_1_._2  _S_c_a_n _t_h_e _C_o_m_m_a_n_d _L_i_n_e

       The command line is scanned as defined in chapter 3.

       _1_1_._3  _L_o_c_a_t_e _t_h_e _C_o_o_k_b_o_o_k

       The  current  directory  is scanned for the cookbook.  Names
       which a cookbook may have include

                 howto.cook    Howto.cook    .howto.cook
                 how.to.cook   How.to.cook   .how.to.cook
                  cookfile      Cookfile       .cookrc
                  cook.file     Cook.file      .cook.rc
       The first so named file found in the current directory  will
       be  used.   The  order  of  search  is not defined.  You are
       strongly advised to have just _o_n_e of these name forms in any
       directory.  The name _H_o_w_t_o_._c_o_o_k is the preferred form.

       _1_1_._4  _F_o_r_m _t_h_e _L_i_s_t_i_n_g _F_i_l_e_n_a_m_e

       The listing file, if not explicitly named in the environment
       variable or on the command line, will be  the  name  of  the
       cookbook, with any suffix removed and '.list' appended.

       _1_1_._5  _C_r_e_a_t_e _t_h_e _L_i_s_t_i_n_g _f_i_l_e

       The  listing  file  is created.  If ccooookk is executing in the
       background, or the --NNooTTTTyy option has been specified,  _s_t_d_o_u_t
       and  _s_t_d_e_r_r  will  be  redirected into the listing file.  If
       ccooookk is executing in the foreground, and the  --NNooTTTTyy  option
       has not been specified, _s_t_d_o_u_t and _s_t_d_e_r_r will be redirected
       into a pipe to a _t_e_e(1) command; which will, in  turn,  copy
       the output into the named file.

       A  heading  line  with the name of the file and the date, is
       generated.


       
       Peter Miller                                        Page 103





       Cook                                              User Guide



       _1_1_._6  _S_c_a_n _t_h_e _C_o_o_k_b_o_o_k

       When ccooookk  reads  the  cookbook  it  evaluates  all  of  the
       statements   it  finds  in  it.   Usually  these  statements
       instantiate recipes, although other things are possible.

       Recipes  contain   statements   that   are   not   evaluated
       immediately,  but  which  are remembered for later execution
       when cooking a target.  The meaning of a cookbook is defined
       in chapter X.

       _1_1_._7  _D_e_t_e_r_m_i_n_e _t_a_r_g_e_t_s _t_o _c_o_o_k

       If  no  target  files  are  named  on  the command line, the
       targets of the first defined explicit or ingredients recipe.
       It is an error if this is none.

       _1_1_._8  _C_o_o_k_i_n_g _a _T_a_r_g_e_t

       A derivation graph is formed using all of the targets given.
       Once the derivation graph is  formed,  it  will  be  walked,
       looking for files which are out of date.

       To  build  the  derivation  graph  for  a  target,  each the
       following steps is performed in the order given:

         1.  CCooookk exploits knowledge of the derivation  graph  that
             the user may provide to it:

                +o If  the  _g_r_a_p_h___e_x_t_e_r_i_o_r___f_i_l_e variable is set, and
                  the file name is listed in it, the file is not  a
                  leaf,  and  the derivation will backtrack and try
                  another alternative.

                +o If the _g_r_a_p_h___e_x_t_e_r_i_o_r___p_a_t_t_e_r_n  variable  is  set,
                  and  the  file  name  matches one of the patterns
                  listed in it, the file is not  a  leaf,  and  the
                  derivation   will   backtrack   and  try  another
                  alternative.

                +o If the _g_r_a_p_h___l_e_a_f___f_i_l_e variable is set,  and  the
                  file  name  is  listed  in it, the file is a leaf
                  file of the derivation.   There  is  no  need  to
                  attempt  to  apply  any  recipes.   It will be an
                  error if the file does not exist.

                +o If the _g_r_a_p_h___l_e_a_f___p_a_t_t_e_r_n variable  is  set,  and
                  the  file name matches one of the patterns listed
                  in it, the file is a leaf file of the derivation.
                  There is no need to attempt to apply any recipes.
                  It will be an error if the file does not exist.
             These optimizations require an  accurate  source  file
             manifest,  but  can  result is substantial performance
             improvements.

       
       Peter Miller                                        Page 104





       Cook                                              User Guide



         2.  CCooookk  scans  through  the   instantiated   ingredients
             recipes   in   the   order  they  were  defined.   All
             ingredients recipes with the target  in  their  target
             list are used.

             If  a  recipe  is used, then any ingredients also have
             their derivation graph constructed.  When walking  the
             graph,  if any of the ingredients are younger than the
             target, all other explicit or  implicit  recipes  with
             the same target will be deemed to be out of date.10

         3.  CCooookk  then  scans  through  the  instantiated explicit
             recipes in the order they were defined.  All  explicit
             recipes with the target in their target list are used.

             If a recipe is a used, the ingredients also have their
             derivation graph constructed.  When walking the graph,
             if any ingredients are out of date or the target  does
             not  yet  exist  (or  the  "forced" flag is set in the
             recipe's  _s_e_t  clause)  the  recipe   body   will   be
             performed.   If  a  recipe has no ingredients, it will
             not be performed,  unless  the  target  does  not  yet
             exist, or it is forced.

         4.  If  the  target  was  not  in  the  target list of any
             explicit recipe,  ccooookk  then  scans  the  instantiated
             implicit  recipes  in  the order they were defined, in
             two passes.   Implicit  recipes  which  not  not  have
             pattern  elements  in  the basename of the targets are
             scanned before implicit recipes which do have patterns
             in  the  basename.   Usually  this  has no significant
             effect, however in heavily heterogeneous  builds  this
             method  is  often  used in constructing the dependency
             files, so that  all  architectures  may  use  the  one
             implicit  dependency recipe, rather than stating every
             architecture explicitly.  Within each pass, the  order
             of scan is the order of definition.

             Implicit  recipe targets and ingredients may contain a
             wildcard  character  (%%),  which  is  why   they   are
             implicit.   When  expressions  are evaluated into word
             lists in an implicit recipe, any word  containing  the
             wildcard  character  (%%)  will  be expanded out by the
             current wildcard expansion.

             If the target matches a pattern in the targets  of  an
             implicit  recipe,  it is a candidate.  Each ingredient
             of a candidate recipe is recursively cooked.   If  any
             ingredient  cannot be cooked, then the implicit recipe

       ____________________

       10.A  target  which  does  not exist yet is considered to be
          infinitely ancient, and thus everything is  younger  than
          it.

       Peter Miller                                        Page 105





       Cook                                              User Guide



             is not used.  If all ingredients can be  cooked,  then
             the implicit recipe is used.

             If   an   implicit   recipe  is  a  used,  the  forced
             ingredients   also   have   their   derivation   graph
             constructed.   It  is  an error if a forced ingredient
             cannot be constructed.

             Only the first implicit recipe to get to this point is
             used.  The scan stops at this point.

         5.  If the target is not the subject of any ingredients or
             explicit  recipe,  and  no  implicit  recipes  can  be
             applied,  then  several  derivations are attempted, in
             the order specified:

                +o If the _g_r_a_p_h___i_n_t_e_r_i_o_r___f_i_l_e variable is  set,  and
                  the  file name is listed in it, the file is a not
                  leaf file of the derivation.  Cook will backtrack
                  and try another alternative.

                +o If  the  _g_r_a_p_h___i_n_t_e_r_i_o_r___p_a_t_t_e_r_n  variable is set,
                  and the file name matches  one  of  the  patterns
                  listed  in it, the file is a not leaf file of the
                  derivation.  Cook will backtrack and try  another
                  alternative.

                +o If  the  _g_r_a_p_h___l_e_a_f___f_i_l_e variable is set, and the
                  file name is listed in it, the  file  is  a  leaf
                  file  of  the derivation.  It will be an error if
                  the file does not exist.

                +o If the _g_r_a_p_h___l_e_a_f___p_a_t_t_e_r_n variable  is  set,  and
                  the  file name matches one of the patterns listed
                  in it, the file is a leaf file of the derivation.
                  It will be an error if the file does not exist.

                +o If    either    of    the    _g_r_a_p_h___l_e_a_f___f_i_l_e   or
                  _g_r_a_p_h___l_e_a_f___p_a_t_t_e_r_n variables are  set,  then  the
                  file  is  not  a  leaf,  and  the derivation will
                  backtrack and try another alternative.

                +o If the file exists, then it is up  to  date,  and
                  the file is a leaf file of the derivation.

                +o If the file does not exist then CCooookk doesn't know
                  how, and the derivation will  backtrack  and  try
                  another alternative.

       If  a  command in the body of any recipe fail, ccooookk will not
       that body any further, and will not perform the body of  any
       recipe  for  which  the  target of the failed actions was an
       ingredient, directly or indirectly.


       
       Peter Miller                                        Page 106





       Cook                                              User Guide



       CCooookk will trap recursive looping of targets.

          +o If the file exists, the it is up to date, or

          +o If the file does not exist then ccooookk doesn't know  how.

       _1_1_._9  _T_h_e _D_e_p_e_n_d_e_n_c_y _G_r_a_p_h

       The  above section describes how Cook derives the dependency
       graph.  Once the dependency graph has been  derived,  it  is
       then  walked.  The next section describes a little about how
       Cook walks the dependency graph.

       Cook is a simple kind of expert system.  You give it  a  set
       of  of  recipes for how to construct things, and a target to
       be constructed.  The recipes can be  decomposed  into  pair-
       wise ordered dependencies between files.

       Cook  determines  how  to build the target by constructing a
       _d_i_r_e_c_t_e_d _a_c_y_c_l_i_c _g_r_a_p_h.  The vertexes of this graph are  the
       files  in the system, the edges in this graph are the inter-
       file dependencies.  The edges  of  the  graph  are  directed
       because  the pair-wise dependencies are ordered resulting in
       a _a_c_y_c_l_i_c graph - things which look like loops are  resolved
       by the direction of the edges.

       For  example, if you have a simple cookbook (with the recipe
       bodies omitted for simplicity) like this:
            program: one.o two.o;
            one.o: one.c one.h;
            two.o: two.c two.h one.h;
       here is the corresponding directed acyclic graph.
       

                                 program



                        one.o               two.o




                   one.c     one.h     two.c     two.h



       There are several things that can be  done  with  the  graph
       once it has been derived:
       *  It can be walked to verify and regenerate the referential
       integrity of the files (the usual case), or
       * it can walked to print  the  pair-wise  dependencies  (the
       -pairs option), or
       *  it  can be walked to generate a shell script (the -script

       
       Peter Miller                                        Page 107





       Cook                                              User Guide



       option) which does  something  very  similar  to  the  first
       option.

       _1_1_._9_._1  _E_d_g_e _T_y_p_e_s
       Each  of the arrows in the above graph have a specific type.

       _s_t_r_i_c_t edges mean that Cook will decide  that  a  target  is
             out-of-date  if its time stamp is not strictly younger
             than all of the ingredients.  This  is  almost  always
             what you want.

       _w_e_a_k  edges mean that Cook will decide that a target is out-
             of-date if its time stamp is older  than  any  of  the
             ingredients.   This means that the times stamps of the
             target and ingredients may be equal - this  is  useful
             for  hard links and symbolic links.  You specify edges
             of this type by appending the ``(weak)'' string to the
             name of the ingredient.

       _e_x_i_s_t_s edges  mean that Cook will arrange for the ingredient
             to be cooked before the recipe is run,  but  the  time
             stamp  _i_s  _n_o_t  _c_o_n_s_u_l_t_e_d.  The ingredient cannot ever
             make the target  out-of-date.   This  is  useful  form
             coping with version stamps which change often, but you
             don't want to re-link unless something  else  changes.
             You  specify  edges  of  this  type  by  appending the
             ``(exists)'' string to the name of the ingredient.
       The default edge type is ``_s_t_r_i_c_t''.  You can use the "time-
       adjust" setting (see the "set" command) to make this simpler
       on very fast machines.

       _1_1_._1_0  _F_i_l_e _S_t_a_t_u_s

       CCooookk determines the time a file was last modified by  asking
       the  operating  system.   Because this operation tends to be
       performed  frequently,  ccooookk  maintains  a  cache  of   this
       information,   rather  than  make  redundant  calls  to  the
       operating system.  Because this information is cached, it is
       possible for ccooookk's memory of a file's last-modified time to
       become inconsistent with  the  file's  actual  last-modified
       time.   In particular, ccooookk doe _n_o_t ask the operating system
       for the "new" last-modified time of a recipe target  once  a
       recipe  body is completed.  Careful use of the set clearstat
       clause  will  generally  prevent  this.   For  example,  the
       following  recipe  needs  to create a directory when writing
       its output:
            bin/%: [%_obj]
            {
                    if [not [exists bin]] then
                            mkdir bin;
                    [cc] -o [target] [need];
            }
       If there were several programs being  cooked,  e.g.  _b_i_n_/_f_o_o
       and  _b_i_n_/_b_a_r,  the second time ccooookk performed the recipe, it

       
       Peter Miller                                        Page 108





       Cook                                              User Guide



       would erroneously attempt to make the _b_i_n directory a second
       time  -  contrary to the test.  This is because _[_e_x_i_s_t_s _b_i_n_]
       used the cache, and nothing tells ccooookk that the cache is now
       wrong.  The recipe should have been written
            bin/%: [%_obj]
            {
                    if [not [exists bin]] then
                            mkdir bin
                                    set clearstat;
                    [cc] -o [target] [need];
            }
       which  tells  ccooookk  that it should remove any files named in
       the _m_k_d_i_r command from the cache.

       An alternative way of performing the above example is to set
       the _m_k_d_i_r recipe flag:
            bin/%: [%_obj]
                    set mkdir
            {
                    [cc] -o [target] [need];
            }
       This  flag  instructs  ccooookk  to create the directory for the
       target before running the recipe body.  There is  a  similar
       _u_n_l_i_n_k  flag, which unlinks the targets of the recipe before
       running the recipe body.  These two flags take care of most,
       but not all, uses of the _c_l_e_a_r_s_t_a_t flag.

       A  second  mechanism  used  by  ccooookk  to determine the last-
       modified times of files is a file _f_i_n_g_e_r_p_r_i_n_t.   This  is  a
       cryptographically  strong  hash  of  the contents of a file.
       The  chances  of  two  different  files  having   the   same
       fingerprint  is less than 1 in 2**200.  If ccooookk notices that
       a file has  changed,  because  its  last-modified  time  has
       changed,  a  fingerprint  is  taken of the file and compared
       with  the  remembered  fingerprint.   If  the   fingerprints
       differ,  the  file  is  considered  to be different.  If the
       fingerprints match, the  file  is  considered  not  to  have
       changed.

       This description of fingerprints is somewhat simplified, the
       actual mechanics depends on remembering two different  last-
       modified times, as well as the fingerprint, in a file called
       _._c_o_o_k_._f_p in the current directory.

       Fingerprinting can cause some surprises.  For example,  when
       you  use  the  _t_o_u_c_h(1)  command, ccooookk will often fail to do
       anything, and report instead that everything is  up-to-date.
       This  is  because  the fingerprint has not changed.  In this
       situation, either remove  the  _._c_o_o_k_._f_p  file,  or  use  the
       --NNoo__FFiinnggeerrPPrriinntt command line option.





       
       Peter Miller                                        Page 109





       Cook                                              User Guide



       _1_2_.  _O_p_t_i_o_n _P_r_e_c_e_d_e_n_c_e

       At  various  points in the description there are a number of
       flags and options with the same, or similar,  names.   These
       are in fact different levels of the same option.

       The different levels, from highest precedence to lowest, are
       as follows.

       Error     This level is used  to  disable  undesirable  side
                 effects when an error occurs.

       Command Line Options  specified on the command line override
                 almost everything.  There are some isolated  cases
                 where  there is no equivalent command line option.
                 They are in scope for the entire ccooookk session.

       Execute   When a command attached to a recipe  is  executed,
                 the  flags  in  the  'sseett'  clause  are given this
                 precedence.  They are in scope for the duration of
                 the execution of the command they are bound to.

       Recipe    When  a recipe is considered for use, the flags in
                 the 'sseett' clause are given the  precedence.   They
                 are in scope for the evaluation of the ingredients
                 names and the execution of the recipe  body;  they
                 are not in scope while cooking the ingredients.

       Cookbook  When  a  'sseett'  statement  is  encountered  in the
                 cookbook, the  option  are  given  this  priority.
                 They  are  in  scope  until  the  end  of the ccooookk
                 session.

       Environment Variable
                 When the  options in the CCOOOOKK environment variable
                 are set, they are given this precedence.  They are
                 in scope for the entire ccooookk session.

       Default   All options have a default setting.  The  defaults
                 noted  in  chapter  3  are  given this precedence.
                 They are in scope for the entire ccooookk session.














       
       Peter Miller                                        Page 110





       Cook                                              User Guide



       _1_3_.  _F_i_l_e _n_a_m_e _p_a_t_t_e_r_n_s

       There are two pattern matchers to choose from.

       The  tough  part  about  designing  a  pattern  matcher  for
       something  like  Cook  is  that _i_d_e_a_l_l_y the patterns must be
       reversible.  That is, it must be possible to  use  the  same
       string  both  as  a  pattern  to be matched against and as a
       template for building a string once a pattern  has  matched.
       Rather  like the difference between the left and right sides
       of an editor search-and-replace command in an  editor  using
       the  same  description  for  both the search pattern and the
       replace template.  This is why classic  regular  expressions
       are not the default.

       The  choice  of  which pattern matcher to use is dictated by
       flag settings:

       set match-mode-cook
            This causes patterns to be matched using Cook's  native
            patterns.  This is the default.

       set match-mode-regex
            This  causes  patterns  to  be  matched  using  regular
            expressions.

       The match mode to use may be set at the cookbook level
            set match-mode-cook;
       or at the recipe level
            %.o: %.c
                    set match-mode-cook
            {
                    [cc] -o %.o -c %.c;
            }
       if you want to change your mind temporarily.

       The match mode also affects match functions, such as _f_i_l_t_e_r,
       _f_i_l_t_e_r___o_u_t,  _f_r_o_m_t_o,  _m_a_t_c_h___m_a_s_k,  _m_a_t_c_h_e_s and _p_a_t_s_u_b_s_t.  If
       you use these in your user-defined functions, you need to be
       extra careful about this.

       The  match  mode  also  affects the graph variables, used to
       specify explicit graph interior and leaf files.

       _1_3_._1  _C_o_o_k _P_a_t_t_e_r_n_s

       The native Cook pattern matcher has symmetric left-hand-side
       and  right-hand-side  patterns.   This  is best demonstrated
       with an example recipe:
            %.c %.h: %.y
                    set match-mode-cook
            {
                    yacc -d %.y;
                    mv yy.tab.c %.c;

       
       Peter Miller                                        Page 111





       Cook                                              User Guide



                    mv yy.tab.h %.h;
            }
       Notice how the left-hand-side of the  recipe  (the  targets)
       uses  the same style of patterns as the right-hand-side (the
       ingredients and the recipe body).

       This matcher has eleven match "fields", referenced as %%  and
       %%00  to %%99.  The %% character can be escaped as %%%%.  The %% and
       %%11 to %%99 forms match any character except slash  (//);  these
       forms  may  not  match  a  leading  empty  string,  to avoid
       problems with false matches against absolute paths.  The  %%00
       form  matches  all  characters, but must be either empty, or
       have whole path components, including the trailing // on each
       component.

       A few examples will make this clearer:

                        +-------------------------+
                        |string    does not match |
                        +-------------------------+
                        |%.c       snot/fred.c    |
                        |%1/%2.c   etc/boo/fred.c |
                        +-------------------------+
       +---------------------------------------------------------------+
       |string                 matches                 setting         |
       +---------------------------------------------------------------+
       |%.c                    fred.c                  %="fred"        |
       |%1/%2.c                snot/fred.c             %1="snot"       |
       |                                               %2="fred"       |
       |%0%5.c                 fred.c                  %0=""           |
       |                                               %5="fred"       |
       |%0%6.c                 snot/fred.c             %0="snot/"      |
       |                                               %6="fred"       |
       |%0%7.c                 etc/boo/fred.c          %0="etc/boo/"   |
       |                                               %7="fred"       |
       |/usr/%1/%1%2/%3.%2%4   /usr/man/man1/fred.1x   %1="man"        |
       |                                               %2="1"          |
       |                                               %3="fred"       |
       |                                               %4="x"          |
       +---------------------------------------------------------------+
       The  %%00 behavior is designed to allow patterns to range over
       subtrees in a controlled manner.  Note that the use of  this
       sort  of  pattern in a recipe will result in deeper searches
       than the naive recipe designer would expect.

       _1_3_._1_._1  _E_x_a_m_p_l_e_s
       There are two main places where patterns are used: with  the
       _m_a_t_c_h___m_a_s_k and _f_r_o_m_t_o functions, and in recipes.

       You  can  perform  file  name  filtering  and  rewriting  as
       follows:
            source_files = [collect cat MANIFEST];
            object_files =
                    [fromto %0%.c %0%.o [match_mask %0%.c [manifest]]]

       
       Peter Miller                                        Page 112





       Cook                                              User Guide



                    [fromto %0%.y %0%.gen.o [match_mask %0%.y [manifest]]]
                    ;

       The recipes to go with the above files may be
            %0%.o: %0%.c
                    single-thread ["if" %0 "then" %.o]
            {
                    /* note: no slash before dot */
                    cc -c -I%0. %0%.c;
                    if %0 then
                            mv %.o %0%.o;
            }
       This recipe can compile files  in  a  large  project,  where
       source  files  appear  in  a number of sub-directories.  The
       ``-I%0.'' ensures that there are locally include-able  files
       in  the  sub-directories.   If  the ``%0'' had been entirely
       omitted from the recipe, it will only compile files  in  the
       current directory.

       A  common _y_a_c_c recipe, used when there is more than one yacc
       grammar in a project, looks like this:
            %0%.gen.c %0%.gen.h: %0%.y
                    single-thread yy.tab.c yy.tab.h
            {
                    yacc -d %0%.y
                    yy = [collect echo %0% | sed "'s/[^A-Za-z0-9]/_/'"];
                    sed "'s/[yY][yY]/"[yy]"_/g'" yy.tab.c > %0%.gen.c;
                    sed "'s/[yY][yY]/"[yy]"_/g'" yy.tab.h > %0%.gen.h;
                    rm yy.tab.c yy.tab.h;
            }
       To be more selective about  the  ``%0''  portion,  use  more
       pattern elements before or after it.

       _1_3_._2  _R_e_g_u_l_a_r _E_x_p_r_e_s_s_i_o_n_s

       The  regular  expression  pattern matcher uses POSIX regular
       expressions.  It has asymmetric  left-hand-side  and  right-
       hand-side  patterns.   This  is  best  demonstrated  with an
       example recipe:
            \\(.*\\)\\.c \\(.*\\)\\.h: \\1.y
                    set match-mode-regex
            {
                    yacc -d \\1.y;
                    mv yy.tab.c \\1.c;
                    mv yy.tab.h \\1.h;
            }
       Notice how the left-hand-side of the  recipe  (the  targets)
       uses  a completely different style of patterns as the right-
       hand-side (the ingredients and the recipe body).

       All those backslashes are necessary, because Cook  uniformly
       applies  C  escapes  to  strings  when it reads them, and it
       doesn't know you mean a regular expression  backslash  until
       you use it in a recipe context.

       
       Peter Miller                                        Page 113





       Cook                                              User Guide



       See  _r_e___f_o_r_m_a_t(7)  for  a definition of POSIX 1003.2 regular
       expressions; you want the ``basic'' REs.

       Please note that characters which are special to  Cook  will
       need  to be escaped with a backslash, or enclosed in quotes.
       These  include  curly  braces  (``{''  and  ``}''),   square
       brackets   (``[''  and  ``]''),  colon  (``:'')  and  equals
       (``='').  Backslash always  needs  to  be  escaped,  whether
       encoded  in  a  string  or  not,  because within a string it
       serves to escape the string terminator.

       You also need to remember  that  dot  (``.'')  is  a  common
       character  in  filenames, and frequently significant in file
       name patters, but it is a regular expression wildcard.   You
       need to escape it to make it literal.

       You  need  to make absolutely certain that when recipes have
       more than one left-hand-size (as in the yacc  example)  that
       the  patterns  _a_l_l  assign  identical values to their nested
       sub-expressions.

       The usual right-hand-side  replacements  are  available:  an
       escaped  number  is  replaced  with  the  _n-th  nested  sub-
       expression; and the ampersand (``&'')  is  replaced  by  the
       whole  left-hand-side  (if you have more than one left-hand-
       side, this is ambiguous).  Backslash may be used  to  escape
       them.

       _1_3_._2_._1  _E_x_a_m_p_l_e_s
       There  are two main places where patterns are used: with the
       _m_a_t_c_h___m_a_s_k and _f_r_o_m_t_o functions, and in recipes.

       You  can  perform  file  name  filtering  and  rewriting  as
       follows:
            set match-mode-regex;
            source_files = [collect cat MANIFEST];
            object_files =
                    [fromto \\(.*\\)\\.c \\1.o
                            [match_mask \\(.*\\)\\.c [manifest]]]
                    [fromto \\(.*\\)\\.y \\1.gen.o
                            [match_mask \\(.*\\)\\.y [manifest]]]
                    ;

       The recipes to go with the above files may be
            \\(.*\\)\\.o: \\1.c
                    single-thread ["if" [not [in [relative_dirname \\1] .]]
                            "then" [notdir \\1.o]]
            {
                    cc -c -I[[relative_dirname \\1] \\1.c;
                    if [not [in [relative_dirname \\1] .]] then
                            mv [notdir \\1.o] \\1.o;
            }
       This  recipe  can  compile  files  in a large project, where
       source files appear in a  number  of  sub-directories.   The

       
       Peter Miller                                        Page 114





       Cook                                              User Guide



       ``-I\\1.'' ensures that there are locally include-able files
       in the sub-directories.

       A common _y_a_c_c recipe, used when there is more than one  yacc
       grammar in a project, looks like this:
            \\(.*\\)\\.gen.c \\(.*\\)\\.gen.h: \\1.y
                    single-thread yy.tab.c yy.tab.h
            {
                    yacc -d \\1.y
                    yy = [collect echo \\1 | sed "'s/[^A-Za-z0-9]/_/'"];
                    sed "'s/[yY][yY]/"[yy]"_/g'" yy.tab.c > \\1.gen.c;
                    sed "'s/[yY][yY]/"[yy]"_/g'" yy.tab.h > \\1.gen.h;
                    rm yy.tab.c yy.tab.h;
            }
       To  be  more  selective  about the ``\\(.*\\)'' portion, use
       more pattern elements before or after it.







































       
       Peter Miller                                        Page 115





       Cook                                              User Guide



       _1_4_.  _S_u_p_p_l_i_e_d _C_o_o_k_b_o_o_k_s

       A number of cookbooks are supplied with ccooookk.  To  make  use
       of one, a preprocessor directive of the form
            #include "_w_h_i_c_h_o_n_e"
       must appear at the start of your cookbook.

       CCooookk  does not have any "built-in" recipes.  All recipes are
       stored  in  text  files,  so  they  are  more  easily  read,
       understood,  copied,  hacked  or  corrected.   The  supplied
       cookbooks live in the _/_u_s_r_/_s_h_a_r_e_/_c_o_o_k directory.

       You  may  supply  your  own  "system"  recipes,  by  placing
       cookbooks  into  a directory called _$_H_O_M_E_/_._c_o_o_k or using the
       --IInncclluuddee  command  line  option,  possibly  in  your   _$_C_O_O_K
       environment variable.

       _1_4_._1  _a_s

       This cookbook defines how to use the assembler.

       _1_4_._1_._1  _r_e_c_i_p_e_s


       %.o: %.s  Construct   object  files  from  assembler  source
                 files.

       _1_4_._1_._2  _v_a_r_i_a_b_l_e_s


       as        The assembler command.   Not  altered  if  already
                 defined.

       as_flags  Options   to  pass  the  assembler  command.   Not
                 altered if already defined.  The default is empty.

       as_src    Assembler source files in the current directory.

       dot_src   Source   files   constructable   in   the  current
                 directory  (unioned  with  existing  setting,   if
                 necessary).

       dot_obj   Object   files   constructable   in   the  current
                 directory  (unioned  with  existing  setting,   if
                 necessary).

       dot_clean Files  which  may  be  removed  from  the  current
                 directory in a clean target.







       
       Peter Miller                                        Page 116





       Cook                                              User Guide



       _1_4_._2  _c

       This cookbook describes how to work with C  files.   Include
       file dependencies are automatically determined.

       _1_4_._2_._1  _r_e_c_i_p_e_s


       %.o: %.c  Construct  object  files form C source files, with
                 automatic include file dependency detection.

       %.ln: %.c Construct lint object files from C  source  files,
                 with  automatic include file dependency detection.

       _1_4_._2_._2  _v_a_r_i_a_b_l_e_s


       c_incl    The C include  dependency  sniffer  command.   Not
                 altered if already defined.

       cc        The  C  compiler  command.  Not altered if already
                 defined.

       lint      The lint command.  Not altered if already defined.

       cc_flags  Options  to  pass  to the C compiler command.  Not
                 altered if already defined.  The default is  "-O".

       cc_include_flags Options passed to the C compiler and c_incl
                 controlling include file searching.   Not  altered
                 if already defined.  The default is empty.

       cc_src    C source files in the current directory.

       dot_src   Source   files   constructable   in   the  current
                 directory  (unioned  with  existing  setting,   if
                 necessary).

       dot_obj   Object   files   constructable   in   the  current
                 directory  (unioned  with  existing  setting,   if
                 necessary).

       dot_clean Files  which  may  be  removed  from  the  current
                 directory in a clean target.

       dot_lint_obj Lint object files constructable in the  current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       _1_4_._2_._3  _S_e_e _A_l_s_o
       The ``library'' cookbook,  for  linking  C  sources  into  a
       library.
       The  ``program''  cookbook,  for  linking  C  sources into a
       program.

       
       Peter Miller                                        Page 117





       Cook                                              User Guide



       _1_4_._3  _f_7_7

       This cookbook describes how to work with Fortran files.

       _1_4_._3_._1  _r_e_c_i_p_e_s


       %.o: %.f77 Construct object files form Fortran source files.

       _1_4_._3_._2  _v_a_r_i_a_b_l_e_s


       f77       The  Fortran  compiler  command.   Not  altered if
                 already defined.

       f77_flags Options to pass to the Fortran  compiler  command.
                 Not  altered  if  already defined.  The default is
                 "-O".

       f77_src   Fortran source files in the current directory.

       dot_src   Source  files   constructable   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       dot_obj   Object  files   constructable   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       dot_clean Files  which  may  be  removed  from  the  current
                 directory in a clean target.

       _1_4_._3_._3  _S_e_e _A_l_s_o
       The ``library'' cookbook, for linking Fortran sources into a
       library.
       The ``program'' cookbook, for linking Fortran sources into a
       program.


















       
       Peter Miller                                        Page 118





       Cook                                              User Guide



       _1_4_._4  _g_7_7

       This  cookbook  is  the same as the ``f77'' cookbook, but it
       sets the _f_7_7 variable to the GNU Fortran compiler, g77.

       _1_4_._5  _g_c_c

       This cookbook is the same as the ``c'' cookbook, but it sets
       the _c_c variable to the GNU C compiler, gcc.

       _1_4_._6  _h_o_m_e

       This  cookbook  defined  where  certain directories are, and
       some common uses of those directories, relative to $HOME.

       _1_4_._6_._1  _v_a_r_i_a_b_l_e_s


       home      The current users' home directory.

       bin       The directory to place program binaries into.

       include   The directory to place include files into.

       lib       The directory to place libraries into.

       cc_include_flags The [include] directory is appended to  the
                 search options.

       cc_link_flags The  [lib] directory is appended to the search
                 options.

       _1_4_._7  _l_e_x

       This cookbook describes how to work with lex files.

       _1_4_._7_._1  _r_e_c_i_p_e_s


       %.c: %.l  Construct C source files from lex source files.

       _1_4_._7_._2  _v_a_r_i_a_b_l_e_s


       lex       The lex command.  Not altered if already  defined.

       lex_flags Options  to  pass to the lex command.  Not altered
                 if already defined.  The default is empty.

       lex_src   Lex source files in the current directory.

       dot_src   Source  files   constructible   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       
       Peter Miller                                        Page 119





       Cook                                              User Guide



       dot_obj   Object  files   constructible   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       dot_clean Files  which  may  be  removed  from  the  current
                 directory in a clean target.

       dot_lint_obj Lint  object files constructible in the current
                 directory  (unioned  with  existing  setting,   if
                 necessary).

       _1_4_._8  _l_i_b_r_a_r_y

       This cookbook defines how to construct a library.

       If  an include file (or files) are defined for this library,
       you will have to append them to [install] in your _H_o_w_t_o_._c_o_o_k
       file.

       _1_4_._8_._1  _v_a_r_i_a_b_l_e_s


       all       targets of the all recipe

       install   targets of the install recipe

       me        The   name  of  the  library  to  be  constructed.
                 Defaults to the last component of the pathname  of
                 the current directory.

       ar        The archive command.

       install   targets  of  the install command.  Only defined if
                 the [lib] variable is defined.

       _1_4_._8_._2  _r_e_c_i_p_e_s


       all       construct the targets defined in [all].

       clean     remove the files named in [dot_clean].

       clobber   remove the files name in [dot_clean] and [all].

       install   Construct the  files  named  in  [install].   Only
                 defined if the [lib] variable is defined.

       uninstall Remove the files named in [install].  Only defined
                 if the [lib] variable is defined.






       
       Peter Miller                                        Page 120





       Cook                                              User Guide



       _1_4_._9  _p_r_i_n_t

       This cookbook is  used  to  print  files.   It  will  almost
       certainly need to be changed for every site.

       _1_4_._9_._1  _r_e_c_i_p_e_s


       %.lw: %.ps Print a PostScript file.

       %.lp: %   Print a text file.

       _1_4_._9_._2  _v_a_r_i_a_b_l_e_s


       lp        The   print   command.   Not  altered  if  already
                 defined.

       lp_flags  Options passed to the print command.  Not  altered
                 if already defined.  Defaults to empty.

       _1_4_._1_0  _p_r_o_g_r_a_m

       This cookbook defines how to construct a program.

       If  your program uses any libraries, you will have to append
       them to [ld_libraries] in your _H_o_w_t_o_._c_o_o_k file.

       _1_4_._1_0_._1  _v_a_r_i_a_b_l_e_s


       all       Targets of the all recipe.

       install   targets of the install recipe

       ld        The name of the linker command.   Not  altered  if
                 already  defined.   Set  to the same as the ``cc''
                 variable if set, otherwise set to the same as  the
                 ``f77''  variable if set, otherwise set to ``ld''.

       ld_flags  Not altered if already defined.   The  default  is
                 empty.

       ld_libraries Options  passed to the C compiler when linking,
                 these are typically library search paths (-L)  and
                 libraries  (-l).   Not altered if already defined.
                 The default is empty.

       me        The  name  of  the  program  to  be   constructed.
                 Defaults  to the last component of the pathname of
                 the current directory.




       
       Peter Miller                                        Page 121





       Cook                                              User Guide



       _1_4_._1_0_._2  _r_e_c_i_p_e_s


       all       Construct the targets named in [all].

       clean     Remove the files named in [dot_clean].

       clobber   Remove the files named in [dot_clean] and [all].

       install   Construct the  files  named  in  [install].   Only
                 defined if the [lib] variable is defined.

       uninstall Remove the files named in [install].  Only defined
                 if the [lib] variable is defined.

       _1_4_._1_0_._3  _S_e_e _A_l_s_o
       The ``c'' cookbook, for C sources.
       The ``f77'' cookbook, for Fortran sources.
       The ``usr'' or  ``usr.local''  or  ``home''  cookbooks,  for
       defining install locations.

       _1_4_._1_1  _r_c_s

       This cookbook is used to extract files from RCS.

       _1_4_._1_1_._1  _r_e_c_i_p_e_s


       %: RCS/%,v Extract files from RCS.

       %: %,v    Extract files from RCS.

       _1_4_._1_1_._2  _v_a_r_i_a_b_l_e_s


       co        The RCS checkout command.

       co_flags  Flags for the co command, default to empty.

















       
       Peter Miller                                        Page 122





       Cook                                              User Guide



       _1_4_._1_2  _r_e_c_u_r_s_i_v_e

       This  cookbook  may  be  used  to  construct  recursive cook
       directory structures,  where  the  top-level  cookbook  only
       invokes cookbooks in deeper directories.

       All  targets  given  to  this  cookbook  result  in all sub-
       directories containing a _H_o_w_t_o_._c_o_o_k file having ccooookk invoked
       with the same target.

       _1_4_._1_2_._1  _R_e_c_i_p_e_s
       The  _a_l_l  recipe  is  defined,  but it does nothing, it only
       exists to set the default target name.

       _1_4_._1_3  _s_c_c_s

       This cookbook is used to extract files from SCCS.

       _1_4_._1_3_._1  _r_e_c_i_p_e_s


       %: SCCS/s.% Extract files from SCCS.

       %: s.%    Extract files from SCCS.

       _1_4_._1_3_._2  _v_a_r_i_a_b_l_e_s


       get       The SCCS get command.

       get_flags Flags for the get command, default to empty.

       _1_4_._1_4  _t_e_x_t

       This cookbook is used to process text documents.

       Include file dependencies are automatically  detected.   The
       requirements  for  various  preprocessors  are automatically
       detected (_e_._g_. eqn, tbl, pic, graf).

       _1_4_._1_4_._1  _r_e_c_i_p_e_s


       %.ps: %.t PostScript for generic *roff source.

       %: %.t    Straight text from *roff source.

       _1_4_._1_4_._2  _v_a_r_i_a_b_l_e_s


       text_incl The    text_incl    command     (finds     include
                 dependencies).  Not altered if already set.



       
       Peter Miller                                        Page 123





       Cook                                              User Guide



       text_roff The    text_roff   command   (finds   preprocessor
                 requirements).  Not altered if already set.

       roff_flags Arguments passed to text_roff, and indirectly  to
                 the  *roff  program.   Not altered if already set.
                 Defaults to empty.

       _1_4_._1_5  _u_s_r_._l_o_c_a_l

       This cookbook defined where  certain  directories  are,  and
       some   common   uses   of  those  directories,  relative  to
       /usr/local.

       _1_4_._1_5_._1  _v_a_r_i_a_b_l_e_s


       bin       The directory to place program binaries into.

       include   The directory to place include files into.

       lib       The directory to place libraries into.

       cc_include_flags The [include] directory  is  added  to  the
                 search options.

       cc_link_flags The  [lib]  directory  is  added to the search
                 options.

       _1_4_._1_6  _u_s_r

       This  cookbook  defined  where  certain   directories   are,
       relative to /usr.

       _1_4_._1_6_._1  _v_a_r_i_a_b_l_e_s


       bin       The directory to place program binaries into.

       include   The directory to place include files into.

       lib       The directory to place libraries into.














       
       Peter Miller                                        Page 124





       Cook                                              User Guide



       _1_4_._1_7  _y_a_c_c___m_a_n_y

       This  cookbook  describes  how  to use yacc.  The difference
       with the "yacc" cookbook is that this cookbook allows you to
       have  more  that  one  yacc  generated  parser  in  the same
       program, by using the classic _s_e_d(1) hack of the output.

       _1_4_._1_8  _y_a_c_c

       This cookbook describes how to use yacc.

       You will have to add "-d" to the  [yacc_flags]  variable  if
       you want %.h files generated.

       If  a  _y_._o_u_t_p_u_t  file  is  constructed,  it will be moved to
       _%_._l_i_s_t.

       _1_4_._1_8_._1  _r_e_c_i_p_e_s


       %.c %.h: %.y Construct C source and header files  from  yacc
                 source files.  Applied if -d in [yacc_flags].

       %.c: %.y  Construct  C  source files from yacc source files.
                 Applied if -d not in [yacc_flags].

       _1_4_._1_8_._2  _v_a_r_i_a_b_l_e_s


       yacc_src  Yacc source files in the current directory.

       dot_src   Source  files   constructable   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       dot_obj   Object  files   constructable   in   the   current
                 directory   (unioned  with  existing  setting,  if
                 necessary).

       dot_clean Files  which  may  be  removed  from  the  current
                 directory in a clean target.

       dot_lint_obj Lint  object files constructable in the current
                 directory  (unioned  with  existing  setting,   if
                 necessary).










       
       Peter Miller                                        Page 125





       Cook                                              User Guide



       _1_5_.  _G_l_o_s_s_a_r_y

       This document employs a number of terms specific to ccooookk.

       _b_o_d_y      A  set  of  statements,  usually  commands,  to be
                 performed to _c_o_o_k the _t_a_r_g_e_ts of  a  _r_e_c_i_p_e  after
                 the _i_n_g_r_e_d_i_e_n_ts exist.

       _c_o_m_m_a_n_d   A  command  is a list of words to be passed to the
                 _o_p_e_r_a_t_i_n_g _s_y_s_t_e_m to be executed.

       _c_o_o_k      When used as a verb, refers to  the  actions  ccooookk
                 would  perform  to  create  a _t_a_r_g_e_t, according to
                 some _r_e_c_i_p_e.

       _c_o_o_k_b_o_o_k  A file containing input for ccooookk, usually _r_e_c_i_p_es.

       _e_x_p_l_i_c_i_t _r_e_c_i_p_e An  explicit recipe is one where the _t_a_r_g_e_ts
                 contain  no  patterns.   That  is,  there  are  no
                 percent ('%%') characters in any of the _t_a_r_g_e_ts.

       _f_i_n_g_e_r_p_r_i_n_t A  cryptographically strong hash of the contents
                 of a file, use to determine if the  file  contents
                 have changed.

       _f_l_a_g      A  flag  modifies  the behavior of a cook session,
                 _r_e_c_i_p_e or command.

       _f_o_r_c_e_d _i_n_g_r_e_d_i_e_n_t A files which must exist before  a  _t_a_r_g_e_t
                 file  of  an  _i_m_p_l_i_c_i_t  _r_e_c_i_p_e may be cooked.  The
                 inability to construct a forced ingredient  is  an
                 error.

       _f_u_n_c_t_i_o_n  A function is an action applied to a word list.

       _g_a_t_e      A gate is a condition which allows the conditional
                 application of a _r_e_c_i_p_e.  The gate condition is in
                 addition  to  the requirement that the ingredients
                 are cookable.

       _i_m_p_l_i_c_i_t _r_e_c_i_p_e An implicit recipe is a recipe with patterns
                 in the _t_a_r_g_e_ts.  That is, there is a percent ('%%')
                 character in at least one of the _t_a_r_g_e_ts.

       _i_n_g_r_e_d_i_e_n_t A files which must exist before a _t_a_r_g_e_t file may
                 be cooked.  In an _i_m_p_l_i_c_i_t _r_e_c_i_p_e the inability to
                 construct of an ingredient means that  the  _r_e_c_i_p_e
                 will  not  be  applied.  In an explicit recipe the
                 inability to construct an ingredient is an  error.

       _l_a_s_t_-_m_o_d_i_f_i_e_d _t_i_m_e
                 UNIX imbues files with several attributes.  One of
                 these is a time-stamp of when the  file  was  last
                 modified.   Usually this is when the file was last

       
       Peter Miller                                        Page 126





       Cook                                              User Guide



                 written to.

       _r_e_c_i_p_e    A _r_e_c_i_p_e consists of several parts.

                   1.  A set of _t_a_r_g_e_ts to be cooked,

                   2.  A set of ingredients of those _t_a_r_g_e_ts, and

                   3.  An optional set of forced ingredients.

                   4.  An optional set of flags.

                   5.  An optional gate.

                   6.  An optional body .

       _t_a_r_g_e_t    The object of a _r_e_c_i_p_e, a thing which is cooked.

       _t_o_u_c_h     UNIX imbues files with several attributes.  One of
                 these  is  a  time-stamp of when the file was last
                 modified.  Usually this is when the file was  last
                 written  to,  however  it  is  possible  to simply
                 adjust  this  attribute,  rather   than   actually
                 writing to the file; this is colloquially known as
                 _t_o_u_c_hing a file.

       _v_a_r_i_a_b_l_e  A variable is a named place holder  for  a  value.
                 The value may be changed.



























       
       Peter Miller                                        Page 127





       Cook                                              User Guide



























































       Peter Miller                                        Page 128









                                 CONTENTS



       1.   Introduction ........................................ 1
            1.1    Why You Want To Use Cook ..................... 1
            1.2    How to Use this Manual ....................... 2
            1.3    Ancient History .............................. 2

       2.   Cook from the Outside ............................... 4
            2.1    What can cook do for me? ..................... 4
            2.2    What is cook doing? .......................... 4
            2.3    What can cook always do? ..................... 4
            2.4    If something goes wrong ...................... 5
            2.5    The Reference Manual ......................... 5

       3.   Cook from a Cookbook ................................ 6
            3.1    What does Cook do? ........................... 6
            3.2    How do I tell Cook what to do? ............... 7
            3.3    Creating a Cookbook .......................... 8

       4.   Cooking in Parallel ................................ 10
            4.1    Command Line Option ......................... 10
            4.2    Cookbook Variable ........................... 10
            4.3    Recipe Writing .............................. 10
            4.4    File Locking ................................ 12
            4.5    Virtual Machine ............................. 12
            4.6    Virtual Machine, Revisited .................. 14

       5.   Include File Dependencies .......................... 17
            5.1    The Manual Method ........................... 17
            5.2    Debugging Cookbooks ......................... 17
            5.3    Tools ....................................... 19
            5.4    The Small Method ............................ 19
            5.5    The Large Method ............................ 20
            5.6    The Cascade Method .......................... 21
            5.7    Dependencies on Derived Files ............... 22
            5.8    Renaming Include Files ...................... 23

       6.   Building Large Projects ............................ 25
            6.1    Whole Project Build ......................... 25
            6.2    Private Work Areas .......................... 31
            6.3    Whole Project Build Advantages .............. 34
            6.4    Heterogeneous Build ......................... 34
            6.5    Installing Things ........................... 36
            6.6    Miscellaneous ............................... 37
            6.7    File Fingerprints ........................... 38
            6.8    Coping with Links ........................... 41
            6.9    Coping with Version Stamps .................. 41

       7.   Cookbook Language Definition ....................... 43
            7.1    Lexical Analysis ............................ 43
                   7.1.1   Words and Keywords .................. 43


       
                                     i









                   7.1.2   Escape Sequences .................... 43
                   7.1.3   Quoting ............................. 44
                   7.1.4   Comments ............................ 44
            7.2    Preprocessor ................................ 44
                   7.2.1   include ............................. 44
                   7.2.2   include-cooked ...................... 45
                   7.2.3   include-cooked-nowarn ............... 46
                   7.2.4   if .................................. 46
                   7.2.5   ifdef ............................... 47
                   7.2.6   ifndef .............................. 47
                   7.2.7   pragma .............................. 47
            7.3    Syntax and Semantics ........................ 48
                   7.3.1   Overall Structure ................... 48
                   7.3.2   The Compound Statement .............. 48
                   7.3.3   Variables and Expressions ........... 48
                   7.3.4   Recipes ............................. 51
                   7.3.5   The Explicit Recipe Statement ....... 51
                   7.3.6   The Implicit Recipe Statement ....... 57
                   7.3.7   The Ingredients Recipe Statement .... 58
                   7.3.8   The Cascade Recipe Statement ........ 59
                   7.3.9   Commands ............................ 59
                   7.3.10  The Simple Command Statement ........ 59
                   7.3.11  The Data Command Statement .......... 60
                   7.3.12  The Set Statement ................... 61
                   7.3.13  The Fail Statement .................. 62
                   7.3.14  The If Statement .................... 62
                   7.3.15  The Loop and Loopend Statements ..... 63
                   7.3.16  Functions ........................... 63

       8.   Built-In Functions ................................. 66
            8.1    addprefix ................................... 66
            8.2    addsuffix ................................... 66
            8.3    and ......................................... 66
            8.4    basename .................................... 67
            8.5    cando ....................................... 67
            8.6    catenate .................................... 68
            8.7    collect_lines ............................... 68
            8.8    collect ..................................... 69
            8.9    cook ........................................ 69
            8.10   count ....................................... 70
            8.11   defined ..................................... 70
            8.12   dirname ..................................... 70
            8.13   dir ......................................... 71
            8.14   dos-path .................................... 71
            8.15   downcase .................................... 72
            8.16   entryname ................................... 72
            8.17   execute ..................................... 72
            8.18   exists ...................................... 73
            8.19   exists-symlink .............................. 73
            8.20   expr ........................................ 74
            8.21   filter_out .................................. 75
            8.22   filter ...................................... 75
            8.23   find_command ................................ 76


       
                                    ii









            8.24   findstring .................................. 76
            8.25   firstword ................................... 77
            8.26   fromto ...................................... 77
            8.27   getenv ...................................... 78
            8.28   glob ........................................ 78
            8.29   head ........................................ 79
            8.30   home ........................................ 79
            8.31   if .......................................... 79
            8.32   in .......................................... 80
            8.33   interior_files .............................. 80
            8.34   join ........................................ 81
            8.35   leaf_files .................................. 81
            8.36   matches ..................................... 81
            8.37   match_mask .................................. 82
            8.38   mtime ....................................... 82
            8.39   mtime-seconds ............................... 82
            8.40   notdir ...................................... 83
            8.41   not ......................................... 83
            8.42   operating_system ............................ 84
            8.43   options ..................................... 85
            8.44   or .......................................... 86
            8.45   pathname .................................... 86
            8.46   patsubst .................................... 86
            8.47   prepost ..................................... 87
            8.48   print ....................................... 87
            8.49   quote ....................................... 87
            8.50   read_lines .................................. 88
            8.51   readlink .................................... 88
            8.52   read ........................................ 88
            8.53   relative_dirname ............................ 88
            8.54   resolve ..................................... 89
            8.55   shell ....................................... 89
            8.56   sort_newest ................................. 90
            8.57   sort ........................................ 90
            8.58   split ....................................... 90
            8.59   stringset ................................... 91
            8.60   stripdot .................................... 91
            8.61   strip ....................................... 92
            8.62   substr ...................................... 92
            8.63   subst ....................................... 93
            8.64   suffix ...................................... 93
            8.65   tail ........................................ 94
            8.66   un-dos-path ................................. 94
            8.67   unsplit ..................................... 94
            8.68   upcase ...................................... 95
            8.69   uptodate .................................... 95
            8.70   wildcard .................................... 95
            8.71   word ........................................ 96
            8.72   words ....................................... 97
            8.73   write ....................................... 97

       9.   Predefined Variables ............................... 98
            9.1    arg ......................................... 98


       
                                    iii









            9.2    command-line-goals .......................... 98
            9.3    __FILE__ .................................... 98
            9.4    __FUNCTION__ ................................ 98
            9.5    graph_leaf_file ............................. 98
            9.6    graph_exterior_file ......................... 98
            9.7    graph_interior_file ......................... 98
            9.8    graph_leaf_pattern .......................... 98
            9.9    graph_exterior_pattern ...................... 99
            9.10   graph_interior_pattern ...................... 99
            9.11   __LINE__ .................................... 99
            9.12   need ........................................ 99
            9.13   parallel_hosts .............................. 99
            9.14   parallel_jobs ............................... 99
            9.15   parallel_rsh ................................ 99
            9.16   search_list ................................. 99
            9.17   self ....................................... 100
            9.18   target ..................................... 100
            9.19   targets .................................... 100
            9.20   thread-id .................................. 100
            9.21   timestamp_granularity ...................... 100
            9.22   younger .................................... 100
            9.23   version .................................... 100

       10.  Functions Library ................................. 101
            10.1   capitalize ................................. 101
            10.2   defined-or-null ............................ 101
            10.3   defined-or-default ......................... 101
            10.4   repeat ..................................... 101
            10.5   variable_by_path ........................... 102

       11.  Actions when Cooking .............................. 103
            11.1   Scan the COOK Environment Variable ......... 103
            11.2   Scan the Command Line ...................... 103
            11.3   Locate the Cookbook ........................ 103
            11.4   Form the Listing Filename .................. 103
            11.5   Create the Listing file .................... 103
            11.6   Scan the Cookbook .......................... 104
            11.7   Determine targets to cook .................. 104
            11.8   Cooking a Target ........................... 104
            11.9   The Dependency Graph ....................... 107
            11.10  File Status ................................ 108

       12.  Option Precedence ................................. 110

       13.  File name patterns ................................ 111
            13.1   Cook Patterns .............................. 111
            13.2   Regular Expressions ........................ 113

       14.  Supplied Cookbooks ................................ 116
            14.1   as ......................................... 116
            14.2   c .......................................... 117
            14.3   f77 ........................................ 118
            14.4   g77 ........................................ 119


       
                                    iv









            14.5   gcc ........................................ 119
            14.6   home ....................................... 119
            14.7   lex ........................................ 119
            14.8   library .................................... 120
            14.9   print ...................................... 121
            14.10  program .................................... 121
            14.11  rcs ........................................ 122
            14.12  recursive .................................. 123
            14.13  sccs ....................................... 123
            14.14  text ....................................... 123
            14.15  usr.local .................................. 124
            14.16  usr ........................................ 124
            14.17  yacc_many .................................. 125
            14.18  yacc ....................................... 125

       15.  Glossary .......................................... 126







































       
                                     v

































































                                    vi


