Makefile ialah format fail yang biasa digunakan dalam sistem Linux. Ia boleh digunakan untuk menerangkan proses penyusunan dan kebergantungan program, membolehkan pengguna menggunakan arahan make dengan mudah untuk membina dan mengurus program. Sintaks dan peraturan Makefile agak mudah, tetapi terdapat beberapa butiran dan kes khas yang perlu diberi perhatian, jika tidak, kompilasi mungkin gagal atau hasil yang tidak dijangka mungkin berlaku. Artikel ini akan memperkenalkan anda kepada beberapa ralat dan perangkap biasa dalam Linux Makefiles, dan cara mengelakkan dan menyelesaikannya, supaya anda boleh menggunakan dan menulis Makefiles dengan lebih baik di bawah Linux.
Keputusan: Nilai pembolehubah bukanlah apa yang anda tetapkan, tetapi ruang antara nilai dan aksara ulasan diperuntukkan kepada pembolehubah, menjadikan pelaksanaan bertentangan dengan kehendak anda dan tidak mudah dikesan.
Penerangan contoh adalah seperti berikut (versi 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
Sambungan 1: Malah, proses pengesahan juga membawa kepada perangkap lain, perangkap dalam pernyataan ifeq(), lihat perangkap 2
Sambungan 2: Pernyataan penugasan berubah mempunyai perangkap ini, bagaimana pula dengan pernyataan definisi makro ? dan ayat yang serupa dengan yang berikut
CFLAGS += -DTMP=1 #注释语句 INCFLAGS += -I$(APP_COMMON_SRC_DIR)/Include #注释语句 main:mian.o gcc $$@
Malah, ujian sebenar menunjukkan bahawa ini tidak akan menjejaskan nilai definisi makro "TMP" dalam fail sumber, serta nilai laluan "INCFLAGS".
Pengalaman: Melalui pengesahan di atas, anotasi akan mempengaruhi nilai pembolehubah yang ditakrifkan di dalam fail Makefile, tetapi tidak akan menjejaskan nilai selepas -D dan -I. Oleh itu, adalah disyorkan bahawa ulasan dalam Makefile tidak harus ditulis selepas pernyataan, tetapi dalam baris sebelum pernyataan, untuk mengelakkan masalah yang sama.
Penerangan contoh adalah seperti berikut (versi 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
Menurut ujian sebenar, telah ditunjukkan bahawa beberapa ruang selepas $(TmpDir) tidak mempunyai kesan, tetapi ruang selepas /Source akan memberi kesan
Pengalaman:Dalam Makefile, yang terbaik adalah memastikan ketekalan parameter, sama ada terdapat ruang, dll. Ia tidak longgar seperti pengaturcaraan dalam bahasa seperti bahasa C.
Contohnya lebih kurang seperti berikut:
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) $
Sila klik untuk memasukkan pengenalan kandungan berkaitan fail dependency .d
Malah, daripada keputusan, kita boleh membuat kesimpulan secara kasar bahawa terdapat masalah dengan fail dependency .d, kerana menulis semula mana-mana fail memerlukan penyusunan semula, iaitu fungsi yang sepatutnya diberikan oleh fail dependency .d.
陷阱:目标路径的问题,即同一文件目标的引用时要保持路径一致。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。
Atas ialah kandungan terperinci Linux Makefile Dos and Don't: Cara Mengelakkan Kesilapan dan Kesalahan Biasa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!