/* * * MakeMake - a program to construct a makefile from C source code * * Usage: makemake file1.c file2.c file3.c ... filen.c * * MakeMake reads the C source files and creates * a file called 'makefile' in the current directory. For each * source file entered on the command line, makemake adds an entry * of the form: * * filex.o : filex.c ... header file list ... * cc $(OPT) filex.c * * where the header file list is the transitive closure of all * files #included in filex.c (i.e. if filex.c #includes "header.h", and * "header.h" #includes "subheader.h", both "header.h" and "subheader.h" * appear in the list of header files). MakeMake only examines header * files delimited by double quotes ("). System header files enclosed * in angle brackets (< and >) are not examined. * * The target of the makefile is assumed to be a program called 'main', * with dependencies as shown: * * main : file1.o file2.o file3.o ... filek.o * main : filek+1.o ... filen.o * # ------- construction command goes here --------- * * At this point, the programmer should edit the resulting makefile * to add the statement sequence which builds the program from the * compiled object code by replacing the '#' comment line. * * The makefile has a hook for specifying compilation options through * symbol OPT. * * Written and placed in the public domain by Tim McGrath 4/2/87 * */ #include #define LINEMAX 80 #define MAINPGM "main" long malloc(); char *strcat(),*strcpy(); FILE *makefile; main(argc,argv) char **argv; int argc; { int dependent_count; char **dependents; int i; if ((makefile = fopen("makefile","w")) == 0L) { puts("Can't create makefile"); exit(1); } fprintf(makefile,"OPT = \n\n"); depend_file(argc,argv,MAINPGM," ",".o"); for (i = 1; i < argc; i++) { get_dependents(argv[i],&dependents,&dependent_count); depend_file(dependent_count,dependents,argv[i],".o",""); free_space(dependents,dependent_count); } fclose(makefile); exit(0); } free_space(dp,dc) /* * Purpose: free up list of file names * Inputs: dp - points to list of pointers to strings * dc - number of pointers in the list */ char **dp; int dc; { while (dc > 0) { free(*dp++); dc--; } free(dp); } char * file_exten(pgm_name,xtension,bufout) /* * Purpose: append new extension onto file name * Inputs: pgm_name - pointer to name of file * xtension - pointer to new file name extension (2 chars only) * Outputs: bufout - points to area for new file name * Returns: bufout */ char *pgm_name,*xtension,*bufout; { int i = 0; while (*pgm_name) { bufout[i++] = *pgm_name; if (*pgm_name++ == '.' && xtension[0] != '\0') { bufout[i++] = xtension[1]; break; } } bufout[i] = '\0'; return(bufout); } depend_file(ct,flist,pgm_name,pgmx,filex) /* * Purpose: print file name and list of dependents * Inputs: ct - number of dependents in the list * flist - pointer to a list of pointers to dependent names * pgm_name - name of file whose dependents are being printed * pgmx - extension for pgm_name file (or "" if none) * filex - extension for dependent file names (or "" if none) */ char **flist,*pgm_name,*pgmx,*filex; int ct; { int i; char buf[LINEMAX], add_name[LINEMAX], pname[LINEMAX]; start_line(file_exten(pgm_name,pgmx,pname),buf); if (strcmp(pgm_name,MAINPGM)) strcat(strcat(buf," "),pgm_name); for (i = 1; i < ct; i++) { file_exten(flist[i],filex,add_name); if (columns(buf)+strlen(add_name)+1 >= LINEMAX - 1) { fputs(buf,makefile); fputc('\n',makefile); start_line(file_exten(pgm_name,pgmx,pname),buf); } strcat(strcat(buf," "),add_name); } fputs(buf,makefile); fputc('\n',makefile); if (strcmp(pgm_name,MAINPGM)) fprintf(makefile,"\tcc $(OPT) %s\n",pgm_name); else { fputs("# ------- construction command goes here ---------",makefile); fputc('\n',makefile); } } start_line(with_name,buf) /* * Purpose: give each line a standard indentation * Inputs: with_name - name of root file on each line * buf - place to put indented line */ char *with_name,*buf; { strcpy(buf,with_name); strcat(buf,"\t"); if (columns(buf) < 16) strcat(buf,"\t"); if (columns(buf) < 24) strcat(buf,"\t"); strcat(buf,":"); } columns(s) /* * Purpose: count the number of columns a line spans * Inputs: s - the characters in a line * Returns: the number of columns (including tab expansion) */ char *s; { int col = 0; while (*s) { if (*s++ == '\t') while (++col & 7); else ++col; } return(col); } get_dependents(fn,depv,depc) /* * Purpose: return a list of files depending on a C source file * Inputs: fn - name of the c source file * Outputs: depv - list of dependents (an array of pointers to filenames) * depc - number of dependents */ char *fn,***depv; int *depc; { char **lst; int i; lst = (char **) malloc(1024*sizeof(char *)); move_name(&lst[0],fn); fputs(fn,stdout); fputc('\n',stdout); i = 0; scan_file(lst,&i,fn); *depv = lst; *depc = i+1; } move_name(p,s) /* * Purpose: Allocate space for a new filename and copy it * Inputs: p - location for new pointer to filename * s - pointer to file name */ char **p,*s; { *p = (char *) malloc(strlen(s)+1); strcpy(*p,s); } scan_file(file_name_list,last_list_used,fn) /* * Purpose: search a C source file file #includes, and search the #includes * for nested #includes * Inputs: fn - name of file to scan * Outputs: file_name_list - list of included files * last_list_used - last used filename position in file_name_list */ char **file_name_list, *fn; int *last_list_used; { FILE *fp,*fopen(); char buf[1024],ifn[LINEMAX]; int j,k; fp = fopen(fn,"r"); if (!fp) { fprintf(stdout,"Couldn't open file %s\n",fn); return; } while (fgets(buf,1024,fp)) { if (strncmp(buf,"#include",8) == 0) { j = 8; while (buf[j] == ' ' || buf[j] == '\t') j++; if (buf[j++] != '"') continue; k = 0; while (buf[j]) { if (buf[j] == '"' || buf[j] == '\n') break; else ifn[k++] = buf[j++]; } ifn[k] = '\0'; if (add_name(file_name_list, last_list_used, ifn)) scan_file(file_name_list, last_list_used, ifn); } } fclose(fp); return; } add_name(file_name_list, last_list_used, fn) /* * Purpose: Add a file name to the list if it's not there already * Inputs: file_name_list - pointer to array of pointers to file names * last_list_used - last element in array with a filename * fn - name of file * Returns: 1 if file name added, 0 otherwise */ char **file_name_list, *fn; int *last_list_used; { int i; for (i = 0; i <= *last_list_used; i++) if (!strcmp(file_name_list[i],fn)) return(0); *last_list_used += 1; move_name(&file_name_list[*last_list_used],fn); return(1); }