本文转自:http://blog.csdn.net/clever101/article/details/8147352

决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译平台的问题(发现一些开源代码已经在使用VS2010开发,但我还没安装VS2010,我想在VS2008下编译这些代码);另一方面源码在服务器端编译的话,使用IDE的方式编译还是不太方便。

本文主要分为三部分:第一部分讲述namke工具使用makefile的用法;第二部分讲述makefile的主要语法;第三部分讲述自己动手实践学习写makefile文件。第四部分是编写一个工具将vc工程文件转化为Makefile文件。

首先要清楚的是在VS环境下使用Makefile的工具是nmake。因此我们需要弄明白nmake的使用Makefile文件常用命名行用法。nmake使用Makefile文件常用命名行用法是:

namke /f  makefile /x stderrfile  [macrodefs] [targets]

其中makefile为makefile文件,/x stderrfile为可选参数,即把namke错误存储到文件stderrfile。

接着介绍makefile的主要语法。makefile的注释以#开头,如:

# this is my first makefile

Makefile的一个重要组成部分是宏。Makefile中的宏和C语言的中宏类似,其实质就是字符串替换。其语法很简单,如下:

macro name =  macro value

直译就是宏名 =  宏的值

VS预定义了很多宏,如OUTDIR,你可以在你的Makefile重新定义这些宏以覆盖原来的值。

宏可以使用环境变量,如你的系统有一个OPEN_SOURCE的环境变量,然后你可以这样定义宏:

THIRD_PARTY  =  $(OPEN_SOURCE)

宏的引用用法是 $(宏名)。

接着介绍Makefile的第二个重要组成部分预处理指令。Makefile的预处理指令和C语言的预处理指令类似,其常用指令如下:

!ERROR string      ——    显示错误“string”, 然后停止执行,错误代码为U1050

!MESSAGE string  ——   显示字符串,这个一般用于信息显示C语言的#pragma message

!INCLUDE [<]filename[>] —— 包含makefile。

!IF const ——  如果成立(非零),则处理!F和下一个!ELSE或!ENDIF之间的语句

还有诸如!IFDEF macroname、!IFNDEF macroname、!ELSE、!ELSEIF、!ELSEIFDEF、!ELSEIFNDEF、!ENDIF和C语言的#if之类的指令的意义是一致的,这里就不一一详述了。

Makefile的第三个主要组成部分是描述块。描述块的结构如下:

目标:依赖项

命令

这里略微解释下什么叫目标、依赖项和命令。所谓目标就是用户最终希望得到的结果,也就是nmake需要生成的结果。目标可以是一个文件、目录,也可以什么都不是。如果目标不存在或者目标的时间戳(文件的最后修改时间)比依赖项早,或者目标类型不是文件,nmake将运行描述块中的“命令”。

依赖项是指在生成目标所需要使用到的对象。一个目标可以有一个或多个依赖项,也可以没有依赖项。多个依赖项以空格分隔。如果指定的依赖项不存在,则在其他描述块的目标中寻找,但首先需要生成这个目标。

命令是nmake在生成目标时所调用的命令。与用户自己在命令行中执行效果是一样的。

在使用namke进行程序构建时,nmake采用了时间戳判断机制。在生成一个目标时,会判断目标文件是否存在或目标的最后修改时间是否晚于所有依赖项的最后修改时间。如果所有依赖项的最后修改时间都比目标的最后修改时间晚,则说明当前的目标文件是使用现有的依赖项生成,是最新的,没有必要再进行生成。

介绍到这里,可能你对Mdakefile的语法细节有了大致的了解,但估计你对Makefile的常用文件结构还不了解。如果缺少对这一层的理解,你还是对如何编写Makefile文件一头雾水。下面介绍一下常用的Makefile文件结构。Makefile文件结构可以是如下的结构:

# 宏定义

……

# 描述块

