zoukankan      html  css  js  c++  java
  • Linux 编程学习笔记----动笔makefile档

    Befroe Beginning.

    在设置暑假的plan ,关于Linux的书籍如今在看的是ALP和Linux高级程序设计(杨宗德)第三版.在计划中的是Linux高级环境编程.

    如今開始关于Linux程序设计的第一篇学习笔记.

    本来打算把名字写成教程,只是认为自己全然是新手在自学,还是写学习笔记比較负责和适合.

    希望能够一起学习进步.

    引入

    首先我们如果这样一个场景.我们有一个程序包括了三个文件,各自是源代码文件main_plus,c和function_plus.c以及头文件mydefine_plus.h.

    当中main主要是调用功能函数,功能函数则是实现简单的累加,头文件声明函数和一些库函数.代码分别例如以下:

    main_plus.c

    /*************************************************************************
        > File Name: main_plus.c
        > Author: suool
        > Mail: 1020935219@qq.com 
        > Created Time: 2014年07月23日 星期三 17时31分23秒
    ************************************************************************/
    
    /**@file main_plus.c */
    /** 接收參数,调用功能函数,输出结果. */
    
    #include "mydefine_plus.h"
    
    int main(void)
    {
        int a=0, b=0;
        printf("这是一个求和的程序,请输入数字a和b,程序讲输出a到b的累加结果.
    ");
        printf("Please enter integer a:");
        scanf("%d", &a);
        printf("
    Please enter integer b:");
        scanf("%d", &b);
        if(a>b)
        {
            printf("
    The sum is %d
    ", plus(b,a));
        }
        else
        {
            printf("
    The sum is %d
    ", plus(a,b));
        }
        return 0;
    }
    function_plus.c
    /*************************************************************************
    	> File Name: function_plus.c
    	> Author: suool
    	> Mail: 1020935219@qq.com 
    	> Created Time: 2014年07月23日 星期三 17时31分40秒
     ************************************************************************/
    /**@file function_plus.c */
    /** 对a到b的累加求和*/
    
    #include "mydefine_plus.h"
    
    int plus(int a, int b)
    {
        int sum = a;
        int i;
        for (i=a+1; i<=b; i++)
        {
            sum += i;
        }
        return sum;
    }
    
    mydefine_plus.h.
    /*************************************************************************
    > File Name: mydefine_plus.h
    > Author: suool
    > Mail: 1020935219@qq.com 
    > Created Time: 2014年07月23日 星期三 17时36分16秒
    ************************************************************************/
    /** @file mydefine_plus.h */
    /** 函数声明和包括*/
    
    #ifndef _MYDEFINE_PLUS_H
    #define _MYDEFINE_PLUS_H
    #include <stdio.h>
    int plus(int a, int b);
    #endif
    

    如今我们要编译这个程序,我们能够怎么做呢?

    这就是这次要解决的问题.

    make文件编写

    对于上面的问题,我们传统的解决方法是这种:

    即是分别编译这两个文件,然后链接变成目标可运行文件,

    当然,对于三个甚至五个的这种程序都是能够的,可是假设对于更大的程序呢?

    或者我们改动了某个程序,难道要又一次编写这些命令?

    显然,这不是一个明智的选择,因此,我们便导出make文件,即自己主动运行编译的文件.仅仅要运行一下make命令,everything is done  !

    so, let`s see how to do it.

    首先我们先把这个程序的文件的makefile文件贴一下,例如以下:

    makefile

    main : main_plus.o function_plus.o
    	gcc -o main main_plus.o function_plus.o
    main_plus.o : main_plus.c mydefine_plus.h
    	gcc -c main_plus.c
    function_plus.o : function_plus.c mydefine_plus.h
    	gcc -c function_plus.c
    clean:
    	rm -f *.o main
    makefile文件的凝视是#后面的语句.

    有Makefile文件后,无论我们什么时候改动了源程序其中的什么文件,我们仅仅要运行make命令,我们的编译器都仅仅会去编译与我们改动的文件有关的文件,其他的文件不会处理.

    验证例如以下:先运行一次make命令,例如以下:

    这次自己主动编译了两个c文件,我们如今改动function_plus.c文件,再次运行make命令,结果例如以下:

    这次仅仅是对刚刚改动的文件进行了编译.


    makefile文件编写规则

    观察其结构我们能够得出make文件的编写基本规则:

    Makefile文件里,凝视以"#"開始

    Makefile文件里最重要的是描写叙述文件的依赖关系的说明,其一般的格式为:

    target : components

    TAB rule

    即是这样:

    目标 : 须要的条件 (注意冒号两边有空格)

        命令  (注意前面用tab键开头

    解释一下:

      1 目标能够是一个或多个,能够是Object File,也能够是运行文件,甚至能够是一个标签。

      2 须要的条件就是生成目标所须要的文件或目标

      3 命令就是生成目标所须要运行的脚本

      总结一下,就是说一条makefile规则规定了编译的依赖关系,也就是目标文件依赖于条件,生成规则用命令来描写叙述。

    在编译时。假设须要的条件的文件比目标更新的话。就会运行生成命令来更新目标。

    须要注意的是上面的claen命令,clean后面没有条件,而clean本身也不是文件,它仅仅只是是一个动作名字,其冒号后什么也没有,那么,make就不会自己主动去找文件的依赖性,也就不会自己主动运行其后所定义的命令。

    比如:上面的makefile文件的第一行,生成的终于的文件为main,他所依赖的是两个.o文件,而这两个文件依赖于源文件的编译.

    Makefile的经常使用变量

    Makefile 有三个很实用的变量:$@,$^,$<。其意义为:

    $@:目标文件

    $^:全部的依赖文件

    $<:第一个依赖文件

    则上面的可简化为:

    #这是简化后的Makefile
    main : main_plus.o function_plus.o
    	gcc -o $@ $^
    main_plus.o : main_plus.c mydefine_plus.h
    	gcc -c $<
    function_plus.o : function_plus.c mydefine_plus.h
    	gcc -c $<
    clean:
    	rm -f *.o main

    make怎样工作

    在默认的方式下,也就是我们仅仅输入make命令.那么,

        1.make会在当前文件夹下找名字叫“Makefile”或“makefile”的文件
        2.假设找到.它会找文件里的第一个目标文件(target),在上面的样例中,他会找到“main”这个文件,并把这个文件作为终于的目标文件
        3.假设main文件不存在,或是main所依赖的后面的 .o 文件的文件改动时间要比main这个文件新。那么。他就会运行后面所定义的命令来生成main这个文件
        4.假设main所依赖的.o文件也不存在,那么make会在当前文件里找目标为.o文件的依赖性。假设找到则再依据那一个规则生成.o文件。(这有点像一个堆栈的过程)
        5.当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是运行文件main了

    makefile中使用变量

    首先看下:

    main : main_plus.o function_plus.o
    	gcc -o $@ $^
    这里的依赖项有两个,可是假设有非常多个呢?那个时候我们须要添加新的依赖相,要在这里加入,假设没有使用符号,那么还须要在以下的命令下加入,因此,非常easy遗漏.But 还好,makefile能够定义变量,这样:

    object = main_plus.o function_plus.o
    main : $(object)
    	gcc -o $@ $(object)

    让make自己主动推导

    GNU的make非常强大,它能够自己主动推导文件以及文件依赖关系后面的命令,于是我们就不是必需去在每个[.o]文件后都写上类似的命令,由于,我们的make会自己主动识别,并自己推导命令。

    仅仅要make看到一个[.o]文件,它就会自己主动的把[.c]文件加在依赖关系中。假设make找到一个whatever.o,那么whatever.c。就会是whatever.o的依赖文件。

    而且 gcc -c whatever.c 也会被推导出来,于是,我们的makefile再也不用写得这么复杂。

    最新的makefile:

    #这是简化后的Makefile
    main : main_plus.o function_plus.o
    	gcc -o $@ $^
    main_plus.o : mydefine_plus.h
    function_plus.o : mydefine_plus.h
    clean:
    	rm -f *.o main

    清空目标文件的规则

    每一个Makefile中都应该写一个清空目标文件(.o和运行文件)的规则,这不仅便于重编译。也非常利于保持文件的清洁。一般的风格都是:

            clean:
                rm edit $(objects) $@

    更为稳健的做法是:

            .PHONY : clean
            clean :
                    -rm edit $(objects)

    前面说过,.PHONY意思表示clean是一个“伪目标”,。

    而在rm命令前面加了一个小减号的意思就是,或许某些文件出现故障。但不要管。继续做后面的事。当然,clean的规则不要放在文件的开头,不然。这就会变成make的默认目标。相信谁也不愿意这样。

    不成文的规矩是——“clean从来都是放在文件的最后”。


    so,大概的内容就是这样,接下来我要写一下关于C语言的东西了,由于既然是Linux程序设计,当然重点还是在语言和代码上面,而不是OS本身.

    接下来的内容:

    1.ANSI C文件I/O管理

    2.POSIX文件以及文件夹管理

    3.Linux一些编码功能和规格

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    《设计原本》读书笔记01
    SQL SERVER存储过程的几种示例
    SQLSERVER2008 存储过程基本语法
    (转)C#程序开发中经常遇到的10条实用的代码
    (转)C#正则表达式Regex类的用法
    常用正则表达式
    (转)通过WMI获取网卡MAC地址、硬盘序列号、主板序列号、CPU ID、BIOS序列号
    checkbox:全选与反全选
    checkbox:获取所有已选中的值
    Quartz(任务调度)- Cron
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4813967.html
Copyright © 2011-2022 走看看