zoukankan      html  css  js  c++  java
  • makefile学习小结

     =============2016/08/15================

    上午完成makefile的试验,缩短了代码量,现在make强大,有缺省的变量,能自己推导关系,不需要gcc –MM -MG

    1)需要的usr/lib等缺省目录的参数,仅仅 -lcxl, -lpthread

    #LDFLAGS = -L${PWD} -L${PSLSE_DIR} -lm -lcxl -lpthread -lrt

    LDFLAGS = -L${PSLSE_DIR} -lcxl –lpthread

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

    2)LDLIB也是认可的参数,所以上面的一句话也可以变成如下

    LDFLAGS = -L${PSLSE_DIR}

    LDLIBS = -lm –lcxl –lpthread

    CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
    CPPFLAGS += -D_GNU_SOURCE
    CPPFLAGS += -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR} -I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
    LDFLAGS += -L${PSLSE_DIR}         
    LDLIBS += -lcxl -lpthread
    LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99


    依次顺序:
    cc CFLAGS CPPFLAGS -c -o 目标.c 目标.o


    然后再链接
    cc CFLAGS CPPFLAGS LDFLAGS 目标.c 有关联.o LDLIBS -o 目标

    cc -std=gnu99 -Wall -Werror -g -Wno-comment -D_GNU_SOURCE -I../libs/pslse/libcxl -I../libs/capi/inc -I../libs/argconfig/inc -I../libs/capi/inc/capi -I../libs/argconfig/inc/argconfig -I../libs/capi/src -I../libs/argconfig/src -L../libs/pslse/libcxl   textswap.c readthrd.o writethrd.o textswap_proc.o ../libs/capi/src/capi.o ../libs/capi/src/build_version.o ../libs/capi/src/wqueue_emul.o ../libs/capi/src/snooper.o ../libs/capi/src/wqueue.o ../libs/capi/src/worker.o ../libs/capi/src/fifo.o ../libs/capi/src/utils.o ../libs/argconfig/src/suffix.o ../libs/argconfig/src/report.o ../libs/argconfig/src/argconfig.o  -lcxl -lpthread -o textswap

    CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
    CPPFLAGS += -D_GNU_SOURCE
    CPPFLAGS += -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR} -I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
    LDFLAGS += -L${PSLSE_DIR}
    LDLIBS += -lcxl -lpthread
    LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99

    Objects = readthrd.o writethrd.o textswap_proc.o

    Objects += $(patsubst %.c,%.o,$(wildcard ${CAPI_DIR}/*.c ${ARGCONFIG_DIR}/*.c))

    APP = textswap unittest searchtest lfsrtest iotest
    all: ${APP}

    #depends1.mk :
    #       echo "begin to generate depends1.mk"
    #       echo $(shell cd ${CAPI_DIR}); pwd
    #       @$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends1.mk
    #
    #-include depends1.mk

    ${APP}: ${Objects}

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

    3)

    3.1目标可以是多重,同一个目标可以写多次.

     clean::

       xxxxx

    clean::

       yyyyy

    1. 双冒号规则中:

    对于一个没有依赖而只有命令行的双冒号规则,当引用此目标时,规则的命令将会被无条件执行。

    而普通单冒号规则,当规则的目标文件存在时,此规则的命令永远不会被执行(目标文件永远是最新的)。

    3.2

    执行多个目标的方法,写在all后面

    如:

    ALL = textswap unitest

    all:${ALL}

    ${APP}: ${Objects}

    4)-L{$LIBDIR}指向  动态库,静态库。

      编译会先找动态库.so,如果没有,再找静态库.a
    LDFLAGS += -L${PSLSE_DIR}
    但是使用的是动态库,则需要设置$LD_LIBRARY_PATH+= ,指向.so的位置。
    否则只在/usr/lib  等系统目录以及键入程序运行的目录查找

    如果动态库和静态库都存在那么会优先链接动态库,如果找不到动态库,就直接使用静态库。
    如果为了调试要强制使用静态库,可以在CFLAGS中加入-static (但是其缺点就是static是指所有库的目录下的静态库,如果想一部分是静态库,一部分是动态库,则无法工作
    比如出现如此问题
    bs/argconfig/src/report.o ../libs/argconfig/src/argconfig.o  -lcxl -lpthread -o textswap
    /usr/bin/ld: cannot find -lpthread
    /usr/bin/ld: cannot find -lc
    collect2: error: ld returned 1 exit status
    因为也调用了动态库
    LDFLAGS += -L${PSLSE_DIR}
    LDLIBS += -lcxl -lpthread

    -lcxl,-lptheread 只有.so文件,没有.a文件

    一个方法是直接指明.a,根据顺序赋值给LDLIBS,写在前方
    CFLAGS += -std=gnu99 -Wall -Werror -g -Wno-comment
    CPPFLAGS += -D_GNU_SOURCE
    CPPFLAGS += -I${PSLSE_DIR} -I${CAPI_INC_DIR} -I${ARGCONFIG_INC_DIR} -I${CAPI_H_DIR} -I${ARGCONFIG_H_DIR} -I${CAPI_DIR} -I${ARGCONFIG_DIR}
    LDFLAGS += -L${PSLSE_DIR}
    LDLIBS += ${PSLSE_DIR}/libcxl.a -lpthread
    LIBCFLAGS += -g -Wall -m64 -DDEBUG -std=gnu99

    5)patsubst函数是吧某一个集合,完成替换

    如下这样写是错误的

    Objects += $(patsubst %.c,%.o,${CAPI_DIR} ${ARGCONFIG_DIR})

    改为

    Objects += $(patsubst %.c,%.o,$(wildcard ${CAPI_DIR}/*.c ${ARGCONFIG_DIR}/*.c))

    另外再贴一次:

    1、wildcard : 扩展通配符
    2、notdir : 去除路径
    3、patsubst :替换通配符

    例子:
    建立一个测试目录,在测试目录下建立一个名为sub的子目录
    $ mkdir test
    $ cd test
    $ mkdir sub

    在test下,建立a.c和b.c2个文件,在sub目录下,建立sa.c和sb.c2 个文件

    建立一个简单的Makefile
    src=$(wildcard *.c ./sub/*.c)
    dir=$(notdir $(src))
    obj=$(patsubst %.c,%.o,$(dir) )

    all:
    @echo $(src)
    @echo $(dir)
    @echo $(obj)
    @echo "end"

    执行结果分析:
    第一行输出:
    a.c b.c ./sub/sa.c ./sub/sb.c

    wildcard把 指定目录 ./ 和 ./sub/ 下的所有后缀是c的文件全部展开。

    第二行输出:
    a.c b.c sa.c sb.c
    notdir把展开的文件去除掉路径信息

    第三行输出:
    a.o b.o sa.o sb.o

    在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
    任何输出。
    或者可以使用
    obj=$(dir:%.c=%.o)
    效果也是一样的。

    这里用到makefile里的替换引用规则,即用您指定的变量替换另一个变量。
    它的标准格式是
    $(var:a=b) 或 ${var:a=b}
    它的含义是把变量var中的每一个值结尾用b替换掉a

    今天在研究makefile时在网上看到一篇文章,介绍了使用函数wildcard得到指定目录下所有的C语言源程序文件名的方法,这下好了,不用手工一个一个指定需要编译的.c文件了,方法如下:

    SRC = $(wildcard *.c)

    等于指定编译当前目录下所有.c文件,如果还有子目录,比如子目录为inc,则再增加一个wildcard函数,象这样:

    SRC = $(wildcard *.c) $(wildcard inc/*.c)

    yxr注:

    其实 SRC = $(wildcard *.c inc/*.c)也可以,wildcard可以带多个参数

    ==================2016/08/12 ===========

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

    执行shell中命令

    PATH="/data/"

    all:
    echo ${PATH}
    echo $$PATH

    例子中的第一个${PATH}引用的是Makefile中的变量,而不是shell中的PATH环境变量,后者引用的事Shell中的PATH环境变量。

    如果是shell的 $$ (进程id) 如何输出它?

    已经了解到:$$$$ ($$->$)

    在makefile里面也可以这样调shell
    如: CURRENT_DIR=$(shell pwd)

      contents := $(shell cat foo)
      files := $(shell echo *.c)

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

    depends.mk deps:
            @if [ 'x${V}' = 'x' ];                                                 
             then                                                                  
                echo "  DEPENDS";                                                  
             else                                                                  
                echo $(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends.mk;
            fi
            @$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends.mk

    -include depends.mk

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

    -include depends.mk有两个点:一是 - 表示如果没有depends.mk,也不报错

    另一点是运行make的时候,强制执行depends.mk这个目标下的动作!!!!

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

    -----强制目标-----

    target:

    因为没有命令,所以make target ,与makefile 所在目录下是否存在与target 同名的文件没有直接关系。

     

    -----双冒号规则-----

    target::

    commands

    无论makefile 所在目录下存不存在与target 同名文件,make target 导致commands 的执行,与使用'.PHONY' 定义的伪目标效果相同。


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

    http://blog.csdn.net/wzw88486969/article/details/11739737

     如果一个规则没有命令或者依赖,而且它的目标不是一个存在的文件名,在执行此规则时,目标总会被认为是最新的。也就是说,这个规则一旦被执行,make 就认为它所表示的目标已经被更新过。当将这样的目标(FORCE)作为一个规则的依赖时(如上的 vmlinux: ),由于依赖总被认为是被更新过的,所以作为依赖所在的规则定义的命令总会被执行。

     http://blog.chinaunix.net/uid-27057175-id-4432189.html

    待看

    ?????

    但是如下这句话不能运行

    test:
            @echo "hello:OBJ_DIR=${OBJ_DIR}"

    或者如下也不行

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

    test:PORCE
            @echo "hello:OBJ_DIR=${OBJ_DIR}"

    PHONY+=FORCE
    FORCE:

    .PHONY: $(PHONY)
    -------------------

     但是案例可以成功的运行,见鬼?????!!!!!

    LIBCAPI=${LIBCAPI_DIR}/libcapi.a
    LIBARGCONFIG=${LIBARGCONFIG_DIR}/libargconfig.a
    LIBCXL=${PSLSE_DIR}/libcxl.a

    CXL_FLAGS_HACK=-I$(abspath ${PSLSE_DIR}) -DPAGED_RANDOMIZER=0 -g

    ${LIBCAPI}: FORCE
            $(MAKE) -C ${LIBCAPI_DIR}
            echo "shanon:FORCE successfully!"

    ===================2016/08/12

    2.6 函数 (Functions)     $()
    makefile 里的函数跟它的变量很相似——使用的时候,你用一个 $ 符号跟开括号,函 数名,空格后跟一列由逗号分隔的参数,最后 用关括号结束。例如,在 GNU Make 里 有一个叫 'wildcard' 的函 数,它有一个参数,功能是展开成一列所有符合由其参数 描述的文 件名,文件间以空格间隔。你可以像下面所示使用这个命令:
    SOURCES = $(wildcard *.c)
    这行会产生一个所有以 '.c' 结尾的文件的列表,然后存入变量 SOURCES 里。当然你不需要一定要把结果存入一个变量。
    另一个有用的函数是 patsubst ( patten substitude, 匹配替 换的缩写)函数。它 需要3个参数——第一个是一个需要匹配的 式样,第二个表示用什么来替换它,第三 个是一个需要被处理的 由空格分隔的字列。例如,处理那个经过上面定义后的变量,
    OBJS = $(patsubst %.c,%.o,$(SOURCES))
    这行将处理所有在 SOURCES 字列中的字(一列文件名),如果它的 结尾是 '.c' ,就 用 '.o' 把 '.c' 取代。注意这里的 % 符号将匹 配一个或多个字符,而它每次所匹配 的字串叫做一个‘柄’(stem) 。 在第二个参数里, % 被解读成用第一参数所匹配的 那个柄。

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

    它使用变量 CC 做为编译器(象我们在前面的例子),

    并且传递变量 CFLAGS (给 C 编译器,C++ 编译器用 CXXFLAGS ),

    CPPFLAGS ( C 预 处理器旗 标),

    TARGET_ARCH (现在不用考虑这个),然后它加 入旗标 '-c' ,后面跟变量 $< (第一个依靠名),然后是旗 标 '-o' 跟变量 $@ (目的文件名)。

    depends.mk deps:
            @if [ 'x${V}' = 'x' ];                                                 
             then                                                                  
                echo "  DEPENDS";                                                  
             else                                                                  
                echo $(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends.mk;
            fi
            $(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends.mk

    -include depends.mk 

    ========================================

    文件需要先编译,再链接

    编译

    cc -c

    链接

    cc -o

    目标:依赖文件

    动作

    =========

    摘抄:

    需要注意的是,如果相关行写成一行,“命令”之前用分号“;”隔开,如果分成多行书写的话,后续的行务必以tab字符为先导。

    对于makefile 而言,空格字符和tab字符是不同的。

     所有规则所在的行必须以tab键开头,而不是空格键。初学者一定对此保持警惕,因为这是新手最容易疏忽的地方,因为 几个空格键跟一个tab键在肉眼是看不出区别的,但make命令却能明察秋毫,非常敏感。

    此外,如果在makefile文件中的行尾加上空格键的话,也会导致make命令运行失败。。

     @的作用

       应该是取消回显

       @$(CC) $(CPPFLAGS) -MM -MG $(wildcard *.c) $(wildcard *.cpp)  > depends.mk

     则这个命令不显示!但是会执行

    ar产生静态库.a文件

    libargconfig.a: $(patsubst %.c,%.o,$(wildcard *.c))

    =======

     在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o,
    patsubst表示把dir中的.c文件转为.o文件

    ===========

    减号, 横杠的作用

    表示即使命令执行返回错误,仍然执行

    命令出错

    每当命令运行完后,make会检测每个命令的返回码,如果命令返回成功,那么make会执行下一条命令,当规则中所有的命令成功返回后,这个规则就 算是成功完成了。如果一个规则中的某个命令出错了(命令退出码非零),那么make就会终止执行当前规则,这将有可能终止所有规则的执行。

    有些时候,命令的出错并不表示就是错误的。例如mkdir命令,我们一定需要建立一个目录,如果目录不存在,那么mkdir就成功执行,万 事大吉,如果目录存在,那么就出错了。我们之所以使用mkdir的意思就是一定要有这样的一个目录,于是我们就不希望mkdir出错而终止规则的运行。

    为了做到这一点,忽略命令的出错,我们可以在Makefile的命令行前加一个减号“-”(在Tab键之后),标记为不管命令出不出错都认为是成功的。如:

     clean:
              -rm -f *.o
    

    还有一个全局的办法是,给make加上“-i”或是“--ignore-errors”参数,那么,Makefile中所有命令都会忽略错误。而如 果一个规则是以“.IGNORE”作为目标的,那么这个规则中的所有命令将会忽略错误。这些是不同级别的防止命令出错的方法,你可以根据你的不同喜欢设 置。

    ===

    多个目标,静态模式和自动依赖

    静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。我们还是先来看一下语法:

    <targets...>: <target-pattern>: <prereq-patterns ...>

       <commands>

    ...

    targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。

    target-parrtern是指明了targets的模式,也就是的目标集模式。

    prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。

    这样描述这三个东西,可能还是没有说清楚,还是举个例子来 说明一下吧。如果我们的<target-parrtern>定义成“%.o”,意思是我们的集合中都是以“.o”结尾的,而如果我们 的<prereq-parrterns>定义成“%.c”,意思是对<target-parrtern>所形成的目标集进行二次 定义,其计算方法是,取<target-parrtern>模式中的“%”(也就是去掉了[.o]这个结尾),并为其加上[.c]这个结尾, 形成的新集合。

    所以,我们的“目标模式”或是“依赖模式”中都应该有“%”这个字符,如果你的文件名中有“%”那么你可以使用反斜杠“”进行转义,来标明真实的“%”字符。

    看一个例子:

       objects = foo.o bar.o

     

       all: $(objects)

     

       $(objects): %.o: %.c

               $(CC) -c $(CFLAGS) $< -o $@

     

    上面的例子中,指明了我们的目标从$object中获 取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foobar”,并为其加下“.c”的后 缀,于是,我们的依赖目标就是“foo.cbar.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就 是“foo.c bar.c”),“$@”表示目标集(也褪恰癴oo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:

       foo.o : foo.c

               $(CC) -c $(CFLAGS) foo.c -o foo.o

       bar.o : bar.c

               $(CC) -c $(CFLAGS) bar.c -o bar.o

    试想,如果我们的“%.o”有几百个,那种我们只要用这种很简单的“静态模式规则”就可以写完一堆规则,实在是太有效率了。“静态模式规则”的用法很灵活,如果用得好,那会一个很强大的功能。再看一个例子:

     

       files = foo.elc bar.o lose.o

     

       $(filter %.o,$(files)): %.o: %.c

               $(CC) -c $(CFLAGS) $< -o $@

       $(filter %.elc,$(files)): %.elc: %.el

               emacs -f batch-byte-compile $<

    $(filter%.o,$(files))表示调用Makefile的filter函数,过滤“$filter”集,只要其中模式为“%.o”的内容。其的它内容,我就不用多说了吧。这个例字展示了Makefile中更大的弹性。

    3.8 自动生成依赖性

    在Makefile中,我们的依赖关系可能会需要包含一系列的头文件,比如,如果我们的main.c中有一句“#include "defs.h"”,那么我们的依赖关系应该是:

       main.o : main.c defs.h

    但是,如果是一个比较大型的工程,你必需清楚哪些C文件包 含了哪些头文件,并且,你在加入或删除头文件时,也需要小心地修改Makefile,这是一个很没有维护性的工作。为了避免这种繁重而又容易出错的事情, 我们可以使用C/C++编译的一个功能。大多数的C/C++编译器都支持一个“-M”的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例 如,如果我们执行下面的命令:

       cc -M main.c

    其输出是:

       main.o : main.c defs.h

    于是由编译器自动生成的依赖关系,这样一来,你就不必再手动书写若干文件的依赖关系,而由编译器自动生成了。需要提醒一句的是,如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来。

    gcc-M main.c的输出是:

       main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h

            /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h

            /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h

            /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h

            /usr/include/bits/sched.h /usr/include/libio.h

            /usr/include/_G_config.h /usr/include/wchar.h

            /usr/include/bits/wchar.h /usr/include/gconv.h

            /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h

            /usr/include/bits/stdio_lim.h

     

    gcc-MM main.c的输出则是:

       main.o: main.c defs.h

    举例:

    [shannon@CentOS7-64 src]$ gcc -MM textswap.c
    textswap.o: textswap.c textswap.h readthrd.h writethrd.h version.h

  • 相关阅读:
    QR码与DM码的对比
    JBPM在Eclipse中运行时页面错误ProcessEngine cannot be resolved to a type
    C. A Mist of Florescence
    B. A Tide of Riverscape
    A. A Blend of Springtime
    A. Gennady the Dentist
    D. Lizard Era: Beginning
    E. Jzzhu and Apples
    D. Jzzhu and Cities
    C. Jzzhu and Chocolate
  • 原文地址:https://www.cnblogs.com/e-shannon/p/5756627.html
Copyright © 2011-2022 走看看