多⽬录⼯程的makefile书写⽰例
关于程序的编译和链接
——————————
在此,我想多说关于程序编译的⼀些规范和⽅法,⼀般来说,⽆论是C、C++、还是pas,⾸先要把源⽂件编译成中间代码⽂件,在Windows下也就是 .obj ⽂件,UNIX下是 .o ⽂件,即 Object File,这个动作叫做编译(compile)。然后再把⼤量的Object File合成运⾏⽂件,这个动作叫作链接(link)。
编译时,编译器须要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你须要告诉编译器头⽂件的所在位置(头⽂件⾥应该仅仅是声明,⽽定义应该放在C/C++⽂件⾥),仅仅要全部的语法正确,编译器就能够编译出中间⽬标⽂件。⼀般来说,每⼀个源⽂件都应该对应于⼀个中间⽬标⽂件(O⽂件或是OBJ⽂件)。
链接时,主要是链接函数和全局变量,所以,我们能够使⽤这些中间⽬标⽂件(O⽂件或是OBJ⽂件)来链接我们的应⽤程序。链接器并⽆论函数所在的源⽂件,仅仅管函数的中间⽬标⽂件(Object File),在⼤多数时候,由于源⽂件太多,编译⽣成的中间⽬标⽂件太多,⽽在链接时须要明显地指出中间⽬标⽂件名称,这对于编译⾮常不⽅便,所以,我们要给中间⽬标⽂件打个包,在Windows下这样的包叫“库⽂件”(Library File),也就是 .lib ⽂件,在UNIX下,是Archive File,也就是 .a ⽂件。
总结⼀下,源⽂件⾸先会⽣成中间⽬标⽂件,再由中间⽬标⽂件⽣成运⾏⽂件。在编译时,编译器仅仅检测程序语法,和函数、变量是否被声明。假设函数未被声明,编译器会给出⼀个警告,但能够⽣成Object File。⽽在链接程序时,链接器会在全部的Object File中寻函数的实现,假设不到,那到就会报链接错误码(Linker Error),在VC下,这样的错误通常是:Link 2001错误,意思说是说,链接器未能到函数的实现。你须要指定函数的Object File.
make是怎样⼯作的
——————————
edit : main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o /
insert.o search.o files.o utils.o
在默认的⽅式下,也就是我们仅仅输⼊make命令。那么,
1、make会在当前⽂件夹下名字叫“Makefile”或“makefile”的⽂件。
2、假设到,它会⽂件⾥的第⼀个⽬标⽂件(target),在上⾯的样例中,他会到“edit”这个⽂件,并把这个⽂件作为终于的⽬标⽂件。
3、假设edit⽂件不存在,或是edit所依赖的后⾯的 .o ⽂件的⽂件改动时间要⽐edit这个⽂件新,那么,他就会运⾏后⾯所定义的命令来⽣成edit这个⽂件。
4、假设edit所依赖的.o⽂件也不存在,那么make会在当前⽂件⾥⽬标为.o⽂件的依赖性,假设到则再依据那⼀个规则⽣成.o⽂件。(这有点像⼀个堆栈的过程)
5、当然,你的C⽂件和H⽂件是存在的啦,于是make会⽣成 .o ⽂件,然后再⽤ .o ⽂件⽣命make的终极任务,也就是运⾏⽂件edit了。
makefile的⽂件命名
——————————
默认的情况下,make命令会在当前⽂件夹下按顺序寻⽂件名称为“GNUmakefile”、“makefile”、“Makefile”的⽂件,到了解释这个⽂件。在这三个⽂件名称中,最好使⽤“Makefile”这个⽂件名称,由于,这个⽂件名称第⼀个字符为⼤写,这样有⼀种显⽬的感觉。最好不要⽤“GNUmakefile”,这个⽂件是GNU的make识别的。有另外⼀些make仅仅对全⼩写的“makefile”⽂件名称敏感,可是基本上来说,⼤多数的make都⽀持“makefile”和“Makefile”这两种默认⽂件名称。
当然,你能够使⽤别的⽂件名称来书写Makefile,⽐⽅:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,假设要指定特定的Makefile,你能够使⽤make的“-f”和“--file”參数,如:make -f Make.Linux或make --file Make.AIX。
makefile phony________________________上⽂出⾃连接,更多详细信息点击查看_____________
本⽂介绍⼀个尝试的多⽬录⼯程的makefile⽂件书写⽰例,下图为⽬录图:
target.c为主程序,它调⽤了funcA.c和funcB.c中的函数,最终⽣成⼀个名为target.out的成果物.
最外层的Makefile
——————————
all:
#依次在下述⽬录执⾏makefile
make -C funcA
make -C funcB
make -C src
clean:
#依次在下述⽬录执⾏makefile clean
make clean -C funcA
make clean -C funcB
make clean -C src
funcA的Makefile
——————————
DIR = .
INCLUDE_DIR = -I .
LIB_DIR = ../lib
C_SRCS += $(foreach dir, $(DIR),$(wildcard $(dir)/*.c)) C_OBJS  = $(C_SRCS:%.c=release/%.o)
C_FLAGS = $(INCLUDE_DIR)
TARGET = libFuncA.a
.PHONY:all,clean
all:$(TARGET)
$(TARGET):$(C_OBJS)
ar r $@ $^
ranlib $@
cp $@ $(LIB_DIR)
rm -f $@
$(C_OBJS):release/%.o:%.c
@mkdir -p release
@mkdir -p $(dir $@)
gcc $(C_FLAGS) -c $^ -o $@
clean:
-rm -f $(C_OBJS)
-rm -f $(LIB_DIR)/$(TARGET)
funcB的Makefile
——————————
DIR = .
INCLUDE_DIR = -I .
LIB_DIR = ../lib
C_SRCS += $(foreach dir, $(DIR),$(wildcard $(dir)/*.c)) C_OBJS  = $(C_SRCS:%.c=release/%.o)
C_FLAGS = $(INCLUDE_DIR)
TARGET = libFuncB.a
.PHONY:all,clean
all:$(TARGET)
$(TARGET):$(C_OBJS)
ar r $@ $^
ranlib $@
cp $@ $(LIB_DIR)
rm -f $@
$(C_OBJS):release/%.o:%.c
@mkdir -p release
@mkdir -p $(dir $@)
gcc $(C_FLAGS) -c $^ -o $@
clean:
-rm -f $(C_OBJS)
-rm -f $(LIB_DIR)/$(TARGET)
src的Makefile
——————————
LIB_DIR = ../lib
SRC_DIR = .
INCLUDE_DIR = -I ../funcA \
-I ../funcB \
LIBS = -L $(LIB_DIR) -lFuncA -lFuncB
LOCAL_SRCS += $(foreach dir, $(SRC_DIR),$(wildcard $(dir)/*.c))
LOCAL_OBJS  = $(LOCAL_SRCS:%.c=release/%.o)
C_FLAGS = $(INCLUDE_DIR)
.PHONY:all,clean
TARGET = target.out
all:$(TARGET)
$(TARGET):$(LOCAL_OBJS)
gcc $(C_FLAGS) -o $@ $(LOCAL_OBJS) $(LIBS)
mv $@ ../
#LOCAL_OBJS中所有的o⽂件由同名的c⽂件⽣成
$(LOCAL_OBJS):release/%.o:%.c
@mkdir -p release
@mkdir -p $(dir $@)
gcc $(C_FLAGS) -c $^ -o $@
clean:
-
rm -f ../$(TARGET)
-rm -f $(LOCAL_OBJS)
⼀些符号的解释
————————————
$@、$^、$<
这三个分别表⽰:
$@          --代表⽬标⽂件(target)
$^            --代表所有的依赖⽂件(components)
$<          --代表第⼀个依赖⽂件(components中最左边的那个)。
$?          --代表⽰⽐⽬标还要新的依赖⽂件列表。以空格分隔。
$%          --仅当⽬标是函数库⽂件中,表⽰规则中的⽬标成员名。例如,如果⼀个⽬标是"foo.a(bar.o)
",那么,"$%"就是"bar.o","$@"就是"foo.a"。如果⽬标不是函数库⽂件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
静态模式
————————————
静态模式
静态模式能够更加easy地定义多⽬标的规则,能够让我们的规则变得更加的有弹性和灵活。我们还是先来看⼀下语法:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。