Skia构建系统与编译脚本分析

分析下Skia的构建系统,具体编译过程参看Windows下从源码编译Skia。这里以ninja为例来分析。执行下面三条命令就可以完成编译:

SET "GYP_GENERATORS=ninja"
python bin/sync-and-gyp 
ninja -C out\Release

“python bin/sync-and-gyp”会生成ninja脚本。下面来分析脚本层级以及某个模块的脚本内容和结构。关于ninja,参考https://ninja-build.org/manual.html或http://guiquanz.me/2014/07/28/a_intro_to_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.x86
cc = $cl_x86
cxx = $cl_x86
cc_host = $cl_x86
cxx_host = $cl_x86
asm = $ml_x86
build obj\gyp\images.actions_depends.stamp: stamp obj\gyp\libjpeg-turbo.lib $
    obj\gyp\libwebp.actions_depends.stamp

pdbname_c = images.pdb
pdbname_cc = images.pdb
pchprefix = images
defines = -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 -DNDEBUG
asmflags = 
rcflags = /I..\..\gyp
includes = -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\win
midl_includes = 
cflags = /wd4275 /wd4345 /wd4355 /Ox /Ot /fp:precise /W3 /WX /Zi /GR- /MD $
    /we4189 /arch:SSE2 /FS
cflags_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=0
cflags_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 /TP
arflags = 

build obj\src\images\images.bmpdecoderhelper.obj: cxx $
    ..\..\src\images\bmpdecoderhelper.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkDecodingImageGenerator.obj: cxx $
    ..\..\src\images\SkDecodingImageGenerator.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkForceLinking.obj: cxx $
    ..\..\src\images\SkForceLinking.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder.obj: cxx $
    ..\..\src\images\SkImageDecoder.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_FactoryRegistrar.obj: cxx $
    ..\..\src\images\SkImageDecoder_FactoryRegistrar.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_wbmp.obj: cxx $
    ..\..\src\images\SkImageDecoder_wbmp.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_pkm.obj: cxx $
    ..\..\src\images\SkImageDecoder_pkm.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_ktx.obj: cxx $
    ..\..\src\images\SkImageDecoder_ktx.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_astc.obj: cxx $
    ..\..\src\images\SkImageDecoder_astc.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libbmp.obj: cxx $
    ..\..\src\images\SkImageDecoder_libbmp.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libico.obj: cxx $
    ..\..\src\images\SkImageDecoder_libico.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libwebp.obj: cxx $
    ..\..\src\images\SkImageDecoder_libwebp.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libjpeg.obj: cxx $
    ..\..\src\images\SkImageDecoder_libjpeg.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libpng.obj: cxx $
    ..\..\src\images\SkImageDecoder_libpng.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageDecoder_libgif.obj: cxx $
    ..\..\src\images\SkImageDecoder_libgif.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageEncoder.obj: cxx $
    ..\..\src\images\SkImageEncoder.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageEncoder_Factory.obj: cxx $
    ..\..\src\images\SkImageEncoder_Factory.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkImageEncoder_argb.obj: cxx $
    ..\..\src\images\SkImageEncoder_argb.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkJpegUtility.obj: cxx $
    ..\..\src\images\SkJpegUtility.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkMovie.obj: cxx ..\..\src\images\SkMovie.cpp $
    || obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkPageFlipper.obj: cxx $
    ..\..\src\images\SkPageFlipper.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\images\images.SkScaledBitmapSampler.obj: cxx $
    ..\..\src\images\SkScaledBitmapSampler.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\ports\images.SkImageGenerator_skia.obj: cxx $
    ..\..\src\ports\SkImageGenerator_skia.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp
build obj\src\ports\images.SkImageDecoder_WIC.obj: cxx $
    ..\..\src\ports\SkImageDecoder_WIC.cpp || $
    obj\gyp\libjpeg-turbo.actions_rules_copies.stamp

build 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可以设置编译选项。

要增加一个文件,按下面做即可:

  1. 可以新增一条build obj语句,设置某个cpp文件的编译规则
  2. build skia_images.lib语句中加入第1步里生成的obj文件

有了这些基础,就可以单独修改某个模块了。

要单独编译某个模块,可以参考下面的命令:

ninja images
ninja 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的编译,最常见的用法有两种:

  1. 控制某个模块的编译开关
  2. 修改编译选项

模块编译开关

https://skia.org/user/tips,这里说可以通过GYP_DEFINES来控制某个功能,举的例子如下:

GYP_DEFINES='skia_gpu=0 skia_pdf=0' python bin/sync-and-gyp
ninja -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"

修改编译选项

编译选项有两种改法:

  1. 修改ninja中的conditions(skia\gyp\common_conditions.gypi)
  2. 通过环境变量传递

一个一个说吧。

  • 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) 通过环境变量传递

https://skia.org/user/tips,这里说可以通过在命令行环境设置CC、CXX、CFLAGS、CPPFLAGS、CXXFLAGS来传递一些编译选项。

“python bin/sync-and-gyp”语句执行过程中会分析环境变量,整合到输出的构建脚本中。

https://skia.org/user/tips,这里给的示例如下:

CXXFLAGS='-Wunused-parameter' \
    CC='clang' CXX='clang++' python bin/sync-and-gyp
ninja -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”之类的选项。

就这样吧。

其他参考文章详见我的专栏:【CEF与PPAPI开发】。

你可能感兴趣的:(chromium,Skia,Ninja,CEF,PPAPI)