Makefile

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)

通用Makefile

makefile编译阶段,也就是.c生成.o阶段,需用-I参数指定包含的头文件路径,如果有gcc编译参数也在此阶段指定,如-g -wall
链接阶段也就是.o生成目标文件阶段,需要-L 参数指定链接的库文件

#
#  Makefile to build *.cgi
#  
#
# 虚拟机里的工具链
CROSS_COMPILE 	= 
#
# Include the make variables (CC, etc...)
#
AS		= $(CROSS_COMPILE)as
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm
STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump
SIZE		= $(CROSS_COMPILE)size

ifeq (1,${release})
CFLAGS += -Os
else
CFLAGS += -g -DDEBUG_PRINTF
endif


#源文件
SOURCE = $(wildcard *.c)
#.c替换为.o,notdir函数去除路径,使用与makefile与.c在同一路径下
OBJ = $(patsubst %.c,%.o,$(notdir ${SOURCE}))
#不去除路径makefile与.c可位于不同路径
#OBJ = $(patsubst %.c,%.o,${SOURCE})
#头文件查找路径
INCLUDES = -I../LibInclude
#链接库查找路径
LIBS = -L../Lib -lcgic
# 最终的目标文件
TARGET = Target.cgi

${TARGET}:${OBJ}
	$(CC) $(OBJ) -o $@ $(LIBS)

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

clean:
	rm -f $(TARGET) *.o

//通用makefile
https://blog.csdn.net/qq_20553613/article/details/90649734

posted @ 2018-12-20 16:58  hostid  阅读(636)  评论(0)    收藏  举报