Prayer

在一般中寻求卓越
posts - 1256, comments - 190, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Makefile中使用隐含规则来编译程序

Posted on 2010-02-05 15:51 Prayer 阅读(662) 评论(0)  编辑 收藏 引用 所属分类: Shell
Makefile中使用隐含规则来编译程序

本示例演示一个程序的生成过程,使用的程序文件为第4章中的文件。Makefile文件和程序文件在一个文件夹中。Makefile文件如下所示:

CC     := gcc
HEAD   := getarg.h
SRC    := getarg.c writeinfo.o main.c
OBJS   := getarg.o writeinfo.o main.o
TT     := test
Files := $(wildcard ./*)
INC = .
CFLAGS  = -pipe -g -Wall -I$(INC)
LDFLAGS = -Wall -g
all:$(TT)

$(TT):$(OBJS)
@echo "+++++++ Build Standalone Programe : $@ +++++++"
$(CC) $(LDFLAGS) $(OBJS)  -o $@

libtest_d.so:getarg.o writeinfo.o
@echo "+++++++ Build Dynamic lib : $@ +++++++"
$(CC) -shared $(LDFLAGS) getarg.o writeinfo.o -o $@
test_dlib:libtest_d.so main.o
@echo "+++++++ Build Exe by Dynamic lib : $@ +++++++"
$(CC) $(LDFLAGS) main.o -L. -ltest_d -o $@
filelist:
@echo "<<<<<<< Files in this folder >>>>>>"
@file $(Files)
.PHONY : clean filelist 
%.o:%c
$(CC) $(CFLAGS) -c $<  -o $@
clean:
@echo "------- clean ------"  
rm -f *.o
rm -f $(TT)
rm -f libtest_d.so
rm -f test_dlib

在本例中,定义了CC等变量,在变量引用和使用这些变量的时候,需要用$(CC)的形式。

在Makefile和源文件所在目录中,在命令行执行make命令:

$ make
            
执行的结果如下所示:
gcc -pipe -g -Wall -I.   -c -o getarg.o getarg.c
gcc -pipe -g -Wall -I.   -c -o writeinfo.o writeinfo.c
gcc -pipe -g -Wall -I.   -c -o main.o main.c
+++++++ Build Standalone Programe : test +++++++
gcc -Wall -g getarg.o writeinfo.o main.o  -o test

在执行的过程中,默认执行all目标,由于all目标依赖于变量$(TT),$(TT)实际上是test。$(TT)依赖于$(OBJS),$(OBJS)就是getarg.o writeinfo.o main.o。因此,需要产生这三个目标文件。

上述make工作的处理过程是这样的:首先寻找三个目标文件(getarg.o,writeinfo.o和main.o)的生成规则。在所有的规则中,并没有这三个目标文件的生成规则,因此使用默认的目标%.o:%c中的规则生成这三个目标文件。这个时候会使用gcc编译生成这三个目标文件。生成完三个目标文件之后,将执行test目标,进行目标文件的连接。

事实上,上述执行过程中只是直接执行了all目标,在Makefile中还有libtest_d.so、test_dlib和filelist几个目标没有执行,而这些目标可以单独执行。

执行单独的目标filelist:

$ make filelist
            
显示的结果如下:
<<<<<<< Files in this folder >>>>>>
./getarg.c:       ASCII C program text
./getarg.h:       ASCII text
./getarg.o:       ELF 32-bit LSB relocatable, Intel
80386, version 1 (SYSV), not stripped
./main.c:        ASCII C program text
./main.o:        ELF 32-bit LSB relocatable, Intel
80386, version 1 (SYSV), not stripped
./Makefile:      ASCII make commands text
./test:          ELF 32-bit LSB executable, Intel
80386, version 1 (SYSV), for GNU/Linux 2.6.4,
dynamically linked (uses shared libs),
for GNU/Linux 2.6.4, not stripped
./writeinfo.c:        ASCII C program text
./writeinfo.h:        ASCII text
./writeinfo.o:        ELF 32-bit LSB relocatable,
Intel 80386, version 1 (SYSV), not stripped

这条目标执行的命令是使用file命令查看本文件夹下所有的文件。其中,Files := $(wildcard ./*)表示使用通配符寻找目录下的所有文件。

执行生成可执行程序test_dlib的命令:

$ make test_dlib
            
执行的结果如下所示:
+++++++ Build Dynamic lib : libtest_d.so +++++++
gcc -shared -Wall -g getarg.o writeinfo.o -o libtest_d.so
+++++++ Build Exe by Dynamic lib : test_dlib +++++++
gcc -Wall -g main.o -L. -ltest_d -o test_dlib

test_dlib目标是一个可执行程序,它本身需要连接一个动态库libtest_d.so,因此它依赖于目标libtest_d.so和main.o目标,由于main.o已经生成,这样还需要生成libtest_d.so目标。在libtest_d.so目标中,依赖的文件getarg.o和writeinfo.o都已经生成了,因此直接生成这个动态库即可。libtest_d.so生成后,再生成test_dlib可执行程序。

在以上的示例中的test和test_dlib都是可执行的程序,它们的区别在于前者包含了三个目标文件,可以直接执行,后者只包括了main.o一个目标文件,它的执行必须依赖动态库。

继续使用clean清除目标:

$ make clean
执行的结果如下所示:
------- clean ------
rm -f *.o
rm -f test
rm -f libtest_d.so
rm -f test_dlib
在清除目标之后,生成test_dlib可执行程序:
$ make test_dlib
gcc -pipe -g -Wall -I.   -c -o getarg.o getarg.c
gcc -pipe -g -Wall -I.   -c -o writeinfo.o writeinfo.c
+++++++ Build Dynamic lib : libtest_d.so +++++++
gcc -shared -Wall -g getarg.o writeinfo.o -o libtest_d.so
gcc -pipe -g -Wall -I.   -c -o main.o main.c
+++++++ Build Exe by Dynamic lib : test_dlib +++++++
gcc -Wall -g main.o -L. -ltest_d -o test_dlib

在这次执行的过程中,由于getarg.o,writeinfo.o和main.o三个目标文件还没有生成,因此在生成库libtest_d.so之前,需要先编译生成getarg.o和writeinfo.o两个目标,它们使用的是默认的规则。在libtest_d.so生成后,还需要生成main.o的过程,它也需要使用默认的规则。

知识点:通常情况下,为了加速开发,程序员自己编写的程序在无特殊要求下都可以使用隐含规则,这样还可以防止因为Makefile编写错误而导致程序运行错误。


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理