Maison  >  Article  >  Tutoriel système  >  Linux Makefile à faire et à ne pas faire : comment éviter les erreurs et les pièges courants

Linux Makefile à faire et à ne pas faire : comment éviter les erreurs et les pièges courants

WBOY
WBOYavant
2024-02-11 12:12:12808parcourir

Makefile est un format de fichier couramment utilisé dans les systèmes Linux. Il peut être utilisé pour décrire le processus de compilation et les dépendances d'un programme, permettant aux utilisateurs d'utiliser facilement la commande make pour créer et gérer des programmes. La syntaxe et les règles de Makefile sont relativement simples, mais il y a certains détails et cas particuliers auxquels il faut prêter attention, sinon la compilation pourrait échouer ou des résultats inattendus pourraient survenir. Cet article vous présentera quelques erreurs et pièges courants dans les Makefiles Linux, et comment les éviter et les résoudre, afin que vous puissiez mieux utiliser et écrire des Makefiles sous Linux.

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


Piège 1 : Le caractère de commentaire '#' est utilisé après l'espace après l'instruction qui définit la variable

Résultat : La valeur de la variable n'est pas celle que vous lui avez attribuée, mais l'espace entre la valeur et le caractère de commentaire est attribué à la variable, ce qui rend l'exécution contre votre volonté et difficile à détecter.

La description de l'exemple est la suivante (version Makefile : 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 : En fait, le processus de vérification conduit également à un autre piège, le piège dans l'instruction ifeq(), voir piège 2
Extension 2 : L'instruction d'affectation de variable a ce piège, qu'en est-il de l'instruction de définition de macro ? et des phrases similaires à celles-ci

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

main:mian.o
    gcc $$@ 

En fait, les tests réels montrent que cela n'affectera pas la valeur de la définition de macro "TMP" dans le fichier source, ni la valeur du chemin de "INCFLAGS".

Expérience : Grâce à la vérification ci-dessus, l'annotation affectera la valeur des variables définies dans le fichier Makefile, mais n'affectera pas les valeurs après -D et -I. Par conséquent, il est recommandé que les commentaires dans le Makefile ne soient pas écrits après l'instruction, mais dans la ligne précédant l'instruction, pour éviter des problèmes similaires.


Piège 2 : N'utilisez pas arbitrairement d'espaces entre parenthèses dans l'instruction ifeq

Résultat : Le makefile traitera les espaces après les paramètres comme faisant partie des paramètres de comparaison, ce qui entraînera des résultats contraires à vos souhaits.

La description de l'exemple est la suivante (version Makefile : 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

Selon des tests réels, il est démontré que quelques espaces après $(TmpDir) n'ont aucun effet, mais les espaces après /Source auront un impact

Expérience :

Dans Makefile, il est préférable de s'assurer de la cohérence des paramètres, s'il y a des espaces, etc. Ce n'est pas aussi lâche que la programmation dans des langages comme le langage C.


Piège 3 : Pièges lors de l'utilisation de chemins dans l'environnement Mingw

Détails : Lorsqu'il est utilisé correctement et capable de générer des fichiers de dépendance .d, en théorie, la modification de n'importe quel fichier .h ou .c peut être automatiquement compilé, mais le résultat est que le fichier .h ne peut pas être compilé après la modification. fichier, c'est-à-dire qu'aucune mise à jour du fichier n'a été détectée et qu'il n'a donc pas été compilé. Après avoir examiné attentivement le contenu du Makefile, les indices ne sont pas faciles à voir. En fait, il y a un piège derrière cela qui n’est pas facile à détecter.

L'exemple est à peu près le suivant :

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) $

Veuillez cliquer pour accéder à l'introduction du contenu lié au fichier de dépendance .d

En fait, à partir des résultats, nous pouvons déduire grossièrement qu'il y a un problème avec le fichier de dépendance .d, car la réécriture de n'importe quel fichier nécessite une recompilation, qui est la fonction que le fichier de dépendance .d est censé donner.

陷阱:目标路径的问题,即同一文件目标的引用时要保持路径一致。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。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer