• makefile学习


    看跟我一起写Makefile遇到不懂的问题,这里记录下答案

    因为看到自动生成依赖性这节,有几个不懂的,所以补充下:

    %.d: %.c
    @set -e; rm -f $@;
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;
    sed 's,($*).o[ :]*,1.o $@ : ,g' < $@.$$$$ > $@;
    rm -f $@.$$$$

    (1)makefile的选项CFLAGS、CPPFLAGS、LDFLAGS和LIBS的区别

     其实就是系统环境变量。

    LDFLAGS是选项,LIBS是要链接的库。都是喂给ld的,只不过一个是告诉ld怎么吃,一个是告诉ld要吃什么。

    网上不难搜索到上面这段话。不过“告诉ld怎么吃”是什么意思呢?

    看看如下选项:

    LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib

    LIBS = -lmysqlclient -liconv

    这就明白了。LDFLAGS告诉链接器从哪里寻找库文件,LIBS告诉链接器要链接哪些库文件。不过使用时链接阶段这两个参数都会加上,所以你即使将这两个的值互换,也没有问题。

     
    说到这里,进一步说说LDFLAGS指定-L虽然能让链接器找到库进行链接,但是运行时链接器却找不到这个库,如果要让软件运行时库文件的路径也得到扩展,那么我们需要增加这两个库给"-Wl,R"

    LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

    如 果在执行./configure以前设置环境变量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意设置环境变量等号两边不可以有空格,而且要加上引号哦(shell的用法)。那么执行configure以后,Makefile将会设置这个选项, 链接时会有这个参数,编译出来的可执行程序的库文件搜索路径就得到扩展了。

    ------------------------------------------------------------------------------------------------------------------------

    PS:-Wl,R在GraphicsMagick环境下,用为-R, 也就是LDFLAGS = -L/var/xxx/lib -R/var/xxx/lib

    CFLAGS 或 CPPFLAGS的用法
     
    CPPFLAGS='-I/usr/local/libjpeg/include -I/usr/local/libpng/include'
     
    (2)解释这个Makefile

    其实这里主要是为每个C文件建立一个同名的后缀为.d。该文件的作用是使用gcc的-M属性来自动生成.o文件的头文件依赖关系。

    make默认在执行命令前会显示要执行的命令,加上@表示Makefile执行这条命令时,命令不显示出来而不是执行不执行。如果想每个命令都不显示出来,就需要在每行都加一个@,注意命令前面要有TAB符号。set -e 一般都会在命令的头,意思是如果出错了就直接退出。

    第1,2,4都好理解。

    第2行解释: 使用gcc -M 的属性将  $<(第1行的第一个依赖文件,就是%.c。 查看静态模式)的C文件的依赖关系输出到一个临时文件。  这里有点疑惑。  书里面说   .$$$$是当前进程好。   然到Makefile这个脚本将$$$$当成进程号了。姑且这么认为吧。

    第4行解释:将第2行产生的临时文件删除。

    对于第3行, 我知道sed的s命令是一个替换命令。但是里面的用到了太多高深的匹配规则了。  sed命令果真如传闻中的那么强大,对于现在的我来说还真的很陌生。不管咋样, 要把它解决。

    首先,我们先要知道sed是什么概念。

    sed是一个非交互式的流编辑器。所谓非交互式,是指使用sed只能在命令行下输入编辑命令来编辑文本,然后在屏幕上查看输出;而流编辑器是指sed每次只从文件(或输入)读入一行,然后对该行进行指定的处理,并将结果输出到屏幕,接着读入下一行。

    为了简化的阐述,下面将静态模式用一个特例代替---main.c 。 通过第2行,针对main.c编译器生成了如下的依赖关系:

    main.o:main.c defs.h

    而通过第三行将会被替换成main.o main.d:main.c defs.h, 并且把这个依赖关系输出到文件main.d中。

    OK,大致知道了它的意思,接下在,就细细的分析第三行命令的整个执行过程,如下:

    1:将($@.$$$$)的临时文件中的字符串信息(main.o:main.c defs.h)通过 “<” 输送到sed命令中.

    2:sed中的s符号告诉sed命令,这次要做一个替换的任务。s符号的格式为:[address[,address]] s/pattern-to-find/replacement-pattern/[g p w n]。   下面来匹配上面的示例:

        [address[,address]]:是指要处理的行的范围,在这次的操作中采用的是默认值。

        pattern-to-find等价于($*).o[ :]*

        replacement-pattern等价于1.o $@ :

    3:Makefile使用%=main进行替换后,命令变成了sed 's,(main).o[ :]*,1.o main.d : ,g' < main.pid > main.d ;

          接下来就比较好分析了,主要是正则表达式的知识了。   pattern-to-find使用到了4个正则表示式的知识点。

           first, (main)为创建一个字符标签,给后边的replacement-pattern使用。如1.o,展开后就是main.o

           second, . 在正则表达式中‘.’作用是匹配一个字符。所以需要使用转义元字符‘’来转义。

           third, [ :] 匹配一组字符里的任意字符 。

           forth, *匹配0个或多个前一字符

    4 : 通过sed的正则表达式,输入的main.o:main.c defs.h被替换成了main.o main.d : main.c defs.h。

    匹配的地方是main.o : 换成了main.o main.d :后面的main.c 和defs.h是没变的,匹配应该是找最短匹配的,这里(main).o [ :]* 匹配了main.o : ,如果不加*,例如(main).o [ :]就只匹配了main.o ,

    就成了main.o main.d : : main.c defs.h

    这里还有个有趣的东西,平时我们对命令s符号使用‘/’作为参数分割符,其实‘/’只是一种默认的习惯罢了。你也可以使用','来作为分割符号,只要前后统一就OK。这里就是使用了','来作为分割符。

     (3)=和:=的区别

    其实就是=可以找到下面的,所以用=时,注意从后往前找,而用:=时就从前往后找,在跟我一起写Makefile中都有。例子:

    先看下面的Makefile:

    1. #example
    2. B := $(A)
    3. A = later
    4. all:
    5.     @echo $(B)
     执行make命令,我们发现什么都没输出,我们将第3行的:=换成=。
    1. #example
    2. B = $(A)
    3. A = later
    4. all:
    5.     @echo $(B)
    执行make,输出later。
    分析:B :=$(A)时,它只会到这句语句之前去找A的值,因A没有定义所以什么都没有输出。
          B = $(A)时,虽然该语句之前A没有定义,但是在其后定义了,所以能输出later。
    1. #example
    2. A = before1
    3. A = before2
    4. B := $(A)
    5. A = later1
    6. all:
    7.     @echo $(B)
    执行make,输出before2。
    解释:上面Makefile最后一句echo前面的@符号的作用是禁止回显。如我们的Makefile改为如下:
    1. #example
    2. A = before1
    3. B = $(A)
    4. B = before2
    5. C = $(B)
    6. A = later1
    7. B = later2
    8. all:
    9.     echo $(C)
    执行make:
    echo later2
    later2
    分析:C = $(B),应该从Makefile文件最后往前找B,得到B = later2,将最后一句全部变量代替即为:echo later2,因echo前没有@符号,回显该语句,然后再输出later2。
    注意:当我们直接在终端上要用echo输出某个变量的值时,是不能加()的。如我们要输出PAHT
    应该用echo $PATH,而不能用echo $(PATH),否则会报错,注意'$'不能少了。
    Makefile中"?=",含义为:如没定义,则赋值。
    如:TEMP ?= var 等价于
        ifeq($(TEMP),undefined)
        TEMP = var
        endif
  • 相关阅读:
    MySQL锁概述
    MYSQL删除重复记录
    SPRING事务控制
    性能测试中如何确定并发用户数
    Jsoup操作
    linux根据端口号查询进程
    linux下解压jar文件
    开发阶段的logback.xml
    栈--getMin(leetcode 155)
    git "fatal: The remote end hung up unexpectedly"
  • 原文地址:https://www.cnblogs.com/zmlctt/p/4150594.html
Copyright © 2020-2023  润新知