如何在具有CMake构建的Windows DLL中嵌入特定的清单文件?

时间:2011-06-13 19:34:33

标签: windows cmake manifest

所以我有一个使用CMake构建的DLL,需要嵌入特定的清单文件。在Visual Studio设置中,我只需在清单工具/输入和输出/附加清单文件下添加清单文件名,它就可以正常工作。看起来这对CMake应该是可行的,但我一直无法弄明白。

关于如何使用CMake完成此任务的任何想法?

5 个答案:

答案 0 :(得分:13)

cmake-3.4现在已经学会了如何处理列为源文件的* .manifest文件。

https://cmake.org/cmake/help/v3.4/release/3.4.html#other

答案 1 :(得分:8)

无法在CMake中生成Additional Manifest Files字段(我检查了源代码)。所以我们必须偷偷摸摸。

Visual生成自己的清单(yourapp.exe.manifest.intermediate)并将其与您的清单混合。 因此,我们必须生成此清单一次,禁用生成,然后使用生成的清单。

生成清单:

如果您知道如何自己编写完整的清单,则此步骤是可选的。如果你像世界其他地方一样:

  • 像往常一样创建自己的清单
  • 在界面(Additional Manifest Files
  • 中添加
  • 重新编译,重新链接
  • 找到yourapp.exe.manifest(.exe旁边)。将其复制到您的sources目录中并对其进行版本化。不要犹豫,重新命名,如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..." 
)

(您可能需要将$(TargetDir)更改为$(OutDir),具体取决于您编写CMake的方式;使用Visual的Macros按钮查看其值。并记住:#1表示可执行文件,# 2 for dlls)

答案 2 :(得分:4)

我刚刚发现您可以使用mt.exe将多个清单文件(或可执行文件中的嵌入式清单)合并到现有清单文件(或可执行文件)中。这样,您就不必禁用visual studio的自动清单生成。您可以使用mt.exe作为postbuild步骤添加新的清单数据。例如:

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>

答案 3 :(得分:2)

只是自己完成了这个练习,这就是我带到这个页面的原因。 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..." 
                  )

请注意,当目标是应用程序时,您应该在#1命令中使用mt.exe;当它是DLL时,您应该使用#2(至少,据我所知 - 在我将1更改为2之前,它对我无效。

此外,如果您需要,可以使用mt.exe从DLL中提取原始清单。该命令如下所示:

mt -inputresource:odrmanager.dll;#2 -out:odrmanager.manifest

如果您有要合并的依赖项的清单文件,那么手动编辑输出并不是太难。但是,如果您使用Visual Studio解决方案,我有点像Calvin1602让Visual Studio为您执行此操作的技巧文件而不是nmake。

答案 4 :(得分:0)

这非常有帮助。以下是我最终为需要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."
)