A brief introduction to make/makefile [linux]
- 1. What is make/makefile?
- 2. makefile
-
- 2.1 Dependencies and dependency methods
- 2.2 Simple use of make
-
-
- 2.2.1 make test
- 2.2.2 clean
-
- 2.2 make executes multiple steps at a time
- 2.3 Some modifiers
-
- 2.3.1 .PHONY (pseudo target)
- 2.3.2 @
- 2.3.3 $@ $^
1. What is make/makefile?
make/makefile can be said to be partners, both are indispensable.
Make and makefile can be said to be indispensable functions for large-scale projects
In essence
make is a command that comes with the system
makefile is a file
After using make:
The compiler will find the makefile file in the directory and execute it
It can be said that the function of the make command: It is to execute the makefile file in this directory
An error will be reported when there is no makefile in the directory.
So we are learning the functions of make/makefile, mainly focusing on the inside of makefile
2. makefile
If you want to use the make/makefile function, just create a makefile in this directory
touch makefile
Use vim editor to make modifications.
It was found that the file was completely empty, so we want to write a usable makefile. We need to understand the dependencies and dependency methods first
2.1 Dependency and dependency methods
Here is the most common makefile instruction for compiling test
Let’s see what these two lines are
Here we can see that an instruction consists of two parts:
1. Dependencies
2. Dependence method
Next, let’s look at these two parts separately:
Dependencies:
The left side can be said to be the command name.
When using it,
make test
to execute
test.cpp is the file that the test instruction depends on.
Dependency method
The dependency method can be said to be
The content of a function within a function body in a programming language.
It’s the instruction to execute
2.2 Simple use of make
After understanding the details, we can try to write two makefiles.
2.2.1 make test
This is our example above, let’s use it next.
I just wrote a test.cpp file here
Enter here
make test
You can find that it has been executed here.
It is found that there is an additional executable program and the makefile instruction has been executed.
2.2.2 clean
Similarly, we can also write a clean instruction that cleans the executable program like the destructor in C++
clean: rm -rf test
There is no file after the dependency colon, which means that this command has no dependent files
Let’s execute it here
make clean
It was found that the test executable program was deleted
2.2 make executes multiple steps at a time
When talking about this content, the execution process of language will be involved. If you don’t understand it, you can read my previous blog
Compilation process of C language program
Heretest.i,test.s,test.o
They are all generated files from previous program compilation, assembly and linking.
What will happen if you directly use make test.i here?
Isn’t this very simple?
Direct execution
g + + test.cpp -o test.i -E
It’s over.
But what happens if weexecute make test?
We will find that all instructions are executed.
Let us analyze the process here.
When executing the test in the first step, the dependency is found to be the test.o file, but the system cannot find it.
At this time, you will look for commands with test.o
At this time, the test.o command is found, but it is found that test.s is required for execution, and then the test.s file is found again
I kept searching and found test.i and I can create it.
At this time, return to the previous instruction that requires test.i and execute it
Execute and return one by one, similar to recursion
What if we just change the order and the result is the same
It was found that the results will not change because the order does not affect the execution
The system will look for executable instructions and execute them automatically. If not, it will report an error
Just like functions in C language, there is no need to pay attention to the order of reference functions, as long as they can be found by the system
2.3 Partial modifiers
Next are a few more basic modifiers
2.3.1 .PHONY (pseudo target)
When executing the makefile, if the executable file has already been generated, in order to prevent repeated meaningless execution of the instructions to generate the executable file
It will automatically determine whether the source file of the executable file has changed to determine whether to perform compilation
Example:
The first compilation is done here.
When you execute it for the second time, you will find that the system will prevent you from repeating make
How is such a high-level function achieved?
In fact, it’s just through comparing time
we can pass
stat [file name]
View file properties
access: access time
Modify the file content: modify
Make changes to file attributes: change
Note here: When the file attributes are modified, the time of the file content will generally be modified
Because the file content has a size attribute
Logically speaking, when executing instructions on a file, the access time must be changed.
But because the access changes too frequently, the file is on the disk, and multiple users have to change the access when accessing the file, causing the server to be very slow
Therefore, in the newer version, the access time can only be changed after a certain amount of operations on the file
So when the make file performs dependency operations on the source file
Convert the time of the executable program into a timestamp, and convert the modification time of the .cpp file into a timestamp
Compare to determine whether to execute the instruction
If you want to cancel the timestamp comparison here
You can add .PHONY modification (pseudo target)
However, it is not recommended to modify the generated executable file with pseudo-target
You can execute it casually here without comparing timestamps.
2.3.2 @
After we enter make
make will automatically pop up the dependent methods for executing instructions in the makefile
After adding @, you can prevent dependency methods from popping up
2.3.3 $@ $^
These two modifiers are mainly used in dependencies
These two represent the two sides of the dependency relationship.
So what exactly is it used for?
When writing dependency methods, you can use symbols instead of file names
Here you can find that the file is executed normally.