2014-01-23 2 views
2

Я следующую структуру папок:Как написать хороший и эффективный 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 и суб-Makefile, *.mk в подпункте папке, папка include содержит некоторые общие определения. root папка содержит мой основной файл (функция, расположенная здесь). Между тем, в main.c, он будет вызывать функцию из a.c и b.c, c.c является водитель связаны, и будет вызываться из a.c и b.c

Проблема

Я написал суб-Makefile, как (я использую один 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 [email protected] $^ 
    @echo " Archive $(notdir [email protected])" 

#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 [email protected] 
    @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 как:

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 

Вопрос

  1. В главном Makefile, я определить, какие LIB файл я буду использовать, если нужно переместить его в root.mk для лучше?

  2. В суб-Makefile, я не использовал -MM для создания файла зависит, если это вызывает проблемы, я не могу изменить последовательность моих lib*, который я также описанный в Makefile комментарии.

  3. Кажется, моя система makefile НЕ обнаруживает, что я обновляю какой-либо файл head, например, я сначала скомпилировал весь код, а затем я модифицировал один файл head, когда пытаюсь перекомпилировать, ни один источник не скомпилирован

если:

#Automatic dependency magic: 
%.d: src/%.c 
    $(CC) -MM [email protected] $< 

-include (MYPROG_OBJECTS:%.o=%.d) 

нужно добавить в каждый суб-Makefile?

+1

Всегда стоит читать, когда новый в Makefile. [Recursive make считают вредным] (http://aegis.sourceforge.net/auug97.pdf) – RedX

ответ

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 [email protected] -c $< 
     @echo " CC  [email protected]" 

для компиляции объектных файлов по одному.

Что касается ваших вопросов, я не понимаю вопроса № 1.

Вопросы № 2 и № 3 (если я правильно понимаю) - это одно и то же: причина №3 (файлы не перекомпилированы при изменении файла заголовка) заключается в том, что вы не объявляете никаких предварительных условий в файлах заголовков , Make не имеет встроенной поддержки для этого, поэтому вам либо нужно сделать это вручную (добавьте a.o : a.c b.h c.h g.h в свои файлы make-файлов), либо автоматически создайте зависимости.

Генерация зависимости обычно будет использовать -MM или аналогичные флаги, предполагая, что ваш компилятор поддерживает эти флаги.

+0

, если я использую '% o:% c', мне нужно определить' $ (OBJS) 'и' $ (SRCS) ' ? –

+0

Между тем, как написать 'lib' создание файлов? используйте '% a:% o'? –

+0

Вам нужно 'OBJS', потому что вам нужно, чтобы' $ (LIB) 'зависел от них. Вам нужно 'SRCS', чтобы вы могли вычислить' OBJS'. Так да. Для библиотек вы можете просто написать явное правило. Правило шаблона, которое вы предлагаете, будет работать не по большей части, поскольку оно говорит: «Создайте файл' .a' из _one_ '.o' файла», а не как библиотеки. Вы можете сделать это с помощью шаблонов, но поскольку вы, как правило, только создаете одну библиотеку в make-файле, в любом случае, это обычно не стоит. – MadScientist

Смежные вопросы