原文轉自:http://blog.sina.com.cn/s/blog_87c063060101c9yp.htmlhtml
一、在寫 多目錄下makefile的時候,碰到一個錯誤提示,讓我糾結許久,後面仍是解決了,這個錯誤不容易被發現。linux
二、錯誤提示以下:ui
Makefile:8: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.url
三、先來講一下我想幹什麼,有些什麼?spa
想幹什麼: 搭建一個Linux LCD的裸機開發環境,注意是多目錄下面的,想寫 一個比較通用的makefile。code
有什麼:父目錄①←子目錄①(build目錄)、子目錄①(code目錄)htm
子目錄①(build目錄)←Makefile make.ruleblog
子目錄①(code目錄)← 子目錄②(startup)、子目錄②(lib)、子目錄②(foo)、子目錄②(huge)ip
以下圖:開發
1.工程目錄下:
2.build 目錄下
3.code目錄下
4.code目錄下的子目錄都有2個子目錄: src目錄(存放.c文件) 、 include目錄(存放.h文件)
五、下面貼一下makefile的內容
a. build下面的make.rule:
.PHONY:all clean
CC = arm-linux-gcc
LD = arm-linux-ld
AR = arm-linux-ar
ARFLAGS = crs
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump
CFLAGS := -Wall -O2
RM = rm
RMFLAGS = -fr
export CC LD AR RM RMFLAGS ARFLAGS OBJCOPY OBJDUMP CFLAGS
SRCS = $(wildcard *.c)
ASS = $(wildcard *.S)
OBJS := $(SRCS:.c=.o)
ASMS := $(ASS:.S=.o )
DEPS := $(SRCS:.c=.dep)
ifneq ("$(EXE)","")
EXE := $(EXE)
RMS += $(EXE)
endif
ifneq ("$(LIB)","")
LIB := $(LIB)
RMS += $(LIB)
endif
ifneq ($(INCLUDE_DIRS), "")
INCLUDE_DIRS := $(strip $(INCLUDE_DIRS))
INCLUDE_DIRS := $(addprefix -I, $(INCLUDE_DIRS))
endif
ifneq ($(LINK_LIBS), "")
LINK_LIBS := $(strip $(LINK_LIBS))
LIB_ALL := $(notdir $(wildcard $(DIR_LIB)/*))
LIB_FILTERED := $(addsffix %,$(addprefix lib, $(LINK_LIBS)))
$(evel DEP_LIBS = $(filter $(LIB_FILTERED), $(LIB_ALL) ) )
DEP_LIBS := $(addprefix $(DIR_LIBS)/, $(DEP_LIBS))
LINK_LIBS := $(addprefix -l, $(LINK_LIBS))
endif
all: $(EXE) $(LIB)
$(EXE):$(OBJS) $(LIB)
$(CC) $(CFLAGS) $(INCLUDE_DIRS) -o $@ $^
$(LIB):$(ASMS) $(OBJS)
$(AR) -$(ARFLAGS) $@ $^
%.o : %.c
$(CC) $(CFLAGS) $(INCLUDE_DIRS) -o $@ -c $<</P>
%.o : %.S
$(CC) $(CFLAGS) $(INCLUDE_DIRS) -o $@ -c $<</P>
%.dep: %.c
@echo "Creating $@ ..."
@set -e;\
$(RM) $(RMFLAGS) $@.tmp ;\
$(CC) $(INCLUDE_DIRS) -E -MM $(filter %.c, $^) > $@.tmp ; \
sed 's,\(. *\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@ ; \
$(RM) $(RMFLAGS) $@.tmp
clean:
$(RM) $(RMFLAGS) *.bin *.bak *.o *.dep *.a
b. build下面的 Makefile:
.PHONY: all clean touch
ROOT = $(realpath ..)
#注意:由於 huge目錄下 是編譯 可執行文件(最終目標).因此對於 foo bar huge 這三個目錄,huge 須要放到 最後編譯。
DIRS = $(ROOT)/code/startup/src \
$(ROOT)/code/lib/src \
$(ROOT)/code/foo/src \
$(ROOT)/code/huge/src
RM = rm
RMFLAGS = -fr
RMS = $(ROOT)/build/exes $(ROOT)/build/libs
all clean:
@set -e; \
for dir in $(DIRS); \
do \
cd $$dir && $(MAKE) ROOT=$(ROOT) $@; \
done
@set -e;\
if ["$(MAKECMDGOALS)" = "clean" ]; \
then $(RM) $(RMFLAGS) $(RMS); fi
@echo ""
@echo ":-) Completed"
@echo ""
touch:
@echo "Processing ......"
@find $(ROOT) -exec touch {} \;
@echo ""
@echo ":-) Completed"
@echo ""
c.huge/src 下面的 makefile:
正確的寫法以下:
EXE = huge.bin
LIB =
INCLUDE_DIRS = $(ROOT)/code/huge/include \
$(ROOT)/code/startup/include \
$(ROOT)/code/lib/include \
$(ROOT)/code/foo/include
LINK_LIBS = startup lib foo
include $(ROOT)/build/make.rule
d. startup/src 目錄下面Makefile的寫法:
#2012-10-21
EXE =
LIB = libstartup.a
INCLUDE_DIRS = $(ROOT)/code/startup/include \
$(ROOT)/code/foo/include
LINK_LIBS =
include $(ROOT)/build/make.rule
e. foo/src 目錄下的Makefile :
#2012-10-21
EXE =
LIB = libfoo.a
INCLUDE_DIRS = $(ROOT)/code/foo/include
LINK_LIBS =
include $(ROOT)/build/make.rule
f. lib/src 目錄下的Makefile :
#2012-10-21
EXE =
LIB = liblib.a
INCLUDE_DIRS = $(ROOT)/code/lib/include
LINK_LIBS =
include $(ROOT)/build/make.rule
PS:咱們重點注意 咱們標色的 地方,其它地方不用看。
⑴
INCLUDE_DIRS = $(ROOT)/code/huge/include \
$(ROOT)/code/startup/include \
$(ROOT)/code/lib/include \
$(ROOT)/code/foo/include
PS:在 huge目錄下的 C文件 包含了其它目錄下面的頭文件時(如 foo/include 下面的 2440addr.h),
main.c(假設在 huge/src下):
#include"2440addr.h"
#include"stdio.h"
............
像這樣子的 程序,頭文件 在 "別人的目錄下面" 你想用它 就必須 用 INCLUDE_DIRS = 去選擇它的 路徑,可是 它($(ROOT)/code/lib/include ) 必須寫在 $(ROOT)/code/huge/include 的後面。
若是 將 上面改爲 下面這樣,就會出現 "文章開始的錯誤了" :
INCLUDE_DIRS =$(ROOT)/code/lib/include \
$(ROOT)/code/startup/include \
$(ROOT)/code/huge/include \
$(ROOT)/code/foo/include
錯誤提示:Makefile:8: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
同理下面也是同樣的.
⑵
INCLUDE_DIRS = $(ROOT)/code/startup/include \$(ROOT)/code/foo/include