如何解决来自CMake的midl.exe和cppwinrt.exe的问题
这是How to use midlrt.exe to compile .idl to .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选项,但是无论如何似乎都能得到相同的结果。这些是我遇到的问题:
-
MIDLRT生成具有以下问题的头文件“ MyClass.h”:
- 它#includes
,它最终#定义了GetClassName和GetCurrentTime的预处理器宏,这些宏在使用这些名称的WinRT函数中导致编译器错误。 - 我花了几个小时跟踪它,并学习使用#define COM_NO_WINDOWS_H进行编译以防止这种情况。
- 它从WinRT References Contracts目录而不是Include目录中#include不存在的* .h文件:
- #include“ C:\ Program Files(x86)\ Windows Kits \ 10 \ References \ 10.0.18362.0 \ Windows.Foundation.FoundationContract \ 3.0.0.0 \ Windows.Foundation.FoundationContract.h”
- #include“ C:\ Program Files(x86)\ Windows Kits \ 10 \ References \ 10.0.18362.0 \ Windows.Foundation.UniversalApiContract \ 8.0.0.0 \ Windows.Foundation.UniversalApiContract.h”
- 因此,我制作了此文件的副本,并将其替换为
#include
- 它#includes
-
CPPWINRT生成“模块.g.cpp”,其中包含“ MyNamespace.MyClass.h”,但也未生成该.h文件。它会生成“ MyNamespace / MyClass.h”(请注意用“ /”代替“。”),因此我创建了前一个.h并简单地#include了后者.h。
-
CPPWINRT不会生成我在Microsoft示例中看到的所有基本标头。它仅生成与MyClass直接相关的标头-例如,定义模板基类winrt :: MyNamespace :: implementation :: MyClassT ,包装器winrt :: MyNamespace :: MyClass等。
-
winrt :: MyNamespace :: factory_implementation :: MyClass未定义。在那里定义了MyClassT ,但没有定义MyClass。我从Microsoft示例中找到了一个范例,并将其粘贴到:
// Missing from the generated stuff -- derived from a Microsoft example:
namespace winrt::MyNamespace::factory_implementation
{
struct MyClass : MyClassT<MyClass,implementation::MyClass>
{
};
}
- 我收到有关CHECK_NS_PREFIX_STATE定义不一致的编译器警告:在某些地方它是“总是”,而在其他地方是“从不”。所以现在我#define MIDL_NS_PREFIX和#define CHECK_NS_PREFIX_STATE =“ always”
现在,构建可以通过编译器进行,但是链接器中有未解析的外部符号。我认为应该在“ 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
我是否缺少一些简单的东西来解决所有这些问题,包括生成的文件丢失,不完整和不正确?
解决方法
未解决的外部符号错误表明您缺少导入库。在这种情况下,您需要链接到 WindowsApp.lib 伞库,该伞库导出所需的符号。
请注意,您正在观察的符号名称是C ++ / WinRT要求使用Windows SDK标头以及不使用Windows SDK标头进行构建的产物。它通过声明导入(使用WINRT_
前缀来防止与SDK标头声明冲突)解决此问题,然后使用/ALTERNATENAME链接器开关映射重命名的符号。
我不确定这是否可以解决您的所有问题,但您当然希望将${MYDIR}\\GeneratedFiles
添加到其他包含目录中。应当注意不能包含从 winrt 子目录(base.h以及计划的Windows运行时类型的头)生成的头。
cppwinrt 在处理先前从您的.idl编译的.winmd文件时,还将自己类型的存根实现写入${MYDIR}\\GeneratedFiles\\sources
中。不幸的是,这里涉及一个手动步骤:您需要将生成的.h和.cpp文件复制到源树中,并实现框架实现。每当您修改接口定义之一时,这是必需的。
请注意,为我的项目生成的 module.g.cpp 文件不包含我的任何自定义类型标头。也许您使用的是C ++ / WinRT的旧版本(我使用的是v2.0.200203.5)。我相信,随着C ++ / WinRT 2.0版中type-erased factories的引入,这种情况已经改变。除非已经这样做,否则应该使用Microsoft.Windows.CppWinRT NuGet package中的 cppwinrt ,而不是Windows SDK附带的二进制文件。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。