summaryrefslogtreecommitdiff
path: root/dmake/make.c
diff options
context:
space:
mode:
Diffstat (limited to 'dmake/make.c')
-rw-r--r--dmake/make.c1774
1 files changed, 0 insertions, 1774 deletions
diff --git a/dmake/make.c b/dmake/make.c
deleted file mode 100644
index 67af0653d35f..000000000000
--- a/dmake/make.c
+++ /dev/null
@@ -1,1774 +0,0 @@
-/* $RCSfile: make.c,v $
--- $Revision: 1.12 $
--- last change: $Author: kz $ $Date: 2008-03-05 18:29:19 $
---
--- SYNOPSIS
--- Perform the update of all outdated targets.
---
--- DESCRIPTION
--- This is where we traverse the make graph looking for targets that
--- are out of date, and we try to infer how to make them if we can.
--- The usual make macros are understood, as well as some new ones:
---
--- $$ - expands to $
--- $@ - full target name
--- $* - target name with no suffix, same as $(@:db)
--- or, the value of % in % meta rule recipes
--- $? - list of out of date prerequisites
--- $< - all prerequisites associated with rules line
--- $& - all prerequisites associated with target
--- $> - library name for target (if any)
--- $^ - out of date prerequisites taken from value of $<
---
--- AUTHOR
--- Dennis Vadura, dvadura@dmake.wticorp.com
---
--- WWW
--- http://dmake.wticorp.com/
---
--- COPYRIGHT
--- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
---
--- This program is NOT free software; you can redistribute it and/or
--- modify it under the terms of the Software License Agreement Provided
--- in the file <distribution-root>/readme/license.txt.
---
--- LOG
--- Use cvs log to obtain detailed change logs.
-*/
-
-#include "extern.h"
-#include "sysintf.h"
-
-typedef struct cell {
- char *datum;
- struct cell *next;
- size_t len;
-} LISTCELL, *LISTCELLPTR;
-
-typedef struct {
- LISTCELLPTR first;
- LISTCELLPTR last;
- size_t len;
-} LISTSTRING, *LISTSTRINGPTR;
-
-
-static void _drop_mac ANSI((HASHPTR));
-static void _set_recipe ANSI((char*, int));
-static void _set_tmd ANSI(());
-static void _append_file ANSI((STRINGPTR, FILE*, char*, int));
-static LINKPTR _dup_prq ANSI((LINKPTR));
-static LINKPTR _expand_dynamic_prq ANSI(( LINKPTR, LINKPTR, char * ));
-static char* _prefix ANSI((char *, char *));
-static char* _pool_lookup ANSI((char *));
-static int _explode_graph ANSI((CELLPTR, LINKPTR, CELLPTR));
-
-
-#define RP_GPPROLOG 0
-#define RP_RECIPE 1
-#define RP_GPEPILOG 2
-#define NUM_RECIPES 3
-
-static STRINGPTR _recipes[NUM_RECIPES];
-static LISTCELLPTR _freelist=NULL;
-
-static LISTCELLPTR
-get_cell()
-{
- LISTCELLPTR cell;
-
- if (!_freelist) {
- if ((cell=MALLOC(1,LISTCELL)) == NULL)
- No_ram();
- }
- else {
- cell = _freelist;
- _freelist = cell->next;
- }
-
- return(cell);
-}
-
-
-static void
-free_cell(LISTCELLPTR cell)
-{
- cell->next = _freelist;
- _freelist = cell;
-}
-
-
-static void
-free_list(LISTCELLPTR c)
-{
- if(c) {
- free_list(c->next);
- free_cell(c);
- }
-}
-
-
-static void
-list_init(LISTSTRINGPTR s)
-{
- s->first = NULL;
- s->last = NULL;
- s->len = 0;
-}
-
-
-static void
-list_add(LISTSTRINGPTR s, char *str)
-{
- LISTCELLPTR p;
- int l;
-
- if ((l = strlen(str)) == 0)
- return;
-
- p = get_cell();
- p->datum = str;
- p->next = NULL;
- p->len = l;
-
- if(s->first == NULL)
- s->first = p;
- else
- s->last->next = p;
-
- s->last = p;
- s->len += l+1;
-}
-
-
-static char *
-gen_path_list_string(LISTSTRINGPTR s)/*
-=======================================
- Take a list of filepaths and create a string from it separating
- the filenames by a space.
- This function honors the cygwin specific .WINPATH attribute. */
-{
- LISTCELLPTR next, cell;
- int len;
- int slen, slen_rest;
- char *result;
- char *p, *tpath;
-
- if( (slen_rest = slen = s->len) == 0)
- return(NIL(char));
-
- /* reserve enough space to hold the concated original filenames. */
- if((p = result = MALLOC(slen, char)) == NULL) No_ram();
-
- for (cell=s->first; cell; cell=next) {
-#if !defined(__CYGWIN__)
- tpath = cell->datum;
- len=cell->len;
-#else
- /* For cygwin with .WINPATH set the lenght of the converted
- * filepaths might be longer. Extra checking is needed ... */
- tpath = DO_WINPATH(cell->datum);
- if( tpath == cell->datum ) {
- len=cell->len;
- }
- else {
- /* ... but only if DO_WINPATH() did something. */
- len = strlen(tpath);
- }
- if( len >= slen_rest ) {
- /* We need more memory. As DOS paths are usually shorter than the
- * original cygwin POSIX paths (exception mounted paths) this should
- * rarely happen. */
- int p_offset = p - result;
- /* Get more than needed. */
- slen = slen + len - slen_rest + 128;
- if((result = realloc( result, slen ) ) == NULL)
- No_ram();
- p = result + p_offset;
- }
-#endif
-
- memcpy((void *)p, (void *)tpath, len);
- p += len;
- *p++ = ' ';
-
-#if defined(__CYGWIN__)
- /* slen_rest is only used in the cygwin / .WINPATH case. */
- slen_rest = slen - (p - result);
-#endif
-
- next = cell->next;
- free_cell(cell);
- }
-
- *--p = '\0';
- list_init(s);
-
- return(result);
-}
-
-
-PUBLIC int
-Make_targets()/*
-================
- Actually go and make the targets on the target list */
-{
- LINKPTR lp;
- int done = 0;
-
- DB_ENTER( "Make_targets" );
-
- Read_state();
- _set_recipe( ".GROUPPROLOG", RP_GPPROLOG );
- _set_recipe( ".GROUPEPILOG", RP_GPEPILOG );
-
- /* Prevent recipe inference for .ROOT */
- if ( Root->ce_recipe == NIL(STRING) ) {
- TALLOC( Root->ce_recipe, 1, STRING );
- Root->ce_recipe->st_string = "";
- }
-
- /* Prevent recipe inference for .TARGETS */
- if ( Targets->ce_recipe == NIL(STRING) ) {
- TALLOC( Targets->ce_recipe, 1, STRING );
- Targets->ce_recipe->st_string = "";
- }
-
- /* Make sure that user defined targets are marked as root targets */
- for( lp = Targets->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
- lp->cl_prq->ce_attr |= A_ROOT;
-
- while( !done ) {
- int rval;
-
- if( (rval = Make(Root, NIL(CELL))) == -1 )
- DB_RETURN(1);
- else
- done = Root->ce_flag & F_MADE;
-
- if( !rval && !done ) Wait_for_child( FALSE, -1 );
- }
-
- for( lp = Targets->ce_prq; lp != NIL(LINK); lp = lp->cl_next ) {
- CELLPTR tgt = lp->cl_prq;
- if( !(tgt->ce_attr & A_UPDATED)
- && (Verbose & V_MAKE) )
- printf( "`%s' is up to date\n", tgt->CE_NAME );
- }
-
- DB_RETURN( 0 );
-}
-
-
-
-PUBLIC int
-Make( cp, setdirroot )/*
-========================
- Make target cp. Make() is also called on prerequisites that have no rule
- associated (F_TARGET is not set) to verify that they exist. */
-CELLPTR cp;
-CELLPTR setdirroot;
-{
- register LINKPTR dp, prev,next;
- register CELLPTR tcp;
- CELLPTR nsetdirroot;
- char *name, *lib;
- HASHPTR m_at, m_q, m_b, m_g, m_l, m_bb, m_up;
- LISTSTRING all_list, imm_list, outall_list, inf_list;
- char *all = NIL(char);
- char *inf = NIL(char);
- char *outall = NIL(char);
- char *imm = NIL(char);
- int rval = 0; /* 0==ready, 1==target still running, -1==error */
- int push = 0;
- int made = F_MADE;
- int ignore;
- time_t otime = (time_t) 1L; /* Hold time of newest prerequisite. */
- int mark_made = FALSE;
-
-#if defined(__CYGWIN__)
- /* static variable to hold .WINPATH status of previously made target.
- * 0, 1 are .WINPATH states, -1 indicates the first target. */
- static int prev_winpath_attr = -1;
-#endif
-
- DB_ENTER( "Make" );
- DB_PRINT( "mem", ("%s:-> mem %ld", cp->CE_NAME, (long) coreleft()) );
-
- /* Initialize the various temporary storage */
- m_q = m_b = m_g = m_l = m_bb = m_up = NIL(HASH);
- list_init(&all_list);
- list_init(&imm_list);
- list_init(&outall_list);
- list_init(&inf_list);
-
- if (cp->ce_set && cp->ce_set != cp) {
- if( Verbose & V_MAKE )
- printf( "%s: Building .UPDATEALL representative [%s]\n", Pname,
- cp->ce_set->CE_NAME );
- cp = cp->ce_set;
- }
-
- /* If we are supposed to change directories for this target then do so.
- * If we do change dir, then modify the setdirroot variable to reflect
- * that fact for all of the prerequisites that we will be making. */
-
- nsetdirroot = setdirroot;
- ignore = (((cp->ce_attr|Glob_attr)&A_IGNORE) != 0);
-
- /* Set the UseWinpath variable to reflect the (global/local) .WINPATH
- * attribute. The variable is used by DO_WINPATH() and in some other
- * places. */
- UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
-
- /* m_at needs to be defined before going to a "stop_making_it" where
- * a _drop_mac( m_at ) would try to free it. */
- /* FIXME: m_at can most probably not be changed before the next
- * Def_macro("@", ...) command. Check if both this and the next
- * call are needed. */
- m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
-
- if( cp->ce_attr & A_SETDIR ) {
- /* Change directory only if the previous .SETDIR is a different
- * directory from the current one. ie. all cells with the same .SETDIR
- * attribute are assumed to come from the same directory. */
-
- if( (setdirroot == NIL(CELL) || setdirroot->ce_dir != cp->ce_dir) &&
- (push = Push_dir(cp->ce_dir,cp->CE_NAME,ignore)) != 0 )
- setdirroot = cp;
- }
-
- DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
-
- /* FIXME: F_MULTI targets don't have cp->ce_recipe set but the recipes
- * are known nevertheless. It is not necessary to infer them.
- * If (cp->ce_flag & F_MULTI) is true the recipes of the corresponding
- * subtargets can be used. */
- if( cp->ce_recipe == NIL(STRING) ) {
- char *dir = cp->ce_dir;
-
- if( Verbose & V_MAKE )
- printf( "%s: Infering prerequisite(s) and recipe for [%s]\n", Pname,
- cp->CE_NAME );
-
- Infer_recipe( cp, setdirroot );
-
- /* See if the directory has changed, if it has then make sure we
- * push it. */
- if( dir != cp->ce_dir ) {
- if( push ) Pop_dir(FALSE);
- push = Push_dir( cp->ce_dir, cp->CE_NAME, ignore );
- setdirroot = cp;
- }
- }
-
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp = dp->cl_prq;
- if( push ) {
- /* If we changed the directory because of .SETDIR write Pwd into
- * tcp->ce_dir so that it holds an absolute path. */
- if( !(tcp->ce_attr & A_POOL) && tcp->ce_dir ) FREE( tcp->ce_dir );
- tcp->ce_dir = _pool_lookup(Pwd);
- tcp->ce_attr |= A_SETDIR|A_POOL;
- }
- tcp->ce_setdir = nsetdirroot;
- }
-
- DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
- /* If we have not yet statted the target then do so. */
- if( !(cp->ce_flag & F_STAT) && !(cp->ce_attr&A_PHONY) ) {
- if (cp->ce_parent && (cp->ce_parent->ce_flag & F_MULTI)) {
- /* Inherit the stat info from the F_MULTI parent. */
- cp->ce_time = cp->ce_parent->ce_time;
- cp->ce_flag |= F_STAT;
- /* Propagate the A_PRECIOUS attribute from the parent. */
- cp->ce_attr |= cp->ce_parent->ce_attr & A_PRECIOUS;
- }
- else {
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp = dp->cl_prq;
- /* Check if target already exists. */
- Stat_target( tcp, 1, FALSE );
-
- if( tcp->ce_time != (time_t)0L ) {
- /* File exists so don't remove it later. */
- tcp->ce_attr |= A_PRECIOUS;
- }
-
- if( Verbose & V_MAKE )
- printf("%s: Time stamp of [%s] is %ld\n",Pname,tcp->CE_NAME,
- tcp->ce_time);
- }
- }
- }
-
- DB_PRINT( "make", ("(%s, %ld, 0x%08x, 0x%04x)", cp->CE_NAME,
- cp->ce_time, cp->ce_attr, cp->ce_flag) );
-
- /* Handle targets without rule and without existing file. */
- if( !(cp->ce_flag & F_TARGET) && (cp->ce_time == (time_t) 0L) ) {
- if( Makemkf ) {
- rval = -1;
- goto stop_making_it;
- }
- else if( cp->ce_prq != NIL(LINK)
- || (STOBOOL(Augmake) && (cp->ce_flag&F_EXPLICIT)))
- /* Assume an empty recipe for a target that we have run inference on
- * but do not have a set of rules for but for which we have inferred
- * a list of prerequisites. */
- cp->ce_flag |= F_RULES;
- else
- Fatal( "`%s' not found, and can't be made", cp->CE_NAME );
- }
-
- DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
-
- /* set value of $* if we have not infered a recipe, in this case $* is
- * the same as $(@:db), this allows us to be compatible with BSD make */
- if( cp->ce_per == NIL(char) ) cp->ce_per = "$(@:db)";
-
- /* Search the prerequisite list for dynamic prerequisites and if we find
- * them copy the list of prerequisites for potential later re-use. */
- if ( cp->ce_prqorg == NIL(LINK) ) {
- for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next )
- if ( strchr(dp->cl_prq->CE_NAME, '$') != NULL )
- break;
-
- if (dp != NIL(LINK)) {
- cp->ce_prqorg = _dup_prq(cp->ce_prq);
- }
- }
-
- /* Define $@ macro. The only reason for defining it here (that I see ATM)
- * is that $@ is already defined in conditional macros. */
- /* FIXME: check if both this and the previous Def_macro("@", ...) call
- * are needed. */
- m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
-
- /* Define conditional macros if any, note this is done BEFORE we process
- * prerequisites for the current target. Thus the making of a prerequisite
- * is done using the current value of the conditional macro. */
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp=dp->cl_prq;
- if (tcp->ce_cond != NIL(STRING)) {
- STRINGPTR sp;
-
- tcp->ce_pushed = NIL(HASH);
- for(sp=tcp->ce_cond; sp; sp=sp->st_next) {
- if(Parse_macro(sp->st_string,M_MULTI|M_PUSH)) {
- HASHPTR hp;
-
- hp = GET_MACRO(LastMacName);
- hp->ht_link = tcp->ce_pushed;
- tcp->ce_pushed = hp;
- }
- else {
- Error("Invalid conditional macro expression [%s]",sp->st_string);
- }
- }
- }
- }
-
- /* First round, will be repeated a second time below. */
- for( prev=NULL,dp=cp->ce_prq; dp != NIL(LINK); prev=dp, dp=next ) {
- int seq;
-
- /* This loop executes Make() to build prerequisites if needed.
- * The only macro that needs to be reset after a Make() was executed
- * is $@ as it might be used when expanding potential dynamic
- * prerequisites. As UseWinpath is a global variable we also
- * need to restore it. */
- if (m_at->ht_value == NIL(char)) {
- /* This check effectively tests if Make() was run before because
- * Make() frees all dynamic macro values at the end. */
- UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
- m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
- }
-
- /* Make the prerequisite, note that if the current target has the
- * .LIBRARY attribute set we pass on to the prerequisite the .LIBRARYM
- * attribute and pass on the name of the current target as the library
- * name, and we take it away when we are done. */
- next = dp->cl_next;
-
- tcp = dp->cl_prq;
- if( Verbose & V_MAKE )
- printf("Checking prerequisite [%s]\n", tcp->CE_NAME);
-
- seq = (((cp->ce_attr | Glob_attr) & A_SEQ) != 0);
-
- /* This checks if this prerequisite is still in the making, if yes
- * come back later. */
- if( tcp->ce_flag & F_VISITED ) {
- /* Check if this currently or fully made target has the same
- * .SETDIR setting. If yes, continue if it was made or come
- * back later otherwise. */
- if( _explode_graph(tcp, dp, setdirroot) == 0 ) {
- /* didn't blow it up so see if we need to wait for it. */
- if( tcp->ce_flag & F_MADE ) {
- /* Target was made. */
- continue;
- }
- else
- /* Target is still in the making ... */
- goto stop_making_it;
- }
- else
- /* Use the new prerequisite with the new .SETDIR value. */
- tcp = dp->cl_prq;
- }
-
- /* If the previous target (prereq) is not yet ready return if
- * seq is TRUE. */
- if( seq && !made ) goto stop_making_it;
-
- /* Expand dynamic prerequisites. The F_MARK flag is guarging against
- * possible double expandion of dynamic prerequisites containing more
- * than one prerequisite. */
- /* A new A_DYNAMIC attribute could save a lot of strchr( ,'$') calls. */
- if ( tcp && !(tcp->ce_flag & F_MARK) && strchr(tcp->CE_NAME, '$') ) {
- /* Replace this dynamic prerequisite with the the real prerequisite,
- * and add the additional prerequisites if there are more than one.*/
-
- name = Expand( tcp->CE_NAME );
- if( strcmp(name,cp->CE_NAME) == 0 )
- Fatal("Detected circular dynamic dependency; generated '%s'",name);
-
- /* Call helper for dynamic prerequisite expansion to replace the
- * prerequisite with the expanded version and add the new
- * prerequisites, if the macro expanded to more than one, after
- * the current list element. */
- dp = _expand_dynamic_prq( cp->ce_prq, dp, name );
- FREE( name );
-
- /* _expand_dynamic_prq() probably changed dp->cl_prq. */
- tcp = dp->cl_prq;
- if ( tcp ) {
- next = dp->cl_next;
- }
- }
-
- /* Dynamic expansion results in a NULL cell only when the the new
- * prerequisite is already in the prerequisite list or empty. In this
- * case delete the cell and continue. */
- if ( tcp == NIL(CELL) ) {
- FREE(dp);
- if ( prev == NIL(LINK) ) {
- cp->ce_prq = next;
- dp = NULL; /* dp will be the new value of prev. */
- }
- else {
- prev->cl_next = next;
- dp = prev;
- }
- continue;
- }
-
- /* Clear F_MARK flag that could have been set by _expand_dynamic_prq(). */
- tcp->ce_flag &= ~(F_MARK);
-
- if( cp->ce_attr & A_LIBRARY ) {
- tcp->ce_attr |= A_LIBRARYM;
- tcp->ce_lib = cp->ce_fname;
- }
-
- /* Propagate the parent's F_REMOVE and F_INFER flags to the
- * prerequisites. */
- tcp->ce_flag |= cp->ce_flag & (F_REMOVE|F_INFER);
-
- /* Propagate parents A_ROOT attribute to a child if the parent is a
- * F_MULTI target. */
- if( (cp->ce_flag & F_MULTI) && (cp->ce_attr & A_ROOT) )
- tcp->ce_attr |= A_ROOT;
-
- tcp->ce_parent = cp;
- rval |= Make(tcp, setdirroot);
-
- if( cp->ce_attr & A_LIBRARY )
- tcp->ce_attr ^= A_LIBRARYM;
-
- /* Return on error or if Make() is still running and A_SEQ is set.
- * (All F_MULTI targets have the A_SEQ attribute.) */
- if( rval == -1 || (seq && (rval==1)) )
- goto stop_making_it;
-
- /* If tcp is ready, set made = F_MADE. */
- made &= tcp->ce_flag & F_MADE;
- }
-
-
- /* Do the loop again. We are most definitely going to make the current
- * cell now. NOTE: doing this loop here also results in a reduction
- * in peak memory usage by the algorithm. */
-
- for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next ) {
- int tgflg;
- tcp = dp->cl_prq;
- if( tcp == NIL(CELL) )
- Fatal("Internal Error: Found prerequisite list cell without prerequisite!");
-
- name = tcp->ce_fname;
-
- /* make certain that all prerequisites are made prior to advancing. */
- if( !(tcp->ce_flag & F_MADE) ) goto stop_making_it;
-
- /* If the target is a library, then check to make certain that a member
- * is newer than an object file sitting on disk. If the disk version
- * is newer then set the time stamps so that the archived member is
- * replaced. */
- if( cp->ce_attr & A_LIBRARY )
- if( tcp->ce_time <= cp->ce_time ) {
- time_t mtime = Do_stat( name, tcp->ce_lib, NIL(char *), FALSE );
- if( mtime < tcp->ce_time ) tcp->ce_time = cp->ce_time+1L;
- }
-
- /* Set otime to the newest time stamp of all prereqs or 1 if there
- * are no prerequisites. */
- if( tcp->ce_time > otime ) otime = tcp->ce_time;
-
- list_add(&all_list, name);
- if( (tgflg = (dp->cl_flag & F_TARGET)) != 0 )
- list_add(&inf_list, name);
-
- if((cp->ce_time<tcp->ce_time) || ((tcp->ce_flag & F_TARGET) && Force)) {
- list_add(&outall_list, name);
- if( tgflg )
- list_add(&imm_list, name);
- }
- }
-
- /* If we are building a F_MULTI target inherit the time from
- * its children. */
- if( (cp->ce_flag & F_MULTI) )
- cp->ce_time = otime;
-
- /* All prerequisites are made, now make the current target. */
-
- /* Restore UseWinpath and $@ if needed, see above for an explanation. */
- if (m_at->ht_value == NIL(char)) {
- /* This check effectively tests if Make() was run before because
- * Make() frees all dynamic macro values at the end. */
- UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
- m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
- }
-
- /* Create a string with all concatenate filenames. The function
- * respects .WINPATH. Note that gen_path_list_string empties its
- * parameter :( */
- all = gen_path_list_string(&all_list);
- imm = gen_path_list_string(&imm_list);
- outall = gen_path_list_string(&outall_list);
- inf = gen_path_list_string(&inf_list);
-
- DB_PRINT( "mem", ("%s:-C mem %ld", cp->CE_NAME, (long) coreleft()) );
- DB_PRINT( "make", ("I make '%s' if %ld > %ld", cp->CE_NAME, otime,
- cp->ce_time) );
-
- if( Verbose & V_MAKE ) {
- printf( "%s: >>>> Making ", Pname );
- /* Also print the F_MULTI master target. */
- if( cp->ce_flag & F_MULTI )
- printf( "(::-\"master\" target) " );
- if( cp->ce_count != 0 )
- printf( "[%s::{%d}]\n", cp->CE_NAME, cp->ce_count );
- else
- printf( "[%s]\n", cp->CE_NAME );
- }
-
-
- /* Only PWD, TMD, MAKEDIR and the dynamic macros are affected by
- * .WINPATH. $@ is handled earlier, do the rest now. */
-#if defined(__CYGWIN__)
- /* This is only relevant for cygwin. */
- if( UseWinpath != prev_winpath_attr ) {
- Def_macro( "MAKEDIR", Makedir, M_FORCE | M_EXPANDED );
- /* If push is TRUE (Push_dir() was used) PWD and TMD are already
- * set. */
- if( !push ) {
- Def_macro( "PWD", Pwd, M_FORCE | M_EXPANDED );
- _set_tmd();
- }
- }
- prev_winpath_attr = UseWinpath;
-#endif
-
- /* Set the remaining dynamic macros $*, $>, $?, $<, $& and $^. */
-
- /* $* is either expanded as the result of a % inference or defined to
- * $(@:db) and hence unexpanded otherwise. The latter doesn't start
- * with / and will therefore not be touched by DO_WINPATH(). */
- m_bb = Def_macro( "*", DO_WINPATH(cp->ce_per), M_MULTI );
-
- /* This is expanded. */
- m_g = Def_macro( ">", DO_WINPATH(cp->ce_lib), M_MULTI|M_EXPANDED );
- /* These strings are generated with gen_path_list_string() and honor
- * .WINPATH */
- m_q = Def_macro( "?", outall, M_MULTI|M_EXPANDED );
- m_b = Def_macro( "<", inf, M_MULTI|M_EXPANDED );
- m_l = Def_macro( "&", all, M_MULTI|M_EXPANDED );
- m_up = Def_macro( "^", imm, M_MULTI|M_EXPANDED );
-
- _recipes[ RP_RECIPE ] = cp->ce_recipe;
-
- /* We attempt to make the target if
- * 1. it has a newer prerequisite
- * 2. It is a target and Force is set
- * 3. It's set of recipe lines has changed.
- */
- if( Check_state(cp, _recipes, NUM_RECIPES )
- || (cp->ce_time < otime)
- || ((cp->ce_flag & F_TARGET) && Force)
- ) {
-
- if( Measure & M_TARGET )
- Do_profile_output( "s", M_TARGET, cp );
-
- /* Only checking so stop as soon as we determine we will make
- * something */
- if( Check ) {
- rval = -1;
- goto stop_making_it;
- }
-
- if( Verbose & V_MAKE )
- printf( "%s: Updating [%s], (%ld > %ld)\n", Pname,
- cp->CE_NAME, otime, cp->ce_time );
-
- /* In order to check if a targets time stamp was properly updated
- * after the target was made and to keep the dependency chain valid
- * for targets without recipes we store the minimum required file
- * time. If the target time stamp is older than the newest
- * prerequisite use that time, otherwise the current time. (This
- * avoids the call to Do_time() for every target, still checks
- * if the target time is new enough for the given prerequisite and
- * mintime is also the newest time of the given prerequisites and
- * can be used for targets without recipes.)
- * We reuse the ce_time member to store this minimum time until
- * the target is finished by Update_time_stamp(). This function
- * checks if the file time was updated properly and warns if it was
- * not. (While making a target this value does not change.) */
- cp->ce_time = ( cp->ce_time < otime ? otime : Do_time() );
- DB_PRINT( "make", ("Set ce_time (mintime) to: %ld", cp->ce_time) );
-
- if( Touch ) {
- name = cp->ce_fname;
- lib = cp->ce_lib;
-
- if( (!(Glob_attr & A_SILENT) || !Trace) && !(cp->ce_attr & A_PHONY) ) {
- if( lib == NIL(char) )
- printf("touch(%s)", name );
- else if( cp->ce_attr & A_SYMBOL )
- printf("touch(%s((%s)))", lib, name );
- else
- printf("touch(%s(%s))", lib, name );
- }
-
- if( !Trace && !(cp->ce_attr & A_PHONY) )
- if( Do_touch( name, lib,
- (cp->ce_attr & A_SYMBOL) ? &name : NIL(char *) ) != 0 )
- printf( " not touched - non-existant" );
-
- if( (!(Glob_attr & A_SILENT) || !Trace) && !(cp->ce_attr & A_PHONY) )
- printf( "\n" );
-
- Update_time_stamp( cp );
- }
- else if( cp->ce_recipe != NIL(STRING) ) {
- /* If a recipe is found use it. Note this misses F_MULTI targets. */
- if( !(cp->ce_flag & F_SINGLE) ) /* Execute the recipes once ... */
- rval = Exec_commands( cp );
- /* Update_time_stamp() is called inside Exec_commands() after the
- * last recipe line is finished. (In _finished_child()) */
- else { /* or for every out of date dependency
- * if the ruleop ! was used. */
- TKSTR tk;
-
- /* We will redefine $? to be the prerequisite that the recipes
- * are currently evaluated for. */
- _drop_mac( m_q );
-
- /* Execute recipes for each out out of date prerequisites.
- * WARNING! If no prerequisite is given the recipes are not
- * executed at all! */
- if( outall && *outall ) {
- /* Wait for each prerequisite to finish, save the status
- * of Wait_for_completion. */
- int wait_for_completion_status = Wait_for_completion;
- Wait_for_completion = TRUE;
-
- SET_TOKEN( &tk, outall );
-
- /* No need to update the target timestamp/removing temporary
- * prerequisites (Update_time_stamp() in _finished_child())
- * until all prerequisites are done. */
- Doing_bang = TRUE;
- name = Get_token( &tk, "", FALSE );
- /* This loop might fail if outall contains filenames with
- * spaces. */
- do {
- /* Set $? to current prerequisite. */
- m_q->ht_value = name;
-
- rval = Exec_commands( cp );
- /* Thanks to Wait_for_completion = TRUE we are allowed
- * to remove the temp files here. */
- Unlink_temp_files(cp);
- }
- while( *(name = Get_token( &tk, "", FALSE )) != '\0' );
- Wait_for_completion = wait_for_completion_status;
- Doing_bang = FALSE;
- }
-
- Update_time_stamp( cp );
- /* Erase $? again. Don't free the pointer, it was part of outall. */
- m_q->ht_value = NIL(char);
- }
- }
- else if( !(cp->ce_flag & F_RULES) && !(cp->ce_flag & F_STAT) &&
- (!(cp->ce_attr & A_ROOT) || !(cp->ce_flag & F_EXPLICIT)) &&
- !(cp->ce_count) )
- /* F_MULTI subtargets should evaluate its parents F_RULES value
- * but _make_multi always sets the F_RULES value of the master
- * target. Assume F_RULES is set for subtargets. This might not
- * be true if there are no prerequisites and no recipes in any
- * of the subtargets. (FIXME) */
- Fatal( "Don't know how to make `%s'",cp->CE_NAME );
- else {
- /* Empty recipe, set the flag as MADE and update the time stamp */
- /* This might be a the master cell of a F_MULTI target. */
- Update_time_stamp( cp );
- }
- }
- else {
- if( Verbose & V_MAKE )
- printf( "%s: Up to date [%s], prq time = %ld , target time = %ld)\n", Pname,
- cp->CE_NAME, otime, cp->ce_time );
- mark_made = TRUE;
- }
-
- /* If mark_made == TRUE the target is up-to-date otherwise it is
- * currently in the making. */
-
- /* Update all targets in .UPDATEALL rule / only target cp. */
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp=dp->cl_prq;
-
- /* Set the time stamp of those prerequisites without rule to the current
- * time if Force is TRUE to make sure that targets depending on those
- * prerequisites get remade. */
- if( !(tcp->ce_flag & F_TARGET) && Force ) tcp->ce_time = Do_time();
- if( mark_made ) {
- tcp->ce_flag |= F_MADE;
- if( tcp->ce_flag & F_MULTI ) {
- LINKPTR tdp;
- for( tdp = tcp->ce_prq; tdp != NIL(LINK); tdp = tdp->cl_next )
- tcp->ce_attr |= tdp->cl_prq->ce_attr & A_UPDATED;
- }
- }
-
- /* Note that the target is in the making. */
- tcp->ce_flag |= F_VISITED;
-
- /* Note: If the prerequisite was made using a .SETDIR= attribute
- * directory then we will include the directory in the fname
- * of the target. */
- if( push ) {
- char *dir = nsetdirroot ? nsetdirroot->ce_dir : Makedir;
- /* get relative path from current SETDIR to new SETDIR. */
- /* Attention, even with .WINPATH set this has to be a POSIX
- * path as ce_fname neeed to be POSIX. */
- char *pref = _prefix( dir, tcp->ce_dir );
- char *nname = Build_path(pref, tcp->ce_fname);
-
- FREE(pref);
- if( (tcp->ce_attr & A_FFNAME) && (tcp->ce_fname != NIL(char)) )
- FREE( tcp->ce_fname );
-
- tcp->ce_fname = DmStrDup(nname);
- tcp->ce_attr |= A_FFNAME;
- }
- }
-
-stop_making_it:
- _drop_mac( m_g );
- _drop_mac( m_q );
- _drop_mac( m_b );
- _drop_mac( m_l );
- _drop_mac( m_bb );
- _drop_mac( m_up );
- _drop_mac( m_at );
-
- /* undefine conditional macros if any */
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp=dp->cl_prq;
-
- while (tcp->ce_pushed != NIL(HASH)) {
- HASHPTR cur = tcp->ce_pushed;
- tcp->ce_pushed = cur->ht_link;
-
- Pop_macro(cur);
- FREE(cur->ht_name);
- if(cur->ht_value)
- FREE(cur->ht_value);
- FREE(cur);
- }
- }
-
- if( push )
- Pop_dir(FALSE);
-
- /* Undefine the strings that we used for constructing inferred
- * prerequisites. */
- if( inf != NIL(char) ) FREE( inf );
- if( all != NIL(char) ) FREE( all );
- if( imm != NIL(char) ) FREE( imm );
- if( outall != NIL(char) ) FREE( outall );
- free_list(all_list.first);
- free_list(imm_list.first);
- free_list(outall_list.first);
- free_list(inf_list.first);
-
- DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) );
- DB_RETURN(rval);
-}
-
-
-static char *
-_prefix( pfx, pat )/*
-=====================
- Return the relative path from pfx to pat. Both paths have to be absolute
- paths. If the paths are on different resources or drives (if applicable)
- or only share a relative path going up to the root dir and down again
- return pat. */
-char *pfx;
-char *pat;
-{
- char *cmp1=pfx;
- char *cmp2=pat;
- char *tpat=pat; /* Keep pointer to original pat. */
- char *result;
- char *up;
- int first = 1;
- int samerootdir = 1; /* Marks special treatment for the root dir. */
-#ifdef HAVE_DRIVE_LETTERS
- int pfxdl = 0;
- int patdl = 0;
-#endif
-
- /* Micro optimization return immediately if pfx and pat are equal. */
- if( strcmp(pfx, pat) == 0 )
- return(DmStrDup(""));
-
-#ifdef HAVE_DRIVE_LETTERS
- /* remove the drive letters to avoid getting them into the relative
- * path later. */
- if( *pfx && pfx[1] == ':' && isalpha(*pfx) ) {
- pfxdl = 1;
- cmp1 = DmStrSpn(pfx+2, DirBrkStr);
- }
- if( *pat && pat[1] == ':' && isalpha(*pat) ) {
- patdl = 1;
- cmp2 = DmStrSpn(pat+2, DirBrkStr);
- }
- /* If the drive letters are different use the abs. path. */
- if( pfxdl && patdl && (tolower(*pfx) != tolower(*pat)) )
- return(DmStrDup(pat));
-
- /* If only one has a drive letter also use the abs. path. */
- if( pfxdl != patdl )
- return(DmStrDup(pat));
- else if( pfxdl )
- /* If both are the same drive letter, disable the special top
- * dir treatment. */
- samerootdir = 0;
-
- /* Continue without the drive letters. (Either none was present,
- * or both were the same. This also solves the problem that the
- * case of the drive letters sometimes depends on the shell.
- * (cmd.exe vs. cygwin bash) */
- pfx = cmp1;
- pat = cmp2;
-#endif
-
- /* Cut off equal leading parts of pfx, pat. Both have to be abs. paths. */
- while(*pfx && *pat) {
- /* skip leading dir. separators. */
- pfx = DmStrSpn(cmp1, DirBrkStr);
- pat = DmStrSpn(cmp2, DirBrkStr);
-
- /* Only check in the first run of the loop. Leading slashes can only
- * mean POSIX paths or Windows resources (two) slashes. Drive letters
- * have no leading slash. In any case, if the number of slashes are
- * not equal there can be no relative path from one two the other.
- * In this case return the absolute path. */
- if( first ) {
- if( cmp1-pfx != cmp2-pat ) {
- return(DmStrDup(tpat));
- }
- first = 0;
- }
-
- /* find next dir. separator (or ""). */
- cmp1 = DmStrPbrk(pfx, DirBrkStr);
- cmp2 = DmStrPbrk(pat, DirBrkStr);
-
- /* if length of directory name is equal compare the strings. If equal
- * go into next loop. If not equal and directory names in the root
- * dir are compared return the absolut path otherwise break the loop
- * and construct the relative path from pfx to pat. */
- if ( (cmp1-pfx) != (cmp2-pat) || strncmp(pfx,pat,cmp1-pfx) != 0 ) {
- if( samerootdir ) {
- return(DmStrDup(tpat));
- }
- break;
- }
-
- if( samerootdir ) {
-#if __CYGWIN__
- /* If the toplevel directory is /cygdrive (or the equivalent prefix)
- * treat the following level also as rootdir. If we are here cmp1-pfx
- * cannot be zero so we won't compare with an empty cygdrive prefix. */
- if ( (cmp1-pfx) == CygDrvPreLen && strncmp(pfx,CygDrvPre,CygDrvPreLen) == 0 )
- samerootdir = 1;
- else
-#endif
- samerootdir = 0;
- }
- }
-
- result = DmStrDup("");
- up = DmStrJoin("..",DirSepStr,-1,FALSE);
- cmp1 = pfx;
- /* Add "../" for each directory in pfx */
- while ( *(pfx=DmStrSpn(cmp1,DirBrkStr)) != '\0' ) {
- cmp1 = DmStrPbrk(pfx,DirBrkStr);
- result = DmStrJoin(result,up,-1,TRUE);
- }
-
- pat = DmStrSpn(pat,DirBrkStr);
- /* Append pat to result. */
- if( *pat != '\0' ) {
- cmp2 = DmStrDup(Build_path(result, pat));
- FREE(result);
- result = cmp2;
- } else {
- /* if pat is empty and result exists remove the trailing slash
- * from the last "../". */
- if( *result ) {
- result[strlen(result)-1] = '\0';
- }
- }
-
- return(result);
-}
-
-
-static LINKPTR
-_dup_prq( lp )
-LINKPTR lp;
-{
- LINKPTR tlp;
-
- if( lp == NIL(LINK) ) return(lp);
-
- TALLOC(tlp, 1, LINK);
- tlp->cl_prq = lp->cl_prq;
- tlp->cl_flag = lp->cl_flag;
- tlp->cl_next = _dup_prq( lp->cl_next );
-
- return(tlp);
-}
-
-
-static LINKPTR
-_expand_dynamic_prq( head, lp, name )/*
-=======================================
- The string name can contain one or more target names. Check if these are
- already a prerequisite for the current target. If not add them to the list
- of prerequisites. If no prerequisites were added set lp->cl_prq to NULL.
- Set the F_MARK flag to indicate that the prerequisite was expanded.
- Use cl_flag instead?? */
-LINKPTR head;
-LINKPTR lp;
-char *name;
-{
- CELLPTR cur = lp->cl_prq;
-
- if( !(*name) ) {
- /* If name is empty this leaves lp->cl_prq unchanged -> No prerequisite added. */
- ;
- }
- else if ( strchr(name, ' ') == NIL(char) ) {
- /* If condition above is true, no space is found. */
- CELLPTR prq = Def_cell(name);
- LINKPTR tmp;
-
- /* Check if prq already exists. */
- for(tmp=head;tmp != NIL(LINK) && tmp->cl_prq != prq;tmp=tmp->cl_next);
-
- /* If tmp is NULL then the prerequisite is new and is added to the list. */
- if ( !tmp ) {
- /* replace the prerequisite with the expanded version. */
- lp->cl_prq = prq;
- lp->cl_prq->ce_flag |= F_MARK;
- }
- }
- else {
- LINKPTR tlp = lp;
- LINKPTR next = lp->cl_next;
- TKSTR token;
- char *p;
- int first=TRUE;
-
- /* Handle more than one prerequisite. */
- SET_TOKEN(&token, name);
- while (*(p=Get_token(&token, "", FALSE)) != '\0') {
- CELLPTR prq = Def_cell(p);
- LINKPTR tmp;
-
- for(tmp=head;tmp != NIL(LINK) && tmp->cl_prq != prq;tmp=tmp->cl_next);
-
- /* If tmp is not NULL the prerequisite already exists. */
- if ( tmp ) continue;
-
- /* Add list elements behind the first if more then one new
- * prerequisite is found. */
- if ( first ) {
- first = FALSE;
- }
- else {
- TALLOC(tlp->cl_next,1,LINK);
- tlp = tlp->cl_next;
- tlp->cl_flag |= F_TARGET;
- tlp->cl_next = next;
- }
-
- tlp->cl_prq = prq;
- tlp->cl_prq->ce_flag |= F_MARK;
- }
- CLEAR_TOKEN( &token );
- }
-
- /* If the condition is true no new prerequisits were found. */
- if ( lp->cl_prq == cur ) {
- lp->cl_prq = NIL(CELL);
- lp->cl_flag = 0;
- }
-
- /* Is returned unchanged. */
- return(lp);
-}
-
-
-static void
-_drop_mac( hp )/*
-================ set a macro value to zero. */
-HASHPTR hp;
-{
- if( hp && hp->ht_value != NIL(char) ) {
- FREE( hp->ht_value );
- hp->ht_value = NIL(char);
- }
-}
-
-
-
-static int
-_explode_graph( cp, parent, setdirroot )/*
-==========================================
- Check to see if we have made the node already. If so then don't do
- it again, except if the cell's ce_setdir field is set to something other
- than the value of setdirroot. If they differ then, and we have made it
- already, then make it again and set the cell's stat bit to off so that
- we do the stat again. */
-CELLPTR cp;
-LINKPTR parent;
-CELLPTR setdirroot;
-{
- static CELLPTR removecell = NIL(CELL);
-
- if ( removecell == NIL(CELL) )
- removecell = Def_cell(".REMOVE");
-
- /* we may return if we made it already from the same setdir location,
- * or if it is not a library member whose lib field is non NULL. (if
- * it is such a member then we have a line of the form:
- * lib1 lib2 .LIBRARY : member_list...
- * and we have to make sure all members are up to date in both libs. */
-
- if ( setdirroot == removecell )
- return( 0 );
-
- if( cp->ce_setdir == setdirroot &&
- !((cp->ce_attr & A_LIBRARYM) && (cp->ce_lib != NIL(char))) )
- return( 0 );
-
- /* We check to make sure that we are comming from a truly different
- * directory, ie. ".SETDIR=joe : a.c b.c d.c" are all assumed to come
- * from the same directory, even though setdirroot is different when
- * making dependents of each of these targets. */
-
- if( cp->ce_setdir != NIL(CELL) &&
- setdirroot != NIL(CELL) &&
- cp->ce_dir &&
- setdirroot->ce_dir &&
- !strcmp(cp->ce_dir, setdirroot->ce_dir) )
- return( 0 );
-
- if( Max_proc > 1 ) {
- LINKPTR dp;
-
- TALLOC(parent->cl_prq, 1, CELL);
- *parent->cl_prq = *cp;
- cp = parent->cl_prq;
- cp->ce_prq = _dup_prq(cp->ce_prqorg);
- cp->ce_all.cl_prq = cp;
- CeNotMe(cp) = _dup_prq(CeNotMe(cp));
-
- for(dp=CeNotMe(cp);dp;dp=dp->cl_next) {
- CELLPTR tcp = dp->cl_prq;
- TALLOC(dp->cl_prq,1,CELL);
- *dp->cl_prq = *tcp;
- dp->cl_prq->ce_flag &= ~(F_STAT|F_VISITED|F_MADE);
- dp->cl_prq->ce_set = cp;
- }
- }
- cp->ce_flag &= ~(F_STAT|F_VISITED|F_MADE);
-
- /* Indicate that we exploded the graph and that the current node should
- * be made. */
- return(1);
-}
-
-
-
-PUBLIC int
-Exec_commands( cp )/*
-=====================
- Execute the commands one at a time that are pointed to by the rules pointer
- of the target cp if normal (non-group) recipes are defined. If a group recipe
- is found all commands are written into a temporary file first and this
- (group-) shell script is executed all at once.
- If a group is indicated, then the ce_attr determines .IGNORE and .SILENT
- treatment for the group.
-
- The function returns 0, if the command is executed and has successfully
- returned, and it returns 1 if the command is executing but has not yet
- returned or -1 if an error occured (Return value from Do_cmnd()).
-
- Macros that are found in recipe lines are expanded in this function, in
- parallel builds this can mean they are expanded before the previous recipe
- lines are finished. (Exception: $(shell ..) waits until all previous recipe
- lines are done.)
-
- The F_MADE bit in the cell is guaranteed set when the command has
- successfully completed. */
-CELLPTR cp;
-{
- static HASHPTR useshell = NIL(HASH);
- static HASHPTR command = NIL(HASH);
- static int read_cmnd = 0;
- register STRINGPTR rp;
- STRINGPTR orp;
- char *cmnd;
- char *groupfile;
- FILE *tmpfile = 0;
- int do_it;
- t_attr attr;
- int group;
- int trace;
- int rval = 0;
-
- DB_ENTER( "Exec_commands" );
-
- if( cp->ce_recipe == NIL(STRING) )
- Fatal("Internal Error: No recipe found!");
-
- attr = Glob_attr | cp->ce_attr;
- trace = Trace || !(attr & A_SILENT);
- group = cp->ce_flag & F_GROUP;
-
- /* Do it again here for those that call us from places other than Make()
- * above. */
- orp = _recipes[ RP_RECIPE ];
- _recipes[ RP_RECIPE ] = cp->ce_recipe;
-
- if( group ) {
- /* Leave this assignment of Current_target here. It is needed just
- * incase the user hits ^C after the tempfile for the group recipe
- * has been opened. */
- Current_target = cp;
- trace = Trace || !(attr & A_SILENT);
-
- if( !Trace ) tmpfile = Start_temp( Grp_suff, cp, &groupfile );
- if( trace ) fputs( "[\n", stdout );
-
- /* Emit group prolog */
- if( attr & A_PROLOG )
- _append_file( _recipes[RP_GPPROLOG], tmpfile, cp->CE_NAME, trace );
- }
-
- if( !useshell )
- useshell=Def_macro("USESHELL",NIL(char),M_MULTI|M_EXPANDED);
-
- if( !read_cmnd ) {
- command = GET_MACRO("COMMAND");
- read_cmnd = 1;
- }
-
- /* Process commands in recipe. If in group, merely append to file.
- * Otherwise, run them. */
- for( rp=_recipes[RP_RECIPE]; rp != NIL(STRING); rp=rp->st_next) {
- t_attr a_attr = A_DEFAULT;
- t_attr l_attr;
- char *p;
- int new_attr = FALSE;
- int shell; /* True if the recipe shall run in shell. */
-
- /* Reset it for each recipe line otherwise tempfiles don't get removed.
- * Since processing of $(mktmp ...) depends on Current_target being
- * correctly set. */
- Current_target = cp;
-
- /* Only check for +,-,%,@ if the recipe line begins with a '$' macro
- * expansion. Otherwise there is no way it is going to find these
- * now. */
- if( *rp->st_string == '$' && !group ) {
- t_attr s_attr = Glob_attr;
- Glob_attr |= A_SILENT;
- Suppress_temp_file = TRUE;
- cmnd = Expand(rp->st_string);
- Suppress_temp_file = FALSE;
- a_attr |= Rcp_attribute(cmnd);
- FREE(cmnd);
- ++new_attr;
- Glob_attr = s_attr;
- }
-
- l_attr = attr|a_attr|rp->st_attr;
- shell = ((l_attr & A_SHELL) != 0);
- useshell->ht_value = (group||shell)?"yes":"no";
-
- /* All macros are expanded before putting them in the "process queue".
- * Nothing in Expand() should be able to change dynamic macros. */
- cmnd = Expand( rp->st_string );
-
- if( new_attr && (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) {
- size_t len = strlen(p)+1;
- memmove(cmnd,p,len);
- }
-
- /* COMMAND macro is set to "$(CMNDNAME) $(CMNDARGS)" by default, it is
- * possible for the user to reset it to, for example
- * COMMAND = $(CMNDNAME) @$(mktmp $(CMNDARGS))
- * in order to get a different interface for his command execution. */
- if( command != NIL(HASH) && !group ) {
- char *cname = cmnd;
- char cmndbuf[30];
-
- if ( *(p=DmStrPbrk(cmnd," \t\n")) != '\0' ) {
- *p = '\0';
- (void)Def_macro("CMNDARGS",DmStrSpn(p+1," \t\n"),M_MULTI|M_EXPANDED);
- }
- else
- (void) Def_macro("CMNDARGS","",M_MULTI|M_EXPANDED);
-
- (void) Def_macro("CMNDNAME",cname,M_MULTI|M_EXPANDED);
-
- strcpy(cmndbuf, "$(COMMAND)");
- cmnd = Expand(cmndbuf);
- FREE(cname); /* cname == cmnd at this point. */
-
- /* Collect up any new attributes */
- l_attr |= Rcp_attribute(cmnd);
- shell = ((l_attr & A_SHELL) != 0);
-
- /* clean up the attributes that we may have just added. */
- if( (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) {
- size_t len = strlen(p)+1;
- memmove(cmnd,p,len);
- }
- }
-
-#if defined(MSDOS)
- Swap_on_exec = ((l_attr & A_SWAP) != 0); /* Swapping for DOS only */
-#endif
- do_it = !Trace;
-
- /* We force execution of the recipe if we are tracing and the .EXECUTE
- * attribute was given or if the it is not a group recipe and the
- * recipe line contains the string $(MAKE). Wait_for_completion might
- * be changed gobaly but this is without consequences as we wait for
- * every recipe with .EXECUTE and don't start anything else. */
- if( Trace
- && ((l_attr & A_EXECUTE)||(!group && DmStrStr(rp->st_string,"$(MAKE)")))
- ) {
- Wait_for_completion |= Trace;
- do_it = TRUE;
- }
-
- if( group )
- /* Append_line() calls Print_cmnd(). */
- Append_line( cmnd, TRUE, tmpfile, cp->CE_NAME, trace, 0 );
- else {
- /* Don't print empty recipe lines. .ROOT and .TARGETS
- * deliberately might have empty "" recipes and we don't want
- * to output empty recipe lines for them. */
- if ( *cmnd ) {
- /* Print command and remove continuation sequence from cmnd. */
- Print_cmnd(cmnd, !(do_it && (l_attr & A_SILENT)), 0);
- }
- rval=Do_cmnd(&cmnd,FALSE,do_it,cp,l_attr,
- rp->st_next == NIL(STRING) );
- }
-
- FREE(cmnd);
- }
-
- /* If it is a group then output the EPILOG if required and possibly
- * execute the command */
- if( group && !(cp->ce_attr & A_ERROR) ) {
- if( attr & A_EPILOG ) /* emit epilog */
- _append_file( _recipes[RP_GPEPILOG], tmpfile, cp->CE_NAME, trace );
-
- if( trace ) fputs("]\n", stdout);
-
- do_it = !Trace;
- if( do_it )
- {
- Close_temp( cp, tmpfile );
-#if defined(UNIX)
-
- chmod(groupfile,0700);
-#endif
- }
- rval = Do_cmnd(&groupfile, TRUE, do_it, cp, attr | A_SHELL, TRUE);
- }
-
- _recipes[ RP_RECIPE ] = orp;
- cp->ce_attr &= ~A_ERROR;
- DB_RETURN( rval );
-}
-
-
-PUBLIC void
-Print_cmnd( cmnd, echo, map )/*
-================================
- This routine is called to print out the command to stdout. If echo is
- false the printing to stdout is supressed.
- The routine is also used to remove the line continuation sequence
- \<nl> from the command string and convert escape sequences if the
- map flag is set.
- The changed string is used later to actually to execute the command. */
-char *cmnd;
-int echo;
-int map;
-{
- register char *p;
- register char *n;
- char tmp[3];
-
- DB_ENTER( "Print_cmnd" );
-
- if( echo ) {
- printf( "%s\n", cmnd );
- fflush(stdout);
- }
-
- tmp[0] = ESCAPE_CHAR;
- tmp[1] = CONTINUATION_CHAR;
- tmp[2] = '\0';
-
- for( p=cmnd; *(n = DmStrPbrk(p,tmp)) != '\0'; )
- /* Remove the \<nl> sequences. */
- if(*n == CONTINUATION_CHAR && n[1] == '\n') {
- size_t len = strlen(n+2)+1;
- DB_PRINT( "make", ("fixing [%s]", p) );
- memmove( n, n+2, len );
- p = n;
- }
- /* Look for an escape sequence and replace it by it's corresponding
- * character value. */
- else {
- if( *n == ESCAPE_CHAR && map ) Map_esc( n );
- p = n+1;
- }
-
- DB_VOID_RETURN;
-}
-
-
-
-/* These routines are used to maintain a stack of directories when making
- * the targets. If a target cd's to the directory then it is assumed that
- * it will undo it when it is finished making itself. */
-
-static STRINGPTR dir_stack = NIL(STRING);
-
-PUBLIC int
-Push_dir( dir, name, ignore )/*
-===============================
- Change the current working directory to dir and save the current
- working directory on the stack so that we can come back.
-
- If ignore is TRUE then do not complain about _ch_dir if not possible.
-
- Return 1 if the directory change was successfull and 0 otherwise. */
-char *dir;
-char *name;
-int ignore;
-{
- STRINGPTR new_dir;
- int freedir=FALSE;
-
- DB_ENTER( "Push_dir" );
-
- if( dir == NIL(char) || *dir == '\0' ) dir = Pwd;
- if( *dir == '\'' && dir[strlen(dir)-1] == '\'' ) {
- dir = DmStrDup(dir+1);
- dir[strlen(dir)-1]='\0';
- freedir=TRUE;
- }
- else if (strchr(dir,'$') != NIL(char)) {
- dir = Expand(dir);
- freedir=TRUE;
- }
- else
- dir = DmStrDup(dir);
-
- if( Set_dir(dir) ) {
- if( !ignore )
- Fatal( "Unable to change to directory `%s', target is [%s]",
- dir, name );
- if (freedir) FREE(dir);
- DB_RETURN( 0 );
- }
-
- DB_PRINT( "dir", ("Push: [%s]", dir) );
- if( Verbose & V_DIR_SET )
- printf( "%s: Changed to directory [%s]\n", Pname, dir );
-
- if (freedir) FREE( dir );
- TALLOC( new_dir, 1, STRING );
- new_dir->st_next = dir_stack;
- dir_stack = new_dir;
- new_dir->st_string = DmStrDup( Pwd );
-
- Def_macro( "PWD", Get_current_dir(), M_FORCE | M_EXPANDED );
- _set_tmd();
-
- DB_RETURN( 1 );
-}
-
-
-
-PUBLIC void
-Pop_dir(ignore)/*
-=================
- Change the current working directory to the previous saved dir. */
-int ignore;
-{
- STRINGPTR old_dir;
- char *dir;
-
- DB_ENTER( "Pop_dir" );
-
- if( dir_stack == NIL(STRING) ) {
- if( ignore ) {
- DB_VOID_RETURN;
- }
- else
- Error( "Directory stack empty for return from .SETDIR" );
- }
-
- if( Set_dir(dir = dir_stack->st_string) )
- Fatal( "Could not change to directory `%s'", dir );
-
- Def_macro( "PWD", dir, M_FORCE | M_EXPANDED );
- DB_PRINT( "dir", ("Pop: [%s]", dir) );
- if( Verbose & V_DIR_SET )
- printf( "%s: Changed back to directory [%s]\n", Pname, dir);
-
- old_dir = dir_stack;
- dir_stack = dir_stack->st_next;
-
- FREE( old_dir->st_string );
- FREE( old_dir );
- _set_tmd();
-
- DB_VOID_RETURN;
-}
-
-
-
-static void
-_set_tmd()/*
-============
- Set the TMD Macro and the Tmd global variable. TMD stands for "To MakeDir"
- and is the path from the present directory (value of $(PWD)) to the directory
- dmake was started up in (value of $(MAKEDIR)). As _prefix() can return absolute
- paths some special .WINPATH treatment is needed.
-*/
-{
- char *tmd;
-
- if( Tmd )
- FREE(Tmd);
-
- tmd = _prefix(Pwd, Makedir);
- if( *tmd ) {
- Def_macro( "TMD", DO_WINPATH(tmd), M_FORCE | M_EXPANDED );
- Tmd = DmStrDup(tmd);
- } else {
- Def_macro( "TMD", ".", M_FORCE | M_EXPANDED );
- Tmd = DmStrDup(".");
- }
- FREE( tmd );
-}
-
-
-static void
-_set_recipe( target, ind )/*
-============================
- Set up the _recipes static variable so that the slot passed in points
- at the rules corresponding to the target supplied. */
-char *target;
-int ind;
-{
- CELLPTR cp;
- HASHPTR hp;
-
- if( (hp = Get_name(target, Defs, FALSE)) != NIL(HASH) ) {
- cp = hp->CP_OWNR;
- _recipes[ ind ] = cp->ce_recipe;
- }
- else
- _recipes[ ind ] = NIL(STRING);
-}
-
-
-
-PUBLIC void
-Append_line( cmnd, newline, tmpfile, name, printit, map )
-char *cmnd;
-int newline;
-FILE *tmpfile;
-char *name;
-int printit;
-int map;
-{
- Print_cmnd( cmnd, printit, map );
-
- if( Trace ) return;
-
- fputs(cmnd, tmpfile);
- if( newline ) fputc('\n', tmpfile);
- fflush(tmpfile);
-
- if( ferror(tmpfile) )
- Fatal("Write error on temporary file, while processing `%s'", name);
-}
-
-
-
-static void
-_append_file( rp, tmpfile, name, printit )
-register STRINGPTR rp;
-FILE *tmpfile;
-char *name;
-int printit;
-{
- char *cmnd;
-
- while( rp != NIL(STRING) ) {
- Append_line(cmnd = Expand(rp->st_string), TRUE, tmpfile, name, printit,0);
- FREE(cmnd);
- rp = rp->st_next;
- }
-}
-
-
-#define NUM_BUCKETS 20
-
-typedef struct strpool {
- char *string; /* a pointer to the string value */
- uint32 keyval; /* the strings hash value */
- struct strpool *next; /* hash table link pointer */
-} POOL, *POOLPTR;
-
-static POOLPTR strings[ NUM_BUCKETS ];
-
-static char *
-_pool_lookup( str )/*
-=====================
- Scan down the list of chained strings and see if one of them matches
- the string we are looking for. */
-char *str;
-{
- register POOLPTR key;
- uint32 keyval;
- uint16 hv;
- uint16 keyindex;
- char *string;
-
- DB_ENTER( "_pool_lookup" );
-
- if( str == NIL(char) ) DB_RETURN("");
-
- hv = Hash(str, &keyval);
- key = strings[ keyindex = (hv % NUM_BUCKETS) ];
-
- while( key != NIL(POOL) )
- if( (key->keyval != keyval) || strcmp(str, key->string) )
- key = key->next;
- else
- break;
-
- if( key == NIL(POOL) ) {
- DB_PRINT( "pool", ("Adding string [%s]", str) );
- TALLOC( key, 1, POOL ); /* not found so add string */
-
- key->string = string = DmStrDup(str);
- key->keyval = keyval;
-
- key->next = strings[ keyindex ];
- strings[ keyindex ] = key;
- }
- else {
- DB_PRINT( "pool", ("Found string [%s], key->string") );
- string = key->string;
- }
-
- DB_RETURN( string );
-}
-
-
-void
-Unmake( cp )/*
-==============
- Remove flags indicating that a target was previously made. This
- is used for infered makefiles. */
-CELLPTR cp;
-{
- LINKPTR dp, ep;
- CELLPTR tcp, pcp;
-
- DB_ENTER( "Unmake" );
-
- for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
- tcp = dp->cl_prq;
-
- /* Unmake the prerequisites. */
- for( ep = tcp->ce_prq; ep != NIL(LINK); ep = ep->cl_next ) {
- pcp = ep->cl_prq;
-
- Unmake(pcp);
- }
- DB_PRINT( "unmake", ("Unmake [%s]", tcp->CE_NAME) );
-
- tcp->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
- tcp->ce_time = (time_t)0L;
- }
-
- DB_VOID_RETURN;
-}