.cpp - source file

.h - header file

.o - object file

prog - executable file/taget file

C++ build process: different CPU will create different assmbly code; object code is binary mathine language

Key word: extern

eg,extern int b;

This is an non-local decorator, compiler goes to other soure files to search the variable b.

How to do modularization for different cases?

Regular case

quote example between `A`, `B` and `main.cpp`

Header guard

#include "headerfile" can’t be duplicated in any two related files.

Solution:

In c.h file, define

1
2
3
4
#ifdef C_H
#define C_H
......
#endif

No matter which file defines this header file, if duplicated then just ignore instead of error.

my12

Circular dependencies

my13

Solution: pre-prototype, using For decoration, define class F in E.h and define class E in f.h. Then the compiler knows class F wil be defined later in F.h and class E will be defined later in E.h.

Watch out:

  • Never place using namespace in header file, which is only used in source code(.cpp).
  • never palce using namespace before #include.

Difference bettween #include "•" and #include <•>

  • #include "•": indicates a path is provided to locate the header file.
  • #include <•>: indicates that the header file is located in the default library locations defined in the enviromental variables, in IDE settings or operation settings.

Compile methods

simple struct of compile files

compile linux command: `g++ -o prog main.cpp A.cpp`, then create an executable file `prog.o`, run it `/prog.o`

more complicated: makefile

make is a Linux command
Example of a makefile: first row is which files link to the target direclty, seconde row is the Linux command. `g++` is compiler, `-g` is to start debug mode, `-Wall` is to show all warnings during compile, following files are to linke in order, `-o` is output, last file is the name of target to execute later.

Some options:

  • -g - turn on debugging (so GDB gives more friendly output)
  • -Wall - turns on most warnings
  • -O or -O2 - turn on optimizations
  • -o - name of the output file
  • -c - output an object file (.o)
  • -I - specify an include directory
  • -L - specify a lib directory
  • -l - link with library lib.a

Simplify makefile

  • remove abvious dependency
  • only keep one line of build rule, other same build rules are redundant
  • omit target name which is duplicated

The cleanest version is:
simplest version

Advanced version

Build compile rule with self-define variables

Caution: be careful TAB, space is not necessary, which is just for better formatting.
For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CXX = g++ // CXX is self-defined variable, and g++ is the value. This line is to define the compiler tool
CXXFLAGS = -g -Wall // specify flags
OBJECTS = main.o A.o B.o // spcify object files in order
EXEC = prog // specify the name of executable file

// ${} is the format to replace content by variables
${EXEC} : ${OBJECT}
${CXX} ${CXXFLAGS} ${OBJECTS} -o ${EXEC} // build the compile rule

main.o : A.h
A.o : B.h
B.o : A.h

clean : // when you want to make change about the dependency, you have to recompile, then you should delete the objects and target first, so this line is always added at the end of makefile
rm -rf ${OBJECTS} ${EXEC}

If we want to make change to the content of building rule, just change the value of the variables instead of changing rules, because the building rule is generally provided in large project by company

Evolutionary version

Adding auto dependency

1
2
3
4
5
6
7
8
9
10
11
12
13
CXX = g++
CXXFLAGS = -g -Wall -MMD // MMD builds dependency list in .d file
OBJECTS = main.o A.o B.o
DEPENDS = ${OBJECTS:.o=.d} // subtitute .o with .d for dependency files, .d file is autogenerated from .o file by compiler. Compiler is smart, it figures out the dependency.
EXEC = prog

${EXEC} : ${OBJECTS}
${CXX} ${CXXFLAGS} ${OBJECTS} -o ${EXEC}

clean:
rm -rf {DEPENDS} {OBJECTS} {EXEC}

-include ${DEPENDS} // read .d files for returning autogenerated dependencies

Run command

make - compile whole project by makefile, which refers to default implementation in Linux.

gmake - compile whole project by makefile, which refers to Gun make in Unix.

make clean - execute clean line of makefile.

Reference material:
Book: Thinking in C++, Volume 1, 2nd Edition, Bruce Eckel.
Lectures: University of Waterloo, CS 247 (Software Abstraction and Specificati), 2020 spring term, professor Scott Chen.