220 likes | 350 Views
Comments of the checker (Assignment #1). Do not forget to specify your login-name! For next submission: print the id + name + login Remember to initialize local variables. An non-initialized local variable contains "junk" (no compilation error)
E N D
Comments of the checker (Assignment #1) • Do not forget to specify your login-name! • For next submission: print the id + name + login • Remember to initialize local variables. An non-initialized local variable contains "junk" (no compilation error) • You should verify the success every read and write command ! • The return value of printf can be verified using asserts • Code readability should be improved
The Makefile Utility ABC – Chapter 11, 483-489
Motivation • Small programs single file • “Not so small” programs : • Many lines of code • Multiple components • More than one programmer
Motivation – continued • Problems with a single-file program: • Long files are harder to manage(for both programmers and machines) • Every change requires long compilation • Many programmers cannot modify thesame file simultaneously
Motivation – continued • Solution : divide project to multiple files • Target:good division to components • Easy maintenance of project structure, dependencies and creation • Minimum compilation when something is changed
Project maintenance • Traditionally is done in Unix by the Makefile mechanism • A makefile is a file (script) containing : • Project structure (files, dependencies) • Instructions for files creation • The make command reads a makefile, understands the project structure and makes up the executable • Note that the Makefile mechanism is not limited to C programs
Project structure • Project structure and dependencies can be represented as a DAG (= Directed Acyclic Graph) • Example : • Program contains 3 files • main.c., sum.c, sum.h • sum.h included in both .c files • Executable should be the file sum
sum (exe) sum.o main.o main.c sum.h sum.c
makefile sum: main.o sum.o gcc –o sum main.o sum.o main.o: main.c sum.h gcc –c main.c sum.o: sum.c sum.h gcc –c sum.c Rule Rule Rule
Rule syntax Target Dependencies main.o: main.c sum.h gcc –c main.c Rule Tab!!! Action(s)
*.o: *.c dependencies • An *.o file depends (by default) on the corresponding *.c file - if NO action is specified • Example: foo.o: foo.hThe implicit action is : $(CC) -c foo.c -o foo.o ERROR: main.o won't compile when main.c is more recent!!! sum: main.o sum.o gcc –o sum main.o sum.o main.o: sum.h gcc –c main.c sum.o: sum.h gcc –c sum.c touch - updates the timestamp
Additional info on makefile rules • A Rule can have multiple targets • Useful when several targets share dependencies/actions • A Rule can have no action (only defines dependencies) • A target can appear in multiple Rules. However a target should have at most one rule with an action • A rule can have an empty set of dependencies • Example: the target clean – has an empty set of dependencies. Used to clean intermediate files.
Equivalent makefiles • We can compress identical dependencies and use built-in macros to get another (shorter) equivalent makefile : $@ = the target (automatic variable) Variable definition OBJS = main.o sum.o sum: $(OBJS) gcc –o $@ $(OBJS) %.o: %.c sum.h gcc –c $*.c Accessing a variable Evaluates to the current *.c file pattern rule
make operation • Project dependencies DAG is constructed • Target of first rule should be created • We go down the DAG to see if there is a target that should be recreated. This is required when the target file is older than one of its dependencies • In this case we recreate the target according to the action specified, on our way up the tree. Consequently, more files may need to be recreated • If something was changed, linking is performed
make operation - continued • make operation ensures minimum compilation, when the project structure is written properly • Do not write something like:prog: main.c sum1.c sum2.c gcc –o prog main.c sum1.c sum2.cwhich requires compilation of all projectwhen something is changed
Make operation - example FileLast Modified sum 10:03 main.o 09:56 sum.o 09:35 main.c 10:45 sum.c 09:14 sum.h 08:39 Which targets will be recreated?
Make operation - example • Operations performed: gcc –c main.c gcc –o sum main.o sum.o • main.o should be recompiled (main.c is newer). • Consequently, main.o is newer than sum and therefore sum should be recreated (by re-linking).
Automatic generation of dependencies • Using the precompiler • gcc -MM file.c • gcc -MM *.c
Useful gcc Options • Include: -I<path> • Define: -D<identifier> • Optimization: -O<level> Example: gcc –DDEBUG –O2 –I/usr/include example.c –o example -lm
Another makefile example COMMON_DIR = ../common C_FILES = $(COMMON_DIR)/foo.c $(COMMON_DIR)/bar.c main.c OBJ_FILES = $(patsubst %.c,%.o,$(C_FILES)) CFLAGS = -Wall -g -ansi -pedantic-errors -DNDEBUG CC = gcc INCLUDES = -I$(COMMON_DIR) modularity_mat: $(OBJ_FILES) $(CC) $(CFLAGS) $(OBJ_FILES) -lm -o $@ %.o:%.c $(CC) $(CFLAGS) $(INCLUDES) -c $*.c -o $*.o clean: -rm $(OBJ_FILES) modularity_mat depend: @echo -e '\n' >> makefile $(CC) $(INCLUDES) -MM $(C_FILES) >> makefile adding dependencies to the makefile Pattern substitution string function: $(patsubstpattern,replacement,text)
all C files under $(COMMON_DIR), except files whose names ends with main.c Another makefile example COMMON_DIR = ../common C_FILES = $(filter-out %main.c,$(wildcard $(COMMON_DIR)/*.c)) main.c OBJ_FILES = $(patsubst %.c,%.o,$(C_FILES)) CFLAGS = -Wall -g -ansi -pedantic-errors -DNDEBUG CC = gcc INCLUDES = -I$(COMMON_DIR) modularity_mat: $(OBJ_FILES) $(CC) $(CFLAGS) $(OBJ_FILES) -lm -o $@ %.o:%.c $(CC) $(CFLAGS) $(INCLUDES) -c $*.c -o $*.o clean: -rm $(OBJ_FILES) modularity_mat depend: @echo -e '\n' >> makefile $(CC) $(INCLUDES) -MM $(C_FILES) >> makefile adding dependencies to the makefile string functions: $(filter-outpattern,text)$(patsubstpattern,replacement,text)$(wildcardpattern)
Reference • Good tutorial for makefiles http://www.gnu.org/software/make/manual/make.html http://www.cs.huji.ac.il/course/2005/labc/lectures/f_make.pdf