Makefile学习总结

make命令执行时,需要一个makefile文件,以告诉make命令需要怎么样的去编译和链接程序。

很早以前写的培训用的Makefile文档,整理好分享给大家。

本文用Linux服务器下编写C程序来讲解Makefile,主要实现两个目标:

  1. 自己能写简单的Makefile,玩转Linux编程。
  2. 看懂大神写的Makefile。

写个简单的Makefile做开场白

需要说明一下,文档目录结构是用户目录HOME下有src incl bin lib。

src:源码

incl:头文件

bin:执行码

lib:静态/动态库

这是大家最常见的Linux编程目录结构,以下代码编译都是依据这个结构。

 

 

CMake与Make最简单直接的区别_运维_weixin_42491857的博客
https://blog.csdn.net/weixin_42491857/article/details/80741060

 

 

 

Makefile代码

hello:hello.c
	gcc -I${HOME}/incl -c hello.c
	gcc -o hello hello.o
	rm -f hello.o
	mv hello ${HOME}/bin

没接触过Makefile的同学肯定能看出,这段代码不就是把编译、链接、删除、移动写成shell脚本执行吗?没错的,把第一行去掉,其他代码粘贴到shell脚本里同样可以编译成功,一点问题都没有。看来大家都学会了Makefile,本文就到这里。


开个玩笑,简单的Makefile确实可以当shell脚本执行,现在看到的同学至少学会怎么写简单的Makefile,但是只学会简单的Makefile并看不懂大神的Makefile啊。下面深入分析Makefile的其他写法。

Makefile结构说明

Makefile里主要包含了五个东西:变量定义、显式规则、隐晦规则、文件指示和注释。

1、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点像C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。

2、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。 刚才写的疑似shell脚本的Makefile全部都是显示规则。

3、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。

4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样。

5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符。

复杂一些的Makefile

根据上面的结构说明,我们对Makefile一层一层的改写,首先是隐晦规则,告诉大家其中一种用法:

.SUFFIXES: .cpp .c
.cpp.o:
	g++ ${INCL} -c $<

.c.o:
	gcc ${INCL} -c $<

这个隐晦规则其实就是告诉大家,后缀为cpp的文件怎么编译成.o,后缀为c的文件怎么编译成.o。

Makefile详细图解

到目前为止的Makefile已经有模有样了,Makefile代码双手奉上。

#隐含规则
INCL=-I${HOME}/incl

.SUFFIXES: .cpp .c
.cpp.o:
	g++ ${INCL} -c $<

.c.o:
	gcc ${INCL} -c $<

#C++编译
hellocpp:hellocpp.o
	echo "开始编译"
	g++ -o hellocpp hellocpp.o
	rm -f hellocpp.o
	mv hellocpp ${HOME}/bin
	echo "编译结束"

#C编译
hello:hello.o
	echo "开始编译"
	gcc -o hello hello.o
	rm -f hello.o
	mv hello ${HOME}/bin
	echo "编译结束"

细心的同学会发现刚才有个“$<”,如果看的有些蒙圈,那一定要了解预定义变量,下面这些是常用的预定义变量。

$*   不包含扩展名的目标文件名称。

$+   所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件。

$<   第一个依赖文件的名称。

$?   所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。

$@   目标的完整名称。

$^   所有的依赖文件,以空格分开,不包含重复的依赖文件。

$% 如果目标是归档成员,则该变量表示目标的归档成员名称。

注意前方高能,Makefile的最终展现

Makefile详细图解

实际编译结果

Makefile编译结果

看着挺乱的吧,稍微改一改,双手奉上Makefile代码。

#最后形成的Makefile
INCL=-I${HOME}/incl
BIN=$(HOME)/bin
OBJ1=hellocpp.o
OBJ2=hello.o

.SUFFIXES: .cpp .c
.cpp.o:
	g++ ${INCL} -c $<

.c.o:
	gcc ${INCL} -c $<

all: hellocpp hello

#C++编译
hellocpp:${OBJ1}
	@echo "============开始编译============"
	g++ -o $@ $?
	@rm -f ${OBJ1}
	@mv $@ ${BIN}
	@echo "============编译结束============"
	@echo ""

#C编译
hello:${OBJ2}
	@echo "============开始编译============"
	gcc -o $@ $?
	@rm -f ${OBJ2}
	@mv $@ ${BIN}
	@echo "============编译结束============"
	@echo ""

命令前加@,表示当前命令不显示,最后编译结果是这样。

Makefile编译结果

以上是Makefile的全部内容,本文完结。


分享几个Makefile的示例DEMO,

编译SOCKET服务,使用mysql数据库。

编译socket服务

Makefile代码如下

#socket服务端编译(用到mysql数据库)
INCL=-I/usr/local/mysql/include -I$(HOME)/incl
LIB=-L/usr/local/mysql/lib -lmysqlclient -lmysqld -lmysqlservices -L$(HOME)/lib -lbanktest
BINDIR=$(HOME)/bin

.SUFFIXES: .cpp .c

.cpp.o:
	g++ ${INCL} -c $<

.c.o:
	gcc $(INCL) -c $<

all: clean server

server:server.o
	@echo "============开始编译============"
	gcc -o $@ $? $(LIB)
	@mv $@ $(BINDIR)
	@echo "============编译结束============"

clean:
	@rm -f *.o

编译des md5 base64密码服务的Makefile

#编译des md5 base64密码服务
INCL=-I/usr/local/mysql/include -I$(HOME)/incl
LIB=-L/usr/local/mysql/lib -lmysqlclient -lmysqld -lmysqlservices
BINDIR=$(HOME)/bin
LIBDIR=$(HOME)/lib

.SUFFIXES: .cpp .c

.cpp.o:
	g++ ${INCL} -c $<
.c.o:
	gcc $(INCL) -c $<

all: clean des md5 base64

des:des.o main_des.o
	gcc -o $@ $? $(LIB)
	mv $@ $(BINDIR)

md5:md5.o main_md5.o
	gcc -o $@ $? $(LIB)
	mv $@ $(BINDIR)

base64test:base64.o main_base64.o
	gcc -o $@ $? $(LIB)
	mv $@ $(BINDIR)

rsa:rsa.o main_rsa.o
	gcc -o $@ $? $(LIB)
	mv $@ $(BINDIR)

libjiami.a:des.o md5.o base64.o
	ar -r $@ $?
	mv $@ $(LIBDIR)

libdestest:main_des.o
	gcc -o $@ $? $(LIB) -L$(HOME)/lib -ljiami
	mv $@ $(BINDIR)

libtest.so:des.c md5.c base64.c
	gcc -o $@ -fPIC -shared $?
	mv $@ $(LIBDIR)

libmd5test:main_md5.o
	gcc -o $@ $? $(LIB) -L$(HOME)/lib -ltest
	mv $@ $(BINDIR)

libbanktest.a:banktest.o banksql.o
	ar -r $@ $?
	mv $@ $(LIBDIR)

banktest:banktest.o banksql.o
	gcc -o $@ $? $(LIB) -L$(HOME)/lib -ltest
	mv $@ $(BINDIR)

clean:
	rm -f *.o

最后,加几点写Makefile的注意事项

1. tab分隔,不能用空格。

2. 每个makefile最好加一个all

3. 注释用“#”符号

4. 文件指示,引用其他的makefile文件

https://zhuanlan.zhihu.com/p/47390641

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

往事如yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值