Home  >  Article  >  System Tutorial  >  Linux Makefile Dos and Don’ts: How to Avoid Common Mistakes and Pitfalls

Linux Makefile Dos and Don’ts: How to Avoid Common Mistakes and Pitfalls

WBOY
WBOYforward
2024-02-11 12:12:12807browse

Makefile is a commonly used file format in Linux systems. It can be used to describe the compilation process and dependencies of a program, allowing users to easily use the make command to build and manage programs. The syntax and rules of Makefile are relatively simple, but there are some details and special cases that need to be paid attention to, otherwise the compilation may fail or unexpected results may occur. This article will introduce you to some common errors and traps in Linux Makefiles, and how to avoid and solve them, so that you can better use and write Makefiles under Linux.

Linux Makefile 的注意事项:如何避免常见的错误和陷阱


Trap 1: The ‘#’ comment character is used after the space after the statement defining the variable

Result: The value of the variable is not what you assigned it, but the space between the value and the comment character is assigned to the variable, making the execution against your will and not easy to detect.

The example description is as follows (Makefile version: GNU MAKE 3.81):

TmpDir = /Source  #此处随意定义了一个目录,
                  #为了验证此陷阱,特意在赋值语句后空几格并进行注释,

ifeq ($(TmpDir), /Source)
Result = They are equal
else
Result = They are not equal
endif

all:
    @echo $(TmpDir)|||||||
    @echo $(Result)
make之后其结果为 : 
/Source  |||||||      (注意:/Source与|之间的空格,其实是属于TmpDir变量的)
They are not equal

若把 
ifeq ($(TmpDir), /Source) 
改为
ifeq ($(TmpDir), /Source  )  
说明:/Source后面的空格需要跟定义TmpDir与注释符之间的空格数相等

如此一来,再次make,结果为:They are equal

Extension 1:In fact, the verification process also leads to another trap, the trap in the ifeq() statement, see trap 2
Extension 2: Variable assignment Statements have this trap, but what about macro definition statements? and statements similar to the following

CFLAGS  += -DTMP=1   #注释语句
INCFLAGS += -I$(APP_COMMON_SRC_DIR)/Include   #注释语句

main:mian.o
    gcc $$@ 

In fact, actual testing shows that this will not affect the value of the macro definition "TMP" in the source file, as well as the path value of "INCFLAGS".

Experience: Through the above verification, the comment character will affect the value of the variables defined inside the Makefile file, but will not affect the values ​​after -D and -I. Therefore, it is recommended that comments in the Makefile should not be written after the statement, but in the line before the statement, to avoid similar problems .


Trap 2: Do not use spaces in the parentheses of the ifeq statement

Result: The makefile will treat the spaces after the parameters as part of the parameters for comparison, causing the results to go against your wishes.

The example description is as follows (Makefile version: GNU MAKE 3.81):

TmpDir = /Source

#下方的/Source后面空了几格
ifeq ($(TmpDir), /Source )  
Result = They are equal
else
Result = They are not equal
endif

all:
    @echo $(Result)
make之后其结果为 : 
They are not equal

若把 
ifeq ($(TmpDir), /Source ) 
改为
ifeq ($(TmpDir), /Source)  

如此一来,再次make,结果为:They are equal

According to actual testing, it has been shown that the spaces after $(TmpDir) have no effect, but the spaces after /Source will have an impact.

Experience: In the Makefile, it is best to ensure the consistency of parameters, whether there are spaces, etc. It is not as loose as programming in languages ​​such as C language.


Trap 3: Traps when using paths in the mingw environment

Details: When used correctly and able to generate .d dependency files, in theory, modification of any .h or .c file can automatically compile, but the result is that the .h file cannot be compiled if the .h file is modified. The related .c file, that is, no file update was detected, so it was not compiled. After carefully looking at the contents of the Makefile, the clues cannot be easily seen. In fact, there is a trap behind this that is not easy to detect.

