Using MAKE

The "make" command allows easy maintenance of large programs. To avoid recompiling the complete program every time a minor change is made, the program is broken up into modules with dependencies between these modules. A file named "makefile" is used as an implicit argument to the "make" command. This file specifies the dependencies that exist between the modules. When the make command is invoked, the system will check out the dependencies and if a dependent file has been modified, the specified command(s) will be executed. There exists a built-in dependency between .c (c source) and .o (object module) files. For example, the following lines specify the dependency of module1.o on the file dec.c and module1.c. Actually, module1.c is not necessary since there is an implicit dependency.

module1.o: dec.c module1.c 
	cc -c module1.c 

If dec.c or module1.c is modified, make will invoke the command found on the second line ( a tab character must preceed the command) causing a recompilation of module1.c to produce module1.o. If make is invoked and none of the files have been modified since the last compilation of module1.c, then no action is required; i.e. recompilation is not necessary.

A final load module can be produced by specifying its dependency on the appropriate object modules as illustrated by the following two lines:

asm: pass1.o pass2.o 
	cc -o asm pass1.o pass2.o

As an example, consider the following files:

"defines.h"

#define SIZE 50  // maximum array size

"globals.h"

#include 
#include 

int NUMBERS[SIZE];

"module1.c"

#include "defines.h"
#include "globals.h"

/**********************************************************************************/
void fill_arry()  

//Purpose: Fills array NUMBERS with values 0 to SIZE-1
/**********************************************************************************/

{
  int i;


  for(i = 0;i <= (SIZE-1);i++)
    NUMBERS[i] = i;


}

"module2.c"

#include "defines.h"
#include "globals.h"

/**********************************************************************************/
void print_arry () 

// Purpose: Prints out the entire array NUMBERS
/**********************************************************************************/
{
  int i;


  for(i = 0;i <= (SIZE-1);i++)
  {
      if((i % 10) == 0)
	printf("\n");
      printf("%3d",NUMBERS[i]);
  }
  printf("\n");

 
}

/**********************************************************************************/
int sum_arry (int lower, // IN: lower array index value to begin summing
              int upper) // IN: upper array index value to end summing

//Purpose: Sums values from lower to upper
/**********************************************************************************/
{
  int i, sum = 0;  // accumulator


  for (i = lower; i <= upper; i++)
    sum += NUMBERS[i];


  return sum;
}

"main.c"

#include "defines.h" /* global macro definitions */
#include "globals.h" /* global variable declarations */

/***************************************************************************
Main Program
****************************************************************************

Purpose: To fill an array with values and then print them out and a sum
Inputs: None
Outputs: The values in the array and the sum
Author: Doug Ryan
Date: 1/4/2000
Routines Called :
fill_arry - fills the array numbers with values
print_arry - prints the values in the array numbers
sum_arry - sums elements in the array from lower to upper inclusive
Called By: Operating System

***************************************************************************/

extern void fill_arry();
extern void print_arry();
extern int sum_arry(int,int);

int main()
{
  fill_arry ();
  print_arry ();
  printf ("\nSum = %d\n", sum_arry (0,49));
  return 0;
}

There now exists five source modules that need to be compiled. They could be compiled separately using the "cc" command or the dependencies could be set up in a makefile and only the files that have been modified will be recompiled. After recompilation all object modules will be linked. Therefore, a file called "makefile" must be created with the dependencies and the appropriate commands as follows.

"makefile"

# Sample makefile

CC=gcc
CFLAGS=-g -Wall

all: asm

asm: module1.o  module2.o  main.o
	${CC} ${CFLAGS} -o asm module1.o module2.o main.o
module1.o:  module1.c  defines.h  globals.h
	${CC} ${CFLAGS} -c module1.c
module2.o:  module2.c  defines.h  globals.h
	${CC} ${CFLAGS} -c  module2.c
main.o:  main.c  defines.h  globals.h
	${CC} ${CFLAGS} -c  main.c
clean:
	rm -f core *.o

To invoke the make command simply type "make" without the quotes and it will go through and check the dependencies. Also, it is important that you keep your modules to a manageable size so you can take full advantage of how make operates. Modules should contain functions which are grouped according to some central idea such as symbol table routines.


The following files can be downloaded and tested in your own directory.
makefile 
defines.h 
globals.h 
main.c
module1.c 
module2.c

© 2000 Douglas J. Ryan / ryandj@pacificu.edu