学了这么多,我们来实践一下。首先我们来一个简单的控制台工程——ConsoleTest。一切根据工程向导采用默认设置即可。然后在main函数中添加几句简单代码(这个用于判断我们生成的程序是否成功),具体如下:

int _tmain(int argc, _TCHAR* argv[])
{
printf("Hello World! \n");
getchar();
return ;
}

然后我们在ConsoleTest文件夹下新建一个makefile.vc。我们开始正式编写一个makefile文件了。这时我们的大脑可能会一片空白,虽然你学了很多makefile语法,但迈出第一步依然是困难,这是正常的反应。好吧,让我们一步步来吧。首先要告诉你makefile的一个基本原则:以终为始,这个似乎和我们平时进行的过程式编程的原则相悖。所谓以终为始,就是你通过makefile文件首先告诉编译器这个工程是想生成一个exe还是一个dll还是一个静态库。然后告诉编译器要生成这个exe之类需要生成哪些obj文件。在这个例子中,我们要生成一个exe,所以我们在makefile文件的第一行就是:

all:ConsoleTest.exe

接下来就是编译器的一般生成过程:编译加链接命令,具体是

# compile
stdafx.obj: stdafx.cpp
cl -c -D_X86= -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h stdafx.cpp ConsoleTest.obj: ConsoleTest.cpp stdafx.obj
cl -c -D_X86= -DWIN32 -D_DEBUG -D_CONSOLE -Istdafx.h ConsoleTest.cpp # link
ConsoleTest.exe: ConsoleTest.obj
link /INCREMENTAL:YES /NOLOGO /subsystem:console /out:ConsoleTest.exe ConsoleTest.obj kernel32.lib

其中cl语句是VC编译器的编译器的命令行编译,link语句是VC链接器的命令行用法,这里只简单叙述cl和link的用法。

cl的一些常用选项:

-c: 编译但不链接

-D: 定义预处理器,如-D_X86=1:指定在x86平台上编译,-D_DEBUG:定义预处理器_DEBUG,

-I:包含的头文件

cl的最后一个参数是所编译的文件。

link的一些常用选项:

/INCREMENTAL:是否启用增量链接,YES为启用,NO为不启用,

/NOLOGO: 取消显示启动版权标志

/SUBSYSTEM:指定子系统,在PC桌面程序上一般是两个选项:console(控制台程序)和WINDOWS(非控制台程序)。

/out: 指定输出的文件。

link最后的参数是需要链接的obj文件和库文件。

cl和link的详细用法请参考MSDN和参考文献2《VC命令行编译C++》。

我们看到生成的obj文件和ConsoleTest.exe是放到当前的源码文件夹下。一般我们想把它放到debug文件夹下。那么我们该怎么做呢?这时就可以用到makefile中的一个常用部分——宏。我们可以这样定义一个宏,然后创建debug文件夹,具体代码是:

OUTDIR = .\Debug

#这里增加了一个输出:$(OUTDIR)

all: $(OUTDIR) $(OUTDIR)\ConsoleTest.exe

#假如不存在$(OUTDIR)文件夹,就创建它

