帮同事分析Makefile文件

同事想看开源项目contiki,无奈被其复杂的Makefile搞晕而找我帮忙。我大致看了一些,由于这个项目涉及到多个目标平台,结构复杂可想而知啦-_-!!!。这里用相对简单的原生平台(native)来剖析一下。

大致上有四个重要的Makefile文件:

  1. 自己的应用程序Makefile,如examples/email/Makefile:

    这个定义了最终的目标应用程序名,如email:

    CONTIKI_PROJECT = email-client
    all: $(CONTIKI_PROJECT)
    
    APPS = email
    
    CONTIKI = ../..
    include $(CONTIKI)/Makefile.include
    
  2. 根目录的Makefile.include:

    这个提供了统一的Makefile框架,提供一般的编译选项和功能,各个平台可以覆盖这些默认规则。

  3. platform/native/Makefile.native:

    这个是平台相关的硬件,如串口、led等,以及定义最终链接生成的目标文件%.$(Target)的编译规则。原生平台(native)直接在Makefile.include里定义了最终目标%.$(Target)的规则了。其他的平台要定义宏CUSTOM_RULE_LINK来进行覆盖。

  4. cpu/native/Makefile.native

    这个定义目标文件和库的编译。如果这里不是native平台,要定义自己的链接和编译规则,要预先定义几个宏覆盖系统默认的规则:

    CUSTOM_RULE_LINK=1
    CUSTOM_RULE_C_TO_OBJECTDIR_O=1
    CUSTOM_RULE_ALLOBJS_TO_TARGETLIB=1
    

    上面分别对应链接、编译和打包成库。编译和打包成库直接在这个Makefile里,最终的链接在platform//Makefile.里。

讲了这么多,来看一下最技巧性的地方。

CONTIKI_PROJECT = email-client
all: $(CONTIKI_PROJECT)

这里只指定了一个email-client,不带任何扩展名。那make如果知道依赖什么能?这里就要用到make的隐式规则了。

隐式规则

make看到email-client这个目标会采用两条隐式规则:

%:%.c
    gcc $(CFLAGS) %< -o $@

或者

# 这个会生成中间文件xxx.o,make会在完成时删除。
%:%.o
    gcc %< -o $@

%.o:%.c
    gcc $(CFLAGS) -c %< -o $@  

那如果要让make执行我预定义的依赖项:

# @ 表示占位符,如果没有则代表删除这条规则
%:%.$(TAGET)
    @

则要删除%:%.c这条隐式规则才能执行我的%:%.$(TAGET)。至于第二条隐式规则相比我的%:%.$(TAGET)要复杂,make是比较聪明的不回绕远路的。

删除%:%.c规则(不加命令项):

%:%.c

重看Makefile.include

有了上面的知识,下面就比较好理解了,最终的目标是email-client.native,链接规则是:

ifndef CUSTOM_RULE_LINK
%.$(TARGET): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
    $(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} ${filter %.a,$^} $(TARGET_LIBFILES) -o $@
endif

编译规则是:

ifndef CUSTOM_RULE_C_TO_OBJECTDIR_O
$(OBJECTDIR)/%.o: %.c
    $(CC) $(CFLAGS) -MMD -c $< -o $@
    @$(FINALIZE_DEPENDENCY)
endif

打包生产库规则:

ifndef CUSTOM_RULE_ALLOBJS_TO_TARGETLIB
contiki-$(TARGET).a: $(CONTIKI_OBJECTFILES)
    $(AR) $(AROPTS) $@ $^
endif

其他平台的类似,只是中间有很多步骤,这里不细讲。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注