转载请说明原出处,谢谢~~:https://redrain.blog.csdn.net/article/details/111685123
目录
准备环境
1.配置代理
2.下载depot_tools
3.下载skia
4.假如没有梯子
开始编译
1.args的参数说明
2.生成项目文件
3.删除多余的命令
用LLVM编译
Skia剪裁
手动去掉三方库依赖
去掉字体依赖
去掉图片依赖
针对skia老版本
编译cmake
skia是谷歌的一个开源2D引擎,用来实现利用CPU实现2D图形绘制。skia应用非常广泛,chrome、android、firefox、flutter等项目的渲染引擎都是skia。
最近打算给ui库替换为skia渲染引擎,所以搞一下windows下的skia编译。以前也搞过老版本的skia编译https://blog.csdn.net/zhuhongshu/article/details/51272050,现在打算编译一个最新的skia。
这次的skia编译时间为2020-12-22,SHA-1:71f75e3111aebcb9895934ecdf2a84a82ac87ba4
虽然官网中有相关的文档,但是实际编译时会遇到一些官网没有说明的情况,所以专门写一篇文章。
打开网站需要梯子,skia的官网:https://skia.org/
下载文档:https://skia.org/user/download
编译文档:https://skia.org/user/build
skia本身和相关代码的下载都需要梯子,可以用ShadowSocks或者其他代理
git config --global http.proxy 'socks5://127.0.0.1:1080' git config --global https.proxy 'socks5://127.0.0.1:1080'
使用完毕后取消git代理
git config --global --unset http.proxy git config --global --unset https.proxy
depot_tools是编译谷歌系列源码需要用到的工具
git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'
下载后需要添加到Path环境变量
git clone https://skia.googlesource.com/skia.git
打开cmd,切换到skia目录,执行脚本
python2 tools/git-sync-deps
这一步是自动下载skia依赖的三方库,会自动下载到skia/third_party/externals目录;以及用于生成项目文件的工具gn.exe。
如果没有梯子,可以在github上找depot_tools和skia的镜像,也可以用。
但是skia依赖的三方库会比较麻烦。python2 tools/git-sync-deps命令会按照skia/DEPS文件里的列表下载依赖的三方库,几乎都是谷歌的地址。这时需要根据自己的需求自己另外下载需要的三方库放到skia/third_party/externals目录。有网友建立了这些三方库的镜像,可以把DEPS文件中的代码改为:
use_relative_paths = True
vars = {
"checkout_chromium": False,
}
deps = {
"buildtools" : "https://github.com/GoogleDepends/buildtools.git@505de88083136eefd056e5ee4ca0f01fe9b33de8",
"common" : "https://github.com/GoogleDepends/common.git@9737551d7a52c3db3262db5856e6bcd62c462b92",
"third_party/externals/angle2" : "https://github.com/GoogleDepends/angle2.git@1cc49bb2e230555fb3dc33d3400a5f7a0cefe943",
# Dawn requires jinja2 and markupsafe for the code generator, and glslang and shaderc for SPIRV compilation.
# When the Dawn revision is updated these should be updated from the Dawn DEPS as well.
"third_party/externals/dawn" : "https://github.com/GoogleDepends/dawn.git@11652ff8f8b3c3104eb2627717fa652d432d5b84",
"third_party/externals/glslang" : "https://github.com/GoogleDepends/glslang@1f0fcbe5a30fdc9632a8bff36277103fabf0797c",
"third_party/externals/jinja2" : "https://github.com/GoogleDepends/jinja2@b41863e42637544c2941b574c7877d3e1f663e25",
"third_party/externals/markupsafe" : "https://github.com/GoogleDepends/markupsafe@8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"third_party/externals/shaderc" : "https://github.com/GoogleDepends/shaderc@362becca1ff2a841c21fd675ac3a9c1ee9bb5612",
"third_party/externals/dng_sdk" : "https://github.com/GoogleDepends/dng_sdk.git@c8d0c9b1d16bfda56f15165d39e0ffa360a11123",
"third_party/externals/egl-registry" : "https://github.com/GoogleDepends/EGL-Registry@a0bca08de07c7d7651047bedc0b653cfaaa4f2ae",
"third_party/externals/expat" : "https://github.com/GoogleDepends/expat.git@e5aa0a2cb0a5f759ef31c0819dc67d9b14246a4a",
"third_party/externals/freetype" : "https://github.com/GoogleDepends/freetype2.git@0a3d2bb99b45b72e1d45185ab054efa993d97210",
"third_party/externals/harfbuzz" : "https://github.com/GoogleDepends/harfbuzz.git@3a74ee528255cc027d84b204a87b5c25e47bff79",
"third_party/externals/icu" : "https://github.com/GoogleDepends/icu.git@dbd3825b31041d782c5b504c59dcfb5ac7dda08c",
"third_party/externals/imgui" : "https://github.com/GoogleDepends/imgui.git@d38d7c6628bebd02692cfdd6fa76b4d992a35b75",
"third_party/externals/libgifcodec" : "https://github.com/GoogleDepends/libgifcodec@d06d2a6d42baf6c0c91cacc28df2542a911d05fe",
"third_party/externals/libjpeg-turbo" : "https://github.com/GoogleDepends/libjpeg-turbo.git@574f3a772c96dc9db2c98ef24706feb3f6dbda9a",
"third_party/externals/libpng" : "https://github.com/GoogleDepends/libpng.git@386707c6d19b974ca2e3db7f5c61873813c6fe44",
"third_party/externals/libwebp" : "https://github.com/GoogleDepends/libwebp.git@0fe1a89dbf1930fc2554dbe76adad5d962054ead",
"third_party/externals/lua" : "https://github.com/GoogleDepends/lua.git@e354c6355e7f48e087678ec49e340ca0696725b1",
"third_party/externals/microhttpd" : "https://github.com/GoogleDepends/libmicrohttpd@748945ec6f1c67b7efc934ab0808e1d32f2fb98d",
"third_party/externals/opencl-lib" : "https://github.com/GoogleDepends/common-lib-amd-APPSDK-3.0@4e6d30e406d2e5a65e1d65e404fe6df5f772a32b",
"third_party/externals/opencl-registry" : "https://github.com/GoogleDepends/OpenCL-Registry@932ed55c85f887041291cef8019e54280c033c35",
"third_party/externals/opengl-registry" : "https://github.com/GoogleDepends/OpenGL-Registry@14b80ebeab022b2c78f84a573f01028c96075553",
"third_party/externals/piex" : "https://github.com/GoogleDepends/piex.git@bb217acdca1cc0c16b704669dd6f91a1b509c406",
"third_party/externals/sdl" : "https://github.com/GoogleDepends/sdl@5d7cfcca344034aff9327f77fc181ae3754e7a90",
"third_party/externals/sfntly" : "https://github.com/GoogleDepends/sfntly.git@b55ff303ea2f9e26702b514cf6a3196a2e3e2974",
"third_party/externals/spirv-cross" : "https://github.com/GoogleDepends/SPIRV-Cross@871c85d7f0edc6b613e3959bc51d13bfbc2fe2df",
"third_party/externals/spirv-headers" : "https://github.com/GoogleDepends/SPIRV-Headers.git@f8bf11a0253a32375c32cad92c841237b96696c0",
"third_party/externals/spirv-tools" : "https://github.com/GoogleDepends/SPIRV-Tools.git@1c8bda3721e6b9302f694b58c26d32eff341b126",
"third_party/externals/swiftshader" : "https://github.com/GoogleDepends/swiftshader@f99302c4efe6f32297a619d407b4410ec3ee6412",
#"third_party/externals/v8" : "https://chromium.googlesource.com/v8/v8.git@5f1ae66d5634e43563b2d25ea652dfb94c31a3b4",
"third_party/externals/wuffs" : "https://github.com/GoogleDepends/wuffs.git@4080840928c0b05a80cda0d14ac2e2615f679f1a",
"third_party/externals/zlib" : "https://github.com/GoogleDepends/zlib@47af7c547f8551bd25424e56354a2ae1e9062859",
"../src": {
"url": "https://chromium.googlesource.com/chromium/src.git@d086f1bdb67d4d54ba424d42d01eb256c9a3765f",
"condition": "checkout_chromium",
},
}
recursedeps = [
"common",
"../src",
]
gclient_gn_args_from = 'src'
剩下的就是工具gn.exe,这个可以在网上搜索编译好的:https://download.csdn.net/download/qq_35824650/12398406,下载后放到skia\bin目录下。
不过这样做容易出现各个依赖库版本不一致的文件,最好还是弄个梯子。
打开cmd并且切换到skia目录,按照官方的方法执行命令:
生成静态库
bin/gn gen out/Static --args='is_official_build=true'
生成动态库
bin/gn gen out/Shared --args='is_official_build=true is_component_build=true'
但是直接这样做行不通,有几个坑,编译肯定失败。需要额外注意几个参数:
其中is_official_build参数表示是否只编译skia自身,官方示例写为true,这样在编译过程中会因为缺少三方库而编译失败,所以我直接设置为false。
另外有一个坑,就是官方文档的参数描述(单引号以及斜杠)都是linux环境下的,在windows的cmd下直接报错。可以使用Cygwin工具来执行命令,或者对命令中的路径进行转义。最终的命令如下:
生成静态库
bin\gn gen out\Static --args="is_official_build=false is_debug=false win_vc=\"D:/Software/Program/VS2017/VC\" win_sdk=\"C:/Program Files (x86)/Windows Kits/10\" target_cpu=\"x86\"" --ide="vs2017"
生成动态库
bin\gn gen out\Shared --args="is_official_build=false is_debug=false is_component_build=true win_vc=\"D:/Software/Program/VS2017/VC\" win_sdk=\"C:/Program Files (x86)/Windows Kits/10\" target_cpu=\"x86\"" --ide="vs2017"
这样就可以在skia\out目录下看到生成的项目文件了,可以使用vs打开来查看代码。不过编译的话还是需要使用谷歌的ninja工具(depot_tools里有)。命令为:
ninja -C out/Static
但是这个生成的项目依然会编译失败,cmd解析Program Files(x86)中的空格会报错。
打开skia\out\Static\toolchain.ninja文件,搜索所有的文本内容然后删掉:
cmd /c C:/Program Files (x86)/Windows Kits/10/bin/SetEnv.cmd /x86 &&
打开vs安装的目录,比如我的
D:\Software\Program\VS2017\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64
找到三个dll文件道北到skia\out\Static目录下:
接下来就可以执行ninja -C out/Static来编译了,大概需要3小时时间
官方文档里强烈建议使用LLVM的clang来编译,因为skia针对clang有专门优化,性能要比vs编译的更好。为了需要单独下载LLMV环境:https://releases.llvm.org/download.html。我直接安装到C:/LLVM,不然编译时又会因为Program Files(x86)中的空格而报错。这时需要改生成项目的命令加一个参数:
clang_win = "C:\LLVM" cc="clang" cxx="clang"
示例如下:
bin\gn gen out\StaticLLVM --args="is_official_build=false is_debug=false win_vc=\"D:/Software/Program/VS2017/VC\" win_sdk=\"C:/Program Files (x86)/Windows Kits/10\" cc=\"clang\" cxx=\"clang++\" clang_win=\"C:/LLVM\" target_cpu=\"x86\"" --ide="vs2017"
LLVM编译速度比VS快了很多,大概只花了50分钟。vs编译的静态skia.lib大小为1.04G;LLVM编译的静态skia.lib大小是280M,动态库skia.dll大小为skia.dll
前面说到is_official_build参数用来配置只编译skia自身还是自动编译的三方库依赖。如果加入三方库,那么编译的静态库就会非常大。假如我们只需要skia核心功能或者针对某些功能进行剪裁,可以设置is_official_build为true,然后单独设置禁用或启用某个三方库功能。这是官方文档:
Most users of Skia should set
is_official_build=true
, and most developers should leave it to itsfalse
default.This mode configures Skia in a way that's suitable to ship: an optimized build with no debug symbols, dynamically linked against its third-party dependencies using the ordinary library search path.
In contrast, the developer-oriented default is an unoptimized build with full debug symbols and all third-party dependencies built from source and embedded into libskia. This is how we do all our manual and automated testing.
Skia offers several features that make use of third-party libraries, like libpng, libwebp, or libjpeg-turbo to decode images, or ICU and sftnly to subset fonts. All these third-party dependencies are optional and can be controlled by a GN argument that looks something like
skia_use_foo
for appropriatefoo
.If
skia_use_foo
is enabled, enablingskia_use_system_foo
will build and link Skia against the headers and libaries found on the system paths.is_official_build=true
enables allskia_use_system_foo
by default. You can useextra_cflags
andextra_ldflags
to add include or library paths if needed.
文档中说到:所有这些第三方依赖项都是可选的,并且可以由skia_use_foo来控制,如果设置skia_use_foo为false则会禁止这个foo功能。所有的参数信息参见:skia\gn\skia.gni。
有一个skia_use_system_foo配置项。当is_official_build=true时,并且开启了某个skia_use_foo,那么skia_use_system_foo也是默认开启的。skia_use_system_foo表示从系统里查找这个foo库来编译而不是是从skia自带的三方库。这个时候有两个方法来编译这个三方库:
实际上,我们一般直接用skia自带的三方库就可以,我们只是需要禁用某些三方库。比如我要禁用icu、xml、pdf、xps、webp编解码,只保留png、jpg图片编解码功能。
那么我要禁用:
再开启我需要的(默认的各种功能都是开的,所以其实不用单独设置):
另外我系统直接使用skia自带的三方库,而不是另外设置路径,那么需要:
所以最终的命令我:
bin\gn gen out\StaticLLVMSkiaOnlyWithImage --args="is_official_build=true skia_use_system_libpng=false skia_use_system_libjpeg_turbo=false skia_use_system_zlib=false skia_use_icu=false skia_use_expat=false skia_use_libwebp_decode=false skia_use_libwebp_encode=false skia_use_xps=false skia_enable_pdf=false is_debug=false win_vc=\"D:/Software/Program/VS2017/VC\" win_sdk=\"C:/Program Files (x86)/Windows Kits/10\" cc=\"clang\" cxx=\"clang++\" clang_win=\"C:/LLVM\" target_cpu=\"x86\"" --ide="vs2017"
最后用LLVM编出来的静态文件只有15.6M,大大减小了体积和编译时
skia虽然编译时会依赖很多三方库,包括字体相关freetype库,图片相关png、jpeg、gif等等。但是如果是单单windows平台的话,其实用不到这些依赖。字体功能windows系统有GDI和DriectWrite,图片功能使用WIC组件。所以这些三方库完全可以去掉,单单使用include和src文件夹里的代码来编译就可以。
在src\ports目录下,是skia为了适配各个平台而专门写的适配代码。其中字体相关的有:
其中SkFontHost_win.cpp是GDI字体渲染的实现,SkFontMgr_indirect.cpp、SkFontMgr_win_dw.cpp、SkScalerContext_win_dw.cpp、SkTypeface_win_dw.cpp是DirectWrite字体渲染的实现。SkFontMgr_win_gdi_factory.cpp是创建GDI实现的工厂,SkFontMgr_win_dw_factory.cpp是创建DirectWrite实现的工厂。skia默认使用DirectWrite功能,因为他效果和性能都更好。但是xp系统下不支持DirectWrite。所以可以修改DirectWrite工厂:
原代码:
sk_sp SkFontMgr::Factory() {
return SkFontMgr_New_DirectWrite();
}
修改后:
sk_sp SkFontMgr::Factory() {
auto fontMgr = SkFontMgr_New_DirectWrite();
if (fontMgr)
return fontMgr;
else
return SkFontMgr_New_GDI();
}
src\ports下图片相关的文件:
src\images目录下:
其中SkImageEncoder.cpp文件里是解析图片的入口:
bool SkEncodeImage(SkWStream* dst, const SkPixmap& src,
SkEncodedImageFormat format, int quality) {
#ifdef SK_USE_CG_ENCODER
(void)quality;
return SkEncodeImageWithCG(dst, src, format);
#elif SK_USE_WIC_ENCODER
return SkEncodeImageWithWIC(dst, src, format, quality);
#elif SK_ENABLE_NDK_IMAGES
return SkEncodeImageWithNDK(dst, src, format, quality);
#else
switch(format) {
case SkEncodedImageFormat::kJPEG: {
SkJpegEncoder::Options opts;
opts.fQuality = quality;
return SkJpegEncoder::Encode(dst, src, opts);
}
case SkEncodedImageFormat::kPNG: {
SkPngEncoder::Options opts;
return SkPngEncoder::Encode(dst, src, opts);
}
case SkEncodedImageFormat::kWEBP: {
SkWebpEncoder::Options opts;
if (quality == 100) {
opts.fCompression = SkWebpEncoder::Compression::kLossless;
// Note: SkEncodeImage treats 0 quality as the lowest quality
// (greatest compression) and 100 as the highest quality (least
// compression). For kLossy, this matches libwebp's
// interpretation, so it is passed directly to libwebp. But
// with kLossless, libwebp always creates the highest quality
// image. In this case, fQuality is reinterpreted as how much
// effort (time) to put into making a smaller file. This API
// does not provide a way to specify this value (though it can
// be specified by using SkWebpEncoder::Encode) so we have to
// pick one arbitrarily. This value matches that chosen by
// blink::ImageEncoder::ComputeWebpOptions as well
// WebPConfigInit.
opts.fQuality = 75;
} else {
opts.fCompression = SkWebpEncoder::Compression::kLossy;
opts.fQuality = quality;
}
return SkWebpEncoder::Encode(dst, src, opts);
}
default:
return false;
}
#endif
}
我们可以开启SK_USE_WIC_ENCODER宏(skia没有开启),然后把SkJpegEncoder.cpp、SkJPEGWriteUtility.cpp、SkJPEGWriteUtility.h、SkPngEncoder.cpp、SkWebpEncoder.cpp从项目文件中去掉,就可以使用WIC来解析并去掉额外的三方库依赖了
这次搞得skia版本比较高,必须要c++17的支持,所以我专门搞过老版本的编译。编译的是m49分支(对应chrome49版本)。直接用cmkae生成vs2013工程,来编译。老版本的字体依赖的处理和前面的方法一直。图片依赖的处理,它默认就启用了WIC,只要把png、jpeg、gif等解析器的cpp文件从项目中去掉就可以了。
bin\gn gen out\config --ide=json --json-ide-script=..\..\gn\gn_to_cmake.py --args="win_vc=\"D:/Software/Program/VS2017/VC\" win_sdk=\"C:/Program Files (x86)/Windows Kits/10\""
Redrain QQ:491646717 2020-12-25