分析下Skia的构建系统,详细编译过程參看。这里以ninja为例来分析。运行以下三条命令就能够完毕编译:
SET "GYP_GENERATORS=ninja"python bin/sync-and-gyp ninja -C out\Release
“python bin/sync-and-gyp”会生成ninja脚本。以下来分析脚本层级以及某个模块的脚本内容和结构。
关于ninja,參考或。
ninja脚本层级及模块脚本说明
skia\gyp以下的gyp脚本是模板。运行sync-and-gyp时会依据这些模板来动态生成实际的构建脚本。非常多模块依赖、条件等都能够在这个文件夹下的gyp或gypi中找到。
sync-and-gyp之后。out\Release\build.ninja。是总的编译脚本。里面定义了all,还定义了默认编译目标为most。
most相应的ninja脚本是out\Release\obj\gyp\most.ninja。
假设想编译某个单独的模块,能够运行“ninja module_name”,比方“ninja images”,“ninja giflib”等。
详细到某个模块的编译脚本,都在out\Release\obj\gyp\文件夹下。某个模块的ninja脚本中,定义了详细的编译规则。以images.ninja(相应skia_images.lib)为例来说明下,它的内容例如以下:
arch = environment.x86cc = $cl_x86cxx = $cl_x86cc_host = $cl_x86cxx_host = $cl_x86asm = $ml_x86build obj\gyp\images.actions_depends.stamp: stamp obj\gyp\libjpeg-turbo.lib $ obj\gyp\libwebp.actions_depends.stamppdbname_c = images.pdbpdbname_cc = images.pdbpchprefix = imagesdefines = -DSK_INTERNAL -DSK_GAMMA_SRGB -DSK_GAMMA_APPLY_TO_A8 $ -DSK_ALLOW_STATIC_GLOBAL_INITIALIZERS=1 -DSK_SUPPORT_GPU=0 $ -DSK_FORCE_DISTANCE_FIELD_TEXT=0 -DSK_BUILD_FOR_WIN32 $ -D_CRT_SECURE_NO_WARNINGS -DGR_GL_FUNCTION_TYPE=__stdcall $ -D_HAS_EXCEPTIONS=0 -DNDEBUG -DNDEBUGasmflags = rcflags = /I..\..\gypincludes = -I..\..\include\images -I..\..\include\private -I..\..\src\lazy $ -I..\..\src\core -I..\..\src\image -I..\..\include\c $ -I..\..\include\config -I..\..\include\core -I..\..\include\pathops $ -I..\..\gyp\config\win -I..\..\third_party\externals\libjpeg-turbo $ -I..\..\third_party\externals\libpng -I..\..\third_party\libpng $ -I..\..\third_party\externals\giflib -I..\..\third_party\giflib $ -I..\..\third_party\etc1 -I..\..\third_party\ktx $ -I..\..\third_party\externals\libwebp\src -I..\..\include\utils $ -I..\..\src\utils -I..\..\include\utils\winmidl_includes = cflags = /wd4275 /wd4345 /wd4355 /Ox /Ot /fp:precise /W3 /WX /Zi /GR- /MD $ /we4189 /arch:SSE2 /FScflags_c = -DSK_A32_SHIFT=24 -DSK_B32_SHIFT=16 -DSK_G32_SHIFT=8 $ -DSK_R32_SHIFT=0 -DSK_A32_SHIFT=24 -DSK_B32_SHIFT=16 -DSK_G32_SHIFT=8 $ -DSK_R32_SHIFT=0cflags_cc = -DSK_A32_SHIFT=24 -DSK_B32_SHIFT=16 -DSK_G32_SHIFT=8 $ -DSK_R32_SHIFT=0 -DSK_A32_SHIFT=24 -DSK_B32_SHIFT=16 -DSK_G32_SHIFT=8 $ -DSK_R32_SHIFT=0 /TParflags = build obj\src\images\images.bmpdecoderhelper.obj: cxx $ ..\..\src\images\bmpdecoderhelper.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkDecodingImageGenerator.obj: cxx $ ..\..\src\images\SkDecodingImageGenerator.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkForceLinking.obj: cxx $ ..\..\src\images\SkForceLinking.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder.obj: cxx $ ..\..\src\images\SkImageDecoder.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_FactoryRegistrar.obj: cxx $ ..\..\src\images\SkImageDecoder_FactoryRegistrar.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_wbmp.obj: cxx $ ..\..\src\images\SkImageDecoder_wbmp.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_pkm.obj: cxx $ ..\..\src\images\SkImageDecoder_pkm.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_ktx.obj: cxx $ ..\..\src\images\SkImageDecoder_ktx.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_astc.obj: cxx $ ..\..\src\images\SkImageDecoder_astc.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libbmp.obj: cxx $ ..\..\src\images\SkImageDecoder_libbmp.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libico.obj: cxx $ ..\..\src\images\SkImageDecoder_libico.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libwebp.obj: cxx $ ..\..\src\images\SkImageDecoder_libwebp.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libjpeg.obj: cxx $ ..\..\src\images\SkImageDecoder_libjpeg.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libpng.obj: cxx $ ..\..\src\images\SkImageDecoder_libpng.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageDecoder_libgif.obj: cxx $ ..\..\src\images\SkImageDecoder_libgif.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageEncoder.obj: cxx $ ..\..\src\images\SkImageEncoder.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageEncoder_Factory.obj: cxx $ ..\..\src\images\SkImageEncoder_Factory.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkImageEncoder_argb.obj: cxx $ ..\..\src\images\SkImageEncoder_argb.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkJpegUtility.obj: cxx $ ..\..\src\images\SkJpegUtility.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkMovie.obj: cxx ..\..\src\images\SkMovie.cpp $ || obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkPageFlipper.obj: cxx $ ..\..\src\images\SkPageFlipper.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\images\images.SkScaledBitmapSampler.obj: cxx $ ..\..\src\images\SkScaledBitmapSampler.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\ports\images.SkImageGenerator_skia.obj: cxx $ ..\..\src\ports\SkImageGenerator_skia.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild obj\src\ports\images.SkImageDecoder_WIC.obj: cxx $ ..\..\src\ports\SkImageDecoder_WIC.cpp || $ obj\gyp\libjpeg-turbo.actions_rules_copies.stampbuild skia_images.lib: alink obj\src\images\images.bmpdecoderhelper.obj $ obj\src\images\images.SkDecodingImageGenerator.obj $ obj\src\images\images.SkForceLinking.obj $ obj\src\images\images.SkImageDecoder.obj $ obj\src\images\images.SkImageDecoder_FactoryRegistrar.obj $ obj\src\images\images.SkImageDecoder_wbmp.obj $ obj\src\images\images.SkImageDecoder_pkm.obj $ obj\src\images\images.SkImageDecoder_ktx.obj $ obj\src\images\images.SkImageDecoder_astc.obj $ obj\src\images\images.SkImageDecoder_libbmp.obj $ obj\src\images\images.SkImageDecoder_libico.obj $ obj\src\images\images.SkImageDecoder_libgif.obj $ obj\src\images\images.SkImageDecoder_libwebp.obj $ obj\src\images\images.SkImageDecoder_libjpeg.obj $ obj\src\images\images.SkImageDecoder_libpng.obj $ obj\src\images\images.SkImageEncoder.obj $ obj\src\images\images.SkImageEncoder_Factory.obj $ obj\src\images\images.SkImageEncoder_argb.obj $ obj\src\images\images.SkJpegUtility.obj $ obj\src\images\images.SkMovie.obj $ obj\src\images\images.SkPageFlipper.obj $ obj\src\images\images.SkScaledBitmapSampler.obj $ obj\src\ports\images.SkImageGenerator_skia.obj $ obj\src\ports\images.SkImageDecoder_WIC.obj || $ obj\gyp\images.actions_depends.stamp libflags =
能够看到,ninja脚本分例如以下几部分:
- 编译平台和工具链
- 编译选项(defines、cflags、includes等)
- 编译规则(build obj開始的语句)
- 生成库的规则(build skia_images.lib那行)
假设我们要改动某个子模块,依据上面分析,就能够改动相应的ninja脚本,defines能够添加一些宏定义,includes能够设置包括路径。cflags、cflags_c、cflags_cc能够设置编译选项。
要添加一个文件,按以下做就可以:
- 能够新增一条build obj语句,设置某个cpp文件的编译规则
- build skia_images.lib语句中添加第1步里生成的obj文件
有了这些基础,就能够单独改动某个模块了。
要单独编译某个模块,能够參考以下的命令:
ninja imagesninja codec
要清理某个模块,能够參考以下的命令:
ninja -t clean images
模块间的依赖
skia\gyp以下的gyp脚本是模板,运行sync-and-gyp时会依据这些模板来动态生成实际的构建脚本。这里的一些gyp脚本定义了模块间的依赖关系。比方images.gyp,有这些依赖:
'dependencies': [ 'core.gyp:*', 'giflib.gyp:giflib', 'libjpeg-turbo-selector.gyp:libjpeg-turbo-selector', 'etc1.gyp:libetc1', 'ktx.gyp:libSkKTX', 'libwebp.gyp:libwebp', 'utils.gyp:utils', ]
然后后面又分平台又一次设置了依赖条件和源文件。我发如今Windows下,运行“python bin/sync-and-gyp”生成的skia\out\Release\obj\gyp\images.ninja中,就没有SkImageDecoder_libpng.cpp哦。
编译选项
在运行“python bin/sync-and-gyp”之前。能够设置一些环境变量来控制Skia的编译。最常见的使用方法有两种:
- 控制某个模块的编译开关
- 改动编译选项
模块编译开关
,这里说能够通过GYP_DEFINES来控制某个功能,举的样例例如以下:
GYP_DEFINES='skia_gpu=0 skia_pdf=0' python bin/sync-and-gypninja -C out/Debug
在Windows下,这样设置GYP_DEFINES:
set "GYP_DEFINES=skia_gpu=0 skia_pdf=0"
注意,假设你真的设置了skia_gpu=0,默认编译过程会出错。这是由于bench工具要求定义skia_gpu。只是假设你不须要这个工具倒没关系,出错时各种lib已经正常生成了。
skia\gyp\common_variables.gypi这个文件中有提到了能够使用的开关(应该有个文档说明吧,我没找到,Skia的资料还是太少),比方skia_gpu、skia_pdf、skia_egl、skia_angle等。以下的语句可供參考:
set "GYP_DEFINES=skia_gpu=0 skia_pdf=0 skia_egl=0 skia_angle=0"
改动编译选项
编译选项有两种改法:
- 改动ninja中的conditions(skia\gyp\common_conditions.gypi)
- 通过环境变量传递
一个一个说吧。
- 1) conditions
打开skia\gyp\common_conditions.gypi看看就知道有哪些条件了。比方Windows的Release版本号,编译器选项设置例如以下:
'msvs_settings': { 'VCCLCompilerTool': { 'DebugInformationFormat': '3', # programDatabase (/Zi) 'Optimization': '<(skia_release_optimization_level)', # Changing the floating point model requires rebaseling gm images #'FloatingPointModel': '2', # fast (/fp:fast) 'FavorSizeOrSpeed': '1', # speed (/Ot) 'PreprocessorDefinitions': ['NDEBUG'], 'RuntimeLibrary': '2', # rtMultiThreadedDLL (/MD) 'EnableEnhancedInstructionSet': '2',# /arch:SSE2 'RuntimeTypeInfo': 'false', # /GR- }, 'VCLinkerTool': { 'GenerateDebugInformation': 'true', # /DEBUG }, }
能够看到,设置了RuntimeLibrary为 /MD(多线程动态库)。假设要改动,直接改这个文件,整个编译时就都变了(我没试哈,仅仅是分析)。其他的选项相似。
- 2) 通过环境变量传递
,这里说能够通过在命令行环境设置CC、CXX、CFLAGS、CPPFLAGS、CXXFLAGS来传递一些编译选项。
“python bin/sync-and-gyp”语句运行过程中会分析环境变量。整合到输出的构建脚本中。
。这里给的示比例如以下:
CXXFLAGS='-Wunused-parameter' \ CC='clang' CXX='clang++' python bin/sync-and-gypninja -C out/Debug
在Windows下,应该这样设置:
set "CFLAGS=-DYOURMACRO=1 -DXXX=16"set "CXXFLAGS=-DYOURMACRO=1 -DXXX=16"
我前面给出的images.ninja演示样例,我设置了CFLAGS、CXXFLAGS、CPPFLAGS。所以你会看到该ninja脚本中cflags_c、cflags_cc都添加了“-DSK_A32_SHIFT=24”之类的选项。
就这样吧。
其他參考文章详见我的专栏:【】。