您的位置:首页 > 运维架构 > Linux

学习make工具的用法及makefile的写法

2007-11-23 10:55 477 查看
  目前,Windows平台(Windows 95/98/ME/NT/2000/XP)、Linux和Unix平台都提供make工具,开发人员可以利用自定义的makefile来自动完成程序的编译、代码生成、打包和文档发布等工作,十分方便。
所有的这些make工具都是命令行工具,而且各个平台下的makefile文件格式相识,但又各不相同,有很大细节上的差异,另外make的实现也不一样。需要学习后加以使用:
Windows:
Microsoft ---nmake (6.0) ----随MS VS6.0发布。用于Microsoft开发环境。
Borland---make(5.2) ---随Borland 公司的软件开发工具发布(delphi 5 C++Builder 6,etc),用于Borland 开发环境。
Linux:
GNU---gmake,make, 在Linux中gmake和make是一样的。
SunOS:
CCS & XPG4 ---make, 是unix中通用的make
GNU ---gmake, 是与gnu开发工具配合使用的工具。
一、目的
(1) 掌握以上提到的各种make工具的命令行开关用法及相应的makefile的写法
(2) 学会使用make来进行C/CPP 工程项目的自动build。
(3) 学习的重点在Unix 的 make 和GNU的gmake。
二、实例学习
2.1.创建一个仅包含一个文件的程序helloc
在系统中,自己的工作目录内创建一个目录helloc

并生成包含如下内容的helloc.c文件:

#include <stdio.h>

int main()
{
    int i, out;
    printf("%s/n", "Hello, Welcome to C world");
    i = 20;
    out = Fac(i);
    printf("I'd like show you the Fac( %d ) = %d ./n", i, out);
    return 0;
}

int Fac(int i)
{
if (i<=0) {return 0;}else if ( (1==i) || (2==i) ) {return 1;}
else if (i <= 1000 ) { return Fac(i-2) + Fac( i -1 ); } else { return -1;}
}

以及一个helloc.h文件
#ifndef HELLO_H
#define HELLO_H

int Fac(int i);
#endif
 
你可以在多个操作系统下编译它,
Windows: VC6
在“我的电脑--属性--高级--环境变量”中, 添加如下变量:
INCLUDE (这个环境变数告诉编译器说,必要的 libraries 在哪里)
D:/Program Files/Microsoft Visual Studio/VC98/Include
LIB(告诉编译器说,必要的 header files 在哪里)
D:/Program Files/Microsoft Visual Studio/VC98/Lib
PATH(为了让我们能够在任何 working directory 都叫得到编译器,当然我们必须设定 PATH)
X:/Program Files/Microsoft Visual Studio/Common/MSDev98/Bin;X:/Program Files/Microsoft Visual Studio/VC98/Bin
X表示安装盘符,注意这里是两个路径,因为cl.exe要用到MSDev98/Bin目录下的MSPDB60.DLL。
也可以写一个批次档(Microsoft Visual Studio/VC98/Bin/VCVARS32.BAT)如下:
set PATH=C:/BORLAND/CBuilder3/BIN
set INCLUDE=C:/BORLAND/CBuilder3/INCLUDE
set LIB=C:/BORLAND/CBuilder3/LIB
如果已经存在这些变量,则把以上值分别加在对应的变量值的后面,注意在添加前用分号隔开。
命令提示符:
cl hello.c,编译程序会生成.obj和.exe。(cl是MS 的C/C++ compiler命令行版,版本号一般是12.0(随MS VS 6发布),)
 
Linux: cc hello.c 或 gcc hello.c,编译程序会生成缺省的a.out文件,可以执行。(一般情况下在linux中cc与gcc相同。是GNU的通用编译器(一般是gcc 2.91,2.95或3.0,其中2.91是稳定版本,一般叫egcs)。)

SunOS: cc hello.c 与Linux中的gcc一样,也会产生一个a.out文件。
运行程序得到的结果如下:
Hello, Welcome to C world
I'd like show you the Fac( 20 ) = 6765 .
可以得出结论,仅包含一个源文件的程序,无须采用什么makefile就可以简单地编译。
 
下面我们来看一个稍微复杂的情况。
2.2.包含两个源文件的工程C1
首先是c1.cpp文件:
// c1.cpp : Defines the entry point for the console application.
#include <iostream.h>
#include "complex.h"
int main(int argc, char* argv[])
{
    cout<<"Hello World!/n"<<endl;
    // TODO: Place code here.
    Complex a(1.5, 3.0), b(2.0, 3.0);
    cout<<"The result of b(1.5, 3.0) == b(2.0, 3.0) is:"<<(a==b?"True": "False")<<endl;
    Complex c(1.0, 3.0), d(1.0, 3.0);
    cout<<"The result of b(1.0, 3.0) == b(1.0, 3.0) is:"<<(c==d?"True": "False")<<endl;
    return 0;
}

接着是complex.cpp:
//complex.cpp
#include "complex.h"
template <typename T> bool eq(T& a, T&b)
{ return (a==b);}
bool operator ==( const Complex &a, const Complex &b )
{ return eq( a.real, b.real )  &&  eq( a.imaginary, b.imaginary ); }
 
