Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6073714
  • 博文数量: 2759
  • 博客积分: 1021
  • 博客等级: 中士
  • 技术积分: 4091
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-11 14:14
文章分类

全部博文(2759)

文章存档

2019年(1)

2017年(84)

2016年(196)

2015年(204)

2014年(636)

2013年(1176)

2012年(463)

分类: LINUX

2014-12-15 09:16:05

原文地址:跟我一行一行写Makefile 作者:cqw_cu_

跟我一行一行写Makefile

引言

简介

想必很多读者都拜读过陈皓的《跟我一起写Makefile》一文,我也是该文的忠实读者,从中受益颇深,该文至今我读了不下五遍,现在偶尔也会翻阅一下,因为有的东西看的时候懂了,但记忆不深刻,用到的时候还是写不出来,更别谈灵活运用了。

 

该文不写Makefile理论,因为我自知以我目前的水平再写Makefile理论,只能是画虎不成反类犬。

 

全文以实例、提问的方式引导读者思考,这样能有效的突出重点,也有利于读者加深记忆,还可以延长读者的观看时间,避免打瞌睡。

参考资料

《跟我一起写Makefile-陈皓.pdf

有好心人整理了一份pdf版本,目录清晰,排版整洁,比直接拉着网页看简便快捷多了,直接到百度搜索即可下载。

工程下载

文章所有的Makefile文件及源码文件已经上传到CSDN,可0分下载,CSDN下载路径如下:

Makefile.1

实例工程netembryo中包含如下的源文件和头文件:

main.cget_info.cmulticast.crtsp.cSock.csocket.curl.csock_ntop_host.cconfig.hrtsp.hurl.hwsocket.hwsocket-internal.h

 

Makefile.1main.c get_info.cmulticast.crtsp.cSock.csocket.curl.csock_ntop_host.c编译为.o文件,然后将编译生成的.o文件链接为可执行文件main

实例

Makefile.1内容截图如下:

main: main.o Sock.o socket.o sock_ntop_host.o url.o rtsp.o multicast.o get_info.o

        gcc -g -o main main.o Sock.o socket.o sock_ntop_host.o url.o rtsp.o multicast.o get_info.o

 

main.o: main.c

 

Sock.o: Sock.c

        gcc -c -I. Sock.c

 

socket.o: socket.c

        gcc -c -I. socket.c

 

sock_ntop_host.o: sock_ntop_host.c

        gcc -c -I. sock_ntop_host.c

 

url.o: url.c

        gcc -c -I. url.c

 

rtsp.o: rtsp.c

        gcc -c -I. rtsp.c

 

multicast.o: multicast.c

        gcc -c -I. multicast.c

 

get_info.o: get_info.c

        gcc -c -I. get_info.c

 

.PHONY: clean

 

clean:

        -rm -rf main *.o

提问

问题:

1.       第一个箭头处,没有写编译命令,而是让make“自动推导”,该处make自动推导出的编译命令是什么?

2.       第二个箭头处,“.PHONY”是伪目标,伪目标的定义是什么,在Makefile中伪目标有哪些妙用?

3.       第三个箭头处,“rm”命令前面的“-”有什么作用?

4.       clean也是一个目录,为什么clean没有依赖,也不会生成目标文件clean

5.       如果把编译命令中的“-I.”选项去掉,能编译通过吗,为什么?

6.       你觉得Makefile.1哪些地方好,哪些地方不好,你会如何优化?

Makefile.2

Makefile.1目标、依赖和命令都比较清晰,对于小型工程这样写也没什么不好。如果工程文件多达几百个,这样写,整个Makefile就会显得比较臃肿,更重要的是不易修改、维护和扩展。

 

Makefile.2Makefile.1进行第一阶段的优化,引入了“变量”、“静态模式”、“自动化变量”特性,让Makefile的体积一下缩小很多。这会让刚接触Makefile的新手感觉不易读,写成这样,不是为了炫技,而是这些都是Makefile中实用的特性,是很有必要掌握的,可以对照陈皓的“跟我一起写Makefile”一起看。

实例

Makefile.2内容截图如下:

OBJS = main.o Sock.o socket.o sock_ntop_host.o url.o rtsp.o multicast.o get_info.o

 

