• 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)
    
  • 相关阅读:
    struts2中struts.xml配置文件详解【未整理】
    程序员,别了校园入了江湖
    xml常用的error-page
    struts2中struts.xml配置文件详解
    Struts 2初体验
    Hibernate 抛出的 Could not execute JDBC batch update
    MyEclipse快捷键
    CSS 字体
    绑定事件 addEventListener
    设置DIV最小高度以及高度自适应随着内容的变化而变化
  • 原文地址:https://www.cnblogs.com/retry/p/10150418.html
Copyright © 2020-2023  润新知