<转>Windows平台下Makefile学习笔记(一)的更多相关文章

  1. [转]Windows平台下Makefile学习笔记

    Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译 ...

  2. <转>Windows平台下Makefile学习笔记(二)

    本文转自:http://blog.csdn.net/clever101/article/details/8286066 上次我们学习了怎么用Makefile编译一个控制台工程.这次我们学习一下如何使用 ...

  3. 【VS开发】Windows平台下Makefile学习笔记

    作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译平台的问题(发现一些开源代码已经在使用VS2010开 ...

  4. windows平台下VLC2.0.5编译

    windows平台下VLC2.0.5编译说明 时隔一年多,又要搞流媒体了,不过这次是要做流媒体服务器. 暂时决定使用vlc+ffmpeg+live555,虽然听有些前辈说这个组合的性能较差,只能作为学 ...

  5. Windows平台下MySQL常用操作与命令

    Windows平台下MySQL常用操作与命令 Windows平台下MySQL常用操作与命令,学习mysql的朋友可以参考下. 1.导出整个数据库 mysqldump -u 用户名 -p --defau ...

  6. Windows平台下Git服务器搭建

    第一步:下载Java,下载地址:http://www.java.com/zh_CN/ 第二步:安装Java.安装步骤不再详述. 第三步:配置Java环境变量. 右键”计算机” => ”属性” = ...

  7. Windows平台下PHP开发环境的配置

    Windows平台下PHP开发环境的配置 一.基本环境 1.Windows XP 32位 2.Apache 2.2.25,下载地址:http://mirror.bit.edu.cn/apache/ht ...

  8. Mac平台与Windows平台下AndroidStudio增量升级

    Android Studio增量升级什么情况下使用最合适呢? 比如现在的as版本是2.2版本,而你的as版本2.0版本,这个时候点Check For Updates就没有反应了,因为你已经2个有版本没 ...

  9. Windows 平台下Git 服务器搭建

    由于项目中一直在使用git作为版本管理,自己对git的理解.使用都还不是怎么的熟悉,所以准备深入了解一下git及一些常用命令的使用,于是干脆把服务端架上,通过自己的PC作为服务端同时作为客户端的角色进 ...

随机推荐

  1. urllib url解析学习

    #!/usr/bin/env python # encoding: utf-8 from urllib.parse import * #urlparse:解析url分段 #urlsplit:类似url ...

  2. linux文件系统之loop环设备--新建一个文件系统并挂载

    1.  /dev目录下有所有已经连接到操作系统上的设备,他们能在/dev里出现就表示他们在硬件层面和系统核心层面被识别了.对于stdin.stdout.zero等设备是可以直接用> <这些 ...

  3. 函数名后加const

    通过把类成员函数声明为const   以表明它们不修改类对象. 任何不会修改数据成员的函数都应该声明为const类型.如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员 ...

  4. 计蒜客 28201.Choosing Ice Cream-gcd (BAPC 2014 Preliminary ACM-ICPC Asia Training League 暑假第一阶段第一场 A)

    开始水一波博客 题目链接: A. Choosing Ice Cream 传送门 题意就是n个冰淇淋,骰子有k个面,问你是否能在公平的概率下转几次骰子能确定买哪个冰淇淋. 举个例子,假设我只有一个冰淇淋 ...

  5. Wannafly挑战赛4 A解方程【二分/set/hash求解方程】

    https://www.nowcoder.com/acm/contest/35/A 题目描述 给出n个整数和x,请问这n个整数中是否存在三个数a,b,c使得ax2+bx+c=0,数字可以重复使用. 输 ...

  6. request与response对象.

    request与response对象. 1. request代表请求对象 response代表的响应对象. 学习它们我们可以操作http请求与响应. 2.request,response体系结构. 在 ...

  7. [BZOJ 1567] Blue Mary的战役地图

    Link: BZOJ 1567 传送门 Solution: 矩阵Hash/二维$Hash$模板题 涉及到需要快速查询.匹配的题目,考虑直接上$Hash$ 矩阵$Hash$其实就是每行先各$Hash$一 ...

  8. 六. 异常处理8.throws子句

    如果一个方法可以导致一个异常但不处理它,它必须指定这种行为以使方法的调用者可以保护它们自己而不发生异常.做到这点你可以在方法声明中包含一个throws子句.一个 throws 子句列举了一个方法可能抛 ...

  9. linux下打包,压缩,解压缩

    Linux下最常用的打包程序就是tar了,使用tar程序打出来的包我们常称为tar包,tar包文件的命令通常都是以.tar结尾的.生成tar包后,就可以用其它的程序来进 行压缩了,所以首先就来讲讲ta ...

  10. JAVA常见算法题(六)

    package com.xiaowu.demo; /** * 输入两个正整数m和n,求其最大公约数和最小公倍数. * * @author WQ * */ public class Demo6 { pu ...