目录
一、Makefile简介
1.make解决的问题:
1) 大量代码的关系维护
2) 减少重复编译时间
二、Makefile文件命名规则
三、Makefile语法规则
1.Makefile基本规则三要素:
1)目标:
2)依赖文件:
3)命令:
四、make命令格式
五、Makefile示例
1.最简单的Makefile
2.第二个版本Makefile
六、Makefile中的变量
1.自定义变量
1)定义变量方法:
2)引用变量:
3)makefile的变量名:
2.自动变量
3.模式规则
七、Makefile中的函数
1. Makefile中的伪目标
makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,其中也可以执行操作系统的命令。
Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
大项目中源代码比较多,手工维护、编译时间长而且编译命令复杂,难以记忆及维护
把代码维护命令及编译命令写在makefile文件中,然后再用make工具解析此文件自动执行相应命令,可实现代码的合理编译
在改动其中一个文件的时候,能判断哪些文件被修改过,可以只对该文件进行重新编译,然后重新链接所有的目标文件,节省编译时间
makefile和Makefile都可以,推荐使用Makefile。
make安装:
sudo apt install make
一条规则:
目标:依赖文件列表
命令列表
举例说明:
测试代码:
test:
echo "hello world"
test:test1 test2
echo "test"
test1:
echo "test1"
test2:
echo "test2"
make是一个命令工具,它解释Makefile 中的指令(应该说是规则)。
make命令格式:
make [ -f file ][ options ][ targets ]
1.[ -f file ]:
2.[ options]
3.[ targets ]:
五、Makefile工作原理
1)若想生成目标, 检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来 生成该依赖文件
2) 检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新
总结:
Ø 分析各个目标和依赖之间的关系
Ø 根据依赖关系自底向上执行命令
Ø 根据修改时间比目标新,确定更新
Ø 如果目标不依赖任何条件,则执行对应命令,以示更新
测试程序: test.c add.c sub.c mul.c div.c
test:test.c add.c sub.c mul.c div.c
gcc test.c add.c sub.c mul.c div.c -o test
缺点:效率低,修改一个文件,所有文件会被全部编译
test:test.o add.o sub.o mul.o div.o
gcc test.o add.o sub.o mul.o div.o -o test
test.o:test.c
gcc -c test.c
add.o:add.c
gcc -c add.c
sub.o:sub.c
gcc -c sub.c
mul.o:mul.c
gcc -c mul.c
div.o:div.c
gcc -c div.c
在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单变量定义及使用。
变量名=变量值
$(变量名)或${变量名}
示例:
#变量
OBJS=add.o sub.o mul.o div.o test.o
TARGET=test
$(TARGET):$(OBJS)
gcc $(OBJS) -o $(TARGET)
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
mul.o:mul.c
gcc -c mul.c -o mul.o
div.o:div.c
gcc -c div.c -o div.o
test.o:test.c
gcc -c test.c -o test.o
clean:
rm -rf $(OBJS) $(TARGET)
除了使用用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值。
CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项 如:-I
CFLAGS: C编译器的选项 -Wall -g -c
LDFLAGS : 链接器选项 -L -l
注意:自动变量只能在规则的命令中中使用
参考示例:
#变量
OBJS=add.o sub.o mul.o div.o test.o add.o
TARGET=test
CC=gcc
#$@: 表示目标
#$<: 表示第一个依赖
#$^: 表示所有的依赖
$(TARGET):$(OBJS)
#$(CC) $(OBJS) -o $(TARGET)
$(CC) $^ -o $@
echo $@
echo $<
echo $^
add.o:add.c
$(CC) -c $< -o $@
sub.o:sub.c
$(CC) -c $< -o $@
mul.o:mul.c
$(CC) -c $< -o $@
div.o:div.c
$(CC) -c $< -o $@
test.o:test.c
$(CC) -c $< -o $@
clean:
rm -rf $(OBJS) $(TARGET)
模式规则示例:
%.o:%.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
Makefile第三个版本:
OBJS=test.o add.o sub.o mul.o div.o
TARGET=test
$(TARGET):$(OBJS)
gcc $(OBJS) -o $(TARGET)
%.o:%.c
gcc -c $< -o $@
makefile中的函数有很多,在这里给大家介绍两个最常用的。
- wildcard – 查找指定目录下的指定类型的文件
src = $(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src
- patsubst – 匹配替换
obj = $(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
在makefile中所有的函数都是有返回值的。
Makefile第四个版本:
SRC=$(wildcard *.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
TARGET=test
$(TARGET):$(OBJS)
gcc $(OBJS) -o $(TARGET)
%.o:%.c
gcc -c $< -o $@
【变量】=【值】#普通赋值
【变量】:=【值】#覆盖之前的值
【变量】?=【值】#如果没有赋值过,则赋值等号后的值
【变量】+=【值】#添加等号后面的值
关键字 | 功能 |
---|---|
ifeq | 判断参数是否不相等,相等为 true,不相等为 false。 |
ifneq | 判断参数是否不相等,不相等为 true,相等为 false。 |
ifdef | 判断是否有值,有值为 true,没有值为 false。 |
ifndef | 判断是否有值,没有值为 true,有值为 false。 |
条件判断的使用方式如下:
ifeq (ARG1, ARG2)
ifeq 'ARG1' 'ARG2'
ifeq "ARG1" "ARG2"
ifeq "ARG1" 'ARG2'
ifeq 'ARG1' "ARG2"
clean用途: 清除编译生成的中间.o文件和最终目标文件
make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令,解决方案:
Ø 伪目标声明: .PHONY:clean
声明目标为伪目标之后,makefile将不会该判断目标是否存在或者该目标是否需要更新
clean命令中的特殊符号:
Makefile第五个版本:
SRC=$(wildcard *.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
TARGET=test
$(TARGET):$(OBJS)
gcc $(OBJS) -o $(TARGET)
%.o:%.c
gcc -c $< -o $@
.PHONY:clean
clean:
rm -rf $(OBJS) $(TARGET)
总结: 一条规则,两个函数,三个变量。
cmake_minimum_required(VERSION 3.2) # 指明cmake最低版本
include_directories(./) # 将指定目录添加到编译器的头文件搜索路径之下
file(GLOB srcs ./*.c) # 为source添加过滤器
add_executable(dpi ${srcs}) # 使用指定的源文件来生成目标可执行文件
target_link_libraries(dpi pcap) #添加的库pcap
····················································································································
PROJECT_SOURCE_DIR
PROJECT_SOURCE_DIR为包含PROJECT()的最近一个CMakeLists.txt文件所在的文件夹,如以下文件结构:
test
|
+-----build
|
+-----include
|
+-----lib
|
+-----src
|
+main.cpp
|
+CMakeLists.txt
|
+-----CMakeLists.txt
test/CMakeLists.txt文件内容为
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(test)
ADD_SUBDIRECTORY(src)
test/src/CMakeLists.txt文件内容为
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
#PROJECT(main)
在build中执行
cmake ..
(两个小数点别丢了)则PROJECT_SOURCE_DIR的值为(parent_path)/test,
取消#PROJECT(main)的注释,PROJECT_SOURCE_DIR的值为(parent_path)/test/src
····················································································································
$(origin O)该形式是$(origin
在u-boot的Makefile中的开始位置(line69~line76),有这么一段代码:
ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif
ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)
该代码的意思是:如果定义了O,且O定义的位置是“command line”(命令行),则BUILD_DIR赋值为O的值。
什么意思呢?就是说,我们若在执行make命令时是执行“$make O=~/home/uboot”这样的话,就是在command line中定义了O,并且O的值为“~/home/uboot”,通过Makefile就可以将BUILD_DIR赋值为~/home/uboot。
如果我们没有在命令行中定义O,而是编译时直接是使用“$make”,那么BUILD_DIR就不会被赋值,而为空。
Makefile 中调用另外的 Makefile 文件,呈现出 Makefile 的层级结构。上层 make 过程要将所执行的 Makefile 中的变量传递给子 make 过程,需要明确地指出。在 GNU make 中,实现此功能的指示符是 export。
当一个变量使用 export 进行声明后,变量和它的值将被加入到当前工作的环境变量中,以后在 make 执行的所有规则的命令都可以使用这个变量。
all : main1 main2
main1 : main1.o
gcc main1.o -o main1
main2 : main2.o
gcc main2.o -o main2
%.o : %.c
gcc -c $< -o $@
我们知道,一个Makefile中只有一个最终目标,就是第一个目标,上面的代码中,显然就是 all,那么all的依赖元素有2个,分别为main1和main2,而make具有自动推导,make在生成all的时候,自然要自动推导出main1和main2,这样我们就能通过一个Makefile生成了2个目标,分别是main1和main2,而这两个都是可执行程序,很巧妙的用法。
make在读到$$i
的时候会把它扩展成$i
(有点转义字符的意味)
$(MAKE) –C $$dir || exit 1,|| exit (转到dir这个目录下面make,如果执行结果为0(失败)就执行exit 1,意思就是返回错误)
echo:会在shell中显示echo这条命令和这条命令的输出结果
@echo:不会在shell中显示echo这条命令,但是会显示命令的输出结果
从Makefile中读取指令install代表的指令,执行安装,例如makefile 中设定的install是:
……
install:
install -d $(bindir)
install -m 0755 hello $(bindir)
……
make install 就是去执行下面两条命令
install -d $(bindir)
install -m 0755 hello $(bindir)
这里的install 是linux系统命令,用法自己去查。
make install 这条命令来进行安装(当然有些软件需要先运行 make check 或 make test来进行一些测试),这一步一般需要你有 root 权限(因为要向系统写入文件)
./configure
make
make install