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.  
  56. èchar *strcpy(), *strncpy();
  57. void  qsort(), exit();
  58.  
  59. main(argc, argv)
  60. int argc;
  61. char *argv[];
  62. {
  63.         int strcmp(), i;
  64.         
  65.         parse_arguments(argc, argv);    /* starting arguments... */
  66.  
  67.         initially_read_in_directory();                         
  68.  
  69.         for (i=0; i < count; i++)
  70.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  71.             if (newer_than_object(i))   /* aha!  Object old */
  72.               compile(files[i]);      /* recompile source */
  73.           }
  74.  
  75.         if (compiled || out_of_date_object_file())      /* don't link if nothing has changed! */
  76.           link_load();
  77.         else
  78.           printf("File '%s' is up to date.\n",
  79.                  (outname[0] == '\0'? "a.out" : outname));
  80.  
  81.         fini();
  82. }
  83.  
  84. parse_arguments(argc, argv)
  85. int argc;
  86. char *argv[];
  87. {
  88.         /** parse the starting arguments setting the flags etc as
  89.             specified...fail from this routine if bad args! **/
  90.         
  91.         int c;
  92.         extern char *optarg;
  93.         extern int optind, opterr;
  94.  
  95.         opterr = 0;     /* supress getopt error message! */
  96.         outname[0] = 0; /* initialize to nothing!        */
  97.  
  98.         while ((c = getopt(argc, argv, "l:o:Onigw")) != EOF) 
  99.           switch (c) {
  100.             case 'g' : cc_debug++;              break;
  101.             case 'i' : ignore++;                break;
  102.             case 'w' : no_warn++;               break;
  103.             case 'l' : strcpy(libname[libraries++], optarg);
  104.                                                 break;
  105.             case 'n' : no_execute++;            break;
  106.             case 'O' : optimize++;              break;
  107.             case 'o' : strcpy(outname, optarg); break;
  108.             default  : exit(fprintf(stderr,
  109.                 "Usage: %s -[i|n|O|g|w] [-l library] [-o name]\n", argv[0]));
  110.           }
  111. è}
  112.         
  113. initially_read_in_directory()
  114. {       
  115.         /* initialize the system variables and read in and sort the
  116.            current directory... */
  117.  
  118.         dirp = opendir(".");    /* current directory */
  119.  
  120.         while (read_directory(files[count++]) && count < MAXFILES)
  121.                 ;
  122.  
  123.         if (count >= MAXFILES) {
  124.           fprintf(stderr,
  125.         "*** Warning: read more files than this program can deal with! ***\n");
  126.           fprintf(stderr,
  127.         "***          Create continuing, but it might be wrong!        ***\n");
  128.         }
  129.  
  130.         qsort(files, (unsigned) --count, FNAMELEN, strcmp);
  131. }
  132.  
  133. fini()
  134. {
  135.         /* close everything and let's leave! */
  136.  
  137.         closedir(dirp);
  138. }
  139.  
  140. int
  141. read_directory(buffer)
  142. char *buffer;
  143. {
  144.         /** return the next name in the directory...
  145.             returns non-zero iff not out of entries **/
  146.  
  147.         if ((dp = readdir(dirp)) != NULL) 
  148.           strncpy(buffer, dp->d_name, FNAMELEN);
  149.         
  150.         return(dp != NULL);
  151. }
  152.  
  153. int
  154. suffix(sf, string)
  155. char *sf, *string;
  156. {
  157.         /** returns true iff the suffix of 'string' is 'sf' **/
  158.  
  159.         register int i, j;
  160.  
  161.         i = strlen(string);
  162.         j = strlen(sf);
  163.  
  164.         while (string[i] == sf[j] && j > 0) {
  165.           i--;
  166. è          j--;
  167.         }
  168.  
  169.         return(sf[0] == string[i] && j == 0 ? 1 : 0 );
  170. }
  171.  
  172. int
  173. newer_than_object(n)
  174. int n;
  175. {
  176.         /** returns true iff the source file with index 'n' has a last
  177.             modified time greater than that of the corresponding object
  178.             file... **/
  179.         
  180.         struct stat buffer;
  181.         long source_time;
  182.         char filename[FNAMELEN], *ctime();
  183.  
  184.         if (stat(files[n], &buffer) != 0) 
  185.           exit(printf("*** Error: Could not stat %s ***\n", files[n]));
  186.  
  187.         source_time = buffer.st_mtime;
  188.         
  189.         /** look for object file: same name but the last character should
  190.             be an 'o' rather than a 'c' or 'p'... **/
  191.  
  192.         strcpy(filename, files[n]);
  193.         filename[strlen(filename)-1] = 'o';
  194.  
  195.         buffer.st_mtime = 0L;
  196.  
  197.         if (stat(filename, &buffer) != 0)
  198.           if (errno != ENOENT)
  199.             exit(printf("*** Error: Could not stat %s [%d] ***\n",
  200.                  filename, errno));
  201.           else 
  202.             buffer.st_mtime = 0L;
  203.  
  204.         return(source_time > buffer.st_mtime);
  205. }
  206.  
  207. compile(name)
  208. char *name;
  209. {
  210.         /** compile the specified source file... **/
  211.  
  212.         char buffer[SLEN];
  213.         register int ret = 0;
  214.  
  215.     if (name[strlen(name)-1] == 'c')
  216.           sprintf(buffer, "%s -c %s%s%s", CC, optimize? "-O ": "", 
  217.                 cc_debug? "-g ":"", name);
  218.     else
  219.           sprintf(buffer, "%s -c %s%s", PC, no_warn? "-w ":"", name);
  220.  
  221. è        printf("\t%s\n", buffer);
  222.  
  223.         if (! no_execute) {
  224.           ret = system(buffer);
  225.  
  226.           if (ret != 0) {
  227.             printf("** return code = %d from compile! **\n", ret);
  228.             if (! ignore)
  229.               exit(ret);
  230.           }
  231.         }
  232.  
  233.         compiled++;
  234. }
  235.  
  236.  
  237. link_load()
  238. {
  239.         /** link and load the corresponding object files to create an
  240.             executable file... **/
  241.  
  242.         char buffer[LONG_SLEN], *basename();
  243.         register int i, ret = 0, first_pc = 0;
  244.  
  245.         if (outname[0] != 0)
  246.           sprintf(buffer, "%s -o %s -n", CC, outname);
  247.         else
  248.           sprintf(buffer, "%s -o a.out -n", CC);
  249.  
  250.         for (i=0; i < count; i++)
  251.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  252.         strcat(buffer, " ");
  253.         strcat(buffer, files[i]);
  254.         buffer[strlen(buffer)-1] = 'o'; /* make it the object file */
  255.       }
  256.           if (suffix(".p", files[i]) && first_pc++) {
  257.             strcpy(libname[libraries++], "pc");
  258.           }
  259.  
  260.         /** add libraries specified **/
  261.  
  262.         for (i=0; i < libraries; i++)
  263.           sprintf(buffer, "%s -l%s", buffer, libname[i]);
  264.  
  265.         printf("\t%s\n", buffer);
  266.  
  267.         if (! no_execute) {
  268.           ret = system(buffer);
  269.  
  270.           if (ret != 0) {
  271.             printf("** return code = %d from link/load! **\n", ret);
  272.             if (! ignore)
  273.               exit(ret);
  274.           }
  275.         }
  276. è}
  277.  
  278. int
  279. out_of_date_object_file()
  280. {
  281.         /** returns true iff executable file is older than any of the
  282.             object files in the directory...if executable name is 
  283.             specified, then it checks the date of THAT file... **/
  284.  
  285.         char filename[FNAMELEN];
  286.         struct stat buffer;
  287.         long mod_date;
  288.         register int i;
  289.  
  290.         strcpy(filename, outname[0] != 0? outname: "a.out");
  291.  
  292.         if (stat(filename, &buffer) != 0)
  293.           if (errno != ENOENT)
  294.             exit(printf("*** Could not stat %s [%d] ***\n", 
  295.                  filename, errno));
  296.           else
  297.             return(1);  /* not found: must be out of date!! */
  298.  
  299.         mod_date = buffer.st_mtime;
  300.  
  301.         for (i=0; i < count; i++)
  302.           if (suffix(".c", files[i]) || suffix(".p", files[i])) {
  303.         strcat(filename, files[i]);
  304.         filename[strlen(filename)-1] = 'o';  /* make it an obj file */
  305.  
  306.             stat(filename, &buffer);    /* no problem? */
  307.  
  308.             if (buffer.st_mtime > mod_date)
  309.               return(1);
  310.           }
  311.  
  312.         return(0);
  313. }
  314.