如何编写一个优质高效的makefile

时间:2014-01-23 02:05:41

标签: c makefile

我有以下文件夹结构:

TOPDIR
|
├── a
│   ├── a.c
│   ├── a.h
│   └── a.mk
├── b
│   ├── b.c
│   ├── b.h
│   └── b.mk
├── c
│   ├── c.c
│   ├── c.h
│   └── c.mk
├── include
│   └── common.h
├── root
│    ├── main.c
│    └── root.mk
└── Makefile

每个条件

我的目标是在Makefile下编写主TOPDIR,在子文件夹中编写子文件*.mkinclude文件夹包含一些常见的定义。 root文件夹包含我的主文件(main函数位于此处)。同时,在main.c中,它会调用来自a.cb.c的函数,c.c与驱动程序相关,并将从a.c和{{1}调用}

问题

我写的子makefile就像(例如我使用一个b.c,其他的相同,只有a.mk有一点不同):

root.mk

我写了#MODULE will be modified for each sub folder MODULE = a LIB = $(MAKE_DIR)/libs/lib$(MODULE).a SRCS = $(wildcard *.c) OBJS = $(patsubst %.c, %.o, $(SRCS)) #generate lib file from obj file $(LIB): $(OBJS) @mkdir -p ../libs @$(AR) cr $@ $^ @echo " Archive $(notdir $@)" #compile obj file from source file $(OBJS): $(SRCS) @$(CC) $(CFLAGS) -c $^ @echo " CC $(OBJS)" .PHONY: clean clean: @$(RM) -f $(LIB) $(OBJS) @$(RM) -f *.expand @echo " Remove Objects: $(OBJS)" @echo " Remove Libraries: $(notdir $(LIB))" ,如:

root.mk

我写了主PROG = ../prog/DEMO SRCS = $(wildcard *.c) OBJS = $(patsubst %.c, %.o, $(SRCS)) #generate finial target file for run $(PROG): $(SRCS) @mkdir -p ../prog @$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $@ @echo " Generate Program $(notdir $(PROG)) from $^" .PHONY: clean clean: @$(RM) -f $(OBJS) $(PROG) @$(RM) -f *.expand @$(RM) -rf ../prog ../libs @echo " Remove Objects: $(OBJS)" @echo " Remove Libraries: $(notdir $(PROG))" ,如:

Makefile

问题

  1. 在主MAKE_DIR = $(PWD) ROOT_DIR := $(MAKE_DIR)/root DRV_DIR := $(MAKE_DIR)/driver INCLUDE_DIR := $(MAKE_DIR)/include DEBUG_DIR := $(MAKE_DIR)/debug INC_SRCH_PATH := INC_SRCH_PATH += -I$(ROOT_DIR) INC_SRCH_PATH += -I$(DRV_DIR) INC_SRCH_PATH += -I$(INCLUDE_DIR) INC_SRCH_PATH += -I$(DEBUG_DIR) LIB_SRCH_PATH := LIB_SRCH_PATH += -L$(MAKE_DIR)/libs CC = gcc LD = ld #problem happan here, if I change the sequence of LIB, #during the finial link, it will find some function un-referenced, #why can I put liba first? LIBS := -lc -lb -la CFLAGS := CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH) CFLAGS += -Wall -O -ggdb CFLAGS += -DDEBUG -D_REENTRANT LDFLAGS := export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH all: @$(MAKE) -C a -f a.mk @$(MAKE) -C b -f b.mk @$(MAKE) -C c -f c.mk @$(MAKE) -C root -f root.mk .PHONY: clean clean: @$(MAKE) -C debug -f debug.mk clean @$(MAKE) -C driver -f driver.mk clean @$(MAKE) -C mw -f mw.mk clean @$(MAKE) -C root -f root.mk clean 中,我定义了我将使用哪个Makefile文件,如果需要将其移至LIB以获得更好的效果?

  2. 在sub-makefile中,我没有使用root.mk生成依赖文件,如果这导致问题我无法更改-MM的序列,我在{ {1}}评论。

  3. 好像我的makefile系统无法检测到我更新了一些头文件,例如,我先编译整个代码,然后,我修改了一个头文件,当我尝试重新编译时,没有编译源代码

  4. 如果:

    lib*

    需要添加到每个子makefile中吗?

1 个答案:

答案 0 :(得分:3)

这条规则绝对是错误的:

$(OBJS): $(SRCS)
        @$(CC) $(CFLAGS) -c $^
        @echo "    CC        $(OBJS)"

目标线将扩展为:

a.o b.o c.o d.o : a.c b.c c.c d.c

那不对。这与写这个相同:

a.o : a.c b.c c.c d.c
        ...
b.o : a.c b.c c.c d.c
        ...
c.o : a.c b.c c.c d.c
        ...
d.o : a.c b.c c.c d.c
        ...

这意味着无论何时更改任何源文件,都将重建所有目标文件。你应该在这里使用模式规则:

%.o : %.c
        @$(CC) $(CFLAGS) -o $@ -c $<
        @echo "    CC        $@"

一次编译一个目标文件。

就你的问题而言,我不明白问题#1。

问题#2和#3(如果我理解正确的话)是相同的:#3(更改头文件时没有重新编译文件)的原因是你没有声明头文件的任何先决条件。 Make没有任何内置的支持,因此您必须手动执行(将a.o : a.c b.h c.h g.h添加到makefile)或者自动生成依赖项。

依赖关系生成通常会使用-MM或类似的标志,假设您的编译器支持这些标志。