'Make' is a tool programmers use to streamline compile & build of programs, given MULTIPLE source code files.  Up to this installment, 'make' would be overkill, considering we have our 'goc' script.  In this explore, we take one source file, break into 4 components, and examine how 'make' does its thing.

 

  1. Save the 2nd block of text to a tile named 'Makefile'
  2. IMPORTANT:  When saving 'Makefile', for each line beginning with 'gcc' (or 'rm'), INDENT with ONE TAB
  3. Per the comments, divide the 1rst block of text into 'pgm28.h'  'pgm28main.c'  'pgm28fileio.c'  'pgm28misc.c'
  4. We will NOT use the single-build 'goc' shell script.  Build the program 'pgm28' by entering 'make' in terminal window

 

(right-click to download)

/* pgm28 whole program source */

/* pgm28.h  header */

#define MAXITEMS 5
#define MAXSTRLEN 129

enum statevals {RET_ERR = -1, RET_OK, LOOPEND = 0, LOOPRUN};

struct programdata {
     char buffer[MAXSTRLEN];
     char line5[MAXSTRLEN];
     char *p2argv;
     int num_records;
     int real_num_lines;
     };

/* pgm28main.c source */

#include <stdio.h>
#include <string.h>
#include "pgm28.h"

/* REQ'd -- these functions are called from 'main()' so */
/* they need to be 'explained' as to their prototype */
/* since they're located in other source files */

void double_records(struct programdata *);
void display_structure(struct programdata *);
int get_line_5_in_file(struct programdata *);

int main(int argc, char *argv[]) {
     struct programdata pd;

     if (argc != 2) {
          printf("\nPlease supply argument: filename\n\n");
          return(RET_ERR);
          }
     else
          pd.p2argv = argv[1];

     if (get_line_5_in_file(&pd) != RET_OK) {
          printf("\nAbort: file error\n\n");
          return(RET_ERR);
          }

     double_records(&pd);
     display_structure(&pd);

     return(RET_OK);
     }

/* pgm28 misc source */

#include <stdio.h>
#include "pgm28.h"

void double_records(struct programdata *pd) {
     pd->num_records *= 2;
     }

void display_structure(struct programdata *pd) {
     printf("\nStructure member \"buffer\" contains: %s\n", pd->buffer);
     printf("Structure member \"line5\" contains: %s\n", pd->line5);
     printf("Structure member \"p2argv\" contains: %s\n", pd->p2argv);
     printf("Structure member \"num_records\" contains: %d\n", pd->num_records);
     printf("Structure member \"real_num_lines\" contains: %d\n\n", pd->real_num_lines);
     }

/* pgm28 fileio source */

#include <stdio.h>
#include <string.h>
#include "pgm28.h"

int get_line_5_in_file(struct programdata *pd) {
     char *nl_pos;
     int file_line_num;
     FILE *fileptr;

     fileptr = fopen(pd->p2argv, "r");
     if (fileptr == NULL) {
          perror("fopen() to read ");
          return(RET_ERR);
          }

     file_line_num = 1;
     while (fgets(pd->buffer, MAXSTRLEN - 1, fileptr) != NULL) {
          nl_pos = strchr(pd->buffer, (int) '\n');
          *nl_pos = (char) '\0';

          if (file_line_num == 5)
               strcpy(pd->line5, pd->buffer);
          file_line_num++;
          }

     pd->num_records = file_line_num;
     pd->real_num_lines = file_line_num;

     fclose(fileptr);
     return(RET_OK);
     }

 

# makefile for pgm28

# combine 3 object files into the final executable named 'pgm28'
pgm28 : pgm28main.o pgm28fileio.o pgm28misc.o
gcc -Wall -o pgm28 pgm28main.o pgm28fileio.o pgm28misc.o

# this file is effectively 'main.c' -- and re-compiles w/ any change in header 'pgm28.h'
pgm28main.o : pgm28main.c pgm28.h
gcc -Wall -Wno-misleading-indentation -c pgm28main.c

# this souce holds FILE I/O functions -- and re-compiles w/ any change in header 'pgm28.h'
pgm28fileio.o : pgm28fileio.c pgm28.h
gcc -Wall -Wno-misleading-indentation -c pgm28fileio.c

# miscellaneous functions here -- and re-compiles w/ any change in header 'pgm28.h'
pgm28misc.o : pgm28misc.c pgm28.h
gcc -Wall -Wno-misleading-indentation -c pgm28misc.c

# remove intermediary object ('.o') files... invoke with "make clean"
clean :
rm pgm28main.o pgm28fileio.o pgm28misc.o