---
date: 2024-04-18
---

# Writing Makefile for C++ Projects

## Setting variables
Let's start by setting some basic variables:

```makefile
# The program name:
NAME = program

# The compiler
CXX = c++
```

> [!notes] Considerations
> > **Note:**
> The variable `CXX` is used to specify the C++ compiler. The command `c++` is analogous to using `cc` for compiling C programs. This is similar to how `g++`/`gcc` are used for GNU Compilers, and `clang`/`clang++` for Clang compilers.

## Flags
Here, we are setting the compilation flags used in École 42's C++ modules.

More specifically:
- `-Wall`: Enable all compiler's warning messages
- `-Wextra`: Enable extra warning messages that are not turned on by `-Wall`
- `-Werror`: Turn all warning messages into errors
- `-std=c++98`: Specify the C++ version to conform

```makefile
CXXFLAGS = -Wall -Wextra -Werror -std=c++98
```

## Specifying the source files
In the `SRCS` variable we can specify all the `.cpp` files used in the project. These are the files that are going to be compiled into object files (`.o`) and then combined into an executable file.

```makefile
SRCS = main.cpp
OBJS = $(SRCS:.cpp=.o)
INCLUDES = main.hpp
```

> [!notes] Notes on OBJS
> The `OBJS` variable is a special computed variable that takes all the values from the `SRCS` variable that has the `.cpp` extension and turns into a `.o` file.

## Defining some basic rules
When writing a Makefile we usually define 4 basic rules. Those are:

- `all`: Compile the program
- `clean`: Clean all object files
- `fclean`: Clean all object files + the executable file
- `re`: Clean everything that was generated and generate everything again (`fclean` + `all`)

```makefile
all: $(NAME)

$(NAME): $(OBJS)
	$(CXX) $(CXXFLAGS) $(OBJS) -o $(NAME)

clean:
	$(RM) $(OBJS)

fclean: clean
	$(RM) $(NAME)


re: fclean all
```

Let's analyze each line here.

### all
To compile the program we just have to run `make all` but as `all` is the first rule that is getting specified, simply running `make` will execute `make all`.

```makefile
all: $(NAME)
```

As we can see here, `all` depends on the creation of `$(NAME)` which is the program name, in other words the executable file. At this point, we don't have the executable file yet, so `make` searches for a rule that creates `$(NAME)`:

```makefile
$(NAME): $(OBJS)
	$(CXX) $(CXXFLAGS) $(OBJS) -o $(NAME)
```

The creation of `$(NAME)` depends on the creation of all object files on this project so they are created. After the creation of `$(OBJS)` we finally can run `$(CXX)` (the compiler) specifying `$(CXXFLAGS)` (our compilation flags) passing all the object files to compile and naming the final product to `$(NAME)`.

To better illustrate this imagine you have 2 C++ files:

```sh
main.cpp
other.cpp
```

We want to name our executable file as `program`:

```makefile
c++ -Wall -Wextra -Werror -std=c++98 main.o other.o -o program
```

This is the actual command that gets executed.

### Creating object files

This is the rule used to create object files. It basically says: For any C++ file, generate an object file. It also depends on the `INCLUDES` so if any header file changes, all object files are going to get regenerated. Then it compiles each `.cpp` file (represented by the automatic variable `$<` here) to an object file (with the `-c` flag) and outputs a file with the same name but with the `.o` extension. Here `$@` represents each `.o` file:

```makefile
%.o: %.cpp $(INCLUDES)
	$(CXX) $(CXXFLAGS) -c $< -o $@
```

### Implementing clean

To implement `clean`, `fclean` and `re` is really simple.

`clean` just removes all object files so:
```makefile
clean:
	$(RM) $(OBJS)
```

`fclean` calls clean to remove all object files and in addition, also removes the executable file:
```makefile
fclean: clean
	$(RM) $(NAME)
```

`re` runs `fclean` and `all`:
```makefile
re: fclean all
```

### .PHONY?
`.PHONY` is used to indicate that a target is not a real file but a command or routine to be executed. For example, running `make clean` executes the `clean` routine, even though there is no file named `clean`.

```makefile
.PHONY: all clean fclean re
```

This sums up the creation of a basic Makefile for some basic C++ projects.
