Wednesday, May 7, 2008

Information about make file
Typing out the gcc commands for a project gets less appealing as the project gets bigger.
The "make" utility automates the process of compiling and linking. With make, the
programmer specifies what the files are in the project and how they fit together, and then
make takes care of the appropriate compile and link steps. Make can speed up your
compiles since it is smart enough to know that if you have 10 .c files but you have only
changed one, then only that one file needs to be compiled before the link step. Make has
some complex features, but using it for simple things is pretty easy.
Running make
Go to your project directory and run make right from the shell with no arguments, or in
emacs (below) [esc]-x compile will do basically the same thing. In any case, make
looks in the current directory for a file called Makefile or makefile for its build
instructions. If there is a problem building one of the targets, the error messages are
written to standard error or the emacs compilation buffer.
Makefiles
A makefile consists of a series of variable definitions and dependency rules. A variable in
a makefile is a name defined to represent some string of text. This works much like
macro replacement in the C pre-processor. Variables are most often used to represent a
list of directories to search, options for the compiler, and names of programs to run.
Variables are not pre-declared, you just set them with '='. For example, the line :
CC = gcc
will create a variable named CC, and set its value to be gcc. The name of the variable is
case sensitive, and traditionally make variable names are in all upper case letters.
While it is possible to make up your own variable names, there are a few names that are
considered standard, and using them along with the default rules makes writing a
makefile much easier. The most important variables are: CC, CFLAGS, and LDFLAGS.
CC The name of the C compiler, this will default to cc or gcc in most
versions of make.
CFLAGS A list of options to pass on to the C compiler for all of your source
files. This is commonly used to set the include path to include nonstandard
directories (-I) or build debugging versions (-g).
LDFLAGS A list of options to pass on to the linker. This is most commonly
used to include application specific library files (-l) and set the
library search path (-L).
To refer to the value of a variable, put a dollar sign ($) followed by the name in
parenthesis or curly braces...
CFLAGS = -g -I/usr/class/cs107/include
$(CC) $(CFLAGS) -c binky.c
The first line sets the value of the variable CFLAGS to turn on debugging information and
add the directory /usr/class/cs107/include to the include file search path. The
second line uses CC variable to get the name of the compiler and the CFLAGS variable
6
to get the options for the compiler. A variable that has not been given a value has the
empty-string value.
The second major component of a makefile is the dependency/build rule. A rule tells how
to make a target based on changes to a list of certain files. The ordering of the rules does
not make any difference, except that the first rule is considered to be the default rule --
the rule that will be invoked when make is called without arguments (the most common
way).
A rule generally consists of two lines: a dependency line followed by a command line.
Here is an example rule :
binky.o : binky.c binky.h akbar.h
tab$(CC) $(CFLAGS) -c binky.c
This dependency line says that the object file binky.o must be rebuilt whenever any of
binky.c, binky.h, or akbar.h change. The target binky.o is said to depend on
these three files. Basically, an object file depends on its source file and any non-system
files that it includes. The programmer is responsible for expressing the dependencies
between the source files in the makefile. In the above example, apparently the source
code in binky.c #includes both binky.h and akbar.h-- if either of those two .h
files change, then binky.c must be re-compiled. (The make depend facility tries to
automate the authoring of the makefile, but it's beyond the scope of this document.)
The command line lists the commands that build binky.o -- invoking the C compiler
with whatever compiler options have been previously set (actually there can be multiple
command lines). Essentially, the dependency line is a trigger which says when to do
something. The command line specifies what to do.
The command lines must be indented with a tab characte -- just using spaces will not
work, even though the spaces will sortof look right in your editor. (This design is a result
of a famous moment in the early days of make when they realized that the tab format was
a terrible design, but they decided to keep it to remain backward compatible with their
user base -- on the order of 10 users at the time. There's a reason the word "backward" is
in the phrase "backward compatible". Best to not think about it.)
Because of the tab vs. space problem, make sure you are not using an editor or tool which
might substitute space characters for an actual tab. This can be a problem when using
copy/paste from some terminal programs. To check whether you have a tab character on
that line, move to the beginning of that line and try to move one character to the right. If
the cursor skips 8 positions to the right, you have a tab. If it moves space by space, then
you need to delete the spaces and retype a tab character.
For standard compilations, the command line can be omitted, and make will use a default
build rule for the source file based on its file extension, .c for C files, .f for Fortran files,
and so on. The default build rule for C files looks like...
$(CC) $(CFLAGS) -c source-file.c
It's very common to rely on the above default build rule -- most adjustments can be made
by changing the CFLAGS variable. Below is a simple but typical looking makefile. It
compiles the C source contained in the files main.c, binky.c, binky.h, akbar.c,
akbar.h, and defs.h. These files will produce intermediate files main.o,
binky.o, and akbar.o. Those files will be linked together to produce the executable
file program. Blank lines are ignored in a makefile, and the comment character is '#'.
7
## A simple makefile
CC = gcc
CFLAGS = -g -I/usr/class/cs107/include
LDFLAGS = -L/usr/class/cs107/lib -lgraph
PROG = program
HDRS = binky.h akbar.h defs.h
SRCS = main.c binky.c akbar.c
## This incantation says that the object files
## have the same name as the .c files, but with .o
OBJS = $(SRCS:.c=.o)
## This is the first rule (the default)
## Build the program from the three .o's
$(PROG) : $(OBJS)
tab$(CC) $(LDFLAGS) $(OBJS) -o $(PROG)
## Rules for the source files -- these do not have
## second build rule lines, so they will use the
## default build rule to compile X.c to make X.o
main.o : main.c binky.h akbar.h defs.h
binky.o : binky.c binky.h
akbar.o : akbar.c akbar.h defs.h
## Remove all the compilation and debugging files
clean :
tabrm -f core $(PROG) $(OBJS)
## Build tags for these sources
TAGS : $(SRCS) $(HDRS)
tabetags -t $(SRCS) $(HDRS)
The first (default) target builds the program from the three .o's. The next three targets
such as "main.o : main.c binky.h akbar.h defs.h" identify the .o's that
need to be built and which source files they depend on. These rules identify what needs to
be built, but they omit the command line. Therefore they will use the default rule which
knows how to build one .o from one .c with the same name. Finally, make
automatically knows that a X.o always depends on its source X.c, so X.c can be
omitted from the rule. So the first rule could b ewritten without main.c --
"main.o : binky.h akbar.h defs.h".
The later targets, clean and TAGS, perform other convenient operations. The clean
target is used to remove all of the object files, the executable, and a core file if you've
been debugging, so that you can perform the build process from scratch . You can make
clean if you want to recover space by removing all the compilation and debugging
output files. You also may need to make clean if you move to a system with a
different architecture from where your object libraries were originally compiled, and so
8
you need to recompile from scratch. The TAGS rule creates a tag file that most Unix
editors can use to search for symbol definitions.
Compiling in Emacs
Emacs has built-in support for the compile process. To compile your code from emacs,
type M-x compile. You will be prompted for a compile command. If you have a
makefile, just type make and hit return. The makefile will be read and the appropriate
commands executed. The emacs buffer will split at this point, and compile errors will be
brought up in the newly created buffer. In order to go to the line where a compile error
occurred, place the cursor on the line which contains the error message and hit ^c-^c.
This will jump the cursor to the line in your code where the error occurred (“cc” is the
historical name for the C compiler).

No comments: