home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / CLFEB88.ZIP / CREATE.C < prev    next >
Encoding:
Text File  |  1988-02-04  |  10.0 KB  |  309 lines

  1. An Incremental Compilation Package in C by Dave Taylor
  2.  
  3. /**                             create.c                        **/
  4.  
  5. /** This program creates an executable file from the *.c and *.p source in 
  6.     the current directory It uses the same technique that 'make' uses to 
  7.     determine if the specified file need be recompiled or not...ie, if the 
  8.     date/time of the source file is more recent than the date/time of the 
  9.     object file (*.o) then the appropriate compiler is invoked...
  10.  
  11.         Create allows the following arguments:
  12.  
  13.            -g           cdb-combatible symbol table and code generated
  14.            -w           suppress 'pc' warning messages
  15.            -O           turn on the optimizing feature of the C compiler
  16.            -o name      use 'name' as the output file
  17.            -l lib       include library 'lib'
  18.            -n           no execution: display commands to be used only.
  19.            -i           ignore bad return codes and go as far as possible 
  20.  
  21.     (C) Copyright 1986, 1987 by Dave Taylor
  22. **/
  23.  
  24. #include <stdio.h>
  25. #include <ndir.h>                       /* directory stuff */
  26. #include <errno.h>                      /* system error    */
  27. #include <sys/types.h>                  /* more types!!!   */
  28. #include <sys/stat.h>                   /* stat stuff...   */
  29.  
  30. #define MAXLIBS         25              /* max libraries specifiable */
  31. #define MAXFILES        250             /* max files total in dir    */
  32. #define FNAMELEN        20              /* max file name length      */
  33. #define LONG_SLEN       255             /* long string...            */
  34. #define SLEN            80              /* regular length string...  */
  35.  
  36. #define CC              "cc"            /* what is the C compiler called?   */
  37. #define PC              "pc"            /* what is the Pascal comp. called? */
  38.  
  39. DIR *dirp;              /* directory structure...  */
  40. struct direct *dp;      /* file entry in directory */
  41.  
  42. char files[MAXFILES][FNAMELEN];         /* all count in directory       */
  43. int  count      = 0,                    /* how many files in directory? */
  44.      ignore     = 0,                    /* -i (ignore errors) flag      */
  45.      optimize   = 0,                    /* -O (optimize) flag set       */
  46.      libraries  = 0,                    /* counts number of libraries   */
  47.      no_execute = 0,                    /* -n (no execute) flag set     */
  48.      compiled   = 0,                    /* count calls to pc & cc       */
  49.      cc_debug   = 0,                    /* -g (debug output) flag set   */
  50.      no_warn    = 0;                    /* -w (no warning) flag set     */
  51. char outname[SLEN],                     /* name of executable file      */
  52.      libname[MAXLIBS][SLEN];            /* list of library names...     */
  53.  
  54. extern int errno;                       /* system error number          */
  55. èchar *strcpy(), *strncpy();
  56. void  qsort(), exit();
  57.  
  58. main(argc, argv)
  59. int argc;
  60. char *argv[];
  61. {
  62.         int strcmp(), i;
  63.         
  64.         parse_arguments(argc, argv);    /* starting arguments... */
  65.  
  66.         initially_read_in_directory();                         
  67.  
  68.         for (i=0; i < count; i++)
  69.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  70.             if (newer_than_object(i))   /* aha!  Object old */
  71.               compile(files[i]);      /* recompile source */
  72.           }
  73.  
  74.         if (compiled || out_of_date_object_file())      /* don't link if nothing has changed! */
  75.           link_load();
  76.         else
  77.           printf("File '%s' is up to date.\n",
  78.                  (outname[0] == '\0'? "a.out" : outname));
  79.  
  80.         fini();
  81. }
  82.  
  83. parse_arguments(argc, argv)
  84. int argc;
  85. char *argv[];
  86. {
  87.         /** parse the starting arguments setting the flags etc as
  88.             specified...fail from this routine if bad args! **/
  89.         
  90.         int c;
  91.         extern char *optarg;
  92.         extern int optind, opterr;
  93.  
  94.         opterr = 0;     /* supress getopt error message! */
  95.         outname[0] = 0; /* initialize to nothing!        */
  96.  
  97.         while ((c = getopt(argc, argv, "l:o:Onigw")) != EOF) 
  98.           switch (c) {
  99.             case 'g' : cc_debug++;              break;
  100.             case 'i' : ignore++;                break;
  101.             case 'w' : no_warn++;               break;
  102.             case 'l' : strcpy(libname[libraries++], optarg);
  103.                                                 break;
  104.             case 'n' : no_execute++;            break;
  105.             case 'O' : optimize++;              break;
  106.             case 'o' : strcpy(outname, optarg); break;
  107.             default  : exit(fprintf(stderr,
  108.                 "Usage: %s -[i|n|O|g|w] [-l library] [-o name]\n", argv[0]));
  109.           }è}
  110.         
  111. initially_read_in_directory()
  112. {       
  113.         /* initialize the system variables and read in and sort the
  114.            current directory... */
  115.  
  116.         dirp = opendir(".");    /* current directory */
  117.  
  118.         while (read_directory(files[count++]) && count < MAXFILES)
  119.                 ;
  120.  
  121.         if (count >= MAXFILES) {
  122.           fprintf(stderr,
  123.         "*** Warning: read more files than this program can deal with! ***\n");
  124.           fprintf(stderr,
  125.         "***          Create continuing, but it might be wrong!        ***\n");
  126.         }
  127.  
  128.         qsort(files, (unsigned) --count, FNAMELEN, strcmp);
  129. }
  130.  
  131. fini()
  132. {
  133.         /* close everything and let's leave! */
  134.  
  135.         closedir(dirp);
  136. }
  137.  
  138. int
  139. read_directory(buffer)
  140. char *buffer;
  141. {
  142.         /** return the next name in the directory...
  143.             returns non-zero iff not out of entries **/
  144.  
  145.         if ((dp = readdir(dirp)) != NULL) 
  146.           strncpy(buffer, dp->d_name, FNAMELEN);
  147.         
  148.         return(dp != NULL);
  149. }
  150.  
  151. int
  152. suffix(sf, string)
  153. char *sf, *string;
  154. {
  155.         /** returns true iff the suffix of 'string' is 'sf' **/
  156.  
  157.         register int i, j;
  158.  
  159.         i = strlen(string);
  160.         j = strlen(sf);
  161.  
  162.         while (string[i] == sf[j] && j > 0) {
  163.           i--;è          j--;
  164.         }
  165.  
  166.         return(sf[0] == string[i] && j == 0 ? 1 : 0 );
  167. }
  168.  
  169. int
  170. newer_than_object(n)
  171. int n;
  172. {
  173.         /** returns true iff the source file with index 'n' has a last
  174.             modified time greater than that of the corresponding object
  175.             file... **/
  176.         
  177.         struct stat buffer;
  178.         long source_time;
  179.         char filename[FNAMELEN], *ctime();
  180.  
  181.         if (stat(files[n], &buffer) != 0) 
  182.           exit(printf("*** Error: Could not stat %s ***\n", files[n]));
  183.  
  184.         source_time = buffer.st_mtime;
  185.         
  186.         /** look for object file: same name but the last character should
  187.             be an 'o' rather than a 'c' or 'p'... **/
  188.  
  189.         strcpy(filename, files[n]);
  190.         filename[strlen(filename)-1] = 'o';
  191.  
  192.         buffer.st_mtime = 0L;
  193.  
  194.         if (stat(filename, &buffer) != 0)
  195.           if (errno != ENOENT)
  196.             exit(printf("*** Error: Could not stat %s [%d] ***\n",
  197.                  filename, errno));
  198.           else 
  199.             buffer.st_mtime = 0L;
  200.  
  201.         return(source_time > buffer.st_mtime);
  202. }
  203.  
  204. compile(name)
  205. char *name;
  206. {
  207.         /** compile the specified source file... **/
  208.  
  209.         char buffer[SLEN];
  210.         register int ret = 0;
  211.  
  212.     if (name[strlen(name)-1] == 'c')
  213.           sprintf(buffer, "%s -c %s%s%s", CC, optimize? "-O ": "", 
  214.                 cc_debug? "-g ":"", name);
  215.     else
  216.           sprintf(buffer, "%s -c %s%s", PC, no_warn? "-w ":"", name);
  217. è        printf("\t%s\n", buffer);
  218.  
  219.         if (! no_execute) {
  220.           ret = system(buffer);
  221.  
  222.           if (ret != 0) {
  223.             printf("** return code = %d from compile! **\n", ret);
  224.             if (! ignore)
  225.               exit(ret);
  226.           }
  227.         }
  228.  
  229.         compiled++;
  230. }
  231.  
  232.  
  233. link_load()
  234. {
  235.         /** link and load the corresponding object files to create an
  236.             executable file... **/
  237.  
  238.         char buffer[LONG_SLEN], *basename();
  239.         register int i, ret = 0, first_pc = 0;
  240.  
  241.         if (outname[0] != 0)
  242.           sprintf(buffer, "%s -o %s -n", CC, outname);
  243.         else
  244.           sprintf(buffer, "%s -o a.out -n", CC);
  245.  
  246.         for (i=0; i < count; i++)
  247.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  248.         strcat(buffer, " ");
  249.         strcat(buffer, files[i]);
  250.         buffer[strlen(buffer)-1] = 'o'; /* make it the object file */
  251.       }
  252.           if (suffix(".p", files[i]) && first_pc++) {
  253.             strcpy(libname[libraries++], "pc");
  254.           }
  255.  
  256.         /** add libraries specified **/
  257.  
  258.         for (i=0; i < libraries; i++)
  259.           sprintf(buffer, "%s -l%s", buffer, libname[i]);
  260.  
  261.         printf("\t%s\n", buffer);
  262.  
  263.         if (! no_execute) {
  264.           ret = system(buffer);
  265.  
  266.           if (ret != 0) {
  267.             printf("** return code = %d from link/load! **\n", ret);
  268.             if (! ignore)
  269.               exit(ret);
  270.           }
  271.         }è}
  272.  
  273. int
  274. out_of_date_object_file()
  275. {
  276.         /** returns true iff executable file is older than any of the
  277.             object files in the directory...if executable name is 
  278.             specified, then it checks the date of THAT file... **/
  279.  
  280.         char filename[FNAMELEN];
  281.         struct stat buffer;
  282.         long mod_date;
  283.         register int i;
  284.  
  285.         strcpy(filename, outname[0] != 0? outname: "a.out");
  286.  
  287.         if (stat(filename, &buffer) != 0)
  288.           if (errno != ENOENT)
  289.             exit(printf("*** Could not stat %s [%d] ***\n", 
  290.                  filename, errno));
  291.           else
  292.             return(1);  /* not found: must be out of date!! */
  293.  
  294.         mod_date = buffer.st_mtime;
  295.  
  296.         for (i=0; i < count; i++)
  297.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  298.         strcat(filename, files[i]);
  299.         filename[strlen(filename)-1] = 'o';  /* make it an obj file */
  300.  
  301.             stat(filename, &buffer);    /* no problem? */
  302.  
  303.             if (buffer.st_mtime > mod_date)
  304.               return(1);
  305.           }
  306.  
  307.         return(0);
  308. }
  309.