学习写makefile
来源:互联网 发布:ambari web 源码编译 编辑:程序博客网 时间:2024/06/04 00:51
学习写makefile
一、本文的起因:
刚毕业到公司之后,系统中都是linux c++程序,开始编写测试程序的时候,只会用命令g++ -g -O -o test test.cpp进行编写,每次打字都很累。。。
上网查了一下,可以直接编写makefile文件,然后直接make即可。于是自己尝试去写,结果好几次都失败了:下一行命令应该用tab键,结果打了好多空格,报了很多错误。
接着又是没有耐心去看繁琐的规则和格式,总也写不好一个完整的makefile。
于是,就放弃写makefile了。直接用公司写好的makefile模板,简单、方便!
最近,觉得自己要积累点知识了,而不是随着项目内容飘来飘去。
所以,本文理论部分基本上是网上内容的总结。加入了自己的理解。如有错误,敬请指出! 谢谢!
涉及到的来源:
http://blog.csdn.net/ruglcc/article/details/7814546/
二、实际的例子
我们先从makefile基本语法开始,再给出自己写makefile的例子,进行逐步深入讲解:
1. makefile基本语法
target ... : prerequisites ... #可以有多目标
command
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
prerequisites就是,要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
2. 逐步学习的例子
看过了makefile基本语法的例子,那么就勇敢地着手写一个吧!因为编写好了makefile后,只需make,即可完成整个编译过程。后续再增加或删除源代码文件,也只需简单修改makefile文件即可。
源代码如下:
main.cpp
#include "hello.h"#include "cal.h"#include <iostream>using namespace std;int main(int argc, char *argv[]){ cout << "begin to print hello-------------------" << endl; print_hello(); print_hello(3); int a = 3; int b = 4; int retcode = 0; cout << "begin to calculate-------------------" << endl; retcode = cal_minus(a,b); retcode = cal_plus(a,b); return 0;}
hello.h
#include <stdio.h>#include <unistd.h>#include <stdlib.h>int print_hello();int print_hello(int times);
hello.cpp
#include "hello.h"#include <iostream>using namespace std;int print_hello(){<span style="white-space:pre"></span>cout << "this is Hello Function!" << endl; return 0;}int print_hello(int times){ if (times <= 0){<span style="white-space:pre"></span>return -1;}<span style="white-space:pre"></span>for (int i = 0; i < times; i++)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>cout << "this is [" << i << "] hello!" << endl; <span style="white-space:pre"></span>} return 0;}
cal.h
#include <stdio.h>#include <unistd.h>#include <stdlib.h>int cal_plus(int a, int b);int cal_minus(int a, int b);
cal.cpp
#include "cal.h"#include <iostream>using namespace std;int cal_plus(int a, int b){ cout << a << "+" << b << "=" << a+b << endl; return (a+b);}int cal_minus(int a, int b){ cout << a << "-" << b << "=" << a-b << endl; return (a-b);}
从代码中可以看到:main.cpp引用了hello.h和cal.h两个头文件,为了使用它们中定义的函数。
2.1 第一版makefile如下:
cc=g++ccflag=-Wall -fpicmain:main.o hello.o cal.o$(cc) -o main main.o hello.o cal.omain.o:main.cpp$(cc) -c main.cppcal.o:cal.cpp cal.h$(cc) -c cal.cpphello.o:hello.cpp hello.h$(cc) -c hello.cppclean:rm *.orm main本文件中清晰地写好了:
1)目标文件main依赖哪些中间文件,main是如何生成的(通过$(cc) -o main main.o hello.o cal.o)
2)中间文件main.o cal.o hello.o依赖哪些源文件和头文件,并通过什么命令生成的。
3)最后,clean是个为目标,通过make clean命令调用 rm *.o rm main
2.2 优化2.1中的makefile
下面是优化的makefile:
cc=g++ccflag=-Wall -fpicmain:main.o hello.o cal.o$(cc) -o $@ $^main.o:main.cpp$(cc) -c main.cppcal.o:cal.cpp cal.h$(cc) -c cal.cpphello.o:hello.cpp hello.h$(cc) -c hello.cppclean:rm *.orm main
2.3 优化2.2中的makefile
下面是优化的makefile:
main:main.o hello.o cal.og++ -o $@ $^%.o:%.cppg++ -c $^clean:rm *.orm main
以下为详细而全面的makefile编写方法:
先说一下编译和链接,这是我们写makefile的最终目的:
0.1 关于程序的编译和链接
在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。
编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。
链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。
总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的ObjectFile.
补充一下自己的经验:gcc和g++编译器都可以进行中间文件的编译,同时也可以链接中间文件形成目标文件。所以,在makefile中,无论是编译中间文件,还是生成目标文件的编译,都是使用gcc或者g++来完成的(When you invoke GCC, it normally does preprocessing, compilation, assembly and linking.)。其中gcc主要编译c程序,g++主要编译g++文件。
还有,需要了解gcc和g++如何使用,也是makefile中重要的一部分。
- Makefile学习教程: 写 Makefile
- 学习写Makefile
- 学习写Makefile文件
- 学习写makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile (1)
- Makefile学习教程: 跟我一起写 Makefile (2)
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Makefile学习教程: 跟我一起写 Makefile
- Java 8: Streams API
- Aizu 0189
- Educational Codeforces Round 15(简单题)
- POJ 2377
- 16-07-31 Cannot refer to the non-final local variable homePageInfo defined in an enclosing scope
- 学习写makefile
- 程序员喜欢的9款最佳的Linux文件比较工具
- NOJ 1031 建筑群最长坡值 简单dp
- POJ 1151
- Struts2中的constant配置详解
- HDU 5776 sum
- Java 设计模式之原型模式的详解(创建模式)
- LeetCode 347 Top K Frequent Elements
- ntlk入门函数解释(text相加, join, split, 数组坐标调用)