What is a Makefile? Why do we need a Makefile?
To compile a C file normally, you can just type the command:
If there are just a few more files, adding them in gcc isn’t a big deal.
However, if you have a complete project that contains thousands or even tens of thousands of files, organized into different folders, it is obviously unrealistic to type commands to compile each file one by one.
Careful students will notice that in these project directories, there is usually a file called Makefile, which either exists directly or can be generated in some way.
A Makefile is a project manager that specifies the compilation rules for the project. It dictates which files to compile first, which files to link, and so on.
A simple Makefile is indeed quite simple, but a complex Makefile can also be very complex.
Let’s write a simple Makefile below.
Assuming there is only one source file hello.c.
root@turbo:~# ls hello.c root@turbo:~#
Open the Makefile and first write the target file, which is the final binary to be generated, followed by a colon and the dependency files, which are the files needed to generate the target file.
On a new line, press the tab key and then write the compilation rule, which is the command we usually type.
hello: hello.c gcc hello.c -o hello
To execute the Makefile, simply type make, and it will compile successfully.
Next, let’s add two more files.
In the Makefile, the target file remains the same, but the dependency files and the compilation rules below need to include the two new files.
This does complicate things a bit.
There are also variables in Makefiles, and when referencing a variable, use the $ symbol. With variables, you can simply append when adding more files next time.
Target=hello Object=hello.c print.c show.c $(Target): $(Object) gcc $(Object) -o $(Target)
However, dependency files are generally not written as .c, because the final executable file is composed of assembled files, which means multiple .o files are linked together to create the executable file, so here it is generally written as .o.
Target=hello Object=hello.o print.o show.o $(Target): $(Object) gcc $(Object) -o $(Target)
So how do we generate .o files? Below, we can continue to write how to generate .o from .c, but there are implicit rules in Makefiles, so these lines can be omitted.
When running make, the process is clear: it first converts .c to .o and then combines the .o files to create the final executable file.
root@turbo:~# make cc -c -o hello.o hello.c cc -c -o print.o print.c cc -c -o show.o show.c gcc hello.o print.o show.o -o hello root@turbo:~#
