home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD2.mdf
/
c
/
tools
/
make
/
nmake
/
make.c
< prev
next >
Wrap
Text File
|
1987-07-21
|
23KB
|
767 lines
/* file make.c */
/* received from km@cadre.arpa, originally a usenet posting.
heavily modified to appear more like UNIX make, working only from the
manual page ( macros, embedded macros, rules, default rules,
multiple targets per line, and special handling of cc for multiple passes
gregg@nlm-vax.arpa
*/
#include <stdio.h>
#include "make.h"
#include "rules.h"
#if MSC
#include <ctype.h>
#endif
#if LC
int _stack = SIZ_STK;
#endif
char *whoami = "Make";
struct macrec *maclist = NULL;
struct defnrec *defnlist = NULL;
struct llist *dolist = NULL;
struct rulerec *rulelist = NULL;
long make(),getmodified();
char *mov_in(),*get_mem(),*extrac_comp(),*new_c_rule;
int execute = TRUE;
int stopOnErr = TRUE;
int madesomething = FALSE;
int knowhow = FALSE;
int no_file = TRUE;
int linecont = LINE_DEFAULT;
char *DRIVE = DRIVE_DEFAULT;
int tree_and_quit = FALSE;
int firstcc = TRUE;
int tmake = FALSE;
int update_time_latest = TRUE;
main(argc,argv)
int argc;
char *argv[];
{
init(argc,argv);
if (tree_and_quit){ prtree();exit(0);}
/* now fall down the dolist and do them all */
while (dolist != NULL) {
madesomething = FALSE;
make(dolist->name);
if (!madesomething) {
if (knowhow) {
fprintf(stderr,"Make: '%s' is up to date.",dolist->name);
} else {
error("Don't know how to make '%s'.",dolist->name);
}
}
dolist = dolist->next;
}
exit( 0 );
}
init(argc,argv)
int argc;
char *argv[];
{
int i,k;
char *filearg;
struct llist *ptr,*ptr2,*ptr3;
int usedefault = TRUE;
for (k=i=0;i < NDRULES ;i++){
/* couldn't init the linked list with the compiler */
dflt_rules[i].dep = def_list[k++];
dflt_rules[i].targ = def_list[k++];
ptr = NULL;
while ( def_list[k] != NULL ) {
ptr2 = MkListMem();
ptr2->name = def_list[k++];
ptr2->next = NULL;
if ( ptr == NULL ) ptr = ptr2;
else {
ptr3 = ptr;
while ( ptr3->next != NULL ) ptr3 = ptr3->next;
ptr3->next = ptr2;
}
}
dflt_rules[i].rule = ptr;
dflt_rules[i].nextrule = (i+1 < NDRULES ) ? &dflt_rules[i+1] : NULL;
k++;
}
for (i=1; i < argc; i++) {
if (argv[i][0] == '-') { /* option */
switch (argv[i][1]) {
case 'f': case 'F': /* arg following is a makefile */
if (++i < argc) {
filearg = argv[i];
usedefault = FALSE;
}
else
panic("'-f' requires filename");
break;
case 'c': case 'C': /* line continuation char */
if ( argv[i][2] != NUL )
linecont = argv[i][2];
else {
if ( ++i < argc || notnull(argv[i][1]) )
linecont = argv[i][0];
else
error("'-c' requires single character");
}
break;
case 'i': case 'I': /* ignore errors on execution */
stopOnErr = FALSE;
break;
case 'x':case 'X': /* print a tree and quit */
tree_and_quit = TRUE;
break;
case 't':case 'T': /* trace selected subroutines */
tmake = TRUE;
break;
case 'w':case 'W': /* if made something, update time to
the latest of the targets */
update_time_latest = FALSE;
break;
case 'n': case 'N': /* don't execute commands - just print */
execute = FALSE;
break;
case 'd': case 'D': /* change the drive to look for FULL NAMES */
if ( argv[i][2] != NUL )
DRIVE[0] = toupper(argv[i][2]);
else {
if ( ++i < argc || notnull(argv[i][1]) )
DRIVE[0] = toupper(argv[i][0]);
else
error("'-d' requires single character");
}
break;
default:
error("unknown option '%s'.",argv[i]);
}
}
else {
/* it must be something to make */
add_do(argv[i]);
no_file = FALSE;
}
}
/*
collect the flags, then read the makefile, otherwise a construct like
make -f make2 aardvark
will make both aardvark and the first target in make2
*/
if (usedefault)
readmakefile(DEFAULT);
else readmakefile(filearg);
adjust(); /* this is where we adjust the rules and macros... */
}/* init */
adjust()
{
struct rulerec *rptr;
struct macrec *mptr;
/* in the case that a .c.obj rule is defined, and a cc macro is not... */
rptr = rulelist;
if (rptr != NULL){
while ( TRUE ) {
if (
( (strcmp(rptr->dep,"c") == 0 ) ||
(strcmp(rptr->dep,"C") == 0 )
)
&&
( (strcmp(rptr->targ,"obj") == 0) ||
(strcmp(rptr->targ,"OBJ") == 0)
)
) break;
else if (rptr->nextrule == NULL) {
rptr = NULL;
break;
}
else rptr = rptr->nextrule;
}
if (rptr != NULL){
/* rptr points to a .c.obj rule */
mptr = maclist;
if (mptr != NULL){
while ( TRUE ) {
if ((strcmp(mptr->name,"CC") == 0 )) break;
else if (mptr->nextmac == NULL) break;
else mptr = mptr->nextmac;
}
if ( strcmp(mptr->name,"CC") != 0 ) {
/* there is .c.obj and no CC macro */
mptr->nextmac = (struct macrec *)get_mem(sizeof (struct macrec));
mptr->nextmac->name = mov_in("CC");
/* here we make the possibly unwarrented assumption that
the compiler is the first string in the first part of
the rule
*/
mptr->nextmac->mexpand = extrac_comp(rptr->rule->name);
mptr->nextmac->nextmac = NULL;
rptr->rule->name = new_c_rule;
}
}
}
}
}/* adjust */
long make(s) /* returns the modified date/time */
char *s;
{
struct defnrec *defnp,*tryrules(),*dummy;
struct llist *depp,*depp2;
struct llist *howp;
long latest,timeof,now();
/* look for the definition */
if ( tmake ) fprintf(stderr,"make\(%s\)\n",s);
defnp = defnlist;
while (defnp != NULL) {
if (strcmp(defnp->name,s) == 0)
break;
defnp = defnp->nextdefn;
}
/*
there might be some adjusting of the lists for implied compilations.
these additions are not done in readmakefile;
they might not be required for these targets.
*/
if (defnp == NULL ){
defnp = tryrules(s);
if (defnp == NULL){ /* tryrules returns a pointer to a defnrec */
/* tryrules fails, and there is no definition */
knowhow = FALSE;
latest = getmodified(s,DEFINED);
if (latest==0) {
/* doesn't exist but don't know how to make */
panic("Can't make '%s'.",s);
}
else {
/* exists - assume it's up to date since we don't know */
if ( tmake ) fprintf(stderr,"make\(%s\) returns, assumed up to date\n",s);
return(latest);
}
}
}
else{ /* there is a definition line */
if (defnp->uptodate) {
if ( tmake ) fprintf(stderr,"make\(%s\) is up to date\n",s);
return(defnp->modified);
}
dummy = tryrules(s);
if (dummy != NULL && defnp->howto == NULL){ /* any explicit howto overrides an implicit one */
/*add depend*/
if (defnp->dependson == NULL)
defnp->dependson = dummy->dependson;
else{
depp2 = defnp->dependson;
while (depp2->next != NULL)
depp2 = depp2->next;
depp2->next = dummy->dependson;
}
/* add howto line */
defnp->howto = dummy->howto;
}
}
/* finished adjusting the lists */
/* check that everything that the current target depends on is uptodate */
latest = 0;
depp = defnp->dependson;
while (depp != NULL) {
timeof = make(depp->name);
latest = max(timeof,latest); /* written this way to avoid side effects */
depp = depp->next;
}
knowhow = TRUE; /* has dependencies therefore we know how */
/* if necessary, execute all of the commands to make it */
/* if (out of date) || (depends on nothing) */
if (latest > defnp->modified || defnp->dependson==NULL) {
/* make those suckers */
howp = defnp->howto;
if (howp == NULL) error("%s is out of date, but there is no command line",s);
while (howp != NULL) {
/* the execute flag controls whether execution takes place */
if (exec_how(howp->name) != 0)
error("error from %s",extrac_comp(howp->name));
howp = howp->next;
}
/* we just made something. Set the time of modification to now. The
old way was to set the time to the latest of the depends, with
a reason like "If we don't actually have a file, it works OK"
switch -w reverts to latest, not system time. Using now works better
when the sources may be in another directory.
*/
defnp->modified = ( update_time_latest == TRUE ) ? now() : latest;
defnp->uptodate = TRUE;
if (defnp->howto != NULL) /* we had instructions */
madesomething = TRUE;
}
if ( tmake ) fprintf(stderr,"make\(%s\) returns, having made something\n",s);
return(defnp->modified);
}
add_do(s) /*this adds to the list of targets to make*/
char *s;
{
struct llist *ptr1, *ptr2;
ptr1 = MkListMem();
ptr1->name = mov_in(s); /*mov_in returns pointer to newly allocated copy of name*/
ptr1->next = NULL;
/* now go down the dolist */
if (dolist == NULL)
dolist = ptr1;
else {
ptr2 = dolist;
while (ptr2->next != NULL)
ptr2 = ptr2->next;
ptr2->next = ptr1;
}
}
expand(src,dest,target,flag) /* expand any macros found*/
char *src,*dest,*target;
int flag;
{
char thismac[INMAX],*ismac(),*ismac_c(),cht[2];
char thismac2[INMAX],*macptr;
int i,pos,back;
back = pos = 0;
while( notnull(src[pos]) ) {
if (src[pos] != '$') dest[back++] = src[pos++];
else {
pos++;
/*found '$'. What kind of macro is this? */
switch(src[pos]){
case '(': /*regular macro*/
case '{': /*regular macro*/
/* do macro stuff */
pos = x_scan(src,pos,thismac); /* get macro */
if ( maclist == NULL && flag == REPT_ERR)
error("can't expand macro \"%s\" \(no macros defined\)",thismac);
else if ( (macptr=ismac(thismac)) == NULL) {
expand(thismac,thismac2,target,flag);
if ((macptr=ismac(thismac2))==NULL && flag==REPT_ERR)
error("Can't expand macro \"%s\"",thismac2);
else
/* thismac2 has expanded macro */
back = mv_expand(macptr,dest,back,target,flag);
}
else
/* did find expansion the first time */
back = mv_expand(macptr,dest,back,target,flag);
break;
case '*': /*target without extension*/
case '@': /*whole target*/
if (flag == NO_TARG){
sprintf(cht,"%c",src[pos]);
error("'$%s' not in a command or dependency line",cht);
}
else {
for (i=0; notnull(target[i]) ; i++) {
if ( target[i] == '.' && src[pos] == '*') break;
dest[back++] = target[i];
}
}
break;
default:
if ( (macptr = ismac_c(src[pos])) != NULL )
back = mv_expand(macptr,dest,back,target,flag);
else {
/*not an approved macro, ignore*/
dest[back++] = '$';
dest[back++] = src[pos];
}
break;
}
pos++;
}
}
dest[back] = NUL;
}
/* is this a character macro? */
char *ismac_c(cc)
char cc;
{
char *str = "A"; /* A is placeholder */
str[0] = cc;
return(ismac(str));
}
/* is this string a macro? */
char *ismac(test)
char *test;
{
struct macrec *ptr;
char rettemp[INMAX];
ptr = maclist;
if ( ptr == NULL ) return( NULL );
strcpy(rettemp,test);
uppercase(rettemp);
while( TRUE ) {
if (strcmp(ptr->name,rettemp) == 0)
return( ptr->mexpand );
else if ( ptr->nextmac == NULL )
return( NULL );
else
ptr = ptr->nextmac;
}
}
x_scan(src,pos,dest)
char *src,*dest;
int pos;
{
char bterm,eterm;
int cnt;
/* load dest with macro, allowing for nesting */
if ( src[pos] == '(' ) eterm = ')';
else if ( src[pos] == '{' ) eterm = '}';
else panic("very bad things happening in x_scan");
bterm = src[pos++];
cnt = 1;
while ( notnull(src[pos]) ) {
if ( src[pos] == bterm ) cnt++;
else if ( src[pos] == eterm ) {
cnt--;
if ( cnt == 0 ) {
*dest = NUL;
return( pos );
}
}
*dest++ = src[pos++];
}
panic("No closing brace/paren for %s",src);
/* NOTREACHED */
}
/* expand and move to dest */
mv_expand(from,to,back,target,flag)
char *from,*to,*target;
int back,flag;
{
int i;
char temp[INMAX];
expand( from,temp,target,flag );
for ( i=0; notnull(temp[i]) ; i++)
to[back++] = temp[i];
return( back );
}
/*
attempts to apply a rule. If an applicable rule is found, returns a
pointer to a (new) struct which can be added to the defnlist
An applicable rule is one in which target ext matches, and a source file
exists
*/
char ext[INMAXSH]; /*place to store the extension*/
struct defnrec *tryrules(string) /*check for user defined rules*/
char *string;
{
struct rulerec *rulep;
struct defnrec *trydef(),*construct();
int found,i;
char s[INMAXSH];
strcpy(s,string);
if ( tmake ) fprintf(stderr,"tryrules\(%s\) ",string);
for (i=0;notnull(s[i]) && s[i] != '.';i++) ; /*skip to beginning of ext */
if (isnull(s[i])) {
/*target has no extension*/
if ( tmake ) fprintf(stderr,"failed\n");
return(NULL);
}
s[i++] = NUL; /*truncate the object and advance to the extension*/
strcpy(ext,s + i );
if (rulelist == NULL)
return(trydef(s,ext)); /*try default rules*/
else{
rulep = rulelist;
while ( TRUE ){
if ((strcmp(ext,rulep->targ) == 0) && exists(s,rulep->dep)) {
found = TRUE;break;
}
else if (rulep->nextrule != NULL){
rulep = rulep->nextrule;
}
else{
found = FALSE;break;
}
}
}
if ( !found ) return(trydef(s,ext));
/*found a user defined rule*/
if ( tmake ) fprintf(stderr,"found user rule\n");
return(construct(s,rulep,REPT_ERR)); /* make a new defnrec with this rule*/
}
struct defnrec *trydef(s,t) /*try the default rules*/
char *s,*t;
{
struct rulerec *rulep;
struct defnrec *construct();
int found;
if (dflt_rules == NULL)
return(NULL);
else{
rulep = dflt_rules;
while ( TRUE ){
if ((strcmp(t,rulep->targ) == 0) && exists(s,rulep->dep)) {
found = TRUE;
break;
}
else if (rulep->nextrule != NULL)
rulep = rulep->nextrule;
else{
found = FALSE;break;
}
}
}
if (!found) {
if ( tmake ) fprintf(stderr,"fails\n");
return(NULL);
}
/*found a default rule*/
if ( tmake ) fprintf(stderr,"found a default rule\n");
return(construct(s,rulep,IGN_ERR)); /* make a new defnrec with this rule, ignoring macros not defined*/
}
struct defnrec *construct(object,rulep,flag) /*construct definition from rule and return pointer to new memory containing it*/
char *object;
struct rulerec *rulep;
int flag;
{
char buf[INMAXSH];
struct defnrec *retval;
struct llist *mkllist(),*mkexphow();
retval = (struct defnrec *)get_mem((unsigned) sizeof(struct defnrec));
strcpy(buf,object); /*object is the stem of the object*/
strcat(buf,".");
strcat(buf,rulep->targ);
retval->name = mov_in(buf);
strcpy(buf,object);
strcat(buf,".");
strcat(buf,rulep->dep);
retval->dependson = mkllist(buf);
retval->uptodate = FALSE;
retval->modified = getmodified(retval->name,DEPENDANT);
retval->nextdefn = NULL;
retval->howto = mkexphow(rulep->rule,retval->name,flag);
return(retval); /*whew*/
}
/* does the file exist? */
exists(name,suffix)
char *name,*suffix;
{
char t[INMAXSH];
strcpy(t,name);
strcat(t,".");
strcat(t,suffix);
return (getmodified(t,DEFINED) != 0L ? TRUE : FALSE );
}
/*debugging*/
/* print the dependencies and command lines... */
prtree()
{
struct defnrec *dummy;
struct macrec *mdum;
struct llist *dum2,*dum3,*rdum2;
struct rulerec *rdum;
int cnt;
dummy = defnlist;
while (dummy != NULL){
fprintf(stderr,"name '%s' modified:%ld\n\n",dummy->name,dummy->modified);
dum2 = dummy->dependson;
fprintf(stderr," depends-on:");cnt =0;
while (dum2 != NULL){
fprintf(stderr,"'%s' ",dum2->name);cnt++;
if (cnt == 5){
cnt = 0;
fprintf(stderr,"\n ");
}
dum2 = dum2->next;
}
printf("\n");
dum3 = dummy->howto;
while (dum3 != NULL){
fprintf(stderr," command: %s\n",dum3->name);
dum3 = dum3->next;
}
dummy = dummy->nextdefn;
fprintf(stderr,"\n");
}
fprintf(stderr," *RULES*\n\n");
fprintf(stderr,"src= dest= rule=\n");
rdum = rulelist;
while ( rdum != NULL ) {
fprintf(stderr,"%4s %4s %s\n",rdum->dep,rdum->targ,rdum->rule->name);
rdum2 = rdum->rule->next;
while ( rdum2 != NULL ) {
fprintf(stderr," %s\n",rdum2->name);
rdum2 = rdum2->next;
}
rdum = rdum->nextrule;
}
/* default rules */
for ( cnt = 0 ; cnt < NDRULES ; cnt++ ) {
rdum = rulelist;
while ( rdum != NULL ) {
if ( (strcmp(rdum->dep,dflt_rules[cnt].dep) == 0) &&
(strcmp(rdum->targ,dflt_rules[cnt].targ) == 0) ) break;
rdum = rdum->nextrule;
}
if ( rdum == NULL ) {
fprintf(stderr,"%4s %4s %s\n",dflt_rules[cnt].dep,dflt_rules[cnt].targ,dflt_rules[cnt].rule->name);
rdum2 = dflt_rules[cnt].rule->next;
while ( rdum2 != NULL ) {
fprintf(stderr," %s\n",rdum2->name);
rdum2 = rdum2->next;
}
}
}
mdum = maclist;
if ( mdum == NULL )
fprintf(stderr,"\n *NO MACROS*\n");
else {
fprintf(stderr,"\n *MACROS*\n\n");
fprintf(stderr," macro expansion\n");
while ( mdum != NULL ) {
fprintf(stderr," %7s %s\n",mdum->name,mdum->mexpand);
mdum = mdum->nextmac;
}
}
} /*debug*/
/* VARARGS */
error(s1,s2)
char *s1,*s2;
{
fprintf(stderr,"%s: ",whoami);
fprintf(stderr,s1,s2);
fprintf(stderr,"\n");
if (stopOnErr) exit(-1);
else return;
}
error2(s1,s2,s3)
char *s1,*s2,*s3;
{
fprintf(stderr,"%s: ",whoami);
fprintf(stderr,s1,s2,s3);
fprintf(stderr,"\n");
if (stopOnErr) exit(-1);
else return;
}
/* VARARGS */
panic(s1,s2)
char *s1,*s2;
{
fprintf(stderr,"%s: ",whoami);
fprintf(stderr,s1,s2);
fprintf(stderr,"\n");
exit(-1);
}
char *extrac_comp(r)
char *r;
{
/* extract the compiler from a rule */
int i,k,x,end,mark;
char *retval,temp[INMAXSH];
i = k = 0;
while ( isspace(r[i]) ) i++;/*skip WS*/
while ( !isspace(r[i]) && notnull(r[i]) ) temp[k++] = r[i++];
temp[k] = NUL;
mark = i;
if ( notnull(r[i]) ) {
while ( notnull(r[i]) && r[i] != BKSLSH ) i++;/* skip to backslash */
if ( notnull(r[i]) && r[++i] == ';') strcat(temp,r+i-2);
}
retval = mov_in(temp);
/* if the rule is <compiler><WS><whatever><numpasses> , fill
new_c_rule with "cc <whatever>"
*/
strcpy(temp,"cc ");
if ( isnull(r[i]) ) end = i;
else end = i-1;
for ( x = mark ; x < end ; x++ ) temp[3+x-mark] = r[x];
temp[3+x-mark] = NUL;
new_c_rule = mov_in(temp);
return(retval);
}