XJCO1921 PROGRAMMING PROJECT
Modular Programming
Zheng Wang
1
Software is big
KLOC = 1000 lines of code; MLOC = 1,000,000 lines of code
Bar code scanners 10-50KLOC
4-speed transmissions (motor 20KLOC
control)
Air traffic ground system 130KLOC
ATM 600KLOC
Call router 2.1MLOC
B-2 Stealth Bomber 3.5MLOC
Windows OS 60M+LOC
Break it up
• Big programs get BIG.
• Most software is many millions of lines of code.
• Organisation is important
3
Let’s think a bit smaller
• Separate functionality into smaller chunks
• Use functions whenever possible
• Avoids repeated code
• Sometimes requires more “communication”
• Organise connections between chunks
• How does this statement get this value?
• Should this loop contain a function call, or should the
• function contain the loop?
• Should I group these together, or do them separately?
4
Scale
• We are thinking today about the code as a whole
• The purpose of a module should be clear and separated
from other modules
• Modularity also applies to functions
• If you can’t describe what your function does in one
sentence you should consider splitting it
5
Module Terminology
• Module Interface (.h)
• The formal description of what is in it
• Module implementation (.c)
• Human-readable description of the details
• Object file (.o)
• Machine-readable description of the details
Interface & Implementation
• If I edit an implementation (.c) file
• It shouldn't affect other modules
• Since they don't have access to the .c file
• But if I edit a header (.h) file
• It should affect any module that uses it
• So we set up the headers first
• Then try not to modify them at all
Compilation pipeline
Helloworld.c
Pre-processing
Compilation
Linking
Pre-processing
The pre-processor expands all the directives that start with
“#”, such as:
#include //importing libraries
#define //creating macros
//conditional comilation:
#ifdef
#if
#ifndef
#elif
#endif
#else
Pre-processing - Example
#define N 10
int main()
int main() {
{ int x = 10;
int x = N; int y = 10;
int y = N; return 0;
return 0; }
}
What does the compiler see? Use: gcc -E file.c
E-commercial shopping website
• A toy online order system (similar to Taobao and
ebay)
• Need to manage customer orders
• We define our key data structures and functions (or
APIs)in a header file
customer.h
11
customer.h
typedef struct customer {
int id;
char *name; Customer data
int n_orders;
order_t *orders; structure
} customer_t;
Functions
int customer_new (customer_t **);
int customer_read (id_t const *, customer_t **);
int customer_update (customer_t const *);
int customer_delete (customer_t *);
int customer_retrive_orders (customer_t *, int *);
12
Header files
• Typically contain
• Data structures
• Function prototypes
• Compilers require function definitions for checking at
compile time
• Functions implemented in another source file, e.g.,
customer.c
• Data struct definitions can be separated from the
body of the code
13
Protecting headers from multiple inclusions
Header files are prone to multiple inclusions:
// customer.h // customer_utils.h
typedef struct customer{ void customer_enqueue_order
... (customer_t);
} customer_t;
What problem we may have?
// main.c //customer_util.c
Protecting headers from multiple inclusions
// customer.h
error: redefinition of ‘struct customer’
typedef struct customer{
...
} customer_t;
Headers’ Guards
//in customer.h
The second inclusion
#ifndef _CUSTOMER_H_
#define _CUSTOMER_H_
will be false, hence
the data structure
typedef struct customer {
int id; will not be defined
char *name;
int n_orders; again
order_t *orders;
} customer_t;
#endif
16
Manual Compilation
• Every time we compile, we type gcc ...
• gcc –g –O3 –o helloworld helloworld.c
• This gets old pretty fast
• So we use the terminal history
• Or we put it in a script
• But it's wasteful of compile time
• Since we can reuse unchanged modules
Quick Recap on Modularity
• If you have 600 .c files
• You don't want to recompile all of them
• It can take all day (literally!)
• And you want to break the program down
• To make it easier to think about
• So we keep already compiled object files (.o)
• And relink them to get the new executable
Linking
Compilation
Linking
You can give the compiler either C files, in which case it compiles them, or .o files, in which case it only links them:
gcc mod1.o mod2.o main.o -o exec
Compilation
• We can stop compilation before linking
• Using the –c flag for gcc
• And saving to a '.o' file
• gcc –c –g –O3 –o helloworld.o helloworld.c
• Then use objdump to examine it
• objdump –h helloworld.o (headers)
• objdump –Sl helloworld.o (disassembly & source)
• objdump –syms helloworld.o (symbols)
Selective Compilation
• If the error module hasn't changed
• Why should we recompile it?
• Doesn't seem like a big idea for small code
• But for big code it becomes significant
• This is one of the ideas behind modules
• We only want to recompile changed modules
• Which is an "if" statement at heart
Dependencies
• Executable changes when the modules do
• helloworld depends on helloworld.o
• Object changes when files it uses do
• helloworld.o depends on helloworld.c (potneital some other head files xx.h)
Make
•Make is a utility to automate this
•A specialised scripting language
•Based on:
•Targets: files to be remade
•Dependencies: files they depend on
•Commands: details of how to make them
•Plus lots of standard conveniences
Make
• Good for modular programming
• The Makefile is a plain text build script
• Efficiently deals with modular code projects by
managing the (slower) compilation process to only
recompile modified code
24
A Trivial Makefile
# Trivial Makefile for helloworld.c
# Z Wang, XJCO 1921
# 1/3/21
#
helloworld: helloworld.c
gcc –o helloworld helloworld.c
A Trivial Makefile
# Trivial Makefile for helloworld.c
# Z Wang, XJCO 1921
# 1/3/21
# COMMENTS
helloworld: helloworld.c
gcc –o helloworld helloworld.c
A Trivial Makefile
# Trivial Makefile for helloworld.c
# Z Wang, XJCO 1921
# 1/3/21 Target Prerequisites
Target
#
helloworld: helloworld.c Dependence line
gcc –o helloworld helloworld.c
What’s happening here?
Source File
helloworld.c
Compiler
gcc
Target
Depends on
helloworld
A Trivial Makefile
# Trivial Makefile for helloworld.c
# Z Wang, XJCO 1921
# 1/3/21 Time stamp on this file
is compared to the time stamp on this file.
#
helloworld: hellowrold.c Dependency Line
gcc –o helloworld helloworld.c
If the target’s time stamp is earlier than the prerequisite’s time stamp, the rule below
this dependency line is executed.
So what is a time stamp?
• The time that the file was last modified.
• If the target’s time is earlier than the prerequisite’s
time, this means that the prerequisite file has been
changed, but the run image has not been updated.
A Trivial Makefile
# Trivial Makefile for helloworld.c
# Z Wang, XJCO 1921
# 1/3/21 Any command (e.g., rm *.o)
#
helloworld: helloworld.c
gcc –o helloworld helloworld.c Rule Line
Must be a tab!!
Example time stamps
• Assume helloworld has TS Jan 22 14:00
• Assume helloworld.c has TS Jan 21 13:55
• Target is LATER than prerequisite, so rule is NOT
executed!
Example time stamps
• Assume helloworld has TS Jan 21 13:00
• Assume helloworld.c has TS Jan 21 13:55
• Target is EARLIER than prerequisite, so rule is
executed!
Example
• Build a source file with code for helloworld.c
• Build a Makefile with an appropriate dependency line.
• Run make
$ make
gcc -o helloworld helloworld.c
• The rule executes since the file helloworld does not even exist yet!
What if you tried make again?
$ make
make: ‘helloworld’ is up to date
$
Makefile Structure EXE DIR = .
EXE = $(EXE DIR)/solver
SRC= main.c checks.c solve.c
CC= cc
COPT= -O
CFLAGS=
OBJ= $(SRC:.c=.o)
.c.o:
$(CC) $(COPT) -c -o $@ $<
$(EXE): $(OBJ)
$(CC) $(OBJ) $(CFLAGS) -o $(EXE)
clean:
rm -f $(OBJ) $(EXE)
main.o: main.c main.h solve.h checks.h
Online tutorials: solve.o: solve.c solve.h checks.h
checks.o: checks.c checks.h
[Link]
36
Makefile Summary
• Build a dependency line for every target.
• Add a rule line to rebuild the target.
• Start the rule line with a tab.
• Add comments to the top of the file.
• Save these lines in an ASCII file called Makefile
Summary
• Modular programming is key to writing larger C
programs
• It is part of the design process
• Makefiles enable efficient compilation
38