Detailed explanation of writing and using Makefile under Linux

Detailed explanation of writing and using Makefile under Linux

Makefile

There may be many source files in a project file, and different functions and modules are placed in different directories. Conventional compilation can no longer handle such problems efficiently, and Makefile is used to solve this problem.

Once the Makefile is written, only one make command is needed to complete all the instructions written in the Makefile file, thereby compiling the entire project file, greatly improving efficiency .

make is a command tool used to interpret the commands in Makefile.

Makefile naming and rules

File naming

Either makefile or Makefile can be used.

Makefile rules

The command rules in the Makefile are as follows:

xxx (target file): xxx (dependent file)
( tab ) command (shell command)
Among them, the target file is the file to be generated in the end (except pseudo targets), the dependent file is the file required to generate the target file, and the command is the shell command.

Note that there must be a tab indentation before the command.

For example:

#Makefile
app: ac bc #Target: Depends on gcc ac bc -o app #Note the indentation at the beginning of this line

After making the above Makefile , ac and bc in the directory will be compiled into the target file app .

How Makefiles Work

Before executing the commands in the Makefile, it will check whether the required dependency files exist.

If it exists : execute the command

If it does not exist : check other rules to see if there are other rules that generate the dependencies required by the current rule. If so, execute the commands in the rule.

For example:

#Makefile
app: ao bo
	gcc ao bo -o app
ao: ac
	gcc -c ac -o ao
bo: bc
	gcc -c bc -o bo

In the Makefile above, when the app rule is executed, it will be found that the required dependent files ao and bo do not exist in the current directory, so it will look down to see if there are other rules to generate this file. When the ao rule is found, it is found that it is the required file, so gcc -c ac -o ao is executed, and the same goes for bo.

When executing the commands in the rules, Makefile will compare the modification time of the target file and the dependent file .<br /> If the dependent file is later than the target file, that is, the dependent file has been modified after the last target generation, the target file will be regenerated.
If the dependent file is earlier than the target file modification time, that is, the dependent file has not been modified since the last target generation, the corresponding command will not be executed.
For example, if you use make twice for a Makefile, the second time it will prompt make: "app" is already up to date .

Taking advantage of this feature, we can generate dependencies and targets in stages, that is, the second Makefile above. In this way, when we only modify the ac file, make will only execute ao rules and app rules again. The bo rule will not be executed because bc has not been modified. This can greatly reduce resource waste.

Makefile variables

Although the above can reduce the duplication of compiled code, if there are 1,000 .c .h files in a project, it will waste a lot of time to write a Makefile. Therefore, we need to adopt some variables to improve efficiency.

Getting variables <br /> We use $(variable name) to use variables.

Custom variables <br /> We use variable name = variable value, such as var = hello, to customize the variables we need.
For example, the first Makefile above can be rewritten as:

#Makefile
rsc = ac bc
app: $(rsc) #Target: Depends on gcc $(rsc) -o app #Note the indentation at the beginning of this line

Predefined variables <br /> Some variables are predefined by the system and we can use them directly.
AR: The name of the archive maintenance program. The default value is ar
CC: The name of the C compiler, the default value is cc
CXX: The name of the C++ compiler, the default value is g++
$@: The full name of the target
$<: The name of the first dependency file
$^: the names of all dependent files
<br /> To make it easier to understand the following examples, let's briefly explain the pattern matching in Makefile.
In %.o:%.c , % is a wildcard character that matches a string , while two % match the same string.
For example, the second Makefile above can be rewritten as:

#Makefile
rcs = ao bo
app: $(rcs)
	$(CC) $(rcs) -o $@
%.o: %.c #The above rule will execute this rule twice $(CC) -c $< -o $@

Makefile Functions

We can see that the Makefile above is relatively simple, but it still does not solve the problem of many files in the project. The acquisition of rcs still requires us to input each file that needs to be compiled. Then, we need to use functions to write these dependent files for us.

