Computer Science 210 Computer Organization Modular Decomposition Making a Library Separate Compilation
Program Decomposition C programs consist of lots of functions Organize these and save them in libraries (like Python modules) Separately compile them for distribution and link them to client applications
Example: An Assembler Text file Object file Sym file Source program listing, error messages (file and/or terminal)
Decompose into Modules Text file Character stream CharacterIO Scanner Tools Token stream Symbol table Parser Opcode table Source program listing, error messages (file and/or terminal) Sym file Object file CharacterIO – handles files, text Scanner – recognizes numbers, symbols, assembler directives Parser – handles syntax checking, code generation
Using a Function Prototype /* This program prints the factorial of 6. */ #include <stdio.h> int factorial(int n); // Prototype shows the function specs int main(){ printf("The factorial of 6 is %d\n", factorial(6)); } int factorial(int n){ if (n == 1) return 1; else return n * factorial(n - 1); A function prototype is a header that appears early, to aid the human reader of the code (like a Java interface, sort of)
Where Should Functions Go? We can put ‘em all in one file with the application; prototypes are at the beginning of the file, and we work top down But this requires recompiling the whole file after one small change Work can’t be divided among many developers Functions can’t be maintained independently of their clients
Create a Library of Functions Place the function prototypes for a module in a header file (.h extension) Place the completed function definitions for that module in an implementation file (.c extension) Compile the c. file, link it to a test driver, test it, and store it away Example: a mylib library with factorial and gcd
Structure of the Program Header file Main function file mylib.h usemylib.c Compile time Compile time Link time Implementation file mylib.c mylib.c and usemylib.c can be compiled in separate steps, by different people, in different organizations They each rely on the interface in mylib.h
The Header File mylib.h /* File: mylib.h Header file for factorial and gcd functions. */ // Returns the factorial of n int factorial(int n); // Returns the greatest common divisor of a and b int gcd(int a, int b); The header file contains function prototypes and may also contain #define macros
The Implementation File mylib.c Implementation file for factorial and gcd functions. */ #include "mylib.h" // Returns the factorial of n int factorial(int n){ if (n == 1) return 1; else return n * factorial(n - 1); } // Returns the greatest common divisor of a and b int gcd(int a, int b){ if (b == 0) return a; return gcd(b, a % b); The implementation file also includes its header file (for consistency checking) – note the quotes rather than the < >
The Test Driver File usemylib.c Test program uses both mylib functions. */ #include <stdio.h> #include "mylib.h" int main(){ printf("The factorial of 6 is %d\n", factorial(6)); printf("The gcd of 9 and 15 is %d\n", gcd(15, 9)); }
Separate Compilation and Linking Save each implementation file with a .c extension Work bottom up, compile each .c file with gcc –c <filename>.c If no errors, link the object files with gcc –o <main filename> <filename>.o ... <filename>.o If no errors, run the program with ./<main filename>
make and Makefiles Many modules to keep track of Which ones are up to date, which ones need to be recompiled? The UNIX make tool and makefiles help to manage this problem
make and Makefiles When you run make, UNIX looks for a file named makefile or Makefile in the current working directory A makefile contains info about the dependencies among program modules and commands to compile and/or link them
Makefile Entries This is the format of an entry. There are one or more entries in a makefile. targets : prerequisites commands A tab must go here Targets are dependent on prerequisites Targets and prerequisites are file names Commands are similar to those we’ve seen already
A Makefile for Compiling mylib mylib.o : mylib.c mylib.h gcc -c mylib.c prerequisites target command
Add Another Entry for usemylib usemylib.o : usemylib.c mylib.h gcc -c usemylib.c mylib.o : mylib.c mylib.h gcc -c mylib.c
Add Another Entry to Link the Program usemylib : usemylib.o mylib.o gcc -o usemylib usemylib.o mylib.o usemylib.o : usemylib.c mylib.h gcc -c usemylib.c mylib.o : mylib.c mylib.h gcc -c mylib.c
Add comments if you like # Here’s a makefile comment (looks like # a Python comment!) usemylib : usemylib.o mylib.o gcc -o usemylib usemylib.o mylib.o usemylib.o : usemylib.c mylib.h gcc -c usemylib.c mylib.o : mylib.c mylib.h gcc -c mylib.c
How make works > make > make mylib.o The first call compares the time stamps of the targets and prerequisites and runs only those commands that “make” the targets up to date The second call runs only the command whose target is the argument mylib.o
For Wednesday Arrays and Pointers