Plab Tirgul 3 Makefiles Libraries Debugging and Common

Plab – Tirgul 3 Makefiles, Libraries, Debugging and Common Bugs

Compilation & linkage Linkage: prog 1 g++ read. o main. o list. o –o prog 1. o . o read. o main. o list. o . c . h Compilation: g++ -c read. c main. c list. c . h read. c read. h main. c list. h list. c

Compilation & linkage • If only one file is modified, will we have to recompile all over again? prog 1 . o . o read. o main. o list. o . c . h • No. The Makefile uses the dependencies graph . c . h read. c read. h main. c list. h list. c

Makefile • Aim: Build only out-of-date files (use timestamps) • Makefile contains: – List of dependecies (no cycles) – “Recovery” scenario when any file is modified main. o: main. c list. h read. h g++ -c main. c Note, the tab here is essential! • In words, if any of the files {main. c, list. h, read. h} was modified after main. o, the command “g++ -c main. c” will be performed

Compilation & linkage • If read. h is modified, what should be done? prog 1 • We have to recreate only a subset of the files!. c . o . o read. o main. o list. o . c . h read. c read. h main. c list. h list. c

Compilation & linkage Makefile example: prog 1: read. o main. o list. o g++ main. o read. o list. o –o prog 1 main. o: main. c read. h list. h g++ -c main. c read. o: read. c read. h g++ -c read. c . o . o read. o main. o list. o . c . h list. o: list. c list. h g++ -c list. c Running make, e. g: make prog 1 make main. o . c . h read. c read. h main. c list. h list. c

Makefiles: macros • Macros are similar to variables – Upper case by convention • Example: OBJECTS = read. o list. o main. o prog 1: ${OBJECTS} g++ ${OBJECTS} -o prog 1

Makefiles: Explicit/implicit rules • We saw “explicit rules” so far, e. g: list. o: list. c list. h g++ -c list. c • Implicit rules (many kinds): – Example, creation by suffices. Create “. o” files from “. c” files . c. o: $*. c g++ -c –o $@ $< $* - the match without the suffix (e. g. list) $@ - file for which the match was made (e. g. list. o) $< - the matched dependency (e. g. list. c)

Makefiles: Explicit/implicit rules • One more example for implicit rule: . java. class: $*. javac $< Result: For every “. java” file that was modified, a new “. class” file will be created. • When no explicit rule defined, an implicit rule will be used. – not always sufficient (e. g. doesn’t check. h files update)

Libraries

Libraries • Library is a collection of functions, written and compiled by someone else, that you may want to use • Examples: – C’s standard libraries – Math library – Graphic libraries • Libraries may be composed of many different object files

Libraries 2 kinds of libraries: • Static libraries: – linked with your executable at compilation time – standard unix suffix: . a • Shared libraries: – loaded by the executable at run-time – standard unix suffix: . so

Static libraries Using the static library libdata. a: g++ -o prog object 1. o object 2. o –ldata Creating the library data. a (2 commands): ar rcu libdata. a data. o stack. o list. o ranlib libdata. a • ar is like tar – archive of object files • ranlib builds a symbol table for the library – to be used by the linker

static vs. shared Static libraries pros: • Independent of the presence/location of the libraries • Less linking overhead on run-time Shared libraries pros: • Smaller executables • No need to re-compile executable when libraries are changed • The same executable can run with different libraries • Dynamic Library Loading (dll) possible

Libraries in makefile libdata. a: ${LIBOBJECTS} ar rcu libdata. a ${LIBOBJECTS} ranlib libdata. a OBJECTS = foo. o bar. o CC = g++ prog: ${OBJECTS} libdata. a ${CC} ${OBJECTS} –ldata –o prog

Debugging 101 1. 2. 3. 4. “Define” the bug --- reproduce it Divide & Conquer Use tools: debugger & more Don’t panic --- think!

Define the bug Spend the time to find out • What is wrong? • Minimal settings that lead to the error? Reproduce the wrong behavior! • Preferably on a small example

Divide & Conquer Consider possible points of failure – check each one of them separately

Use Debugger • Allow to monitor run time behavior • Check where the program crashes • Put breakpoints on specific events • Trace execution of the program

Debugger can save a lot of time • Find why the program crash • Understand the context (call tree, value of variables, etc. ) But… • Don’t be trapped into using debuggers all the time

Other tools • • Intermediate printouts self-checking code asserts Memory allocation & leaks (Lecture)

Don’t Panic There a sensible explanation to the bug – Always! – Don’t rush to blame the compiler/OS – Don’t attribute bugs to mysterious forces Do not try random changes to see if they resolve the program – This will only introduce more bugs!

Some very common bugs (memory/pointers related)

bug 1 (1) (2) (3) (4) struct Student { int id; char * name; }; (5) Student * stud = (Student *) malloc( sizeof(Student) ); stud->id = 123456; stud->name = (char *) malloc(100*sizeof(char)); … Memory leak!!! if (stud != NULL) { “name” is not free(stud); } (6) (7) (8)

bug 2 1) void my. Func() { 2) int * x = random. Num(); 3) int result = *x; //unexpected ! 4) *x = 17; //accessing unallocated space! 5) } 6) 7) int * random. Num() { 8) int j= srand( time(0) ); 9) return &j; 10) } u Never return a pointer of a stack-variable !

bug 3 1) void my. Func(char * input) { 2) char * name = NULL; 3) if (input != NULL ) { 4) name = (char*)malloc(MAX_SIZE); 5) strcpy(name, input); 6) } 7) … 8) free( name ); 9) } u Always use: if (output != NULL ) { free(output); }

bug 4 1) void my. Func(char * input) { 2) char * name; 3) if (input != NULL ) { 4) name = (char*)malloc(MAX_SIZE); 5) strcpy(output, input); 6) } 7) … 8) if ( name != NULL ) { 9) free( name ); 10) } 11) } u Always initialize pointers to NULL !
- Slides: 27