• unix/linux make


    GNU:make

    参考文档

    程序的编译和链接

    一般来说,无论是C还是C++,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。编译时,编译器需要的是语法的正确,函数与变量的声明的正确。只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件( .o 文件或 .obj 文件)。链接时,主要是链接函数和全局变量。所以,我们可以使用这些中间目标文件( .o 文件或 .obj 文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File)

    makefile使用

    基本写法:

    target ... : prerequisites..
    	command 
    
    • 1
    • 2
    • target:可以是一个object file(目标文件),也可以是一个执行文件,还可以是一个标签(label)。
    • prerequisite:生成该target所依赖的文件和/或target
    • command:该target要执行的命令(任意的shell命令)

    核心规则:执行make时,make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。makefile只有一个最终目标,第一条规则的目标为最终目标

    示例:一个包含3个头文件和8个c文件的的工程的Makefile内容

    # Makefile中第一行一定是最终目标
    edit : main.o kbd.o command.o display.o \
            insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
            insert.o search.o files.o utils.o
    
    main.o : main.c defs.h
        cc -c main.c
    kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
    command.o : command.c defs.h command.h
        cc -c command.c
    display.o : display.c defs.h buffer.h
        cc -c display.c
    insert.o : insert.c defs.h buffer.h
        cc -c insert.c
    search.o : search.c defs.h buffer.h
        cc -c search.c
    files.o : files.c defs.h buffer.h command.h
        cc -c files.c
    utils.o : utils.c defs.h
        cc -c utils.c
    clean :
        rm edit main.o kbd.o command.o display.o \
            insert.o search.o files.o utils.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    注:clean不是文件,它是一个动作,冒号后面什么也没有


    伪目标

    “伪目标”并不是一个文件,只是一个标签(label),由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显式地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义。为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显式地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”

    稳健的make clean做法

    .PHONY : clean
    clean :
        -rm edit $(objects)
    
    • 1
    • 2
    • 3

    .PHONY 表示 clean 是一个“伪目标”。而在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然, clean 的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样

    伪目标一般没有依赖的文件。但是,我们也可以为伪目标指定所依赖的文件。伪目标同样可以作为“默认目标”,只要将其放在第一个。 如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,可以使用伪目标的特性

    all : prog1 prog2 prog3
    .PHONY : all
    
    prog1 : prog1.o utils.o
        cc -o prog1 prog1.o utils.o
    
    prog2 : prog2.o
        cc -o prog2 prog2.o
    
    prog3 : prog3.o sort.o utils.o
        cc -o prog3 prog3.o sort.o utils.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    解释:Makefile中第一个目标是默认目标,即all。make通过隐式规则推导出all是一个伪目标,伪目标是一个标签不会生成文件,所以不会产生all文件,但是all依赖于其它三个目标,于是,其它三个目标的规则总是会被决议。也就达到了我们一口气生成多个目标的目的。

    这里的显式.PHONY : all 不写的话一般情况也可以正确的执行,这样make可通过隐式规则推导出, “all” 是一个伪目标,执行make不会生成“all”文件,而执行后面的多个目标。建议:显式写出是一个好习惯。

    伪目标也可以成为依赖

    .PHONY : cleanall cleanobj cleandiff
    
    cleanall : cleanobj cleandiff
        rm program
    
    cleanobj :
        rm *.o
    
    cleandiff :
        rm *.diff
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    make cleanall将清除所有要被清除的文件。cleanobjcleandiff这两个伪目标有点像“子程序”的意思。我们可以输入make cleanallmake cleanobjmake cleandiff命令来达到清除不同种类文件的目的


    隐含规则

    如果要使用隐含规则生成你需要的目标,你所需要做的就是不要写出这个目标的规则。那么,make会试图去自动推导产生这个目标的规则和命令,如果 make可以自动推导生成这个目标的规则和命令,那么这个行为就是隐含规则的自动推导。

    foo : foo.o bar.o
        cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
    
    • 1
    • 2

    等价于

    foo : foo.o bar.o
        cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
    foo.o : foo.c
        cc –c foo.c $(CFLAGS)
    bar.o : bar.c
        cc –c bar.c $(CFLAGS)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    常用隐含规则

    1. 编译C程序的隐含规则:
      .o 的目标的依赖目标会自动推导为 .c ,生成命令是$(CC) –c $(CPPFLAGS) $(CFLAGS)
    2. 编译C++程序的隐含规则:
      .o 的目标的依赖目标会自动推导为 .c 或.cc,并且其生成命令是 $(CXX) –c $(CPPFLAGS) $(CXXFLAGS) 。(建议使用 .cc 作为C++源文件的后缀,而不是 .C )
    3. 链接Object文件的隐含规则:
      目标依赖于 .o ,通过运行C的编译器来运行链接程序生成(一般是 ld ),其生成命令是: $(CC) $(LDFLAGS) .o $(LOADLIBES) $(LDLIBS) 。这个规则对于只有一个源文件的工程有效,同时也对多个Object文件(由不同的源文件生成)的也有效

    还含有其它规则,这些规则在make执行中是有顺序也就是优先级的

    隐含规则总使用的变量
    在隐含规则中的命令中,基本上都是使用了一些预先设置的变量。你可以在你的makefile中改变这些变量的值,或是在make的命令行中传入这些值,或是在你的环境变量中设置这些值,无论怎么样,只要设置了这些特定的变量,那么其就会对隐含规则起作用。

    例如,第一条隐含规则——编译C程序的隐含规则的命令是 $(CC) –c $(CFLAGS) $(CPPFLAGS) 。Make默认的编译命令是 cc ,如果你把变量 $(CC) 重定义成 gcc ,把变量 $(CFLAGS) 重定义成 -g ,那么,隐含规则中的命令全部会以 gcc –c -g $(CPPFLAGS) 的样子来执行了。

    变量分为命令相关(如CC),参数相关(CFLAGS),无默认值则为空
    在这里插入图片描述
    在这里插入图片描述


  • 相关阅读:
    14:00面试,14:06就出来了,问的问题有点变态。。。
    虚拟环境创建、配置及激活
    JVM GC 垃圾收集器
    XML DTD 初学
    市场调查与分析[市场调查员][抽样技术方案][抽样方法][F检验]
    elasticsearch通用工具类
    使用 pubsub-js 进行消息发布订阅
    疆御3行业版无人机基础飞行操作教程,教程适用于DJI Mavic 3E、DJI Mavic 3T
    推荐一种更加便捷的 Python 数据处理方式
    Elasticsearch:ES|QL 的限制
  • 原文地址:https://blog.csdn.net/good_jiojio/article/details/127884779