complex.cpp的头文件如下:
//complex.h
class Complex
{
  friend bool operator ==(const Complex& a, const Complex& b);
  double real, imaginary;
public:
  Complex( double r, double i = 0 ) : real(r), imaginary(i) {}
};
template <typename T> bool eq(T& a, T&b);

这下我们该如何进行呢?
首先考虑在Windows平台下:
>c1 complex.cpp
OK,提示生成了complex.obj
>cl c1.cpp
OK,提示生成了c1.obj
没有.exe,怎么办?用另一个工具link.exe。
>link c1.obj compex.obj
OK,提示生成了c1.exe,很好!运行c1.exe得到:
Hello World!
The result of b(1.5, 3.0) == b(2.0, 3.0) is:False
The result of b(1.0, 3.0) == b(1.0, 3.0) is:True
正确!当然我们可以通过给link加上开关/out:filename来指定一个喜欢的可执行文件名称,而不是link按规则给出的名称,不如执行link c1.obj complex.obj /out:testcomp.exe就将生成complex.exe可执行文件。
 
在Linux中和Unix上,你可以通过下列命令生成可执行文件:
%gcc –c –o complex.o complex.cpp
%gcc –c –o c1.o c1.cpp
%gcc c1.o complex.o –o testcomp
上面的-c参数是指定编译器编译出一个.o文件就可以了,不要再寻找main()函数做链接工作
生成可执行文件testcomp,如果你的系统中gcc不起作用换CC或者cc或者ecgs试试。
的确,多个文件也可以不用make就能生成我们所需的结果。但步骤多。随着工程文件增大,所需输入的命令行将多的无法忍受。这是就的确需要makefile来帮忙了。
2.3.创建第一个make文件
参照《VC++ programmer guide》的帮助,我们写出一个makefile文件,命名为makefile.win,内容如下:
CC = cl
LINK=link
C1OBJS = c1.obj /
complex.obj
all :  c1build
echo "build OK!"
c1build: complex.obj c1.obj
$(LINK) c1.obj complex.obj /out:testcomp.exe
complex.obj:
$(CC) -c complex.cpp
c1.obj:
$(CC) -c c1.cpp
接下来我们执行nmake –f makefile.win, 哦“build OK!”,我们的确可以在目录中找到testcomp.exe。很显然,我们成功了。如果你的计算机中装有Borland 的开发工具,你键入make –f makefile.win,提示的结果是一样的,更妙了,这说明Borland 和 MS的make工具都认识这个makefile。
好了,别以为这就到此为止了,我们还要把这个makefile移植到Linux和SunOS中,最后还要尝试编用在这三种平台下都能make的统一make文件。是不是很cool,不久,你就成了跨平台编程高手了。(快学吧,别得意,这仅仅是雕虫小技!J)
 
2.4.将makefile向Linux和SunOS移植
当我们将工作平台换成Linux (kernel 2.x以上)或SunOS(4.x以上)后,其中cl 和 link就应该更改成统一文件gcc、cc或者CC了。
另外开编译器所用的开关符号也要由“/”转换为“-”,编译后的目标文件后缀一般为.o,而不是Windows下的.obj,执行文件也无须加上.exe后缀,系统是靠文件的权限来识别文件是否可执行的,好!先来看看更改好的makefile.linux文件:
CC = cc
C1OBJS = c1.o /
complex.o
all :  c1build
echo "build OK!"
c1build: complex.o c1.o
$(CC) c1.o complex.o -lstdc++ -o testcomp
complex.obj:
$(CC) -I. -I/usr/include -c  -o complex.o complex.cpp
c1.obj:
$(CC) -I. -I/usr/include -c  -o c1.o c1.cpp
makefile的文件结构上基本上与windows下的一样,细微的差别在编译器的开关和各个平台下的习惯风格。注意开关-lstdc++表示连接程序时使用标准C++库,开关-I表示头文件的查找位置。
在Linux下执行同样的命令:make –f makefile.linux,结果一定是告诉你生成好了testcomp文件,如果不是,把make换成gmake试试,还不行,将makefile中 CC=cc换成CC=gcc在试,…,一定会行的。当你得到testcomp,执行它,你一定会得到在windows下的同样结果
噢,现在Linux下的make搞定了,现在该来玩SunOS了。先原分不动地将这个工程中所有ftp到一个SunOS下,4.x以上版本就可以了,为了不混淆,将makefile.linux拷贝成makefile.solaris,执行同样的命令:make –f makefile.solaris,看看你有什么结果:
CC c1.o complex.o -lstdc++ -o testcomp
ld: fatal: library -lstdc++: not found

看样子是找不到C++标准库的原因,好办,将-lstdc++改成-lCstd,你在试试,你肯定大喜过望,make成功了。太好了,从Linux到SunOS基本没改动什么。

Makefile的确很好,在各种平台间移植可参考性很好。现在,我们已经大概了解Make工具及makefile的用法和写法了。
用make命令来编译自己写的程序确实是很方便。一般情况下,大家都是手工写一个简单Makefile,如果要想写出一个符合自由软件惯例的Makefile就不那么容易了。 Autoconfautomake两个工具可以来帮助我们自动地生成符合自由软件惯例的Makefile,这样就可以象常见的GNU程序一样,只要使用“./configure”,“make”,“make instal”就可以把程序安装到Linux系统中去了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息