这几天刚改了改Duilib,之前为了让Duilib更好的支持透明异形窗体所以把Duilib改为Gdi和Gdi+的双渲染引擎。于是想到了有时间就把渲染引擎完全独立为渲染接口,可以增加更多的渲染引擎。现在来说Skia是个很不错的渲染,之前我只是单独编译了VS2013的Skia做来简单的测试使用,要想把它加到Duilib就得完全编译好Skia并且支持各个版本的VS。
为了搞好各个版本的Skia,花了一天时间才弄得差不多,之间出现不少问题。在网上的Skia编译教程都太老了,不适用于当下的Skia版本了,所以专门把编译过程记录在这里方便以后查看。
要编译Skia会用到谷歌的gyp工具,这个工具可以构建出我们需要的sln等项目文件。使用这个工具前,需要先设置两个环境变量。
一、增加GYP_GENERATORS环境变量。1、可以设置为ninja,这样的话最后不会生成VS项目文件,而是让我们自己用depot_tools工具包中的ninja来手工编译(没啥特别需求就别用这个了)。2、设置为msvs-ninja,这样的话会生成VS项目文件,但是编译的时候还是依靠ninja来让VS自动编译。3、设置为msvs,这样子的话会直接生成VS项目文件,不依赖ninja。我只需要Windows的Skia,所以毫不犹豫的设置为msvs。
二、增加GYP_MSVS_VERSION环境变量。这个环境变量用来指定生成的VS的版本(可以设置为2013,表示VS2013;还能设置2012、2008等等),对于新版本的Skia,只能用2013,所以这个变量不设置也可以。
VS2013版本:
Skia的官网为:https://skia.org/。网站里面有Skia在各个系统的编译教程。我按照Windows的编译教程搞了挺长时间。按照官网的方法,需要的编译环境为:
VS2013
depot_tools
Git(用于检出depot_tools和Skia)
Python2.7版本(一定要2.7这个版本的,安装完后设置好python的环境变量)
Cygwin(这个很必要,直接用Windows命令行会出问题)
但是有个很尴尬的问题,那就是。如果按照教程来编译的话,首先是要检出depot_tools和Skia,然后就发现无法连接到服务器,好在有Github,在上面也有最新版本对应的代码,所以我转到Github去检出depot_tools和Skia。
在按照教程编译时,执行命令:
cd %SKIA_CHECKOUT_DIR%
SET "GYP_GENERATORS=ninja,msvs"
python bin/sync-and-gyp
SET "GYP_GENERATORS="
然后同样很悲剧,sync-and-gyp脚本会自动下载编译Skia所需的所有第三方库和环境,但是由于无法,大多数第三方库都没法下载,自然也无法编译!很尴尬的搞了半天都没成功。
当最后觉得没法办的时候。突然发现当下新版本的Skia源码里面有个cmake目录,里面居然有CMakeLists.txt文件。眼前一亮,我用cmake。执行命令:
cd %SKIA_CHECKOUT_DIR%
cd cmake
cmake .
直接生成了VS2013的工程文件!然后打开工程直接编译,没出现任何问题就生成了Skia.dll和一个demo程序,运行时一切正常!不需要depot_tools、python、cygwin、gyp,也不需要任何第三方库(实际上所需的很多第三方库都是给linux、mac等环境用的,比如jepg、png解析库,Windows并不需要,Skia在Windows中直接用WIC解析图片)。只需要Skia源码和cmake,三句代码指定搞定!而且生成的是一个单独的Skia.dll动态链接库,不像原来的Skia会生成一堆静态库文件。Skia要是早点附加个CMakeLists.txt就不需要那么麻烦了。
我又换命令去尝试生成VS2008、2010、2012等版本的Skia
cd %SKIA_CHECKOUT_DIR%
cd cmake
cmake . -G "Visual Studio 9 2008"
不过很遗憾,虽然最新版本的Skia虽然生成VS工程文件很简单了,但是由于新代码用到很多C++11的特性,所以只支持VS2013版本,其他VS编译时都会报错,更别说VS2008了。
如果要让生成Skia.dll支持xp sp3系统,需要对项目属性做如下修改:
1. 项目菜单->项目属性->配置属性->常规->平台工具集,选择“VS2013WindowsXP(v120_xp)”
2. 项目菜单->项目属性->链接器->系统->所需的最低版本,设置为5.01
3.打开sln后,找到ports项目,找到里面的”SkFontMgr_win_dw_factory.cpp“源文件并且移出,把“src/ports/SkFontMgr_win_gdi_factory.cpp”,再添加到ports项目(这是把DWrite渲染方式改为GDI渲染,原因我在后面说)
如果要支持到xp sp2系统,还需要另外设置:
C/C++->代码生成->运行库,选择“多线程(/MT)";
这样做完,就算是圆满的编译好了Skia最新版本,但是这个并不能满足我的需求。因为最新版本的Skia必须要用VS2013编译,意味着最终程序必须附带VS2013的运行时库,而很多时候项目用的Duilib版本不是VS2013,这样会增加程序体积,也可能导致其他兼容性问题。所以还是需要编译出其他版本的Skia,既然最新版本Skia不支持,那就只能试试老版本的了
VS2010和VS2012版本:
从Github检出Skia后,我浏览Skia版本库历史,尝试了编译很多个时间段的Skia,最终选择了一个2014年的Skia,这个版本的相对来说比较新,可以满足需求,同时也可以做出VS2008到VS2013版本的所有项目文件。我检出的版本为2014.4.11日的:
编译VS2010版本的Skia也比较简单(2010直接升级就能用于2012和2013)。需要的环境如下:
VS2010
设置环境变量GYP_MSVS_VERSION为2010
Python2.7(安装完后设置好python的环境变量)
Cygwin(安装过程中提示安装package时找到python,把这个package装上)
Skia依赖的第三方库
其中Cygwin很重要,我一开始没用Cygwin而是直接用cmd,去编译的时候,python总会执行错误,需要在Cygwin环境下执行命令。
在最新版本的Skia中,原本的syna-and-gyp脚本会自动下载所需的第三方库和各种环境,但是老版本的Skia没有这种脚本,就需要我们自己下载了。我会把我下载好的Skia依赖第三方库文件上传到我的Github上。在Skia的third_party目录新建externals目录,把第三方库文件放到externals目录就可以了,其中包括gyp(用来生成sln,这个很重要)。
这些准备好后,启动Cygwin,执行命令:
cd d:/skia/skia #这里替换为你的Skia检出目录,用英文目录
python gyp_skia
执行完毕后,如果一些顺利,就会生成out目录,里面有生成好的VS2010工程文件,把它可以升级为2012或者2013的。然后打开工程直接编译就OK了,编译时会出现错误:“警告视被为错误”,修改对应项目的属性:“C/C++->常规->将错误视为警告:否”就可以了。
但是有的版本的Skia编译时会提供一些文件缺失的错误,这时就要看错误原因,如果是缺少第三方库那就需要我们自己再去下载对应的第三方库补充到externals目录。如果是缺失Skia本身的文件,就可以从Git中找到缺失的文件补充好(理论上不应该出现这个问题,但是我的确遇到了,不过重新检出了一下就没问题了)。不过经过我的测试,我检出的这个2014.4.11版本的Skia配合我的第三方库,编译时一切正常。
至此,VS2010到VS2013的所有版本都可以编译出来了。但是最麻烦的是VS2008,我单独搞了挺长时间才搞出来2008版本的Skia。
VS2008版本:
所需的环境和Skia版本与VS2010的完全一样,就不再赘述了。为什么编译VS2008的最麻烦?原因如下:
1、Skia的源码原本最低就是支持VS2010的,没有考虑VS2008,用gyp工具生成的默认也是VS2010(当然也可以修改环境变量生成出VS2008版本)。
2、在Windows中,Skia渲染字体有两种方式:GDI或者DWrite,而Skia默认的渲染方法是用DWrite,但是VS2008不支持没有DWrite的头文件(VS2010开始支持),所以会出现编译错误。另外XP系统不支持DWrite,所以如果想让编译出来的Skia支持XP系统,就需要把DWrite渲染方式改为GDI(这也是在编译VS2013那一节中我提到要替换文件的原因)
由于这两个原因,所以需要修改一些项目和源代码,才能顺利编译出支持xp和VS2008的Skia。
首先说一下生成2008工程文件的方法。
正常情况下,设置环境变量GYP_MSVS_VERSION为2008,然后按照VS2010的生成方法,就能生成出VS2008的项目文件。
但是在我尝试生成了很多个版本的Skia后发现,很多情况下,可能是gyp脚本编写有问题,会生成出默认的VS2010项目文件而无法生成VS2008的。如果按照上面的方法没有出现VS2008的项目文件,就需要强行修改一点gyp脚本了。找到"skia\third_party\externals\gyp\pylib\gyp\MSVSVersion.py"文件,这个文件负责gyp生成的VS版本,找到如下代码:
# In auto mode, check environment variable for override.if version == 'auto':version = os.environ.get('GYP_MSVS_VERSION', 'auto')version_map = {'auto': ('10.0', '12.0', '9.0', '8.0', '11.0'),'2005': ('8.0',),'2005e': ('8.0',),'2008': ('9.0',),'2008e': ('9.0',),'2010': ('10.0',),'2010e': ('10.0',),'2012': ('11.0',),'2012e': ('11.0',),'2013': ('12.0',),'2013e': ('12.0',),}
把其中几个数字做出修改,这些数字代码VS的版本,我把默认的生成版本从VS2010改成了VS2008
# In auto mode, check environment variable for override.if version == 'auto':version = os.environ.get('GYP_MSVS_VERSION', 'auto')version_map = {'auto': ('9.0', '12.0', '9.0', '8.0', '11.0'),'2005': ('8.0',),'2005e': ('8.0',),'2008': ('9.0',),'2008e': ('9.0',),'2010': ('9.0',),'2010e': ('9.0',),'2012': ('11.0',),'2012e': ('11.0',),'2013': ('12.0',),'2013e': ('12.0',),}
改完后保存,然后打开cygwin执行命令:
cd d:/skia/skia #这里替换为你的Skia检出目录,用英文目录
python gyp_skia
这样就会生成VS2008的项目文件。但是只生成了项目文件还是不行,编译时会出现很多错误。
首先把最常见的”警告视为错误“的问题改掉。
然后还会提示缺少"stdint.h",这是C++标准头文件,但是VS2010才开始提供,所以我从VS2010找到这个头文件,并且把他放到了"skia/src/core”目录中(这个文件我也会提交到Github)。
最后我们打开Skia解决方案,依次把工程里的DWrite相关代码修改,替换为GDI的:
1、找到“Util”项目,把其中“SkDwrite.cpp/.h”、”SkDwriteFontFileSteam.cpp/.h“、”SkDwriteGeometrySink.cpp/.h“这几个用到dwrite的文件移除掉:
2、找到“Ports”项目,把SkRemotableFontMgr_win_dw.cpp和SkFontHost_win_dw.cpp文件移除。
3、如果上图的位置中,包含的是”SkFontMgr_default_dw.cpp“文件而不是”SkFontMgr_default_gdi.cpp“,那就用”SkFontMgr_default_gdi.cpp“替换”SkFontMgr_default_dw.cpp“
4、打开”src\core\skadvancedtypefacemetrics.cpp“文件,把开头的#include "dwrite.h"头文件的语句注释掉;然后在文件中搜索如下代码并且注释掉:
template SkAdvancedTypefaceMetrics::WidthRange* getAdvanceData(IDWriteFontFace* fontFace,int num_glyphs,const uint32_t* subsetGlyphIDs,uint32_t subsetGlyphIDsLength,bool (*getAdvance)(IDWriteFontFace* fontFace, int gId, int16_t* data));
如果有其他的关于dwrite.h的错误,也类似的修改一下就可以了。做完这些后,就可以用VS2008编译生成Skia了。当然,由于可能其他人用其他版本的Skia,所以我说的步骤里面的文件和一些具体的代码可能会有差别,但是照猫画虎类似的改改就可以了。
用cmake生成VS2008版本的单一文件skia:
在生成好上面说的VS2008版本的Skia后,我又想到了既然最新版本的Skia支持用cmake生成解决方案,那我应该也能自己为老版本的Skia写个CMakeLists.txt来各种版本的Skia。倒腾了一上午,还真搞出来了···,gyp生成的解决方案最麻烦的就是他会把skia拆分为很多个静态库文件,我们要用的话还得依次链接多个静态库文件,用起来很不爽。而用cmake可以生成一个单一的解决方案,编出来就是一个单独的skia,用起来方便多了。
我把最新版的Skia的cmake目录的CMakeLists.txt文件拷贝到前面说的老版本的Skia目录。当然了,这个CMakeLists.txt肯定没法直接用,我对照着新版和老版的Skia的文件差异,修改了CMakeLists.txt,最终使用命令:
cd %SKIA_CHECKOUT_DIR%
cd cmake
cmake . -G "Visual Studio 9 2008"
生成了VS2008的解决方案,但是这个解决方案是没法直接编译的,因为skia涉及的文件有点多,我改的CMakeLists.txt不够完善。所以我编译解决方案,根据提示的错误,移出多余的源文件,修改了不少地方,终于是编译陈功了。但是由于改的步骤不较多,也比较乱,所以我就不专门说明修改步骤了。我把最终生成的VS2008解决方案上传到Github。
这个VS2008的Skia是我想要的最理想的版本。首先由于这是VS2008版本,所以可以很容易升级到VS2013等高版本的VS,而且直接编译,这就满足了实际开发对多种VS版本的需求。其次修改后完全支持xp系统。最后生成的是一个单独的Skia.dll文件,使用简单方便。
生成的release版本的skia.dll大小是1.82M。不过我是用dll版本的Skia发现由于源文件中由于Skia有一些类没有导出,所以有一些功能没法使用。所以建议还是修改工程属性,生成skia的静态库,就可以使用完整的skia功能。如果使用静态库的skia,最终的exe大概会增加1.5M的体积,我感觉是可以接受的大小。
最后,我再附加一个使用这个skia静态库的demo。简单做了个半透明的窗体,附加了文字特效。代码比较简略,凑活着看吧,主要就是测试功能是否正常。这里提示一下,使用skia静态库时记得链接这几个库文件:OpenGL32.lib、usp10.lib、DelayImp.lib、windowscodecs.lib
总结:
也类似的这次编译Skia真是比较麻烦,gyp和depot_tools的确是厉害,不过对于我这样只需要Windows环境的来说用起来就不如CMake那么简单了。我把编译VS2010和VS2008所需要第三方库、生成好的Skia VS2008解决方案、单独skia版本的VS2008解决方案上传到我的Github。其中单独skia版本的VS2008解决方案可以直接编译出skia。地址:点击打开链接
转于:在Windows下编译多种VS版本的Skia