紧接前文用NMAKE创建VS2012 C++工程 HelloWorld
现在想做一些改进
1. 不使用根据obj文件默认生成的exe文件名,并且放在bin目录下
用link的 /out参数
2. obj文件放到独立的obj目录下
需要用copy命令,
3. 改变obj文件名
默认和.cpp文件名相同,修改文件名可以用cl /Fe参数,注意/Fe后面不能有空格,紧跟要输出的文件名,并且仅生成在当前运行nmake的目录下。
这里我没有使用/Fe,仅用默认规则。
4. 头文件放在include目录下,.cpp文件放在src目录下。用cl的/I参数
5. makefile文件应该放在build目录下(题外话:一般我喜欢创建一个builder目录,里面有我自己的newlisp编译脚本)
6. 去掉上一篇里面的exception handling warning 用/EHsc
7. 添加一个Pseudotargets: all, 以便运行make all
慢慢来,首先知道如何定义宏,参考文档:http://msdn.microsoft.com/en-us/library/y2be734c.aspx
其实很简单,形如:
A=B, 或者 A = B
用空格看上去更舒服点。
宏的值可以包含多个用空格间隔的字符串,也可以换行,换行符是\,比如:
A = B\
C\
D
NMAKE提供了一些预处理指令,参考文档:http://msdn.microsoft.com/en-us/library/7y32zxwh.aspx
比如可以用下面的指令取消宏A的定义
!UNDEF A
使用宏很简单,如下:
$(macroname)
会在该处用宏的值来做文本替换。
有了宏,我就可以在makefile中用其定义几个目录, 定义输出的exe文件名称等。
现在来看一下目录结构:
step2
-bin
-build
-include
-obj
-src
在src目录下,main.cpp文件代码:
#include "printer.h"
int main()
{
print();
return 0;
}
printer.cpp文件代码:
#include "printer.h"
#include <iostream>
using namespace std;
void print() {
cout << "HelloWorld step2" << endl;
}
include\printer.h文件代码:
#ifndef STEP2_INCLUDE_PRINTER_H_
#define STEP2_INCLUDE_PRINTER_H_
void print();
#endif
build\makfile文件内容:
INCLUDE_DIR = ..\include
OBJ_DIR = ..\obj
BIN_DIR = ..\bin
SRC_DIR = ..\src
EXE_NAME = step.exe
OBJ_FILES = \
$(OBJ_DIR)\main.obj \
$(OBJ_DIR)\printer.obj
$(OBJ_DIR)\main.obj: $(SRC_DIR)\main.cpp
cl /c /EHsc /I$(INCLUDE_DIR) $(SRC_DIR)\main.cpp
copy main.obj $(OBJ_DIR)
del main.obj
$(OBJ_DIR)\printer.obj: $(SRC_DIR)\printer.cpp
cl /c /EHsc /I$(INCLUDE_DIR) $(SRC_DIR)\printer.cpp
copy printer.obj $(OBJ_DIR)
del printer.obj
$(EXE_NAME): $(OBJ_FILES)
link /out:$(BIN_DIR)\$(EXE_NAME) $(OBJ_FILES)
all: $(EXE_NAME)
当在build目录下运行nmake all的时候,target all将会被执行,all依赖target $(EXE_NAME),因此该target被执行,又依赖$(OBJ_FILES),因此OBJ_FILES里面的每个obj都会被执行,最后回到link命令进行连接。这是一个按照依赖顺序反向执行过程。
这里看到几个系统命令,都是VS2012提供的:
cl, link, copy和del
cl可以参考我的博客常用cl编译命令参数解释
link参考另一篇VS 2012 显示Link的参数
Pseudotargets参考文档:http://msdn.microsoft.com/en-us/library/7sb2acw1.aspx
也就是这个target实际上是个不存在的文件,也不会创建它。pseudotarget必须依赖某个target,但是在pseudotarget所在的description block中不能拥有command block.
在build目录下,运行命令编译好后,执行step.exe,成功。
c:\study\nmake\step2\build>nmake all
Microsoft (R) Program Maintenance Utility Version 11.00.60610.1
Copyright (C) Microsoft Corporation. All rights reserved.
cl /c /EHsc /I..\include ..\src\main.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
main.cpp
copy main.obj ..\obj
1 file(s) copied.
del main.obj
cl /c /EHsc /I..\include ..\src\printer.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
printer.cpp
copy printer.obj ..\obj
1 file(s) copied.
del printer.obj
link /out:..\bin\step.exe ..\obj\main.obj ..\obj\printer.obj
Microsoft (R) Incremental Linker Version 11.00.60610.1
Copyright (C) Microsoft Corporation. All rights reserved.