如何使用CMake版本将特定清单文件嵌入Windows DLL?

问题描述

| 因此,我有一个使用CMake构建的DLL,该DLL需要嵌入特定的清单文件。在Visual Studio设置中,我只需在清单工具/输入和Ouput /附加清单文件下添加清单文件名,即可正常工作。看起来这是应该使用CMake可以实现的功能,但是我一直无法弄清楚。 关于如何使用CMake完成此操作的任何想法?     

解决方法

        cmake-3.4现在已经学习了如何处理* .manifest文件作为源文件列出。 https://cmake.org/cmake/help/v3.4/release/3.4.html#other     ,        无法在CMake中生成“ 0”字段(我检查了源代码)。因此,我们必须更加狡猾。 Visual会生成自己的清单(yourapp.exe.manifest.intermediate)并将其与您的清单混合在一起。 因此,我们必须一次生成此清单,禁用生成,然后再使用生成的清单。 生成清单: 如果您知道如何自己编写完整的清单,则此步骤是可选的。如果您喜欢世界其他地方: 照常创建自己的清单 将其添加到界面(
Additional Manifest Files
) 重新编译,重新链接 找到yourapp.exe.manifest(.exe旁边)。将其复制到您的源目录中并对其进行版本控制。如果更方便,请不要犹豫地重命名它,例如yourapp.final.manifest。 禁用生成:
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...\" 
)
(根据编写CMake的方式,您可能需要将$(TargetDir)更改为$(OutDir);使用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的答案几乎给出了解决方案,但我不得不稍微加一点语法以使其对我有用。以下是最终有效的确切命令:
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
)。 另外,如果需要,可以使用ѭ11来从DLL中提取原始清单。该命令如下所示:
mt -inputresource:odrmanager.dll;#2 -out:odrmanager.manifest
如果您有要合并的依赖项的清单文件,则手动编辑输出不是很困难。但是我有点像Calvin1602的技巧,如果您要使用Visual Studio来为您完成此操作使用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.\"
)
    

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...