学一点Makefile规则

-- TOC --

估计mychar驱动已经差不多了,由于有驱动,以及几个测试程序,我将他们整合在一个makefile中,故此总结一篇makefile的规则。

$ cat Makefile 
obj-m := mychar.o
PWD := $(shell pwd)
PREFIX := /home/xinlin/sources
SRC := $(PREFIX)/linux-5.14.14
CC := gcc
CFLAGS := -Wall -Wextra -I$(PREFIX)/linux-5.14.14/include


# make is make all, this is default target
.PHONY: all
all: mychar others


.PHONY: mychar
mychar:
    $(MAKE) -C $(SRC) M=$(PWD) modules


OTHERS := showcmd try_ioctl try_write eat_mem
.PHONY: others
others: $(OTHERS)

# here use built-in pattern rules to save typing
# make -pn | less
showcmd.o \
try_ioctl.o \
try_write.o \
eat_mem.o: mychar.h
#showcmd: showcmd.c mychar.h
#   $(CC) $(CFLAGS) $< -o $@
#
#try_ioctl: try_ioctl.c mychar.h
#   $(CC) $(CFLAGS) $< -o $@
#
#try_write: try_write.c mychar.h
#   $(CC) $(CFLAGS) $< -o $@
#
#eat_mem: eat_mem.c mychar.h
#   $(CC) $(CFLAGS) $< -o $@


# char @ to make command invisible
# char - to ignore command error and continue
.PHONY: clean
clean:
    rm -f *.o *.ko *.cmd *.dwo *.mod *.mod.c Module.symvers modules.order
    rm -f .m* .M*
    rm -f $(OTHERS)
#@rm -f *.o *.ko *.cmd *.dwo *.mod *.mod.c Module.symvers modules.order
#@rm -f .m* .M*
#@rm -f $(OTHERS)
#-rm  *.o *.ko *.cmd *.dwo *.mod *.mod.c Module.symvers modules.order
#-rm  .m* .M*
#-rm  $(OTHERS)

知识点:

  1. :=赋值的variable,直接在赋值的时候,展开右边的变量引用($);而=赋值,是在command script中再展开;
  2. from top to down,第一个target是default target;
  3. 通过.PHONY显示的定义phony target,有两个好处:(1)不会因为偶然出现的与phony target一样名字的文件而让phony状态失效;(2)可以加快make的执行。
  4. @用在command前,可以让command在make过程中不显示;
  5. -用在command前,如果command执行出错,比如exit不为0,make直接忽略,继续后面的执行;
  6. 没有文件对应的phony target永远会被update,一般不会把phony target作为某个target的prerequisite,这回导致target也会永远被update,但是将phony target作为其它phony target的prerequisite,是个很nice的策略;
  7. \换行;
  8. make内置了一些builtin的pattern rule,可以用make -pn abc| less查看(abc是个不存在target,在没有makefile的目录下可以不需要);上面的makefile就用到了几个这样的rule:
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
%: %.o
#  recipe to execute (built-in):
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.o: %.c
#  recipe to execute (built-in):
        $(COMPILE.c) $(OUTPUT_OPTION) $<

所以,others这个target,定义的CC和CFLAGS,都会被builtin pattern rule使用。.c会先编译成.o,然后.o再链接成bin文件。注意,.o文件增加了对mychar.h文件的依赖,因此mychar.h文件如果更新,所有.o都会被更新,然后接着更新bin文件。

make定义了一些automatic variable,每当一个rule matched,这些automatic variable都会被update,并可以在command script中使用:

$@:表示target;

$<:表示从左到右第一个prerequisite;

$^:表示全部prerequisite,去重后的;

$+:表示全部prerequisite,没去重的;

$?:表示那些比target更新的prerequisite;(newer than target)

好了,全套mychar驱动代码:https://github.com/xinlin-z/mydriver/tree/main/mychar

本文链接:https://cs.pynote.net/sf/linux/dd/202201131/

-- EOF --

-- MORE --