Warning! This site is under development.
This class will be recorded! Its use will be limited to members of the class. Please do not share with others.
Approximate overview
makeMakefilemake?What goes in a (non-trival) C project?
Code we expect to others to use in their programs, or that we expect ourselves to use in other contexts. Good programmers write or find libraries of things they want to use.
Libraries in C usually have the form libNAME.a or libNAME.so. When developing those libraries, we usually work with .o files from the individual C programs that compose the libraries.
We’re going to build a library of useful Math utilities.
gcd (long x, long y) finds the gcd of x and y.exptmod (long base, long expt, long modulus) - computes
(base^expt) mod modulus. (We have a separate function to do
this because base^expt might overflow.What are the source files we want?
.c file: mymath.c (source code)
mygcd-lib.c and myexptmod-lib.c (Sam likes to split independent
things into separate .c files to ease development and recompliation.).h file mymath.h (header file)mymathtest.c (test file)mygcdtest.c and myexpmodtest.cmygcd.c and myexptmod - Command-line versions of these procedures.
MakefileREADME.txtLICENSEWe’ll be building .o files, the libraries, maybe some executables.
To ease sharing and to speed rebuilding, we often divide large projects into many many many files.
In this case, we’re probably doing some .h files (especially if we split up the program into independing parts), a bunch of .c files, some tests (also C files or shell scripts), and executables.
Checking in … do you know the (implicit) steps in going from .c file to executable? [Sam will attempt a survey.]
Variants of the cc command let you do each of these steps.
.s)Optimization
Recall: Our goal is to express a sequence of commands necessary to create a program and to express the dependencies along the way. “If X changes, this has to be rebuilt.”
We express this information using a series of “rules”. (Plus additional stuff.)
TARGET: PREREQUISITES
INSTRUCTIONS
Let’s try doing this for our sample project.
We’re building a sample math utilities package, which we can find
in examples/srmath.
srmath presents one function, gcd (long, long).
srgcd.c contains the implementation of gcdsrmath.h is the general header filesrtest to permit unit testing.gcdtest) and a
utility (gcd).Files
gcd.c srgcd.c srtest.c testdemo.c
gcdtest.c srmath.h srtest.h
How do I build gcd?
cc -c gcd.c -o gcd.o
cc -c srgcd.c -o srgcd.o
cc gcd.o srgcd.o -o gcd
How do I build gcdtest
cc -c srgcd.c -o srgcd.o
cc -c gcdtest.c -o gcdtest.o
cc -c srtest.c -o srtest.o
cc srgcd.o gcdtest.o srtest.o -o gcdtest
Suppose we just changed gcdtest.c. Which of those steps do we need to redo?
cc -c gcdtest.c -o gcdtest.o
cc srgcd.o gcdtest.o srtest.o -o gcdtest
We shouldn’t have to remember that!
If Sam types !s in his terminal window, what will happen?
Ignore the following
jet: engine
type-in-chat
Pattern
TARGET: DEPENDENCIES
INSTRUCTIONS
# All those awesome .o files
gcd.o: gcd.c srmath.h
cc -c gcd.c -o gcd.o
srgcd.o: srgcd.c srmath.h
cc -c srgcd.c -o srgcd.o
srtest.o: srtest.c srtest.h
cc -c srtest.c -o srtest.o
gcdtest.o: gcdtest.c srmath.h srtest.h
cc -c gcdtest.c -o gcdtest.o
# Executables
gcd: gcd.o srgcd.o
cc gcd.o srgcd.o -o gcd
gcdtest: srgcd.o gcdtest.o srtest.o
cc srgcd.o gcdtest.o srtest.o -o gcdtest
Let’s try make
$ make gcd
cc -c gcd.c -o gcd.o
cc -c srgcd.c -o srgcd.o
cc gcd.o srgcd.o -o gcd
If we don’t use tabs
$ make gcd
Makefile:13: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
Making gcdtest
$ make gcdtest
cc -c srgcd.c -o srgcd.o
cc -c gcdtest.c -o gcdtest.o
cc -c srtest.c -o srtest.o
cc srgcd.o gcdtest.o srtest.o -o gcdtest
After changing gcdtest.c
$ make gcdtest
cc -c gcdtest.c -o gcdtest.o
cc srgcd.o gcdtest.o srtest.o -o gcdtest
Basically, make follows the dependencies, asking if any of them targets are older than the dependencies. If so, it re-executes the associated instructions.
Our Makefile has lots of things that we might want to fix/change/generalize.
Question: If I just type make, with a Makefile but without an explicit
target, what should it build?
Standard targets
default, the default thing. Should appear first (or see the next
standard target).all, appears first, what your goals are. When you just type make,
make attempts to make the target of the first specific rule.check (or test), run your test programsinstall, installs your program / you may not writeclean, remove cruftdistclean, remove cruft and anything you builtdist, make a Tarball (or zip for a zipfile)Note: Using @ is a sign not to print out the command.
default:
@echo "Please specify what to make!"
Here are some samples
all: gcd srmathlib.so
check: gcdtest
./gcdtest
install: srmathlib.so
install srmathlib.so /usr/local/lib
clean:
rm -f *.o
distclean:
rm -f *.o *.so gcdtest gcd
Use these if you’re planning on writing code you share with other people.
We use clean and distclean relatively rarely.
.a vs .so vs .dylib (Mac?) vs .dll
.a libraries is in the memory space of your program. If
lots of programs use the same library, we get one copy in each program..so (and other dynamicly linked librareis) get their own
memory space. If lots of programs use the same library, we got one
copy total. (Yay! Save memory. Boo! Dangers.)When we repeat ourselves, we try to avoid doing so.
$@ the target$^ the dependencies$< the first dependency# Executables
gcd: gcd.o srgcd.o
$(CC) $(CFLAGS) $^ -o $@
gcdtest: srgcd.o gcdtest.o srtest.o
$(CC) $(CFLAGS) $^ -o $@
# Libraries
srmathlib.so: srgcd.o
$(CC) $(CFLAGS) -shared srgcd.o -o srmathlib.so
# All those awesome .o files
gcd.o: gcd.c srmath.h
$(CC) $(CFLAGS) -c $< -o $@
srgcd.o: srgcd.c srmath.h
$(CC) $(CFLAGS) -c $< -o $@
srtest.o: srtest.c srtest.h srmath.h
$(CC) $(CFLAGS) -c $< -o $@
gcdtest.o: gcdtest.c srmath.h srtest.h
$(CC) $(CFLAGS) -c $< -o $@
Use % for “Something”
E.g.,
CC = clang
CFLAGS = -g -Wall
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
Note: You get a new automatic variable: $*, which is the stem of a rule.