Linux Makefile文件编写详细步骤与实践(转)

本文深入讲解Makefile的基础结构、变量、函数应用及实践案例,助力高效软件工程管理。

转需

    转载

    Linux Makefile文件编写详细步骤与实践

    1.makefile概述

     Windows环境下IDE会帮你完成makefile文件的编写,但在UNIX环境下你就必须自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile中也可以执行操作系统的命令。makefile带来的好处就是一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具。

    2.makefile文件的基本结构

    1.需要由make工具创建的目标体,一般是目标文件或可执行文件,也可以是一个标签,对于标签这种特性,在后续的“伪目标”章节中会有叙述。
      2.目标文件或可执行文件所依赖的文件。
      3.创建每个目标体时所需要执行的命令,这一行必须以制表符(tab)开头。
      target ... : prerequisites ...
      command
      ...
      ...
     

    3.makefile变量

    变量是在makefile中定义的名字,用来代表一个文本字符串,该文本字符串称为该变量的值,引用时用$引用。
    两种变量定义形式:
    1.递归定义展开方式:VAR=var,在引用该变量的时候进行替换,如果该变量中包含了对其他变量的引用,则在引用该变量的时候一次性将内嵌的变量全部展开。
    2.简单扩展方式:VAR:=var,在定义处展开,只展开一次,不包含对其他变量的引用,消除了嵌套引用。
    重新编写例程可以为:
    OBJS=talent.o hardwork.o
    CC=gcc
    CFLAGS=-Wall -O -g
    success:$(OBJS)
            $(CC) $(CFLAGS) $^ -o success
    talent.o:talent.c talent.h
            $(CC) $(CFLAGS) $^ -o talent.o
    hardwork.o:hardwork.c hardwork.h
            $(CC) $(CFLAGS) $^ -o hardwork.o

    说几个makefile中几个常见的预定义变量及其默认值:
      CC:C编译器的名称,默认cc;
      CFLAGS :C编译器的选项,无默认值;
      CXXFLAGS:C++编译器的选项,无默认值;
    makefile中几个常见的自动变量:
      $<:第一个依赖文件的名称;
      $^:所有不重复的依赖文件,以空格分开;
      $@:目标文件的完整名称;
      $?:所有时间戳比目标文件新的依赖文件,并以空格分开;
      当然还有几个就不介绍啦!

    4.一个简单的makefile

    
     
    1. /*add.c*/
    2. int add(int a,int b)
    3. {
    4. return (a+b);
    5. }
    
     
    1. /* sub.c*/
    2. int sub( int a, int b)
    3. {
    4. return (a-b);
    5. }
    
     
    1. /*mul.c*/
    2. int mul(int a,int b)
    3. {
    4. return (a*b);
    5. }
    
     
    1. #include <stdio.h>
    2. /*func_point.c*/
    3. int process(int (*math_p)(int,int),int x,int y);
    4. extern int add(int,int);
    5. extern int sub(int,int);
    6. extern int mul(int,int);
    7. extern int div(int,int);
    8. int main(void)
    9. {
    10. int a= 8,b= 2;
    11. printf( "add(8,2)=%d\n",process( add,a,b));
    12. printf( "sub(8,2)=%d\n",process(sub,a,b));
    13. printf( "mul(8,2)=%d\n",process(mul,a,b));
    14. printf( "div(8,2)=%d\n",process(div,a,b));
    15. return 0;
    16. }
    17. int process(int (*math_p)(int x,int y),int x,int y)
    18. {
    19. return(math_p(x,y));
    20. }

     

    
     
    1. #makefile
    2. func_point :func_point.o add .o sub .o mul .o div .o
    3. gcc func_point .o add .o sub .o mul .o div .o -o func_point
    4. add .o :add.c
    5. gcc -c add .c
    6. sub .o :sub.c
    7. gcc -c sub .c
    8. div .o :div.c
    9. gcc -c div .c
    10. mul .o :mul.c
    11. gcc -c mul .c
    12. func_point .o :func_point.c
    13. gcc -c func_point .c

    执行make命令的时候,找到缺省的target,即func_point。func_point之后是它的prerequisites文件,首先找到func_point.o这个文件,但这个文件又是后续的target文件,再找到func_point.o目标的prerequisites文件。然后执行func_point.o目标文件下的command,command执行完毕返回上级;找到add.o这个文件,add.o又是后续的目标文件,然后找到add.o目标文件的prerequisites文件,然后执行add.o目标文件的command,执行完毕...依次递归...最后执行func_point目标文件的command。到此为止,这个文件就编译完成了。#后面表示注释。
       读者仔细观察,所有的target文件都要比prerequisites文件新。add.o、sub.o、mul.o、div.o比这些文件的prerequisites文件新。如果有任意一个prerequisites文件比target文件新,那target所对应的command就被执行。这就是Makefile的规则,也是Makefile的核心内容。
       通常Makefile有一个clean目标,用于清除编译过程中产生的中间文件,保留源代码。现在将目标clean加入到我们的Makefile中。

    
     
    1. #makefile
    2. func_point :func_point.o add .o sub .o mul .o div .o
    3. gcc func_point .o add .o sub .o mul .o div .o -o func_point
    4. add .o :add.c
    5. gcc -c add .c
    6. sub .o :sub.c
    7. gcc -c sub .c
    8. div .o :div.c
    9. gcc -c div .c
    10. mul .o :mul.c
    11. gcc -c mul .c
    12. func_point .o :func_point.c
    13. gcc -c func_point .c
    14. clean:
    15. @ echo "clean project"
    16. -rm *.o
    17. @echo "clean complete"

     

    如果在make命令后边跟一个target。那就从这个target开始,如果不指定,那就取默认的,就是第一个target。@符号屏蔽命令的显示,只是将命令执行结果显示到屏幕上。- 符号的意思是不管这条命令执行成功与否,都要继续执行下边的命令。clean目标比较特殊,没有任何prerequisites文件,并且执行它的命令不会生成clean文件。再次次执行make clean,这时所有的目标文件已经清楚了,rm  *.o 这条命令会报错,但是继续执行后边的echo命令。
       如果在当前工作路径下有一个clean文件,我们makefile文件中的clean执行就会被忽略,在我们原来Makefile的最后一行加如下代码就可以了:
      .PHONY:clean
        clean是一个约定俗称的目标,像这样的约定还有。
      all:通常为缺省的目标,执行缺省的编译工作。
      install:编译后的安装工作,将相应的文件拷贝到合适的位置。
      distclean:清除所有编译中生成的文件,只保留源文件。
        好啦!下面我们对刚才的makefile文件进行一下瘦身:

    
     
    1. #makefile
    2. OBJ_FILE=func_point.o add.o sub.o div.o mul.o
    3. func_point:$(OBJ_FILE)
    4. gcc $^ -o $@
    5. clean:
    6. @echo "clean project"
    7. -rm *.o
    8. @echo "clean complete"
    9. . PHONY:clean

    5.函数的使用

       在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
      $(<function>; <arguments>;)或是${<function>; <arguments>;}
      这里,<function>;就是函数名,make支持的函数不多。<arguments>;是函数的参数,参数间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。

    
     
    1. #makefile
    2. SRC_FILE=$(wildcard *.c)
    3. func_point:$(SRC_FILE)
    4. gcc $^ -o $@
    5. clean:
    6. @echo "clean project"
    7. -rm *.o
    8. @echo "clean complete"
    9. . PHONY:clean
    1. /*wildcard是函数的名字,这是系统提供的函数,*.c 是函数的参数。这句话的意思是找出当前工作路径下的所有的以.c结尾的源文件。然后将返回值初始化SRC_FILE变量。 
    2.    -n选项只打印要执行的命令,而不会真的执行命令,这个选项有助于我们检查Makefile写得是否正确,由于Makefile不是顺序执行的,用这个选项可以先看看命令的执行顺序,确认无误了再真正执行命令。 
    3.    -C选项可以切换到另一个目录执行那个目录下的Makefile,比如先退到上一级目录再执行我们的Makefile。 -C后边跟那个目录就行了。*/ 

    6.小项目实践

       假设math目录下有前面的add.c sub.c mul.c div.c源文件,与math同目录下有func_point.c文件!
       math目录下makefile文件如下:

    
     
    1. #Makefile
    2. mymath :add.c sub .c div .c mul .c
    3. gcc -c -fPIC add .c sub .c div .c mul .c
    4. gcc -shared -o libmymath .so add .o sub .o mul .o div .o
    5. # gcc func_point .c -lmymath -o test
    6. install:
    7. @ sudo mv libmymath.so /usr/lib
    8. #test:func_point.c
    9. # gcc func_point -lmymath
    10. clean:
    11. @echo "clean project"
    12. -rm *.o
    13. @echo "clean complete"
    14. .PHONY:clean

    与math同级目录下makefile文件如下:

    
     
    1. all:
    2. make -C math
    3. make -C math install
    4. make -C math clean
    5. gcc func_point.c -Lmath -lmymath -o test

     

    程序介绍:在math同级目录下运行make命令时,它会把math目录下的add.c sub.c mul.c div.c生成动态链接库,并拷贝到/usr/lib中,后清除中间过程文件,在math同级目录下可运行test可执行程序。
        如有错误,欢迎批评改正!

     

     

    0 个人打赏
    文章最后发布于: 2019-04-11 10:27:07
    评论 1
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值