Makefile
一、编译参数
-o并不是编译参数,而是gcc内部的重命名参数。真正参与编译的参数有-c -s -e等。
gcc -o test main.c
若不制定类似于-c -s -e这样的编译参数,直接使用-o参数,gcc会自动默认执行-c -s -e参数,并根据-o参数指定的名称生成可执行文件。
https://www.cnblogs.com/zhangpengshou/p/3587751.html
二、Makefile语法
2.1、编译规则
2.1.1、变量定义与变量操作
https://blog.csdn.net/naughfy/article/details/80150312
obj = test.c
obj := test.c
两者之间的区别?
变量追加、变量替换
makefile 文件变量赋值有以下几种
= // 最通用的用法,用在递归展开方式较多
:= //变量必须之前就定义了,用在直接展开方式较多
?= 如果该变量没有赋值,则对该变量赋值
+= 给变量追加赋值
@echo $(OPT) // 变量使用
make OPT=add //make 传递参数
2.1.1、变量参数传递
https://blog.csdn.net/darennet/article/details/9003010
//宏定义参数传递,用于源代码中宏开关。
CFLAGS += -D POSGP730
-D*表示:#define *
如:-DPOSGP730等价于#define POSGP730
-Wall 表示打开所有编译告警信息
-O2表示优化级别
在makefile中可以预先使用一个未定义的变量, 这个变量可以在make执行时传递给它
比如makefile中有这么一行
include $(M)/$(COMPAT_CONFIG)
这个M可以通过make传递过来
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
其中的M就是$(PWD)
甚至可以进行更复杂的操作, 就像在Makefile中一样
make CFLAG=-DDEBUG
2.1.1、编译查找规则
1、入口: makefile认为"第一个目标作为入口。 重点:第一个、目标。
2、依赖性查找
3、若能找到,则执行对应的操作。(显示)
4、若找不到,makefile强大的自动推倒能力,执行隐士的相关操作。(隐士)
//显示
all:test1.o test2.o
gcc -o $@ $^
test1.o:test1.c
gcc -o test1.o test1.c
test2.o:test2.c
gcc -o test2.o test2.c
//隐士
all:test1.o test2.o
gcc -o $@ $^
test1.o: //自动推倒依赖test1.c 并编译cc -c -o test1.0 test1.c
test2.o:
//隐士
all:test1.o test2.o
gcc -o $@ $^
//自动推倒目标与依赖,并编译cc -c -o test1.0 test1.c
2.1.2、可执行文件生成规则
makefile最终编译生成的可执行程序与伪目标没有任何关系,仅仅取决于arm-linux-gcc -o 之后所定义的名称。 (一般也采用@<)使其名字与伪目标相同。
2.1.2、新旧比对编译
1、如果目标不存在,执行命令。(包括依赖和命令)
2、如果目标存在,依赖文件有更新(依赖文件是递归的,找依赖的依赖,如果有更新,就更新)。执行命令。
3、如果目标存在,且依赖没有更新,(递归的,包括依赖的依赖。。。),不更新,不执行命令。
2.2、通配符
https://www.cnblogs.com/warren-wong/p/3979270.html
2.2、特殊符号
$@:目标的名字
$^:构造所需文件列表所有所有文件的名字
$<:构造所需文件列表的第一个文件的名字
$?:构造所需文件列表中更新过的文件
//$@:就是test1.o $<:就是test1.c
test1.o:test1.c
gcc -o $@ $<
// $^:就是test1.c head.c
test1.o:test1.c head.c
gcc -o $@ $^
%与*通配符的关系:
转义符的使用:
2.3、逻辑判断
https://blog.csdn.net/liuzhuchen/article/details/51776820
if then else then
ifep
2.4、常用函数
wildcard扩展通配符
Makefile规则中,通配符会被自动展开。但在变量
的定义和函数引用
时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...) 。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。
//使用说明
obj = $(wildcard *.c)
//变量定义与函数引用通配符失效,举例说明
//比如函数为swapfun,使用通配符的方式去引用函数
obj = %.c
$(*fun argument)
notdir去除路径
去除所有的目录信息,SRC2里的文件名列表将只有文件名,去除掉已xx.c命名的文件夹信息。
SRC = $(wildcard *.c)
SRC2 = $(notdir wildcard)
patsubst 替换通配符
patsubst( patten substitude, 匹配替换的缩写)函数。
它需要3个参数:第一个是一个需要匹配的式样,第二个表示用什么来替换它,第三个是一个需要被处理的由空格分隔的字列。例如,处理那个经过上面定义后的变量,
OBJS = $(patsubst %.c,%.o,$(SRC2 ))
这行将处理所有在 SRC2 列个中的字(一列文件名),如果它的 结尾是 '.c' ,就用'.o' 把 '.c' 取代。
//使用举例
SOURCES = $(wildcard *.c)
FILES = $(notdir$(SOURCES))
OBJS = $(patsubst %.c, %.o, $(FILES) )
SRC = $(wildcard *.c)
OBJ = $(patsubst %.c,%.o,$(notdir ${SRC}))
三、Makefile例程分析
TARGET = arm-none-linux-gnueabi
CC = $(TARGET)-gcc
AR = $(TARGET)-ar
LD = $(TARGET)-ld
STRIP = $(TARGET)-strip
CFLAGS = -Wall -I../../include -I../../../include -fPIC
LDFLAGS = -L../../lib -ldrivercomm -lmodbus -lmodbustcp -lprintmanage -L ../../lib.arm -lxmlrpcsys
ifeq (1,${release})
CFLAGS += -Os
else
CFLAGS += -g -DDEBUG_PRINTF
endif
NAME = CL_DL_JG_YJ_BMU-H1
PROGRAM_OUTPUT = $(NAME).so
PAC_OUTPUT = $(NAME).pac
PROGRAM_OBJS = Driver.o
TEST_OUTPUT = test
TEST_OBJS = Test.o
all: program test
program: version.h $(PROGRAM_OBJS)
$(CC) -shared $(PROGRAM_OBJS) $(LDFLAGS) -o $(PROGRAM_OUTPUT)
../../pack/pack $(NAME)
test: version.h $(TEST_OBJS)
$(CC) $(TEST_OBJS) -o $(TEST_OUTPUT) $(LDFLAGS) -ldl
newversion:
@if [ ! -f .version ]; then
echo 1 > .version;
else
expr 0`cat .version` + 1 > .version;
fi
compile.h: newversion
@echo #define SOFTWARE_COMPILE_TIME "`date +%H:%M:%S`" >> .ver
@echo #define SOFTWARE_COMPILE_DATE "`date +%Y/%m/%d`" >> .ver
@echo #define SOFTWARE_COMPILE_BY "`logname`" >> .ver
@echo #define SOFTWARE_COMPILE_HOST "`hostname`" >> .ver
@echo #define SOFTWARE_COMPILER "`$(CC) -v 2>&1 | tail -1`" >> .ver
@mv -f .ver $@
version.h: compile.h
@echo #define SOFTWARE_BUILD_VERSION `cat .version` >> .ver
@mv -f .ver $@
.PHONY: clean
clean:
@rm -f *.o *.d version.h compile.h
@rm -f $(PROGRAM_OUTPUT) $(TEST_OUTPUT) $(PAC_OUTPUT)
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
以上述makefile为例,分析makefile的查找规则与执行熟悉。
Makefile常用参数
https://blog.csdn.net/skywalkzf/article/details/6926395
附录
makefile学习笔记: https://www.cnblogs.com/wang_yb/p/3990952.html
strip:
函数名称:去空格函数—strip。
函数功能:去掉字串开头和结尾的空字符, 若字串中间部分也包含空格,则会多个连续空字符合并为一个空字符。
示例:
STR = a b c
LOSTR = $(strip $(STR))
结果是“a b c”。
makefeil:fileter函数 foreach函数
https://www.cnblogs.com/lengbingshy/p/3936116.html
https://www.cnblogs.com/yuguangyuan/p/10929967.html
https://blog.csdn.net/zhoudengqing/article/details/41777957
https://www.cnblogs.com/GyForever1004/category/1155268.html
makefiel中使用shell的语法进行判断
在Makefile中执行shell命令,一行创建一个进程来执行。这也是为什么很多Makefile中有很多行的末尾都是“; ”,以此来保证代码是一行而不是多行,这样Makefile可以在一个进程中执行
http://ju.outofmemory.cn/entry/322934
# 适用与.h与.c处于同一文件的工程
CC = gcc
CFLAGS = -Wall
LIB = -lpthread -levent -lssl -ldl -lcrypto -levent_openssl
#去除编译链接的文件
CLIENT_IGNORE_SOURCE := https-server.c
SERVER_IGNORE_SOURCE := https-client.c
#分别获取需要链接的文件
CLIENT_LOCAL_SOURCE = $(filter-out $(CLIENT_IGNORE_SOURCE),$(wildcard *.c))
SERVER_LOCAL_SOURCE = $(filter-out $(SERVER_IGNORE_SOURCE),$(wildcard *.c))
CLIENT_LOCAL_OBJ = $(patsubst %.c,%.o,$(notdir ${CLIENT_LOCAL_SOURCE}))
SERVER_LOCAL_OBJ = $(patsubst %.c,%.o,$(notdir ${SERVER_LOCAL_SOURCE}))
all:
@echo "Wrong build option, please run 'make client' or "make server" to build.";
@exit 13;
client:${CLIENT_LOCAL_OBJ}
$(CC) $(CLIENT_LOCAL_OBJ) -o $@ $(LIB)
server:${SERVER_LOCAL_OBJ}
$(CC) $(SERVER_LOCAL_OBJ) -o $@ $(LIB)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm *.o client server
//多文件实例
DIR_INC = ./include
DIR_SRC = ./src
DIR_OBJ = ./obj
DIR_BIN = ./bin
SRC = $(wildcard ${DIR_SRC}/*.c)
OBJ = $(patsubst %.c,${DIR_OBJ}/%.o,$(notdir ${SRC}))
TARGET = main
BIN_TARGET = ${DIR_BIN}/${TARGET}
CC = gcc
CFLAGS = -g -Wall -I${DIR_INC}
${BIN_TARGET}:${OBJ}
$(CC) $(OBJ) -o $@
${DIR_OBJ}/%.o:${DIR_SRC}/%.c
$(CC) $(CFLAGS) -c $< -o $@
.PHONY:clean
clean:
find ${DIR_OBJ} -name *.o -exec rm -rf {}
//test2
PWD := `pwd`
CC = gcc
SRC_PATH := .
CFLAGS = -Os
IOT_OBJS = $(wildcard $(SRC_PATH)/*.c $(SRC_PATH)/LibSrc/*.c)
targets = mqtt_demo
LINC += -I$(PWD)/LibSrc
all:$(targets)
$(targets):$(IOT_OBJS)
$(CC) $(CFLAGS) $(IOT_OBJS) $(LINC) -lpthread -lm -o $@
clean:
rm -f *.o $(targets)