linux c编程:make编译一
一个工程中的源文件不计其数,按照不同的功能分类在若干的目录里面,makefile定义了一系列的规则,来制定那些文件需要先编译,那些文件后编译,那些文件重新编译。makefile最大的好处就是自动化编译。一旦写好,只需要一个make命令,整个过程都自动编译。极大提高开发的效率。我们先来看个简单的例子:
如果一个工程里面有1个头文件calc.h和2个C文件main.c,calc.c
main.c的内容如下:
#include "stdio.h"
#include "calc.h"
int main()
{
int n,k;
int c;
n=3;
k=4;
c=calculate(n,k);
printf("the value is %d\n",c);
}
calc.c的内容如下:
#include "calc.h"
int calculate(int n,int k)
{
return n*k;
}
calc.h的内容如下:
#ifdef CALC_H
#define CALC_H
int calculate(int n,int k);
#endif
为了完成对工程文件案的编译,并生成执行文件main,按照如下的方式编译文件
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# gcc main.c calc.c -o main
但是如果我对main.c做了修改。就需要把所有源文件都重新编译一遍,即使其他文件没有任何变化。也要跟着重新编译。一个大的软件项目上千个源文件组成,编译一次耗时很长。一个源文件修改导致全部重新编译肯定不合理。我们可以这样优化下:
gcc -c main.c
gcc -c calc.c
gcc main.o calc.o -o main
如果编译之后有对main.c做了修改,重新编译之需要两步:
gcc -c main.c
gcc main.o calc.o -o main
这样比之前的要省事一些了,但还是有问题,在calc.c和main.c都包含了calc.h。如果我对calc.h做了改动。所有包含calc.h的文件都得改动。而且还得到处去找那些包含了calc.h。还是很麻烦。比如在calc.h中增加了一个宏定义。并且在man.c和calc.c中都有用到这个变量。那么一旦calc.h修改了宏定义变量的值。calc.c和main.c都必须重新编译。
#define max_value 40
那么我们需要一种什么样的编译方式才能最省事呢:
1 如果这个工程没有被编译过,那么我们的所有C文件都要编译并被链接
2 如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并连接目标程序
3 如果这个工程的头文件被修改了,那么我们需要编译引用了这几个头文件的C文件并链接目标程序。
能达到上述目的的就是makefile文件了。在工程的文件路径下新建一个Makefile文件。其中内容如下:
main:main.o calc.o
gcc -o main main.o calc.o
main.o:main.c calc.h
gcc -c main.c
calc.o:calc.c calc.h
gcc -c calc.c
clean:
rm *.o
rm main
执行make命令
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o
来看下Makefile的规则:
1 第一条规则的目标为main。而为了得到main,必须先得到main.o calc.o这2个文件。所以make会进一步查找这2个条件为目标的规则。
2 第二条规则和第三套规则的目标三main.o和calc.o。main.o依赖于main.c和calc.h。为了得到main.o必行执行gcc -c main. Calc.o依赖于calc.c和calc.h。为了得到calc.o必须执行gcc -c calc.c
3 最后的clean操作清除执行过程中产生的临时文件。当用make命令执行的时候,clean下的命令不会执行,要以make clean方式单独执行。执行后,所有*.o和main都被删除。
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 40
drwxr-xr-x 2 root root 4096 Nov 10 09:15 .
drwxr-xr-x 3 root root 4096 Nov 8 10:35 ..
-rw-r--r-- 1 root root 118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root 94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root 1056 Nov 10 09:15 calc.o
-rwxr-xr-x 1 root root 7396 Nov 10 09:15 main
-rw-r--r-- 1 root root 182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root 1196 Nov 10 09:15 main.o
-rw-r--r-- 1 root root 142 Nov 10 09:15 Makefile
执行make clean
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make clean
rm *.o
rm main
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# ls -al
total 24
drwxr-xr-x 2 root root 4096 Nov 10 09:29 .
drwxr-xr-x 3 root root 4096 Nov 8 10:35 ..
-rw-r--r-- 1 root root 118 Nov 10 08:55 calc.c
-rw-r--r-- 1 root root 94 Nov 10 08:54 calc.h
-rw-r--r-- 1 root root 182 Nov 10 08:56 main.c
-rw-r--r-- 1 root root 142 Nov 10 09:15 Makefile
下面我们来修改calc.h中的内容,#define max_value 50
看下编译内容。由于calc.c和main.c都包含了calc.h因此calc.c和main.c都会编译
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c main.c
gcc -c calc.c
gcc -o main main.o calc.o
如果只修改calc.c中的内容。calc.c修改如下
int calculate(int n,int k)
{
printf("the value is %d",max_value);
return n*k+n*k;
}
可以看到只编译了calc.c。main.c没有编译
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
gcc -c calc.c
gcc -o main main.o calc.o
当没有任何文件修改的时候:会提示main is up to date
root@zhf-linux:/home/zhf/zhf/c_prj/make_function# make
make: 'main' is up to date.
那么make是如何工作的呢:
1 make会在当前目录下查找名为makefile或者Makefile的文件
2 如果找到,它会找文件中的第一个目标文件,在上面的例子中,它会找到main这个文件
3 如果main不存在,或者main所依赖的后面的.o文件的修改时间比main晚,那么就会执行后面所定义的命令来生成main这个文件
4 如果main所依赖的.o文件存在,那么make会在当前文件中查找目标为.o文件的依赖性,如果找到,则再根据那个规则生成.o文件
5 当C文件和H文件存在时,make会生成.o文件。然后再用.o文件生成make的终结任务也就是执行文件main
也就是说,main会一层一层的寻找文件的依赖关系,直到编译出一个目标文件。如果在查找过程中依赖的文件找不到那么就会直接退出或报错。
继续来看下之前的makefile文件。在第一条规则的时候。.o文件被重复了两次。如果工程需要加入一个新的.o文件,那么就需要在2个地方加。如果makefile很复杂。那么就可有可能忘掉一个需要加入的地方。而导致编译失败。所以为了makefile的易维护,在makefile中可以使用变量。可以理解为C语言中的宏定义
main:main.o calc.o
gcc -o main main.o calc.o
文件修改如下:
objects=main.o calc.o
main:$(objects)
gcc -o main $(objects)
linux c编程:make编译一的更多相关文章
- 从事UNIX/LInux服务器编程最方便的代码编译工具------(eclipse for c/c++)、(FileZilla)、(Secure CRT) 这三种一定要一起使用 之1
今天主要是将前几天搞的Linux学习的心得写出来,希望帮助更多的人进行,方便从事Unix和Linux编程的同行和刚入门者.主要介绍三种工具并给出安装过程,请大家不必怀疑这个博文,此博文是我自己原创.请 ...
- 【linux草鞋应用编程系列】_5_ Linux网络编程
一.网络通信简介 第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章. 二.linux网络通信 在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...
- 学习linux/unix编程方法的建议(转)
假设你是计算机科班出身,计算机系的基本课程如数据结构.操作系统.体系结构.编译原理.计算机网络你全修过 我想大概可以分为4个阶段,水平从低到高从安装使用=>linux常用命令=>linux ...
- 初探linux内核编程,参数传递以及模块间函数调用
一.前言 我们一起从3个小例子来体验一下linux内核编程.如下: 1.内核编程之hello world 2.模块参数传递 3.模块间 ...
- linux网络编程_1
本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- [转] - Linux网络编程 -- 网络知识介绍
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...
- Linux网络编程10——使用UDP实现五子棋对战
思路 1. 通信 为了同步双方的棋盘,每当一方在棋盘上落子之后,都需要发送给对方一个msg消息,让对方知道落子位置.msg结构体如下: /* 用于发给对方的信息 */ typedef struct t ...
- Linux音频编程指南
Linux音频编程指南 虽然目前Linux的优势主要体现在网络服务方面,但事实上同样也有着非常丰富的媒体功能,本文就是以多媒体应用中最基本的声音为对象,介绍如何在Linux平台下开发实际的音频应用程序 ...
- Linux多线程编程和Linux 2.6下的NPTL
Linux多线程编程和Linux 2.6下的NPTL 在Linux 上,从内核角度而言,基本没有什么线程和进程的区别--大家都是进程.一个进程的多个线程只是多个特殊的进程他们虽然有各自的进程描述结构, ...
随机推荐
- NOI模拟题4 Problem C: 填格子(board)
Solution 首先我们要有敏锐的直觉: 我们将每一列中不选哪种颜色看作是一个序列, 则我们发现这个序列要求相邻两位的颜色不同. 我们还发现, 一个这样的序列对应两种不同的合法的棋盘, 因此统计合法 ...
- OpenSSL使用3(基本原理及生成过程)(转)
1. 基本原理 OpenSSL初接触的人恐怕最难的在于先理解各种概念 公钥/私钥/签名/验证签名/加密/解密/非对称加密 我们一般的加密是用一个密码加密文件,然后解密也用同样的密码.这很好理解,这个是 ...
- js 拦截全局 ajax 请求
你是否有过下面的需求:需要给所有ajax请求添加统一签名.需要统计某个接口被请求的次数.需要限制http请求的方法必须为get或post.需要分析别人网络协议等等,那么如何做?想想,如果能够拦截所有a ...
- Spring MVC 学习
一.基础 Spring MVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高.Spring 3.0更加完善,实现了对Struts 2的超越.现在 ...
- [field:description /]标签如何限制字数?|DedeCms
[field:description /]标签如何限制字数? [field:description function='cn_substr(@me,80)'/]dede 里的所有标记都支持这样使用函数 ...
- HDU1969
记得用PI=acos(-1)反三角函数求,用一次排序,然后二分和贪心 #include<iostream> #include<algorithm> #include<io ...
- linux调整缓存写入磁盘的时间,减少磁盘爆掉的可能性
缓存数据存入磁盘的最长时间,如果这段时间写不完,就会报异常停止写,这样缓存数据会不断积累,导致内存爆掉. echo 0 > /proc/sys/kernel/hung_task_timeout_ ...
- C++测试题练习题1
1.which of the following is not automatically generated by the compiler? a. default constructor b ...
- 终于会用c#中的delegate(委托)和event(事件)了 [转]
原文 : http://www.cnblogs.com/zhangchenliang/archive/2012/09/19/2694430.html 一.开篇忏悔 对自己最拿手的编程语言C#,我想对你 ...
- 使用Powermock和mockito来进行单元测试
转载:http://blog.csdn.net/u013428664/article/details/44095889 简介 Mockito是一个流行的Mocking框架.它使用起来简单,学习成本很低 ...