如何使用 CMake 构建将特定清单文件嵌入到 Windows DLL 中?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6335352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I embed a specific manifest file in a Windows DLL with a CMake build?
提问by Gerald
So I have a DLL that is being built with CMake that requires a specific manifest file to be embedded. In Visual Studio settings I can just add the manifest filename under Manifest Tool/Input and Ouput/Additional Manifest Files, and it works correctly. It seems like this is something that should be doable with CMake, but I have been unable to figure it out.
所以我有一个用 CMake 构建的 DLL,它需要嵌入一个特定的清单文件。在 Visual Studio 设置中,我可以在 Manifest Tool/Input 和 Ouput/Additional Manifest Files 下添加清单文件名,它可以正常工作。这似乎是 CMake 应该可以做到的事情,但我一直无法弄清楚。
Any ideas on how I can accomplish this with CMake?
关于如何使用 CMake 完成此任务的任何想法?
回答by Davy Durham
cmake-3.4 has now learned how to handle *.manifest files listed as source files.
cmake-3.4 现在已经学会了如何处理列为源文件的 *.manifest 文件。
回答by Calvin1602
It's not possible to generate the Additional Manifest Files
field in CMake (I checked the source code). So we have to be sneakier.
无法Additional Manifest Files
在 CMake 中生成该字段(我检查了源代码)。所以我们必须更加狡猾。
Visual generates a manifest of its own ( yourapp.exe.manifest.intermediate ) and mixes it with yours. So we have to generate this manifest once, disable the generation, and use the generated manifest afterwards.
Visual 生成自己的清单( yourapp.exe.manifest.intermediate )并将其与您的混合。所以我们必须生成这个清单一次,禁用生成,然后使用生成的清单。
Generating the manifest :
生成清单:
This step is optional if you know how to write a complete manifest by yourself. If you're like the rest of the world :
如果您知道如何自己编写完整的清单,则此步骤是可选的。如果你和世界其他地方一样:
- Create your own manifest as usual
- Add it in the interface (
Additional Manifest Files
) - Recompile, relink
- Locate yourapp.exe.manifest (next to your .exe). Copy it in your sources directory and version it. Don't hesitate to rename it, like yourapp.final.manifest, if it's clearer for you
- 像往常一样创建自己的清单
- 将其添加到界面 (
Additional Manifest Files
) - 重新编译,重新链接
- 找到 yourapp.exe.manifest(在您的 .exe 旁边)。将其复制到您的源目录中并对其进行版本控制。不要犹豫,重命名它,比如 yourapp.final.manifest,如果你更清楚的话
Disabling the generation :
禁用生成:
IF( WIN32 )
SET ( CMAKE_SHARED_LINKER_FLAGS /MANIFEST:NO )
ENDIF( WIN32 )
Using the generated manifest afterwards :
之后使用生成的清单:
This is done by a manual call to mt.exe (the manifest tool which is normally called after the linker... unless it's disabled) in a post-build step :
这是通过在构建后步骤中手动调用 mt.exe(通常在链接器之后调用的清单工具......除非它被禁用)来完成的:
add_custom_command(
TARGET YourApp
POST_BUILD
COMMAND "mt.exe" -manifest \"$(TargetDir)\yourapp.final.manifest\" -outputresource:"$(TargetDir)$(TargetFileName)"\;\#1
COMMENT "Adding manifest..."
)
(You'll probably need to change $(TargetDir) to $(OutDir) depending on how you wrote your CMake; Use Visual's Macros
button to see their values. And remember : #1 for executables, #2 for dlls)
(您可能需要根据您编写 CMake 的方式将 $(TargetDir) 更改为 $(OutDir);使用 Visual 的Macros
按钮查看它们的值。请记住:#1 用于可执行文件,#2 用于 dll)
回答by myavuzselim
I just found out that you can merge multiple manifest files (or embedded manifests inside executables) into an existing manifest file (or executable) with mt.exe. This way, you don't have to disable automatic manifest generation of visual studio. You can just add new manifest data with mt.exe as a postbuild step. Example:
我刚刚发现您可以使用 mt.exe 将多个清单文件(或可执行文件中的嵌入式清单)合并到现有的清单文件(或可执行文件)中。这样,您就不必禁用 Visual Studio 的自动清单生成。您可以使用 mt.exe 添加新的清单数据作为后期构建步骤。例子:
program.exe has embedded manifest:
program.exe 已嵌入清单:
<?xml version="1.0"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
dpiaware.manifest contains:
dpiaware.manifest 包含:
<?xml version="1.0"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<ms_windowsSettings:dpiAware xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings" xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</ms_windowsSettings:dpiAware>
</windowsSettings>
</application>
</assembly>
Run command:
运行命令:
mt.exe -manifest dpiaware.manifest "-inputresource:program.exe;#1" -outputresource:program.exe;#1
Now program.exe contains embedded manifest:
现在 program.exe 包含嵌入式清单:
<?xml version="1.0"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*"/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<ms_windowsSettings:dpiAware xmlns:ms_windowsSettings="http://schemas.microsoft.com/SMI/2005/WindowsSettings" xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</ms_windowsSettings:dpiAware>
</windowsSettings>
</application>
</assembly>
回答by evadeflow
I justwent through this exercise myself, which is what brought me to this page. Calvin1602's answer pretty much lays out the solution, but I had to finagle the syntax a bit to make it work for me. Here are the exact commands that finally worked:
我自己刚刚完成了这个练习,这就是让我来到这个页面的原因。Calvin1602 的答案几乎列出了解决方案,但我不得不稍微修改语法以使其对我有用。以下是最终起作用的确切命令:
if (WIN32)
set(CMAKE_SHARED_LINKER_FLAGS /MANIFEST:NO)
endif()
add_custom_command(TARGET
odrmanager
POST_BUILD
COMMAND
"mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}\odrmanager.dll.manifest\" -outputresource:\"${CMAKE_CURRENT_BINARY_DIR}\odrmanager\odrmanager.dll\"\;\#2
COMMENT
"Adding custom manifest containing MSVCRT80 dependency..."
)
Note that you should use #1
in the mt.exe
command when the target is an application, and #2
when it's a DLL (at least, as far as I understand it--it didn't work for me until I changed the 1
to a 2
).
请注意,当目标是应用程序和DLL 时,您应该#1
在mt.exe
命令中使用#2
(至少,据我所知 - 在我1
将 a更改为之前它对我不起作用2
)。
Also, you can use mt.exe
to extract the original manifest from the DLL if you want/need to. The command looks like this:
此外,mt.exe
如果您愿意/需要,您可以使用从 DLL 中提取原始清单。该命令如下所示:
mt -inputresource:odrmanager.dll;#2 -out:odrmanager.manifest
It's not too hard to hand-edit the output if you have a manifest file for the dependency you want to merge in. But I sorta like Calvin1602's trick of having Visual Studio do it for you if you're using Visual Studio solution files rather than nmake.
如果您有要合并的依赖项的清单文件,那么手动编辑输出并不太难。但我有点喜欢 Calvin1602 的技巧,如果您使用的是 Visual Studio 解决方案文件而不是让 Visual Studio 为您做这件事制作。
回答by Dan Kegel
This was very helpful. Here's what I ended up doing for a DLL that needed an MSVCR90 manifest, your mileage may vary:
这非常有帮助。这是我最终为需要 MSVCR90 清单的 DLL 所做的事情,您的里程可能会有所不同:
add_custom_command(
TARGET foo
POST_BUILD COMMAND
mt.exe -manifest \"${MYDEPDIR}/msvcr90/Microsoft.VC90.CRT.manifest\" "-inputresource:\"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/foo.dll\";#2" -outputresource:\"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/foo.dll\";#2
COMMENT
"Appending manifest for MSVCRT90 dependency."
)