【发布时间】:2023-04-02 20:33:01
【问题描述】:
所以我有一个使用 CMake 构建的 DLL,它需要嵌入特定的清单文件。在 Visual Studio 设置中,我可以在 Manifest Tool/Input 和 Ouput/Additional Manifest Files 下添加清单文件名,它可以正常工作。这似乎是 CMake 应该可以做到的事情,但我一直无法弄清楚。
关于如何使用 CMake 完成此任务的任何想法?
【问题讨论】:
所以我有一个使用 CMake 构建的 DLL,它需要嵌入特定的清单文件。在 Visual Studio 设置中,我可以在 Manifest Tool/Input 和 Ouput/Additional Manifest Files 下添加清单文件名,它可以正常工作。这似乎是 CMake 应该可以做到的事情,但我一直无法弄清楚。
关于如何使用 CMake 完成此任务的任何想法?
【问题讨论】:
cmake-3.4 现在已经学会了如何处理作为源文件列出的 *.manifest 文件。
【讨论】:
在 CMake 中无法生成 Additional Manifest Files 字段(我检查了源代码)。所以我们必须偷偷摸摸。
Visual 会生成自己的清单 ( yourapp.exe.manifest.intermediate ) 并将其与您的混合。 所以我们必须生成这个清单一次,禁用生成,然后使用生成的清单。
生成清单:
如果您知道如何自己编写完整的清单,则此步骤是可选的。如果你和世界其他地方一样:
Additional Manifest Files)禁用生成:
IF( WIN32 )
SET ( CMAKE_SHARED_LINKER_FLAGS /MANIFEST:NO )
ENDIF( WIN32 )
之后使用生成的清单:
这是通过在构建后步骤中手动调用 mt.exe(通常在链接器之后调用的清单工具......除非它被禁用)来完成:
add_custom_command(
TARGET YourApp
POST_BUILD
COMMAND "mt.exe" -manifest \"$(TargetDir)\\yourapp.final.manifest\" -outputresource:"$(TargetDir)$(TargetFileName)"\;\#1
COMMENT "Adding manifest..."
)
(您可能需要将 $(TargetDir) 更改为 $(OutDir) 取决于您编写 CMake 的方式;使用 Visual 的 Macros 按钮查看它们的值。记住:#1 用于可执行文件,#2 用于dll)
【讨论】:
我刚刚发现您可以使用 mt.exe 将多个清单文件(或嵌入在可执行文件中的清单)合并到现有的清单文件(或可执行文件)中。这样,您不必禁用 Visual Studio 的自动清单生成。您可以使用 mt.exe 添加新的清单数据作为构建后步骤。示例:
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 包含:
<?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>
运行命令:
mt.exe -manifest dpiaware.manifest "-inputresource:program.exe;#1" -outputresource:program.exe;#1
现在 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>
【讨论】:
我刚刚自己完成了这个练习,这就是我来到这个页面的原因。 Calvin1602's answer几乎列出了解决方案,但我不得不稍微修改语法以使其适合我。以下是最终起作用的确切命令:
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..."
)
请注意,当目标是应用程序时,您应该在 mt.exe 命令中使用 #1,而当它是 DLL 时,您应该使用 #2(至少,据我所知——它不适用于直到我将1 更改为2)。
此外,如果您愿意/需要,您可以使用mt.exe 从 DLL 中提取原始清单。命令如下所示:
mt -inputresource:odrmanager.dll;#2 -out:odrmanager.manifest
如果您有要合并的依赖项的清单文件,手动编辑输出并不难。但是如果您使用 Visual Studio 解决方案,我有点喜欢 Calvin1602 让 Visual Studio 为您完成的技巧文件而不是 nmake。
【讨论】:
这很有帮助。这是我最终为需要 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."
)
【讨论】: