转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2855

上一篇我提到了如何用CMake管理Android工程。KlayGE除了Windows、Linux和Android之外,还支持WinRT平台。是的,WinRT虽然和Windows桌面很接近,但在一些细节上存在一些差异,使得它们应该被考虑为两个不同的平台。就好像Android和Linux应该考虑为不同平台一样。

区别

在KlayGE中,WinRT和Windows桌面的区别除了代码上,还涉及到工程文件和开发流程上。WinRT的工程需要考虑资源、打包、签名等,都是Windows桌面不需要的。从概念上看,WinRT开发更像Android这样的移动平台开发。

Android程序构建,用的是MinGW或Unix的makefile的方法,所以只需要把里面定义的编译器等换掉就八九不离十了。WinRT用的是VS2012+的工程文件,需要对其进行修改才能生成WinRT包。这么一来,就不是简单地通过给CMake一个toolchain文件就能解决的。要么就像目前流行地方法一样(比如Ogre),提供完全独立的一套VS工程文件,仅用于WinRT。要么就需要在生成.sln/.vcxproj之后,用个脚本修改它们。要么就更彻底,修改CMake的源代码,让它支持WinRT。

给CMake打补丁

CMake是开源软件,所以可以很容易获取它的代码,加上自己的补丁。按照CMake开发者Brad King的话说,添加WinRT支持已经不是在patch的级别了,而是feature request级别了,因为相当于支持新平台。在修改了几十个文件,和CMake多为开发者讨论多次之后,一个支持x86/x64/ARM的WinRT补丁终于诞生了。有兴趣的朋友可以在这里看到全程。有趣的是,那个ticket的讨论者之一Martell Malone也是KlayGE的用户,他的早期尝试给开发出WinRT补丁提供很大的帮助。

CMake-Add-support-for-WinRT-platforms-and-metro-apps.v5.7z

这个补丁提供了多个改进,使得WinRT的工程文件可以顺利生成。其中包括:

  1. 给VS11和VS12增加WinRT的生成器,以Visual Studio 11 WinRT-x86这样的形式存在。
  2. 增加了CMAKE_VS_WINRT_VERSION,可以在用它来检测WinRT目标平台的版本号。
  3. 识别AppxManifest格式的文件。
  4. 增加了一个名为VS_WINRT_CONTENT的文件属性,并且支持generator expression,可以用来标识出那些是content。VS可以自动把它拷贝到appx目录。
  5. 支持WinRT app的部署。
  6. 在vcxproj里增加了PackageCertificateKeyFile的标志,用于打包的加密认证。
  7. 对于Utility的目标类型,会加入WindowsSDKDesktopARMSupport标志,让VS可以编译utility。

这个补丁是基于CMake git的master分支做的。打上补丁之后,就可以用带WinRT后缀的生成器来产生WinRT的VS2012/2013工程。接下去可以用MSBuild或者在VS里编译,生成appx包,并安装到系统中。目前这个补丁已经提交给CMake,但他们还没找到合适的人来做review。希望过一阵子可以看到这个补丁顺利合并入CMake,这样就不用自己每次打补丁了。

除了修改CMake本身之外,还有些额外的工作需要加入CMakeLists.txt。和Android平台一样,WinRT平台也必须指定一些资源,一同打入包中。不同的是,这里最好是通过VS去拷贝,而不是自己拷贝,否则会有一些顺序问题。凡是加上了VS_WINRT_CONTENT属性的文件,都会在VS里被标记成content,能被正确打包。WinRT也需要Package.appxmanifest文件,同样通过.in和CONFIGURE_FILE来生成工程自己的appxmanifest。

另外我觉得有必要提一下<WindowsSDKDesktopARMSupport>这个标志。如果一个vcxproj带有这个标志,即便是ARM的,也可以直接编译desktop程序的代码,不必遵守Win app store那套。但是,由于没有desktop ARM的SDK,会因为找不到kernel32.lib等文件而无法链接。同时也肯定不能进行数字签名和在ARM上执行。CMake在处理交叉编译的时候用了一个很精巧的方式。在进行编译器检测的时候,它在host平台上编译一个简单程序,通过多个平台相关的#ifdef包含了各个目标平台的名称。生成可执行文件之后,并不执行它,而是打开二进制文件直接找里面的字符串。这么一来,源代码里面不属于那个目标平台的#ifdef都在编译中去掉了,剩下了target平台的名称和其他架构信息。所以,这里要的只是通过编译,而无所谓是否能执行。WindowsSDKDesktopARMSupport标志能让一个命令行的简单程序通过编译,生成exe,这就够了。通过这种方式,可以极大简化编译器检测和utility等类型的处理。

总结

通过修改CMake,WinRT工程也可以纳入CMake的管理。再也不需要单独手工建立一套WinRT的工程文件了。同时,大部分content文件的描述可以和Android的共享,也保证了复用性。