VC++NMAKE
目录
第1章 NMAKE
1.1 运行NMAKE
nmake其实是nmake.exe,它需要在DOS命令窗口下运行。如下图所示,在DOS命令窗口执行nmake /?,试图获取nmake.exe的帮助信息。
执行命令失败,原因是找不到nmake.exe在哪里,根本无法执行nmake.exe。为此,输入它的全路径名(这里是vc6的nmake.exe全路径名,因为中间有空格所以要加上双引号),如下图所示:
每次运行nmake.exe都要指定它的路径名?这也太麻烦了吧?解决方法有两个:
方法一:把C:\Program Files\Microsoft Visual Studio\VC98\Bin增加到环境变量Path;
方法二:运行nmake之前,首先运行VCVARS32.BAT,如下图所示:
说明:
1、方法一对所有程序都会有影响;
2、方法二运行VCVARS32.BAT也是修改环境变量Path,但是它的影响是局部的,只会影响本进程。当上图所示的DOS窗口关闭后,这种影响也随之消失。因此,推荐使用方法二。
每次打开DOS命令窗口,都要执行C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT,是不是挺麻烦的?看看VC++2008开始菜单里的"Visual Studio 2008 命令提示"是怎么做的。它其实是一个快捷方式,其命令如下:
%comspec% /k ""C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86 |
comspec是系统环境变量,运行上面的命令时%comspec%会被替换为该环境变量所代表的字符串,一般就是 c:\windows\system32\cmd.exe。上面命令的实质就是:运行cmd.exe程序,打开DOS命令窗口,然后再运行vcvarsall.bat这个批处理文件。x86是传递给vcvarsall.bat的参数。/k表示运行完vcvarsall.bat之后,DOS命令窗口不自动关闭。现在,就可以在这个DOS命令窗口里运行nmake.exe了。
借鉴VC++2008的做法,若要运行VC++6.0的nmake,可以创建一个快捷方式,让其运行如下命令:
%comspec% /k "C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT" |
运行这个快捷方式,即可在弹出的DOS命令窗口里直接运行VC++6.0的nmake.exe了。
1.1.1 NMAKE的实质
NMAKE的实质是一个解释程序,用来执行makefile文件里的命令。
如:运行nmake,它将在当前目录下查找makefile文件,如果找到了就将其载入内存,然后执行该文件里的命令。
也可以指定其它文件,如:
nmake /ftest.mak 或 nmake /f test.mak |
均会把test.mak载入内存,然后执行这个文件里的命令。
使用NMAKE的重点在于编写makefile,执行预期的操作。
1.2 描述块
1.2.1 定义
makefile里,最重要的就是描述块(Description Blocks)。其结构为:
targets(目标) : dependents(依赖项) commands... (命令) |
下面是一个简单的makefile,它由一个描述块构成。
Test : echo 这是一个描述块 |
注意:
1、目标后面不要紧跟冒号,中间应该有一个空格。也就是说上面"Test :"中间的空格不能缺失;
2、命令以一个或多个制表符(09H)或空格符(20H)开头;
3、命令可以没有,也可以有多个。
运行nmake,这个描述块里的命令将被执行,即"echo 这是一个描述块"将被执行。
1.2.2 多个描述块
一个makefile可以有多个描述块,如下所示:
Test.exe : echo 生成exe Test.lib : echo 生成lib |
上面的makefile有两个描述块:Test.exe、Test.lib。运行nmake时,默认只会执行第一个描述块的命令,即"echo 生成exe"会被执行。
若要执行其它描述块的命令,可以给nmake传递一个参数,如:
nmake Test.lib 将执行描述块Test.lib的命令
若要执行多个描述块的命令,也可以给nmake传递参数,如:
nmake Test.lib Test.exe 将依次执行描述块Test.lib、Test.exe的命令
1.2.3 依赖
描述块里,可以指定依赖项。如:
Test.exe : 1.obj echo 生成exe 1.obj : echo 生成obj |
上面的描述块Test.exe依赖于描述块1.obj。当运行nmake时,将执行描述块Test.exe的命令,但Test.exe依赖于1.obj,因此1.obj里的命令将先被执行,然后才会执行块Test.exe的命令。结果就是"echo生成obj"、"echo生成exe"依次被执行。
一个描述块可以有零个到多个依赖项,多个依赖项之间以空格分隔。如下面的描述块Test.exe,它有两个依赖项1.obj、2.obj。
Test.exe : 1.obj 2.obj echo 生成exe |
1.2.4 长文件名
描述块的目标经常就是一个文件名。如果文件名属于长文件名,就应该用双引号。如下所示:
"VeryLongFileName.exe" : "VeryLongFileName.obj" echo生成exe "VeryLongFileName.obj" : echo生成obj |
1.2.5 多目标
下面有两个描述块,其命令是完全相同的:
A : echo A echo B B : echo A echo B |
可以将它们合并在一起,如下所示:
A B : echo A echo B |
上面的描述块就是多目标描述块。多个目标之间用空格分隔。
1.2.6 合并
一个makefile里允许描述块的目标重复,nmake对重复项将做合并处理。此时,要特别注意单冒号与双冒号的区别——单冒号合并依赖项,不合并内容;双冒号合并依赖项,同时合并内容。下面是一个例子:
makefile |
执行描述块ALL的命令顺序 |
|
单冒号 |
ALL : A echo allA ALL : B echo allB A : echo A B : echo B |
两个ALL被合并为 ALL : A B 合并依赖项 echo allA 不合并内容 执行结果: echo A echo B echo allA 注意:echo allB不会被执行,在这个地方会产生警告。 |
双冒号 |
ALL :: A echo allA ALL :: B echo allB A : echo A B : echo B |
两个ALL被合并为 ALL : A B 合并依赖项 echo allA echo allB 合并内容 执行结果: echo A echo allA echo B echo allB |
1.3
宏
1.3.1 定义、使用
假定某个makefile的内容如下,使用编译程序 cl.exe 编译三个cpp文件。
ALL : cl /c /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" 1.cpp cl /c /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" 2.cpp cl /c /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" 3.cpp |
可以发现,这三个cpp的编译参数是相同的。如果cpp很多,修改编译参数将会比较麻烦。这里,就可以使用宏。新的makefile内容如下:
CPP_PROJ=/c /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" ALL : cl $(CPP_PROJ) 1.cpp cl $(CPP_PROJ) 2.cpp cl $(CPP_PROJ) 3.cpp |
CPP_PROJ=/c /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS"就是用来定义宏的。编译时,通过$(CPP_PROJ)将这个宏代表的字符串提取出来。
注意:
1、宏的名称是区分大小写的;
2、对于不再需要的宏,可以通过!UNDEF命令取消。
1.3.2 作用域
参考下面的makefile:
Test.exe : 1.obj 2.obj echo 生成exe SOURCE=1.c 1.obj : echo 编译$(SOURCE) SOURCE=2.cpp 2.obj : echo 编译$(SOURCE) |
宏SOURCE有两份定义1.c和2.cpp。对于描述块1.obj而言1.c的定义离其最近,所以在1.obj这个块里$(SOURCE)就是1.c;同理在块2.obj里$(SOURCE)就是2.cpp。
1.3.3 宏替换
宏替换的格式为$(macroname:string1=string2)。具体请参考下面的内容:
CPPFILES=1.cpp 2.cpp OBJFILES=$(CPPFILES:.cpp=.obj) |
首先定义宏CPPFILES,其内容为1.cpp 2.cpp。OBJFILES=$(CPPFILES:.cpp=.obj)表示把CPPFILES里的.cpp替换为.obj(不会改变CPPFILES的值)然后赋给OBJFILES,现在OBJFILES的内容为1.obj 2.obj。
1.3.4 文件名宏
假定某个makefile的内容如下。
C:\Release\Test.exe : 1.obj 2.obj echo $@ echo $* echo $** echo $? echo $< |
在这个描述块里,$@、$?、$<……这些都属于文件名宏。具体如下(来自MSDN)
宏名 |
说明 |
$@ |
描述块目标名——路径、文件名、扩展名 这里就是C:\Release\Test.exe |
$$@ |
同上。Valid only as a dependent in a dependency 具体怎么用? |
$* |
描述块目标名——路径、文件名,不含扩展名 这里就是C:\Release\Test |
$** |
所有依赖项 这里就是1.obj 2.obj |
$? |
比当前目标新的依赖项 这里就是1.obj 2.obj里比Test.exe新的依赖项集合 |
$< |
比当前目标新的依赖项,仅在推断规则下有效 |
$<的用法如下所示:将*.c编译为*.obj时可能就会用到这个推断规则,此时会执行描述块.c.obj,$<就是具体的.c文件。
.c.obj : echo $< |
文件名宏还可以加后缀R、D、F、B,如下面的例子:
C:\Release\Test.exe : echo $@ echo $(@R) echo $(@D) echo $(@F) echo $(@B) |
$@就是C:\Release\Test.exe,至于$(@R)、$(@D)、$(@F)、$(@B)的含义见下表(来自MSDN)
后缀 |
说明 |
R |
去掉扩展名,即:C:\Release\Test |
D |
去掉文件名和扩展名,即:C:\Release |
F |
去掉前面的目录,即:Test.exe |
B |
去掉前面的目录和扩展名,即:Test |
1.3.5 递归宏
三个递归宏:MAKE、MAKEDIR、MAKEFLAGS。使用它们的例子如下:
ALL : echo $(MAKE) echo $(MAKEDIR) echo /$(MAKEFLAGS) |
注意:使用MAKEFLAGS的固定格式为/$(MAKEFLAGS)
1.3.6 内置宏
内置宏由nmake创建,makefile里可以修改、使用。vc6的内置宏如下表所示(来自MSDN):
编译器 |
命令宏 |
选项宏 |
Macro Assembler |
AS |
AFLAGS |
Basic Compiler |
BC |
BFLAGS |
C Compiler |
CC |
CFLAGS |
COBOL Compiler |
COBOL |
COBFLAGS |
C++ Compiler |
CPP |
CPPFLAGS |
C++ Compiler |
CXX |
CXXFLAGS |
FORTRAN Compiler |
FOR |
FFLAGS |
Pascal Compiler |
PASCAL |
PFLAGS |
Resource Compiler |
RC |
RFLAGS |
最常用的就是CFLAGS、CPPFLAGS。
1.3.7 环境变量宏
环境变量宏与环境变量之间有着微小的差别,具体请见下一节的内容。
1.4 环境变量
1.4.1 查看
在makefile里,使用set命令可查看环境变量。如下所示
ALL : set |
1.4.2 使用
makefile里使用环境变量的格式为"%%名称%%"。如下面的makefile将显示环境变量OS的内容:
ALL : echo %%OS%% |
1.4.3 环境变量宏
nmake运行时,会为每一个环境变量生成一个宏。如:为环境变量Path、OS……生成宏Path、OS……所以也可以使用"$(名称)"的格式获得环境变量的值,如下面的makefile
ALL : echo $(OS) |
$(OS)取出的是宏OS的值。运行nmake时宏OS被初始化为环境变量OS的值,因此$(OS)取出的就是环境变量OS的值。
明白了这个道理,看看下面的makefile
ALL : set VAR=1 echo $(VAR) echo %%VAR%% |
通过set VAR=1创建了一个环境变量VAR,但是并没有创建宏VAR,因此$(VAR)取不出值。也就是说:makefile内部创建的环境变量无法通过"$(名称)"的格式获取其值。
1.4.4 传递
运行nmake时,可以在命令行里增加环境变量。如:
nmake CFG="Test - DEBUG" VERSION=5.3.1 |
nmake将增加两个环境变量 CFG 和 VERSION,同时根据它们创建宏CFG 和 VERSION。makefile里可以使用$(CFG)和$(VERSION)。
1.5 特殊字符
1.5.1 #
makefile里以#号开头的为注释行,nmake执行时注释行将被忽略。
下面的"#第一个makefile"就是注释行:
#第一个makefile Test : echo 这是一个描述块 |
允许#出现在一行中间,如下所示
STR=123#456 ALL : echo $(STR) |
上面的#456是注释,所以宏STR的值是123,而不是123#456
1.5.2 ^
为了表示如下特殊字符,需要在它们的前面加一个^符号
: ; # ( ) $ ^ \ { } ! @ —
如下面的makefile,宏STR的内容为123#456^789
STR=123^#456^^789 ALL : echo $(STR) |
^和后面的换行符会被解释为换行符,如下面的STR为123^\n。注意:STR=123^的下一行必须为空。
STR=123^ ALL : echo $(STR) |
1.5.3 \
\与后面的换行符会被替换为空格符,如下面的LINK32_OBJS为"StdAfx.obj" "Test.obj" "TestDlg.obj" "Test.res"。
LINK32_OBJS= \ "StdAfx.obj" \ "Test.obj" \ "TestDlg.obj" \ "Test.res" |
说明:
1、\结尾的下一行,行首的空格符、制表符被自动删除;
2、\必须紧跟换行符,如果\后面是空格符或制表符,就起不到连接下一行的作用。
1.5.4 %
两个%号被解释为一个,如:%%OS%%被解释为%OS%,即取环境变量OS的值。
1.5.5 $
两个$号被解释为一个,当然也可以用^$表示一个$。
1.6 规则
首先看下面的makefile
CPP=1.cpp 2.cpp OBJ=$(CPP:.cpp=.obj) ALL : $(OBJ) link $(OBJ) 1.obj : cl /c 1.cpp 2.obj : cl /c 2.cpp |
宏CPP的内容是所有的cpp文件,即1.cpp和2.cpp。宏OBJ=$(CPP:.cpp=.obj)表示宏替换,最终OBJ的内容为1.obj 2.obj。描述块ALL的实际内容如下:
ALL : 1.obj 2.obj link 1.obj 2.obj |
运行nmake时,描述块ALL的命令将被执行。ALL依赖于1.obj 和 2.obj 两个描述块,因此1.obj和2.obj这两个描述块的命令将首先被执行。它们分别编译1.cpp和2.cpp为1.obj和2.obj。最后调用 link 1.obj 2.obj 生成 exe 程序。
如果cpp文件有50个,按照上面的写法岂不是要写50个obj块?有没有更加简单的写法?答案就是使用规则(Rule)。
1.6.1 简单规则
下面是一个使用规则的makefile。.c.obj 就是.c文件编译生成.obj文件的规则;.cpp.obj就是.cpp文件编译生成.obj文件的规则。
CPP=1.c 2.c 3.cpp OBJ=$(CPP:.cpp=.obj) OBJ=$(OBJ:.c=.obj) ALL : $(OBJ) link $(OBJ) 1.obj : echo 1.c .c.obj : echo $< .cpp.obj : echo $** |
执行描述块ALL的命令时,需要1.obj、2.obj、3.obj。
1.obj没有问题,它是一个被明确定义的描述块,echo 1.c 被首先执行。
2.obj没有对应的描述块,这时会在规则里找。现在有两个规则:.c.obj和.cpp.obj。到底选择哪个呢?答案是看2.c和2.cpp哪个存在。如果2.c存在且时间比2.obj要晚就使用.c.obj规则,如果2.cpp存在且时间比2.obj要晚就使用.cpp.obj规则。命令echo $<中的$<是一个文件名宏,它要么是2.c要么是2.cpp。
3.obj与2.obj的处理流程相同,最终echo $**被执行。
1.6.2 预定义规则
预定义规则就是nmake已经定义的规则。上一节中的.c.obj和.cpp.obj就属于预定义规则。
对于预定义规则,makefile里无需再次定义,可直接使用。
下表就是部分预定义规则,节选自MSDN
规则 |
命令 |
缺省命令 |
.asm.exe |
$(AS) $(AFLAGS) $*.asm |
ml $*.asm |
.asm.obj |
$(AS) $(AFLAGS) /c $*.asm |
ml /c $*.asm |
.c.exe |
$(CC) $(CFLAGS) $*.c |
cl $*.c |
.c.obj |
$(CC) $(CFLAGS) /c $*.c |
cl /c $*.c |
.cpp.exe |
$(CPP) $(CPPFLAGS) $*.cpp |
cl $*.cpp |
.cpp.obj |
$(CPP) $(CPPFLAGS) /c $*.cpp |
cl /c $*.cpp |
.cxx.exe |
$(CXX) $(CXXFLAGS) $*.cxx |
cl $*.cxx |
.cxx.obj |
$(CXX) $(CXXFLAGS) /c $*.cxx |
cl /c $*.cxx |
1.6.3 自定义规则
下面的makefile创建了.txt.inf规则。一定要注意.SUFFIXES : .txt,它是.txt.inf规则能用起来的关键。
INFS=1.inf 2.inf Test.txt : $(INFS) copy $(INFS: =/B+)/B $(@F)/B .txt.inf : copy $< $(<B).inf .SUFFIXES : .txt |
这个makefile的执行逻辑:
1、Test.txt依赖于1.inf、2.inf;
2、根据规则.txt.inf生成1.inf和2.inf。其实就是执行如下两条命令:
copy 1.txt 1.inf
copy 2.txt 2.inf
3、最后执行copy $(INFS: =/B+)/B $(@F)/B,其实就是:
copy 1.inf/B+2.inf/B Test.txt/B
最终Test.txt的内容就是1.txt和2.txt合并后的内容。
1.6.4 批量规则
批量规则与简单规则的语法区别在于:批量规则最后是双冒号,简单规则最后是单冒号。参考下面的makefile文件
CPP=1.c 2.c 3.c OBJ=$(OBJ:.c=.obj) ALL : $(OBJ) link $** .c.obj: echo $< |
规则.c.obj后面是单冒号,因此echo $<将被执行三次,依次为1.c、2.c、3.c。把单冒号换成双冒号,则echo $<只执行一次,此时的$<内容是1.c 2.c 3.c。
1.6.5 规则中使用路径
可以在规则中加入路径,如:{src\}.c{Temp\}.obj。这样的话,输入文件(*.c)将在src目录里查找,输出文件(*.obj)将在Temp目录里查找、生成。
1.7 命令
1.7.1 命令前缀
命令前缀@表示命令执行时不会显示这条命令。如下面的del 1.txt执行时不会显示这条命令。
ALL : @del 1.txt |
命令前缀-表示命令执行失败时不会退出nmake。如下面的copy 1.txt 2.txt因为1.txt已经被删除,所以copy会失败并返回非零值。nmake发现copy返回值不为零,一般情况下会中止执行的,但是因为copy前面有-号nmake会继续执行下去。
ALL : del 1.txt -copy 1.txt 2.txt echo 复制完毕 |
命令前缀可以混合使用,如下面的copy命令
ALL : del 1.txt -@copy 1.txt 2.txt echo 复制完毕 |
1.7.2 内联文件
参考下面的makefile
OBJ=1.obj 2.obj 3.obj 4.obj \ 5.obj 6.obj 7.obj 8.obj …… ALL : $(OBJ) link $** |
假如obj文件非常多,那么连接命令 link 1.obj 2.obj 3.obj……将会非常长。在Windows里,命令行的长度是有限制的。如何摆脱这一限制呢?答案就是使用内联文件。改进后的makefile:
OBJ=1.obj 2.obj 3.obj 4.obj \ 5.obj 6.obj 7.obj 8.obj …… ALL : $(OBJ) link @<< $** << |
link @<<中的<<指定了一个匿名的内联文件,nmake会在Temp目录生成一个临时文件。link @<<中的@表示把这个临时文件当作响应文件,link从响应文件里读取命令行参数。
$**是写入临时文件的内容,具体的就是 1.obj 2.obj 3.obj 4.obj……注意$**前的空格符或制表符将被忽略
最后的<<不会写入文件,它表示完成写入。
nmake执行完毕后,内联文件默认会被删除掉。下面的makefile通知nmake保留内联文件,同时还指定了内联文件的名称为inline
OBJ=1.obj 2.obj 3.obj 4.obj \ 5.obj 6.obj 7.obj 8.obj …… ALL : $(OBJ) link @<<inline $** <<KEEP |
还可以指定多个内联文件,如下面的makefile
ALL : copy << /B + << /B 1.txt /B 123 << 456 << |
执行nmake之后,将生成1.txt,其内容为"123\r\n456\r\n"。它的执行逻辑如下:
1、copy命令里有两个<<,执行时将创建两个临时文件;
2、123和<<是往第一个临时文件里写入123\r\n;
3、456和<<是往第二个临时文件里写入456\r\n;
4、copy把两个临时文件合并写入1.txt。
1.8 预处理指令
C/C++里有预处理指令#include、#if...#elif...#else...#endif……。makefile里也有预处理指令,它们以!开头。
语法 |
说明 |
!ERROR text |
显示错误并终止nmake的运行 |
!MESSAGE text |
显示一条消息 |
!INCLUDE [<]filename[>] |
包含一个文件 |
!IF constantexpression !IFDEF macroname !IFNDEF macroname !ELSE[IF constantexpression |IFDEF macroname | IFNDEF macroname] !ELSEIF !ELSEIFDEF !ELSEIFNDEF !ENDIF |
条件预处理 |
!UNDEF macroname |
删除一个宏 |
VC++NMAKE的更多相关文章
- GADL配置编译
GADL配置编译 文章1:Win7(32/64)VS2010配置编译GDAL环境(图文教程+亲测可用!) 转载:http://malagis.com/win7-vs2010-gdal.html 近的一 ...
- VS2015下编译64位GDAL总结
使用VS2015编译最新的64位GDAL(最新gdal2.11),确实有一些问题,看来双方还是太新了,有点不兼容,特总结如下. 以前经常用的通过VisualStudio IDE进行编译的方式现在似乎不 ...
- OSG+VS2010+win7环境搭建---OsgEarth编译
OSG+VS2010+win7环境搭建---OsgEarth编译 转:http://www.cnblogs.com/hnfxs/p/3161261.html Win7下 osg+vs2010环境搭建 ...
- GDAL Configure in Visual Studio 2010 for Win7/ GDAL+VisualStudio2010 Win7 配置
配置环境: OS:Win& *86 Ultimate Edition(EN) VS:Visual Studio 2010(EN) Step1: GDAL源码下载:http://www.gisi ...
- GDAL编译(转)
一.简单的编译 1.使用VisualStudio IDE编译 首先进入GDAL的源代码目录,可以看到有几个sln为后缀的文件名,比如makegdal10.sln,makegdal80.sln,make ...
- GDAL的安装和配置(编译proj.4)
1.下载地址 http://trac.osgeo.org/gdal/wiki/DownloadSource 下面是两个版本: http://pan.baidu.com/s/1bntuXER (1.1 ...
- GDAL编译
使用cmd命令行编译 1.首先在“开始菜单\所有程序\Microsoft Visual Studio 2008\Visual Studio Tools\ Visual Studio 2008命令提示” ...
- VS2008下QT开发环境搭建(转)
原博文地址:http://blog.csdn.net/sunnyboycao/article/details/6364444 VS2008集成QT4.7.2环境搭建 作者:jimmy 日期:2011- ...
- VS2017编译GDAL(64bit)+解决C#读取Shp数据中文路径的问题
编译GDAL过程比较繁琐,查阅了网上相关资料,同时通过实践,完成GDAL的编译,同时解决了SHP数据中文路径及中文字段乱码的问题,本文以“gdal-2.3.2”版本为例阐述整个编译过程. 一.编译准备 ...
随机推荐
- #ifdef DEBUG的理解
今天看到一段代码,对ifdef的概念比较模糊,于是去学习了一下,找到一个很好的解释,如下: 在工程设置里有一些设置会对该工程自动产生一系列的宏,用以控制程序的编译和运行.就好象楼上说的一样,如果你把代 ...
- IMetadataAware接口的特性定制Model元数据
第一步创建元数据类 using System; using System.Collections.Generic; using System.Linq; using System.Reflection ...
- HDU 5615 Jam's math problem
Jam's math problem Problem Description Jam has a math problem. He just learned factorization.He is t ...
- 一维条码打印的C#实现(Code128)
1.CODE128基础知识 CODE128有三个版本: CODE128A: 标准数字和字母, 控制符, 特殊字符 CODE128B: 标准数字和字母, 小写字母, 特殊字符 CODE128C: [00 ...
- .Net文件上传--小数据--un
文件上传控件:FileUpload - 控件,界面+方法+属性Button/LinkButton/ImageButton FileUpload控件:1.SaveAs("要上传到服务器的绝对路 ...
- Android 内部存储和外部存储
应用程序的一些配置文件需要存储在手机上.一般分为内部存储和SD卡存储. 一. 内部存储 ,以 FileOutputStream File file = new File(getFilesDir(),& ...
- [HDOJ4609]3-idiots(FFT,计数)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意:n个数,问取三个数可以构成三角形的组合数. FFT预处理出两个数的组合情况,然后枚举第三个 ...
- [HDOJ5935]Car(精度,数学)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5935 题意:有个老司机在开车, 开车过程中车的速度是不减的. 交警记录了这个老司机在nn个时间点的位置 ...
- Ant build ${renderscript.opt.level}问题解决方案
问题如下: BUILD FAILEDD:\adt-bundle-windows-x86_64-20131030\sdk\tools\ant\build.xml:653: The following e ...
- 记CVTE2014年春季招聘实习生求职历程
进度:目前已经过了网测 明天一面,好紧张,人生第一次实习面试.据说只有一分钟. 网测; 首先在http://exam.cvte.com/ 注册了账号,然后填写相关的个人信息,这里要仔细填写,因为它最后 ...