|
本帖最后由 QianFan 于 2016-3-18 17:06 编辑 , h0 `5 _- h% t# @3 I 回忆我们在windows环境下使用IDE进行开发,只要一股脑的将多有的源文件添加到工程中,点一个按钮,IDE就会为我们生成可执行文件。但是期间发生了什么?我们无从得知。IDE让我们编程简单的同时,也让我们变得更加傻瓜。 ; Z# c' l& j; _9 `5 b. i8 m 在linux下编程,最常用的莫过于gcc了。比如我们编译main.c生成main.exe(在linux下,叫做main.out)或许更好些。只需要在控制台下敲下: qianfan@Ubuntu $ gcc -Wall main.c -o main.out -Wall是允许提示所有的警告。更多参数解释请参考http://gcc.gnu.org/onlinedocs/gcc/Option-Index.html 。这仅仅是编译一个文件。如果是想编译多个文件呢?比如foo.c和main.c构成一个工程,我们可以这样:( `2 r: D: Q( T# j8 s: D2 W qianfan@Ubuntu $ gcc -Wall main.c foo.c -o main.out 9 `; Y E+ H/ } G' J, z! M3 M 可是问题来了。如果你的整个工程中有成百上千个源文件。如果其中任意一个文件发生了变化,在生成一个可执行文件的时候,不管其余的文件是不是已经变化了,都需要将每一个C文件重新编译,最后在一次链接。这无疑浪费了大量的时间。人们想到了一个方法,将每一个源文件单独编译,生成*.o文件。只要源文件没有发生变化,链接的时候就使用之前的*.o文件。这样就减去了编译的时间了。生成*.o文件很简单。只要在编译的时候加上-c就好了。
人总是比较懒的。不情愿在控制台中敲击一千次来编译一千个源文件,他们索性发明了一个叫Makefile的东西。Makefile是一个文件的名字,类似与我们使用IDE创建的工程。Makefile中包含了使用什么命令,参数编译程序,或者进行其他的处理。举一个简单的例子。比如在~/debug/foo下有一个文件叫做Makefile。里面的内容是这样的:([TAB]是你用键盘按一下TAB键。由于显示空格,所以我这里使用TAB来代替他). all:5 F! `) Y+ k9 {0 L/ a [TAB] echo Hello [TAB] echo world! 使用Makefile很简单,只要在控制台进入Makefile的目录,输入make all命令回车即可。
echo Hello; @6 o) P8 h# y0 B* b( ~$ ^ Hello echo world!+ s2 b P7 o$ ^5 O _ world! Makefile总会将他的命令和结果一同输出。如果你不想看到实际执行的命令,你可以在每行命令的前面加上@符号。这样命令就不会输出了。" u& x$ i& S. {+ `6 E: B+ D all: [tab] @echo Hello, J: O, |) _( ~4 t l4 i [tab] @echo world! ; x# \- Q+ ^" z; q5 E 上面的all叫做工作目标,与all在同一行的叫做依赖条件(如果没有依赖条件可以为空)。all下面的以TAB开头的若干行叫做执行命令。一个Makefile中可以有多个工作目标。如果你想执行Makefile中的特定的工作目标,可以在make后面加上工作目标的名字。像make all这样。如果你的make后面没有工作目标的名字。那么make会默认执行他在Makefile中找到的第一个工作目标。上面的make all其实等同于make。 , M$ q0 a" h/ m R# e9 r- m2 E" l: j --------------[我是分割线]---------------- z% c( f5 E! C$ Q# L2 g% I: l3 |4 \ 来看一个实际的例子。在~/debug/foo下有foo.c和main.c两个文件。两个文件共同链接成一个可执行文件。来为他写一个Makefile。$ {) [' U) h5 B9 p: v% w; X OBJS = foo.o main.o* g$ v1 ~" |0 a1 p0 Z DEFS = -DUSE_STDPERIPH_DRIVER CFLAGS = -Wall -g ) {5 h6 A+ H- x 0 A2 X8 F" n9 ? all: main.out/ ?7 p1 q) ?6 ~2 A' [- H clean: [tab] @rm -f $(OBJS) main.out2 ~" l; x5 J8 S 5 k! t: @. ]6 x: d5 Y, }8 c main.out: $(OBJS)% s1 l% u/ p! R4 f3 y1 g) I [tab]gcc $^ -o $@# T: P7 l0 A# z4 u8 }& h# r %.o:%.c [tab]gcc $(DEFS) $(CFLAGS) -c $< -o $@ 5 o6 V6 k# `4 {3 U# d: b- h1 x main.o foo.o : foo.h* v2 D$ d% `+ H+ n8 _9 F 在上面的例子中,
在上面的例子中,条件是foo.c main.c Makefile这三个文件在同一个文件夹中。但是如果不在呢?这样Makefile就找不到main.c foo.c了。比如这样的情况:4 J& R! L- j% w' y; |6 R2 i | inc { foo.h ~/debug/foo/ | Makefile , k5 ]( h! _) J* h/ k | src {foo.c main.c* { k* P' j/ ^1 u 这样的情况下,为了能够让Makefile找到源文件和头文件,需要在Makefile中添加这么两行:( v3 ]. t8 T+ b0 E; d7 Z vpath %.c ./src! X- A6 y) @! ~% G* o vpath %.h ./inc) A6 y/ q8 q( |- {" { 当然,添加vpath %.h ./inc只是为了让make找到foo.h。为了让gcc找到foo.h,不要忘记添加头文件路径(使用-I./inc添加)。 v/ u( v+ e4 F- p , \+ K8 E4 s8 H/ k& ?) |4 w/ \7 K2 ` 4 i* o) o! O( N7 O$ n4 g8 _ 关于Makefile就简单的介绍这么多。更多的Makefile的知识请尽情Google。或者参考书籍(GNU make项目管理)。/ n8 j. r& v+ g/ d# f4 ] 附件1:GNU make的中文手册。仅供参考。 附件2:GNU make项目管理。$ C. Z( `$ R4 a9 i 附件3: 跟我一起写Makefile 合集地址:https://www.stmcu.org.cn/module/forum/thread-603753-1-1.html |
微信公众号
手机版
https://www.stmcu.org.cn/module/forum/thread-603753-1-1.html
https://www.stmcu.org.cn/module/forum/thread-603753-1-1.html
之前也在linux下开发过?