我注意到一个小程序使用vs2012编译时调用的时间比2010年花费的时间要多15ms。这看起来并不多,但可以调用很多次,我们发现在某些function上会有两倍的减速到额外的15ms。
我find了一个解决方法,我在下面的文档中,但是我的问题是,如果这是我做错了,或者如果我看到一个错误的方式Visual Studio 2012实现/ MANIFEST:embedded选项。 对不起,以下的长度,但我觉得很难同时彻底和简短。
关于我的环境:
Windows 7 Enterprise x64 + Service Pack 1 c:\tmp>cl Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60610.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. usage: cl [ option... ] filename... [ /link linkoption... ] c:\tmp>mt Microsoft (R) Manifest Tool version 6.2.9200.16384 Copyright (c) Microsoft Corporation 2012. All rights reserved.
我可以通过启动一个新的空的项目控制台应用程序来重现。 带有这个简单代码的单个源文件:
#include <iostream> #include <string> int main() { std::string buf; while(std::cin >> buf) { std::cout << buf; buf=""; } }
当它由VS编译时,它会有效地发出这个问题(我已经从VS中获取了实际的全path命令,并将其清理完毕,以便您可以从VS2012开发人员命令提示符处发出这些命令) – 将上述代码保存为testing.cpp,然后在开发人员命令提示符VS 2012窗口的相同目录中,执行以下命令:
CL.exe /c /Zi /nologo /W3 /WX- /sdl /O2 /Oi /Oy- /GL /D WIN32 /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Fd"test.pdb" /Gd /TP /analyze- /errorReport:prompt test.cpp link.exe /ERRORREPORT:PROMPT /OUT:test.exe /INCREMENTAL:NO /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"test.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"test.lib" /MACHINE:X86 /SAFESEH test.obj
如果您现在使用记事本查看生成的test.exe,则可以看到embedded式清单是这样的:
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level='asInvoker' uiAccess='false' /> </requestedPrivileges> </security> </trustInfo> </assembly>
如果我用这行重复100次写一个bat文件: echo "Hello" | test.exe
echo "Hello" | test.exe
并执行它,我的系统大约需要4.5s(我使用cygwin时间来确定这个)
$ time ./test.bat "Hello""Hello""Hell o""Hello""Hello""He llo""Hello""Hello"" real 0m4.523s user 0m0.015s sys 0m0.015s
现在,如果我省略/ MANIFEST:从我的链接线embedded,而不是我会得到test.exe.manifest自动生成
link.exe /ERRORREPORT:PROMPT /OUT:test.exe /INCREMENTAL:NO /NOLOGO kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"test.pdb" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"test.lib" /MACHINE:X86 /SAFESEH test.obj
这是VS2010如何在迁移之前构build的工具。 使用上面的行,得到的test.exe.manifest是:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level='asInvoker' uiAccess='false' /> </requestedPrivileges> </security> </trustInfo> </assembly>
这看起来与根据我提供的第一个链接命令embedded在exe文件中相同。 当然,在上面的链接命令后,没有任何内置的清单文件,我可以通过在记事本中查看我的test.exe来确认。 我现在可以embedded刚生成的test.exe.manifest文件
mt.exe -outputresource:test.exe;#1 -manifest test.exe.manifest
现在,如果我看看记事本中的test.exe,我看到一个稍微有点不同的requestedExecutionLevel行的expression式 – 现在看起来更合适的终止。 我不是XML的专家,但我习惯于看到<key></key>
对,而不是<key... \>
这也许是一个有效的语法。
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> </requestedPrivileges> </security> </trustInfo> </assembly>
现在计时100个电话bat文件运行速度大约1.5s
$ time ./test.bat "Hello""Hello""Hell o""Hello""Hello""He llo""Hello""Hello"" real 0m3.095s user 0m0.015s sys 0m0.000s
那么这是一个错误的清单文件的方式生成与<requestedExecutionLevel level=.... \>
而不是<requestedExecutionLevel level=... ></requestedExecutionLevel>
???
或者用mt.exeembedded的东西看起来是完全相同的清单?
我可以通过在“Manifest Tool”>“Input and Output”工作表上将属性“Embed Manifest”设置为“No”,从而更快地构buildtest.exe。 然后我设置'额外的清单文件'$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest(从链接器“清单文件”“清单文件”复制相同的值)。 我确保'输出清单文件'是空的,并在'清单工具'>'所有选项'表中,我设置'其他选项' /outputresource:"$(TargetDir)$(TargetName)$(TargetExt);#1"
但是我们使用CMAKE来构build系统,而且我无法从CMAKE中find这样做的魔法咒语。
我尝试使用mt.exe来提取和重新embedded,但embedded式版本似乎并没有改变。 如果我编辑提取,然后embeddedembedded更快的运行版本,但是,我必须编辑一次来改变它,并再次编辑,把它应该是什么。 所以我创build了一个不带UAC选项的dummy.manifest文件。
dummy.manifest:
?<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> </trustInfo> </assembly>
然后下面的自定义命令可以纠正这个问题:
IF(WIN32) ADD_CUSTOM_COMMAND(TARGET test POST_BUILD COMMAND "mt.exe" "-inputresource:\"$(TargetDir)\\$(TargetFileName);#1\" -out:\"${CMAKE_CURRENT_BINARY_DIR}/$(TargetFileName).fix.manifest\"" COMMAND "mt.exe" "-outputresource:\"$(TargetDir)\\$(TargetFileName);#1\" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}/dummy.manifest\"" COMMAND "mt.exe" "-outputresource:\"$(TargetDir)\\$(TargetFileName);#1\" -manifest \"${CMAKE_CURRENT_BINARY_DIR}/$(TargetFileName).fix.manifest\"" COMMENT "Fixing bad manifest file" ) ENDIF(WIN32)
所以我有一个解决scheme,有点难看。
在我看来,奇怪的清单导致了一些内部错误,需要额外15ms才能解决。 如果这是真的,那么看起来像/ MANIFEST:embedded选项中的一个错误,因为它没有执行2010的2步embeddedmt.exe。