The example is roughly as follows:

TARGET = Temp
# abspath 函数:获取其参数中的文件或者目录的绝对路径
APP_BASE = $(abspath ../..)
DEV_BLD_DIR = $(APP_BASE)/$(TARGET)/Build

TEMP = $(APPSRC:.c=.o)
APPOBJS_TMP = $(TEMP:.S=.o)
# addprefix 函数:把 APPOBJS_TMP 中的文件一一添加前缀 $(DEV_BLD_DIR)/
APPOBJS := $(addprefix $(DEV_BLD_DIR)/,$(APPOBJS_TMP))

APPDEPS_TMP = $(APPOBJS_TMP:.o=.d)
APPDEPS := $(addprefix $(DEV_BLD_DIR)/,$(APPDEPS_TMP))

all: Tmp.bin

-include $(APPDEPS)
......
#省略了若干内容
......
# subst 函数:把$@中的 Source 替换成 Build
# 该编译的命令,在编译源文件的同时,也生成了.d 依赖文件
$(DEV_BLD_DIR)/%.o: %.c
    $(info Compiling $$@) $(CFLAGS) $(INCFLAGS) $

Please click to enter the .d dependency file related content introduction

In fact, from the results, it can be roughly inferred that there is a problem with the .d dependency file, because rewriting any file must be able to be recompiled, which is the function that the .d dependency file is supposed to give.

陷阱:目标路径的问题,即同一文件目标的引用时要保持路径一致。mingw环境下,windows路径(e.g. c:\agc.o) 和 mingw路径(/c/agc.o)都能够识别,对于make而言, c:\abc.o 和 /c/abc.o 是两个不同的目标。若要是不知道这一知识要点,很难发现 .d 文件开头 c:\ 和 /c/ 的区别。(个人疑点:同一环境,不同工程,有些生成的.d依赖文件中.o目标路径和make中引用的路径是一样的,目前也不知是什么原因,总之这个陷阱还是存在的。)

实例陷阱说明:

#以下行将导入所有的.d依赖文件的内容,即以 /c/...开头的内容
-include $(APPDEPS)
#而以下目标依赖关系中,指明目标的路径则是以 c:\...开头的路径
$(DEV_BLD_DIR)/%.o: %.c
#其结果就是导致了因路径表示的不同,而认为不是同一目标的情况出现
#使得make不能找到.o目标文件依赖的所有依赖源文件,其中包括.h头文件
#自然而然,也就不能因为.h文件的更新,而重新编译对应的.c文件来生成.o文件

解决方法:
既然知道了陷阱所在,就可以利用如下命令来解决该问题:

#通过增加sed命令,把生成的.d依赖文件中的.o目标路径改写就可以了。
$(DEV_BLD_DIR)/%.o: %.c
    $(info Compiling $$@) $(CFLAGS) $(INCFLAGS) $'s,.*\.o[ :]*,$@:,g'  $(DEV_BLD_DIR)/$*.d;\
        rm -f $(DEV_BLD_DIR)/$*.d.tmp
    @echo

通过本文,你应该对 Linux Makefile 中的一些注意事项有了一个基本的了解,知道了如何避免和解决一些常见的错误和陷阱,如变量赋值、条件判断、目标文件、伪目标、自动变量等。你也应该明白了 Makefile 的作用和优点,以及如何在 Linux 下正确地使用和编写 Makefile。我们建议你在使用 Makefile 时要遵循一些规范和习惯,如使用缩进、注释、通配符等,以提高 Makefile 的可读性和可维护性。同时,我们也提醒你在使用 Makefile 时要注意一些潜在的问题和挑战,如跨平台、并行编译、递归调用等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下编写出高效和优雅的 Makefile。

The above is the detailed content of Linux Makefile Dos and Don’ts: How to Avoid Common Mistakes and Pitfalls. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:lxlinux.net. If there is any infringement, please contact admin@php.cn delete