红联Linux门户
Linux帮助

linux下Makefile文件的编写

发布时间:2009-07-30 17:11:04来源:红联作者:victorywylbc
开始使用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

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
文章评论

共有 16 条评论

  1. 叔梁纥 于 2012-03-25 11:04:30发表:

    butaimingbai

  2. 木瓜~ 于 2012-03-19 15:32:30发表:

    学习了

  3. yehua243 于 2011-07-17 11:37:45发表:

    luguo路过看看 还不错

  4. butterfly007 于 2011-06-23 17:41:18发表:

    不错

  5. outlaw17 于 2011-06-10 14:39:47发表:

    终于找到组织拉!

  6. ljldx316 于 2011-06-08 09:29:21发表:

    hao 0:w(5(

  7. pokemonzj2011 于 2011-01-12 22:22:27发表:

    更好的建议:

    OBJECTS := file1.o file2.o file3.o main.o
    CC := gcc
    CFLAGS := Wall
    DLIB := lpthread
    TARGET := edit

    $(TARGET) : $(OBJECTS)
    $(CC) -o $(TARGET) $(OBJECTS)

    all : %.o : %.c
    $(CC) -c $(CFLAGS) $< -o $@

    clean:
    rm -rf $(TARGET) $(OBJECTS)

    注释:
    %.o 表示所有的.o文件,即file1.o file2.o file3.o main.o
    $< 表示所有的源文件,即.c文件
    $@ 表示所有的目标文件,即.o文件

  8. ccmethod 于 2011-01-07 16:07:08发表:

    不错,可以在网上搜makefile教程,有更详细的

  9. zing840828 于 2011-01-06 15:37:47发表:

  10. mg271603433 于 2011-01-05 18:33:37发表:

    顶一个。顶一个。

  11. meycine 于 2010-11-25 15:33:08发表:

    学习中

  12. Jokey 于 2010-08-10 16:48:06发表:

    受教啦,谢谢,呵呵

  13. 少华 于 2010-04-14 09:52:36发表:

    很受教育,辛苦了!

  14. mailzhf 于 2009-07-31 15:48:07发表:

    haoduoya

  15. rubbt 于 2009-07-31 15:47:34发表:

    辛苦LZ,学习了.

  16. ineosc 于 2009-07-30 18:16:10发表:

    有深度