zoukankan      html  css  js  c++  java
  • make命令使用 & makefile编写详解

    • 为什么要使用make

    先来想像一个案例,假设我的可执行文件里面包含了四个源代码文件,分别是 main.c haha.c sin_value.c cos_value.c 这四个文件,这四个文件的目的是:

    main.c :主要的目的是让使用者输入角度数据与调用其他三支副程序;

    haha.c :输出一堆有的没有的讯息而已;

    sin_value.c :计算使用者输入的角度(360 sin 数值;

    cos_value.c :计算使用者输入的角度(360 cos 数值。

    这四个文件你可以到 http://linux.vbird.org/linux_basic/0520source/main.tgz 来下载。由于这四个文件里面包含了相关性,并且还用到数学函数在里面,所以如果你想要让这个程序可以跑, 那么就需要这样编译

    # 1. 先进行目标文件的编译,最终会有四个 *.o 的文件名出现:
    [root@study ~]# gcc -c main.c
    [root@study ~]# gcc -c haha.c
    [root@study ~]# gcc -c sin_value.c
    [root@study ~]# gcc -c cos_value.c
    # 2. 再进行链接成为可执行文件,并加入 libm 的数学函数,以产生 main 可执行文件:
    [root@study ~]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
    # 3. 本程序的执行结果,必须输入姓名、360 度角的角度值来计算:
    [root@study ~]# ./main
    Please input your name: VBird <==这里先输入名字
    Please enter the degree angle (ex> 90): 30 <==输入以 360 度角为主的角度
    Hi, Dear VBird, nice to meet you. <==这三行为输出的结果喔!
    The Sin is: 0.50
    The Cos is: 0.87

    编译的过程需要进行好多动作啊!而且如果要重新编译,则上述的流程得要重新来一遍,光是找出这些指令就够烦人的了! 如果可以的话,能不能一个步骤就给他完成上面所有的动作呢?那就利用 make 这个工具吧! 先试看看在这个目录下创建一个名为 makefile 的文件,内容如下:

    # 1. 先编辑 makefile 这个规则档,内容只要作出 main 这个可执行文件
    [root@study ~]# vim makefile
    main: main.o haha.o sin_value.o cos_value.o
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm
    # 注意:第二行的 gcc 之前是 <tab> 按键产生的空格喔!
    # 2. 尝试使用 makefile 制订的规则进行编译的行为:
    [root@study ~]# rm -f main *.o <==先将之前的目标文件去除
    [root@study ~]# make
    cc -c -o main.o main.c
    cc -c -o haha.o haha.c
    cc -c -o sin_value.o sin_value.c
    cc -c -o cos_value.o cos_value.c
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm
    # 此时 make 会去读取 makefile 的内容,并根据内容直接去给他编译相关的文件啰!
    # 3. 在不删除任何文件的情况下,重新执行一次编译的动作:
    [root@study ~]# make
    make: `main' is up to date.
    # 看到了吧!是否很方便呢!只会进行更新 (update) 的动作而已。

    如此一来,将可大大的节省很多编译的时间,要知道,某些程序在进行编译的行为时,会消耗很多的 CPU

    资源呢!所以说, make 有这些好处:

      • 简化编译时所需要下达的指令;
      • 若在编译完成之后,修改了某个源代码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file 不会被更动;
      • 最后可以依照相依性来更新 update 可执行文件。
    • makefile语法

    基本的 makefile 规则是这样的:标的(di四声)

    标的(target): 目标文件1 目标文件2
    <tab> gcc -o 欲创建的可执行文件 目标文件1 目标文件2
    

    那个标的 target 就是我们想要创建的信息,而目标文件就是具有相关性的 object files ,那创建可执行文件的语法就是以 <tab> 按键开头的那一行!特别给他留意喔,“命令列必须要以 tab 按键作为开头”才行!他的规则基本上是这样:

      • makefile 当中的 # 代表注解;
      • <tab> 需要在命令行 (例如 gcc 这个编译器指令) 的第一个字符;
      • 标的 target 与相依文件(就是目标文件)之间需以“:”隔开。

    同样的,我们以刚刚上一个小节的范例进一步说明,如果我想要有两个以上的执行动作时, 例如下达一个指令就直接清除掉所有的目标文件与可执行文件,该如何制作呢?

    # 1. 先编辑 makefile 来创建新的规则,此规则的标的名称为 clean :
    [root@study ~]# vi makefile
    main: main.o haha.o sin_value.o cos_value.o
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm
    clean:
    rm -f main main.o haha.o sin_value.o cos_value.o
    # 2. 以新的标的 (clean) 测试看看执行 make 的结果:
    [root@study ~]# make clean <==就是这里!通过 make 以 clean 为标的
    rm -rf main main.o haha.o sin_value.o cos_value.o

    如此一来,我们的 makefile 里面就具有至少两个标的,分别是 main clean ,如果我们想要创建 main 的话,输入“make main”,如果想要清除有的没的,输入“make clean”即可啊!而如果想要先清除目标文件再编译 main 这个程序的话,就可以这样输入:“make clean main”,如下所示:

    [root@study ~]# make clean main
    rm -rf main main.o haha.o sin_value.o cos_value.o
    cc -c -o main.o main.c
    cc -c -o haha.o haha.c
    cc -c -o sin_value.o sin_value.c
    cc -c -o cos_value.o cos_value.c
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm

    这样就很清楚了吧!但是,你是否会觉得,咦! makefile 里面怎么重复的数据这么多啊!没错!所以我们可以再借由 shell script 那时学到的“变量”来更简化 makefile 喔:

    [root@study ~]# vi makefile
    LIBS = -lm
    OBJS = main.o haha.o sin_value.o cos_value.o
    main: ${OBJS}
    gcc -o main ${OBJS} ${LIBS}
    clean:
    rm -f main ${OBJS}

    bash shell script 的语法有点不太相同,变量的基本语法为:

      1. 变量与变量内容以“=”隔开,同时两边可以具有空格;

      2. 变量左边不可以有 <tab> ,例如上面范例的第一行 LIBS 左边不可以是 <tab>;

      3. 变量与变量内容在“=”两边不能具有“:”;

      4. 在习惯上,变量最好是以“大写字母”为主;

      5. 运用变量时,以 ${变量} $(变量) 使用;

      6. 在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变量!

      7. 在指令列模式也可以给予变量。

    由于 gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,你可以直接在 shell 定义出这个环境变量,也可以在makefile 文件里面去定义,更可以在指令列当中给予这个咚咚呢!例如:

    [root@study ~]# CFLAGS="-Wall" make clean main
    # 这个动作在上 make 进行编译时,会去取用 CFLAGS 的变量内容!
    也可以这样:
    [root@study ~]# vi makefile
    LIBS = -lm
    OBJS = main.o haha.o sin_value.o cos_value.o
    CFLAGS = -Wall
    main: ${OBJS}
    gcc -o main ${OBJS} ${LIBS}
    clean:
    rm -f main ${OBJS}

    咦!我可以利用指令列进行环境变量的输入,也可以在文件内直接指定环境变量,那万一这个 CFLAGS 的内容在指令列与 makefile 里面并不相同时,以那个方式输入的为主?呵呵!问了个好问题啊! 环境变量取用的规则是这样的:

      1. make 指令列后面加上的环境变量为优先;

      2. makefile 里面指定的环境变量第二;

      3. shell 原本具有的环境变量第三。

    此外,还有一些特殊的变量需要了解的喔:

      •  $@:代表目前的标的(target)

    所以我也可以将 makefile 改成:

    [root@study ~]# vi makefile
    LIBS = -lm
    OBJS = main.o haha.o sin_value.o cos_value.o
    CFLAGS = -Wall
    main: ${OBJS}
    gcc -o $@ ${OBJS} ${LIBS} <==那个 $@ 就是 main !
    clean:
    rm -f main ${OBJS}

      

    Over......

  • 相关阅读:
    [转载]#2002 服务器没有响应 (或者本地 MySQL 服务器的套接字没有正确配置
    [转载]使用Cufon技术实现Web自定义字体
    [转载]Fedora14下MySQL、Apache、PHP、phpMyAdmin的安装步聚
    GUID的使用
    访问来源记录
    MongoDB数据库的基本概念
    域登录验证
    sql语法和MongoDB语法的对应关系
    ADO.NET数据集添加虚拟字段
    MongoDB开发常用资源地址
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14403733.html
Copyright © 2011-2022 走看看