这是使用/ manifest时,Visual Studio 2012链接器中的错误:embedded?

我注意到一个小程序使用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。