4、make工具使用(makefile) - 零基础 到 通用makefile,看这一篇就够了!

四、make工具使用(makefile)

1、Makefile

人们通常利用 make 工具来自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。

make 工具通过一个称为 makefile 的文件来完成并自动维护编译工作。makefile 需要按照某种语法进行编写,其中说明了如何编译各个源文件并连接生成可执行文件,并定义了源文件之间的依赖关系。当修改了其中某个源文件时,如果其他源文件依赖于该文件,则也要重新编译所有依赖该文件的源文件。 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

2、Makefile基本规则

taget... : dependencies...

	command

	...
  • target(目标): 程序产生的文件,如可执行文件目标文件;目标也可以是要执行的动作,如 " clean"。

  • dependencies(依赖):是用来产生目标的输入文件,一个目标通常依赖于多个文件。

  • command(命令):是make执行的动作,一个可以有多个命令,每个占一行。注意:每个命令行的起始字符必须为TAB字符!

如果dependencies中有一个或多个文件更新的话,command就要执行,这就是Makefile最核心的内容

3、最简单的Makefile例子

# 源文件:main.c add.c add.h sub.c sub.h

main:main.o add.o sub.o
	gcc main.o add.o sub.o -o main
main.o:main.c add.h sub.h
	gcc -c main.c -o main.o
add.o:add.c add.h
	gcc -c add.c -o add.o
sub.o:sub.c sub.h
	gcc -c sub.c -o sub.o
clean:
	rm -f main main.o add.o sub.o

4、make是如何工作的

1、make会在当前目录下找名字叫“Makefile”或“makefile”

2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“main”这个文件,并把这个文件作为最终的目标文件。

3、如果main文件不存在,或是main所依赖的后面的 .o 文件的文件修改时间要比main这个文件新,那么,他就会执行后面所定义的命令来生成main这个文件。

4、如果main所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。

5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件make的终极任务,也就是执行文件main了。

5、Makefile使用伪目标

常见的伪目标 .PHONY

  • all: target1 target2

  • target1 :

    执行make all

  • install

    执行make install

  • clean

    执行make clean

# 源文件:main.c add.c add.h sub.c sub.h
main:main.o add.o sub.o
	gcc main.o add.o sub.o -o main
main.o:main.c add.h sub.h
	gcc -c main.c -o main.o
add.o:add.c add.h
	gcc -c add.c -o add.o
sub.o:sub.c sub.h
	gcc -c sub.c -o suntract.o
.PHONY:clean
clean:
	rm -f main main.o add.o sub.o

6、makefile中使用变量

objects=main.o add.o sub.o
CC=gcc
main:$(objects)
	$(CC) $(objects) -o main
main.o:main.c add.h sub.h
	$(CC) -c main.c -o main.o
add.o:add.c add.h
	$(CC) -c add.c -o add.o
sub.o:sub.c sub.h
	$(CC) -c sub.c -o sub.o
.PHONT:clean
clean:
	rm -f main main.o add.o sub.o

7、make自动推导

  • GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。
  • 只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么 whatever.c,就会是whatever.o的依赖文件。并且 gcc -c whatever.c 也会被推导出来
objects=main.o add.o sub.o
main:$(objects)
	gcc $(objects) -o main
main.o:add.h sub.h
add.o:add.h
sub.o:sub.h
clean:
	rm -f main main.o add.o sub.o
objects=main.o add.o sub.o
main:$(objects)
	gcc $(objects) -o main
$(objects):	#甚至这行不要也可以
.PHONY:clean 
clean:
	rm -f *.o main

8、Makefile中常见函数

  • wildcard 函数
    • 当前目录下匹配模式的文件。
    • 例如:src=$(wildcard *.c)
  • notdir 函数
    • 去除路径
    • 例如:$(notdir $src)
  • patsubst 函数
    • 模式匹配替换
    • 例如:(patsubst(patsubst %.c,%o,src)
    • 等价于$(src:.c=.o)
  • shell函数
    • 执行shell命令
    • 例如:$(shell ls -d */)
    • 例如:$(shell find -name ‘*.c’)
选项名 作用
$@ 规则的目标文件名
$< 规则的第一个依赖文件名
$^ 规则的所有依赖文件列表
ELF=main
CC=gcc
src=$(wildcard *.c)
objects=$(src:.c=.o)
$(ELF):$(objects)
	$(CC) $^ -o $@
$(objects):
clean:
	rm -f $(objects) $(ELF)

9、多级目录Makefile

ELF=main
CC=gcc
src=$(shell find -name '*.c')
objects=$(src:.c=.o)
$(ELF):$(objects)
$(objects):
clean:
	rm -f $(objects) $(ELF)

10、最终Makefile(通用) – C/C++版本

ELF=main
CC=gcc
CPPFLAGS=	#C++语言编译器参数 例如:-g -Wall 
LDFLAGS=	#连接器参数 例如:-lpthread -lrt -lsqlite3
SRC=$(shell find -name '*.c')
OBJECT = $(SRC:.c=.o)
$(ELF):$(OBJECT)
	$(CC) $(CPPFLAGS) $(OBJECT) -o $(ELF) $(LDFLAGS)
$(OBJECT):
clean:
	rm -f $(OBJECT) $(ELF)

我在项目中用的makefile(C++版本) 如下

ELF=main
CC=g++
CPPFLAGS=-g -Wall 
LDFLAGS=-lpthread -lrt -lsqlite3
SRC=$(shell find -name '*.cpp')
OBJECT = $(SRC:.cpp=.o)
$(ELF):$(OBJECT)
	$(CC) $(CPPFLAGS) $(OBJECT) -o $(ELF) $(LDFLAGS)
$(OBJECT):
clean:
	rm -f $(OBJECT) $(ELF)
参数 描述
-g 生成供 gdb 使用的调试信息。
-Wall 编译后显示所有警告
-lpthread 通过pthreads库加入对多线程的支持,pthread是POSIX指定的标准线程库.
-lrt 一般含有#include<time.h>头文件的代码,编译的时候需要加上-lrt
-lsqlite3 sqlite3数据库

专栏 《linux网络编程》 将持续更新中…
从linux 零基础 到 高并发服务器架构

如果我的文章能够帮到您,可以点个赞!
您的每次 点赞、关注、收藏 都是对我最大的鼓励!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章