美文网首页
makefile学习

makefile学习

作者: 宇文黎琴 | 来源:发表于2017-06-16 17:20 被阅读41次

    title: 2017-6-15makefile
    tags:makefile的书写和熟悉


    示例

    # 指令编译器和选项  
    CC=gcc  
    CFLAGS=-lssl -lcrypto -ldl -Wall -g -DDEBUG -std=gnu99  
    # 宏定义  
    DEFS = -DTEST_ADD -DTEST_SUB=1  
    CFLAGS += $(DEFS)  
    # 头文件查找路径
    INC = -Iport -I../../modbus/rtu \  
      -I../../modbus/ascii -I../../modbus/include -I../../modbus/tcp  
      
    # 静态链接库  
    LDFLAGS =   
    LDLIBS = -lpthread
    # 目标文件  
          
    TARGET=test  
    # 源文件  
    SRCS = test.c \  
      ./test-add/test-add.c \  
      ./test-sub/test-sub.c  
    # 头文件查找路径  
    INC = -I./test-add -I./test-sub  
    # 目标文件  
    OBJS = $(SRCS:.c=.o)  
    # 链接为可执行文件  
    $(TARGET):$(OBJS)  
    #   @echo TARGET:$@  
    #   @echo OBJECTS:$^  
    [tab]$(CC) -o $@ $^  
    clean:  
    [tab]rm -rf $(TARGET) $(OBJS)  
    # 连续动作,请清除再编译链接,最后执行  
    exec:clean $(TARGET)  
    [tab]@echo 开始执行  
    [tab]./$(TARGET)  
    [tab]@echo 执行结束  
    # 编译规则 $@代表目标文件 $< 代表第一个依赖文件  
    %.o:%.c  
    [tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $< 
    
    # 指定编译器  
    CC = gcc  
      
    # CFLAG包括头文件目录  
    CFLAGS = -g -Wall  
      
    # 头文件查找路径  
    INC = -Iport -I../../modbus/rtu \  
      -I../../modbus/ascii -I../../modbus/include -I../../modbus/tcp  
      
    # 静态链接库  
    LDFLAGS =   
    LDLIBS = -lpthread  
    # 目标  
    TARGET = tcpmodbus  
    # 源文件  
    SRC = demo.c port/portother.c \  
     port/portevent.c port/porttcp.c \  
     ../../modbus/mb.c ../../modbus/tcp/mbtcp.c \  
     ../../modbus/functions/mbfunccoils.c \  
     ../../modbus/functions/mbfuncdiag.c \  
     ../../modbus/functions/mbfuncholding.c \  
     ../../modbus/functions/mbfuncinput.c \  
     ../../modbus/functions/mbfuncother.c \  
     ../../modbus/functions/mbfuncdisc.c \  
     ../../modbus/functions/mbutils.c  
      
    # 源文件编译为目标文件  
    OBJS = $(SRC:.c=.o)  
      
    # 链接为可执行文件  
    $(TARGET): $(OBJS)  
    [tab]$(CC) $^ -o $@ $(LDFLAGS) $(LDLIBS)  
      
    # 清除可执行文件和目标文件  
    clean:  
    [tab]rm -f $(OBJS)  
    [tab]rm -f $(TARGET)  
      
    # 编译规则 加入头文件 $@代表目标文件 $< 代表第一个依赖文件  
    %.o:%.c  
    [tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $<
    

    主要目的

    是为了把一些可以变化的参数,编译到文件里面。
    所以要关注#define 的作用域。

    不管是typedef还是define,其作用域都不会扩展到别的文件,即使是同一个程序的不同文件,也不能互相使用。

    语法概要

              target... : prerequisites ...
              command
    

    【target】 也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label)。
    【prerequisites】 就是,要生成那个target所需要的文件或是目标。
    【command】 也就是make需要执行的命令。(任意的Shell命令)

    这个是一个大概的格式,后边所有的语法和变量都是为了简化这种写法。

    【:】冒号是表示的依赖关系。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。
    make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。也就是【target】。

    在Makefile中的命令,必须要以[Tab]键开始。

    Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
    显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
    隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
    变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
    文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
    注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。

    GNU的make工作时的执行步骤入下:(想来其它的make也是类似)

    1.    读入所有的Makefile。
      
    2.    读入被include的其它Makefile。
      
    3.    初始化文件中的变量。
      
    4.    推导隐晦规则,并分析所有规则。
      
    5.    为所有的目标文件创建依赖关系链。
      
    6.    根据依赖关系,决定哪些目标要重新生成。
      
    7.    执行生成命令。
      

    规则包含两个部分,一个是依赖关系,一个是生成目标的方法。

    make一般是使用环境变量SHELL中所定义的系统Shell来执行命令,默认情况下使用UNIX的标准Shell——/bin/sh来执行命令。

    变量

    在 Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在“目标”,“依赖目标”,“命令”或是 Makefile的其它部分中。

    变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及新的变量中。

    $@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。

    = 是最基本的赋值
    := 是覆盖之前的值
    ?= 是如果没有被赋值过就赋予等号后面的值
    += 是添加等号后面的值

    模式规则

    %.o : %.c ; <command ......>
    

    其含义是,指出了怎么从所有的[.c]文件生成相应的[.o]文件的规则。如果要生成的目标是"a.o b.o",那么"%c"就是"a.c b.c"

    BUG记录

    用makefile定义了宏-DKEY="hello world"

    但是gcc这样宏会忽略双引号。如果当成左值,则会把这句话(just)当成了声明变量。

    并且

    宏中有#运算符时,参数不会被展开
    为了能让参数被顺利展开所以就不可以使用"#"符号,最终的宏定义如下

    #define HELLO hello world  
    #define _A(str) _TMP(str)  
    #define _TMP(str) #str  
      
    std::cout << _A(HELLO) << std::endl;  
    

    1.展开_A,由于没有"#"符号,HELLO被顺利展开,变为 _TMP(hello world)
    2._TMP把参数hello world转换为字符串,也就是加上双引号,变为 "hello world"

    相关文章

      网友评论

          本文标题:makefile学习

          本文链接:https://www.haomeiwen.com/subject/ykemqxtx.html