$(wildcard PATTERN. . .)
The function of this function is to get files of a specified type in a specified directory.
The parameter PATTERN is a file of a certain type in a certain directory. Multiple directories and multiple types can be separated by spaces.
The return value is a file list of several files, with the file names separated by spaces.

For example:

$(wildcard ./*.c) returns all files with the suffix c in the current directory.

$(patsubst pattern, replacement, text)
The function of this function is to find out whether the word in text matches the pattern. If so, it is replaced with replacement.
The pattern can include wildcard characters %. If replacement also contains %, then the % in replacement will be consistent with the % in pattern.
The return value is the replaced string.

For example:

$(patsubst %.c, %.o, ac, bc) returns ao, bo.

In this way, our example above can be rewritten as:

#Makefile
rcs = $(wildcard ./*.c)
objs = (patsubst %.c, %.o, $(src))
app: $(objs)
	$(CC) $(objs) -o $@
%.o: %.c #The above rule will execute this rule twice $(CC) -c $< -o $@

Makefile clean rule

After we execute the make command, we will find that there are many files with the suffix o in the current directory, but we only need the final target file app, and the others are redundant. How should we deal with it? The clean rule will help us deal with them.

clean

We only need to add the clean rule to the end of the Makefile, and the commands in the clean rule can be executed after each compilation is completed. like:

#Makefile
rcs = $(wildcard ./*.c)
objs = (patsubst %.c, %.o, $(src))
app: $(objs)
	$(CC) $(objs) -o $@
%.o: %.c #The above rule will execute this rule twice $(CC) -c $< -o $@
clean:
	rm $(objs) -f #rm command delete -f iterative delete

However, you will find that there is an extra clean target file in the current directory. The Makefile strategy will still be used. By comparing the modification time, we often execute clean in time but still cannot clear the file. Then, we need the next operation.

We define clean as a pseudo target, i.e. .PHONY:clean, then it will not generate the target file, there will be no comparison, and it will be executed every time.

For example:

#Makefile
rcs = $(wildcard ./*.c)
objs = (patsubst %.c, %.o, $(src))
app: $(objs)
	$(CC) $(objs) -o $@
%.o: %.c #The above rule will execute this rule twice $(CC) -c $< -o $@
.PHONY: clean #Pseudo target clean:
	rm $(objs) -f #rm command delete -f iterative delete

This is the end of this article about the writing and use of Makefile under Linux. For more relevant content about Linux Makefile writing and use, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • What is Makefile in Linux? How does it work?
  • Definition and use of makefile command packages in Linux
  • Understanding of makefile under Linux

<<:  Bootstrap 3.0 learning notes button style

>>:  Detailed explanation of Vue + Axios request interface method and parameter passing method

Recommend

How to install binary MySQL on Linux and crack MySQL password

1. Make sure the system has the required libaio s...

How to insert a link in html

Each web page has an address, identified by a URL...

How to force vertical screen on mobile pages

I recently wrote a mobile page at work, which was...

vue+tp5 realizes simple login function

This article example shares the specific code of ...

Limiting the number of short-term accesses to a certain IP based on Nginx

How to set a limit on the number of visits to a c...

Detailed explanation of Mencached cache configuration based on Nginx

Introduction Memcached is a distributed caching s...

Use semantic tags to write your HTML compatible with IE6,7,8

HTML5 adds more semantic tags, such as header, fo...

The Complete Guide to Grid Layout in CSS

Grid is a two-dimensional grid layout system. Wit...

Solution to 1045 error when navicat connects to mysql

When connecting to the local database, navicat fo...

Solve the problem of ifconfig being unavailable in docker

Recently, when I was learning docker, I found tha...

Implementation of vue3.0+vant3.0 rapid project construction

Table of contents 1. Project Construction 2. Vue3...

A brief introduction to Tomcat's overall structure

Tomcat is widely known as a web container. It has...

Implementation code for installing vsftpd in Ubuntu 18.04

Install vsftpd $ sudo apt-get install vsftpd -y S...

Example of how to achieve ceiling effect using WeChat applet

Table of contents 1. Implementation 2. Problems 3...