Makefile的编写

Makefile 的编写

 

开始使用 Linux 编程时,一个很讨厌的问题就是如何写 Makefile 文件,由于在 Linux 下不像在 Windows 下那么熟悉,有那么多好的软件(也许是对 Linux 孤陋寡闻了)。虽然象 Kylix Anjuta 这样的集成编译环境,但是 Kylix 太大太慢,用它编写 console 程序不亚于高射炮打蚊子——大材小用,而 Anjuta 又太不稳定,况且字体有那么难看。不说了,还是言归正传,看看 Makefile 该如何编写。

 

1. 简单的 GCC 语法:

如果你只有一个文件(或者只有几个文件),那么就可以不写 Makefile 文件(当然有 Makefile 更加方便),用 gcc 直接编译就行了。在这里我们只介绍几个我经常用的几个参数,第一是 “-o” ,它后面的参数表示要输出的目标文件,再一个是 “-c” ,表示仅编译( Compile ),不连接( Make ),如果没有 ”-c” 参数,那么就表示连接,如下面的几个命令:

gcc –c test.c ,表示只编译 test.c 文件,成功时输出目标文件 test.o

gcc –c test.c –o test.o ,与上一条命令完全相同

gcc –o test test.o ,将 test.o 连接成可执行的二进制文件 test

gcc –o test test.c ,将 test.c 编译并连接成可执行的二进制文件 test

gcc test.c –o test ,与上一条命令相同

gcc –c test1.c ,只编译 test1.c ,成功时输出目标文件 test1.o

gcc –c test2.c ,只编译 test2.c ,成功时输出目标文件 test2.o

gcc –o test test1.o test2.o ,将 test1.o test2.o 连接为可执行的二进制文件 test

gcc –c test test1.c test2.c ,将 test1.o test2.o 编译并连接为可执行的二进制文件 test

注:如果你想编译 cpp 文件,那么请用 g++ ,否则会有类似如下莫名其妙的错误:

cc3r3i2U.o(.eh_frame+0x12): undefined reference to `__gxx_personality_v0’......

还有一个参数是 ”-l” 参数,与之紧紧相连的是表示连接时所要的链接库,比如多线程,如果你使用了 pthread_create 函数,那么你就应该在编译语句的最后加上 ”-lpthread” ”-l” 表示连接, ”pthread” 表示要连接的库,注意他们在这里要连在一起写,还有比如你使用了光标库 curses ,那么呢就应该在后面加上 ”-lcurses” ,比如下面的写法:

gcc –o test test1.o test2.o –lpthread –lcurses

当然 gcc 的参数我感觉有几百个,不过我们平时在 x86 机器上用的就这么些,况且这里也不是 GCC 教程,所以,就此打住。

 

2. Makefile 基本语法

我这里没有 Makefile 的详细设计书,只是凭着看别人的 Makefile 文件和一些网上的参考资料,作一些简单的介绍(我自己理解的,不对的地方还请各位老大们指出,鄙人将不甚感激)

2.1 目标:

大家在看别人使用 Makefile 文件时肯定经常见到有的人常用 make all, make install, make clean 等命令,同样只有一个 Makefile 文件,那么 all install clean 参数是如何控制 Makefile 文件的运行呢(这句话有问题,但我不知道该怎么说,大家能看懂我的意思,就放我一马吧)?在这里,如果向上面的命令如果能够正确运行的话,那么在 Makefile 文件里一定有这样的几行,他们的开始一定是

all: ×××××××

       ×××××××××××

install: ××××××

       ×××××××××××

clean: ×××××××××

        ×××××××××××

当然也不尽然,因为 all install clean 我们可以用其他的变量来代替,但是着了我们就简单起见,就下定论了,各位别怪。

在上面提到的 all install clean 等就是我们所说的目标。 make all 命令,就告诉 make 我们将执行 all 所指定的目标。为了便于理解 Make 程序的流程,我们给大家看一个与 gcc 毫无关系的 Makefile 文件:

# #表示 Makefile 文件中的注释,下面是 Makefile 文件的具体内容

all:

        @echo you have typed command “make all”

clean:

        @echo you have typed command “make clean”

install:

        @ehco you have typed command “make $@

#Makefile 文件结束

注意在这里, all: clean: install: 行要顶格些,而所有的 @echo 前要加 tab 键来跳格缩进。下面是运行结果:

[root@xxx test]#cat Makefile

# #表示 Makefile 文件中的注释,下面是 Makefile 文件的具体内容

all:

        @echo you have typed command “make all”

clean:

        @echo you have typed command “make clean”

install:

        @ehco you have typed command “make $@

[root@xxx test]#make all

you have typed command “make all”

[root@xxx test]#make clean

you have typed command “make clean”

[root@xxx test]#make install

you have typed command “make install

[root@xxx test]#

不知大家注意到没有,我们在 Makefile 文件里有一个符号 $@ ,其中 $ 表示变量名,其后的要当作变量来解释, $@ Makefile 预先定义的一个变量,表示目标命令,比如在上面的文件里属于 install 目标,那么 $@ 就表示 install ,同样,如果你将 clean 目标下面的加引号的 ”make clean” 换为: ”make $@” ,那么命令 make clean 的输出与原来是一摸一样的。大家可以下来试试。

2.2 依赖

我们现在提出这样一个问题:我如何用一个 make 命令将替代所有的 make all make install make clean 命令呢?当然我们可以象刚才那样写一个 Makefile 文件:

[root@xxx test]#cat Makefile

# #表示 Makefile 文件中的注释,下面是 Makefile 文件的具体内容

all:

        @echo you have typed command “make all”

clean:

        @echo you have typed command “make clean”

install:

        @ehco you have typed command “make $@

doall:

        @echo you have typed command “make $@ l”

        @echo you have typed command “make all”

        @echo you have typed command “make clean”

       @ehco you have typed command “make install

[root@xxx test]#make doall

you have typed command “make doall

you have typed command “make all”

you have typed command “make clean”

you have typed command “make install

[root@xxx test]#

在这里, doall: 目标有 4 调语句,他们都是连在一起并都是由 tab 键开始的。当然,这样能够完成任务,但是太笨了,我们这样来写:

[root@xxx test]#cat Makefile

# #表示 Makefile 文件中的注释,下面是 Makefile 文件的具体内容

all:

        @echo you have typed command “make all”

clean:

        @echo you have typed command “make clean”

install:

        @ehco you have typed command “make $@

doall: all clean install

        @echo you have typed command “make $@ l”

[root@xxx test]#make doall

you have typed command “make all”

you have typed command “make clean”

you have typed command “make install

you have typed command “make doall

[root@xxx test]#

相信大家已经看清了 doall: 的运行方式,它先运行 all 目标,然后运行 clean 目标,然后是 install ,最后是自己本身的目标,并且每个 $@ 还是保持着各自的目标名称。

在这里,我们称 all, clean, install 为目标 doall 所依赖的目标,简称为 doall 的依赖。也就是你要执行 doall ,请先执行他们( all, clean, install ),最后在执行我的代码。

注意依赖一定是 Makefile 里面的目标,否则你非要运行,结局是注定的:

[root@xxx test]#cat Makefile

all:

        @echo you have typed command “make all”

xxx: all WAHAHA:

[root@xxx test]make xxx

you have typed command “make all”

make: *** No rule to make target ‘WAHAHA’, needed by `xxx’,  Stop .

【轻松一下】我们能否利于“相互依赖”来作弄一下 make

[root@xxx test]#cat Makefile

tar1: tar2

tar2: tar1

        @echo this line cann’t be shown on you screen!

[root@xxx test]make tar1

make: Circular tar2 <- tar1 dependency dropped.

呵呵,骗不了的

 

3 .实战:

有了上面的说明,我们就可以开始写一些弱智一些地 Makefile 文件了。比如我们有如下的文件:

tmp/

   +---- include/

   |      +---- f1.h

   |      +----f2.h

   +----f1.c

   +----f2.c

   +---main.c

其中 f1.c #include “include/f1.h” f2.c #include”include/f2.h” main.c 中又 #include”include/f1.h”, #include”include/f2.h” ,主函数在 main.c 中,要将他们联合起来编译为目标为 testmf 的文件,我们就可以按下面的方式写(当然是弱智的):

[root@xxx test]#cat Makefile

main: main.o f1.o f2.o

        gcc –o testmf main.o f1.o f2.o

f1.o: f1.c

        gcc –c –o file1.o file1.c

f2.o: f2.c

        gcc –c –o file2.o file2.c

main.o

        gcc –c –o main.o main.c

clean:

        rm –rf f1.o f2.o main.o testmf

[root@xxx test]make

gcc –c –o main.o main.c

gcc –c –o file1.o file1.c

gcc –c –o file2.o file2.c

gcc –o testmf main.o f1.o f2.o

[root@xxx test]ls

f1.c f1.o f2.c f2.o main.c main.o include/ testmf

如果你的程序没有问题的话,就应该可以执行了 ./testmf

大家可能发现问题了:对目标文件 f1.o f2.o main.o ,他们的写法是如此的类似,我们能够将他们一块写?有的,不过今天没时间了,以后再写吧。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值