1. USING PREPROCESSOR DIRECTIVES FOR CONDITIONAL INCLUSION OF CODE ------------------------------------------------------------------- Before your code goes to the compiler, it gets pre-processed. This is the stage on which #include'd files are pasted into your .cc or .cpp files, #define's get resolved etc. Most (but not all) operations that the pre-processor performs resemble familiar search-and-replace of a text editor. Here is a brief summary of pre-processor commands. Preprocessor directives start with `#', like #define or #include. No object code is generated during preprocessing. Preprocessor edits the source code according to directives and passes it to the compiler. #define directive could be called in two ways: ~~~~~~~~ #define MAX 3 // all occurences of MAX in the code are replaced with `3' or #define MAX // variable MAX is "defined" in the source code. // see #ifdef, #ifndef. #include directive includes ("pastes") the entire .h file into the code ~~~~~~~~ of a .cc (or .cpp) file. The resulting source code is passed to the compiler. #ifdef directive allows conditional inclusion of portions of code ~~~~~~ into the resulting source code, like this: #define MAN // defines MAN. Note that it's not necessary to supply // a value for MAN. #ifdef MAN // now if MAN is defined only the code before #else cout << "man"; // will be included in the final code #else cout << "woman"; // if MAN is undefined only this line will be included #endif // in the final code The #else part is optional, you can just say #ifdef ... #endif . You can use the same technique for including only one of the files text.h or graphic.h, based on some value defined (or not) with #define. The question is how to define a value without changing the code. `#define MAN' line inside the code is equivalent to the directive -DMAN when you compile you code: g++ hw4.cc -DMAN -o hw4 ^ do it like this, and MAN will be defined in hw4.cc g++ hw4.cc -o hw4 ^ do it like this and MAN will be undefined in hw4.cc #ifndef .. #else .. #endif works in a similar way, but will choose the first code segment if the symbol is *not* defined. Read more on -D directive in `man g++' or `man gcc'. If you have to #include several header (.h) files which, in turn, may include other header files, there is a possibility that the contents of a header file will be pasted into the source twice (or more). The compiler will see two definitions for the same variable names and complain of "objects being re-defined". To avoid this, and paste each header file only once, the following trick is used. Let's say you may have my_header.h included several times: #ifndef __MY_HEADER_H__ #define __MY_HEADER_H__ ... ... all of you code ... #endif // end of __MY_HEADER_H__ Notice that all standard library .h files (iostream.h, math.h etc.) use this trick. 2. MAKEFILES ------------ For more details read `man make'. In makefile you list your targets (executables, object files etc.) along with commands to make them, thus saving you the typing of compiler commands all the time. For example if you have a makefile (it's name is always `makefile' or `Makefile' and to invoke commands inside it you just type `make'): hw3: hw3.c student.h g++ hw3.c -o hw3 then after you type `make' the command `g++ hw3.c -o hw3' will be executed. It acts as batch file, in a way. Important Note: Makefiles are *NOT* plaintext! You need a TAB in front of each *command*, but no TAB should precede a *target*: hw3: hw3.c student.h ##no TAB before target hw3: g++ hw3.c -o hw3 ##TAB before g++ .. to identify it as a command Another important issue about makefile is that it checks the dependencies between sources, object files, and executables. Suppose we have source files code1.cpp, code2.cpp, code3.cpp along with their header files incl1.h, incl2.h, and incl3.h. We want to generated executables prog1 and prog2 out of those sources. When we develop code, we might change some of the source files and then our executables would be out of date (as they were made using older versions of the code). `make' command checks which sources have been changed and which executables should be recompiled to keep them up to date. Dependencies go from top to bottom of a makefile. If you just type `make' only the topmost target will be made. If you type `make' followed by the name of a particular target, only this target will be made, like `make prog2', or `make code1.o'. `all' is a generic target which should be always on top. Use it when you want to generate several executables at once. # Sample Makefile. everything after `#' is a comment # all : prog1 prog2 prog1 : code1.o code2.o g++ code1.o code2.o -o prog1 prog2 : code1.o code3.o g++ code1.o code3.o -o prog2 code1.o : code1.cpp incl1.h g++ -c code1.cpp -DVERSION1 -o code1.o code2.o : code2.cpp incl2.h g++ -c code2.cpp -o code2.o code3.o : code3.cpp incl3.h g++ -c code3.cpp -o code3.o