main: $(OBJS)

        gcc -g -o main $(OBJS)

 

$(OBJS): %.o : %.c

        gcc -c -I. $<

 

.PHONY: clean

 

clean:

        -rm -rf main *.o

提问

1.       第一个箭头处,定义变量使用了“=”号,还有“:=”和“+=”号,此三种定义变量的方式有什么不同,各自适用于什么样的场景?

2.       第二个箭头处,使用了Makefile的“静态模式”,如何使用静态模式?

3.       第三个箭头处,使用了Makefile的“自动化变量”,Makefile有哪些自动化变量,各自代表什么意思?

4.       你觉得Makefile.2哪些地方好,哪些地方不好,你会如何进行优化?

Makefile.3

Makefile.2相对于Makefile.1已经简便、轻巧了很多,但还是要巧一些编译命令,就像在C语言中使用魔数一样,不易阅读,也不易修改、维护,所以一般将魔数定义为宏。

 

Makefile.3Makefile.2的基础上对Makefile.1进行第二阶段的优化,对编译命令进行优化。

实例

Makefile.3内容截图如下:

CC= gcc

CFLAGS= -g -Wall -Werror

INCLUDES= -I.

SOURCES= main.c get_info.c multicast.c rtsp.c Sock.c socket.c sock_ntop_host.c url.c

 

OBJS := $(SOURCES:.c=.o)

 

main: $(OBJS)

         $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(OBJS)

 

$(OBJS): %.o : %.c

        $(CC) -c $(CFLAGS) $(INCLUDES) $<

 

.PHONY: clean

 

clean:

        -rm -rf main *.o

提问

1.       矩形处,将编译命令定义为变量,这样有什么好处?

2.       第一个箭头处,OBJS变量的值是什么?

Makefile.4

Makefile.4Makefile.3的基础引入“模式规则”,改动非常小,但该特性十分重要且有用,在很多开源项目如ffmpeg中都可见到。

实例

Makefile.4内容截图如下:

CC= gcc

CFLAGS= -g -Wall -Werror

INCLUDES= -I.

SOURCES= main.c get_info.c multicast.c rtsp.c Sock.c socket.c sock_ntop_host.c url.c

 

OBJS := $(SOURCES:.c=.o)

 

%.o: %.c

        $(CC) -c $(CFLAGS) $(INCLUDES) $<

 

main: $(OBJS)

         $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(OBJS)

 

$(OBJS): %.o : %.c

 

.PHONY: clean

 

clean:

        -rm -rf main *.o

提问

问题:

1.       第一个箭头处,使用了Makefile中的什么规则,该规则的作用是什么?

2.       第二个箭头处,没有命令部分,该命令还是Makefile自动推导的吗,为什么?

Makefile.5

Makefile.1-Makefile.4都是在一个Makefile文件中完成的,就像写c程序一样,把全部东西都塞在一个文件中,显然不是一种好的设计。

 

Makefile.5Makefile.4的基础上将Makefile一分为二。

实例

Rules5.mak内容截图如下:

CC= gcc

CFLAGS= -g -Wall -Werror

INCLUDES= -I.

SOURCES= main.c get_info.c multicast.c rtsp.c Sock.c socket.c sock_ntop_host.c url.c

Makefile.5内容截图如下:

include ./Rules5.mak

 

OBJS := $(SOURCES:.c=.o)

 

all: $(OBJS) main

 

.PHONY: all clean

 

%.o: %.c

        $(CC) -c $(CFLAGS) $(INCLUDES) $<

 

main: $(OBJS)

         $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(OBJS)

 

$(OBJS): %.o : %.c

 

clean:

        -rm -rf main *.o

 

提问

问题:

1.       第一个箭头处,“include”的作用是什么?

2.       第二个箭头处,会生成“all”这个目标文件吗,为什么?

Makefile.6

上面的Makefile依然不够灵活,如果有时需要将源码编译为库文件,供其它部件调用接口,有时需要将其编译为二进制文件,该如何改造和优化呢?

Makefile.7

上面的Makefile存在一个很大的缺陷,就是修改了头文件,make命令无法检测到更新,不会重新编译工程,该如何改造和优化呢?

阅读(1279) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~