首页 > 解决方案 > CMake 中 midl.exe 和 cppwinrt.exe 的问题

问题描述

这在某种程度上是如何使用 midlrt.exe 将 .idl 编译为 .winmd 的后续内容?

我的 CMakeLists.txt 中有这个。我的问题不是关于 CMake 逻辑,而是关于 midl 和 cppwinrt 命令的输出,以及随后的编译和链接错误。我怀疑我可能缺少一些命令行选项。

# Pathnames for WinRT References
set (WINSDKREFDIR "$ENV{WindowsSdkDir}References\\$ENV{WindowsSDKVersion}")

# Remove trailing \ from $ENV{WindowsSDKVersion}
string (REGEX MATCH "[^\\]*" WINSDKVER $ENV{WindowsSDKVersion})

# COMMAND lines wrapped in this post for readability, not wrapped in the actual CMakeLists.txt
add_custom_target (MYLIB_PREBUILD ALL
  COMMAND midl /winrt /ns_prefix /x64 /nomidl
    /metadata_dir
      "${WINSDKREFDIR}windows.foundation.foundationcontract\\3.0.0.0"
    /reference 
      "${WINSDKREFDIR}windows.foundation.foundationcontract\\3.0.0.0\\Windows.Foundation.FoundationContract.winmd"
    /reference
      "${WINSDKREFDIR}Windows.Foundation.UniversalApiContract\\8.0.0.0\\Windows.Foundation.UniversalApiContract.winmd"
    /out "${MYDIR}\\GeneratedFiles" "${MYDIR}\\MyClass.idl"
  COMMAND cppwinrt
    -in "${MYDIR}\\GeneratedFiles\\MyClass.winmd"
    -ref ${WINSDKVER} -component -pch "pch.h" -out "${MYDIR}\\GeneratedFiles"
)

add_dependencies (MYLIB MYLIB_PREBUILD)

在 cppwinrt 命令中,我尝试了不同形式的 -ref [spec] 和 -pch 选项,但无论如何似乎都得到了相同的结果。这些是我遇到的问题:

    // Missing from the generated stuff -- derived from a Microsoft example:
    namespace winrt::MyNamespace::factory_implementation
    {
        struct MyClass : MyClassT<MyClass, implementation::MyClass>
        {
        };
    }

现在构建通过编译器,但我在链接器中有未解析的外部符号。我认为这些东西应该在“winrt/base.h”中内联定义,但是 cppwinrt 没有导出这样的文件(正如我在 Microsoft 示例中看到的那样),系统目录中的等效文件只包含原型,而不包含身体:

WINRT_GetRestrictedErrorInfo
WINRT_RoInitialize
WINRT_RoOriginateLanguageException
WINRT_SetRestrictedErrorInfo
WINRT_WindowsCreateString
WINRT_WindowsCreateStringReference
WINRT_WindowsDeleteString
WINRT_WindowsPreallocateStringBuffer
WINRT_WindowsDeleteStringBuffer
WINRT_WindowsPromoteStringBuffer
WINRT_WindowsGetStringRawBuffer
WINRT_RoGetActivationFactory
WINRT_WindowsDuplicateString

我是否遗漏了一些简单的东西来解决所有这些与丢失、不完整和不正确的生成文件有关的问题?

标签: cmakec++-winrtmidlcppwinrt

解决方案


未解决的外部符号错误表明您缺少导入库。在这种情况下,您需要链接到导出所需符号的WindowsApp.lib伞库。

请注意,您观察到的符号名称是 C++/WinRT 要求使用和不使用 Windows SDK 标头进行构建的产物。它通过声明导入来解决这个问题(带有WINRT_前缀以防止与 SDK 标头声明冲突),然后使用/ALTERNATENAME链接器开关映射重命名的符号。

我不确定这是否会解决您的所有问题,但您肯定希望添加${MYDIR}\\GeneratedFiles到您的其他包含目录中。这应该注意无法包含winrt子目录中生成的标头(base.h 以及预计的 Windows 运行时类型标头)。

当cppwinrt${MYDIR}\\GeneratedFiles\\sources处理之前从您的 .idl(s) 编译的 .winmd 文件时,它还会将您自己类型的存根实现写入. 不幸的是,这里涉及到一个手动步骤:您需要将生成的 .h 和 .cpp 文件复制到源代码树中,并实现框架实现。每当您修改其中一个接口定义时,都需要这样做。

请注意,为我的项目生成的module.g.cpp文件不包含我的任何自定义类型标头。也许您使用的是旧版本的 C++/WinRT(我使用的是 v2.0.200203.5)。我相信随着C++/WinRT 2.0 版中类型擦除工厂的引入,这种情况发生了变化。除非您已经这样做了,否则您应该使用Microsoft.Windows.CppWinRT NuGet 包中的cppwinrt,而不是(过去)随 Windows SDK 提供的二进制文件。


推荐阅读