910643ccbb
+ Addition of function prototypes and include files. + Change function definitions to ANSI C style. + Initial support for CMake
309 lines
6.9 KiB
C
309 lines
6.9 KiB
C
/*
|
|
* Do the actual making for make
|
|
*
|
|
* $Header$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
/* UNIX specific */
|
|
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
|
|
#ifndef unix
|
|
#define unix
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
|
#ifndef unix
|
|
#define unix
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef unix
|
|
#include <unistd.h>
|
|
#include <utime.h>
|
|
#endif
|
|
#include "h.h"
|
|
|
|
void docmds(struct name *np);
|
|
|
|
#ifndef max
|
|
#define max(a,b) ((a)>(b)?(a):(b))
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Exec a shell that returns exit status correctly (/bin/esh).
|
|
* The standard EON shell returns the process number of the last
|
|
* async command, used by the debugger (ugg).
|
|
* [exec on eon is like a fork+exec on unix]
|
|
*/
|
|
static int dosh(char *string, char *shell)
|
|
{
|
|
return system(string);
|
|
}
|
|
|
|
|
|
/*
|
|
* Do commands to make a target
|
|
*/
|
|
static void docmds1(struct name *np, struct line *lp)
|
|
{
|
|
bool ssilent;
|
|
bool signore;
|
|
int estat;
|
|
register char * q;
|
|
register char * p;
|
|
char * shell;
|
|
register struct cmd * cp;
|
|
|
|
|
|
if (*(shell = getmacro("SHELL")) == '\0')
|
|
#ifdef unix
|
|
shell = "/bin/sh";
|
|
#endif
|
|
for (cp = lp->l_cmd; cp; cp = cp->c_next)
|
|
{
|
|
strcpy(str1, cp->c_cmd);
|
|
expand(str1);
|
|
q = str1;
|
|
ssilent = silent;
|
|
signore = ignore;
|
|
while ((*q == '@') || (*q == '-'))
|
|
{
|
|
if (*q == '@') /* Specific silent */
|
|
ssilent = TRUE;
|
|
else /* Specific ignore */
|
|
signore = TRUE;
|
|
q++; /* Not part of the command */
|
|
}
|
|
|
|
if (!domake)
|
|
ssilent = 0;
|
|
|
|
if (!ssilent)
|
|
fputs(" ", stdout);
|
|
|
|
for (p=q; *p; p++)
|
|
{
|
|
if (*p == '\n' && p[1] != '\0')
|
|
{
|
|
*p = ' ';
|
|
if (!ssilent)
|
|
fputs("\\\n", stdout);
|
|
}
|
|
else if (!ssilent)
|
|
putchar(*p);
|
|
}
|
|
if (!ssilent) {
|
|
putchar('\n');
|
|
fflush(stdout);
|
|
}
|
|
|
|
if (domake)
|
|
{ /* Get the shell to execute it */
|
|
if ((estat = dosh(q, shell)) != 0)
|
|
{
|
|
if (estat == -1)
|
|
fatal("Couldn't execute %s", shell);
|
|
else
|
|
{
|
|
printf("%s: Error code %d", myname, estat);
|
|
if (signore)
|
|
fputs(" (Ignored)\n", stdout);
|
|
else
|
|
{
|
|
putchar('\n');
|
|
if (!(np->n_flag & N_PREC))
|
|
if (remove(np->n_name) == 0)
|
|
printf("%s: '%s' removed.\n", myname, np->n_name);
|
|
exit(1);
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void docmds(struct name *np)
|
|
{
|
|
register struct line * lp;
|
|
|
|
|
|
for (lp = np->n_line; lp; lp = lp->l_next)
|
|
docmds1(np, lp);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get the modification time of a file. If the first
|
|
* doesn't exist, it's modtime is set to 0.
|
|
*/
|
|
void modtime(struct name *np)
|
|
{
|
|
struct stat info;
|
|
|
|
if (stat(np->n_name, &info) < 0)
|
|
{
|
|
if (errno != ENOENT)
|
|
fatal("Can't open %s", np->n_name);
|
|
|
|
np->n_time = 0L;
|
|
}
|
|
else
|
|
np->n_time = info.st_mtime;
|
|
}
|
|
|
|
|
|
/*
|
|
* Update the mod time of a file to now.
|
|
*/
|
|
void touch(struct name *np)
|
|
{
|
|
#ifdef unix
|
|
if (!domake || !silent)
|
|
printf(" touch(%s)\n", np->n_name);
|
|
|
|
if (domake)
|
|
{
|
|
struct utimbuf a;
|
|
time_t timeval;
|
|
|
|
a.actime = a.modtime = time(&timeval);
|
|
if (utime(np->n_name, &a) < 0)
|
|
printf("%s: '%s' not touched - non-existant\n",
|
|
myname, np->n_name);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void make1(struct name *np, struct line *lp, struct depend *qdp)
|
|
{
|
|
register struct depend * dp;
|
|
register char *p;
|
|
|
|
if (dotouch)
|
|
touch(np);
|
|
else
|
|
{
|
|
strcpy(str1, "");
|
|
for (dp = qdp; dp; dp = qdp)
|
|
{
|
|
if (strlen(str1))
|
|
strcat(str1, " ");
|
|
strcat(str1, dp->d_name->n_name);
|
|
qdp = dp->d_next;
|
|
free((char *)dp);
|
|
}
|
|
setmacro("?", str1, 4);
|
|
setmacro("@", np->n_name, 4);
|
|
p = strrchr(np->n_name, '.');
|
|
if (p) *p = 0;
|
|
setmacro("*", np->n_name, 4);
|
|
if (p) *p = '.';
|
|
if (lp) /* lp set if doing a :: rule */
|
|
docmds1(np, lp);
|
|
else
|
|
docmds(np);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Recursive routine to make a target.
|
|
*/
|
|
int make(struct name *np, int level)
|
|
{
|
|
register struct depend * dp;
|
|
register struct line * lp;
|
|
register struct depend * qdp;
|
|
time_t dtime = 1;
|
|
bool didsomething = 0;
|
|
int dynamic = 0;
|
|
|
|
|
|
if (np->n_flag & N_DONE)
|
|
return 0;
|
|
|
|
if (!np->n_time)
|
|
modtime(np); /* Gets modtime of this file */
|
|
|
|
if (rules)
|
|
{
|
|
for (lp = np->n_line; lp; lp = lp->l_next)
|
|
if (lp->l_cmd)
|
|
break;
|
|
if (!lp) {
|
|
dyndep(np);
|
|
dynamic = 1;
|
|
}
|
|
}
|
|
|
|
if (!(np->n_flag & N_TARG) && np->n_time == 0L)
|
|
fatal("Don't know how to make %s", np->n_name);
|
|
|
|
for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next)
|
|
{
|
|
for (dp = lp->l_dep; dp; dp = dp->d_next)
|
|
{
|
|
char *sv = 0;
|
|
if (dynamic) {
|
|
char *s = getmacro("<");
|
|
|
|
if (s) {
|
|
sv = malloc((unsigned)(strlen(s)+1));
|
|
if (!sv) {
|
|
fatal("no space for saved $<",NULL);
|
|
}
|
|
strcpy(sv, s);
|
|
}
|
|
}
|
|
make(dp->d_name, level+1);
|
|
if (dynamic && sv) {
|
|
setmacro("<", sv, 4);
|
|
free(sv);
|
|
}
|
|
if (np->n_time < dp->d_name->n_time)
|
|
qdp = newdep(dp->d_name, qdp);
|
|
dtime = max(dtime, dp->d_name->n_time);
|
|
}
|
|
if (!quest && (np->n_flag & N_DOUBLE) && (np->n_time < dtime))
|
|
{
|
|
make1(np, lp, qdp); /* free()'s qdp */
|
|
dtime = 1;
|
|
qdp = (struct depend *)0;
|
|
didsomething++;
|
|
}
|
|
}
|
|
|
|
np->n_flag |= N_DONE;
|
|
|
|
if (quest)
|
|
{
|
|
long t;
|
|
|
|
t = np->n_time;
|
|
time(&np->n_time);
|
|
return t < dtime;
|
|
}
|
|
else if (np->n_time < dtime && !(np->n_flag & N_DOUBLE))
|
|
{
|
|
make1(np, (struct line *)0, qdp); /* free()'s qdp */
|
|
time(&np->n_time);
|
|
}
|
|
else if (level == 0 && !didsomething)
|
|
printf("%s: '%s' is up to date\n", myname, np->n_name);
|
|
return 0;
|
|
}
|
|
|
|
|