Cobalt編譯流程分析

Cobalt Build Flow

1、Cobalt Build Introduction
Cobalt目前使用Pythone+GYP+Ninja進行編譯,使用Python來收集信息以及傳遞參數,例如當前編譯平臺,Cobalt編譯對接的平臺。Gyp用來存儲編譯參數,構建編譯框架,例如每個模塊下面都有一個xxx.gyp,然後將當前模塊編譯成一個目標。Ninja用來處理目標依賴,編譯鏈接文件,例如從編譯鏈配置文件中讀取編譯方式爲gcc,讀取build.ninja中的依賴,然後依照依賴編譯源文件。

2、Python Call Flow
(1), 回顧下之前測試GYP方法,命令爲gyp main.gyp –-depth=. 這裏直接使用gyp文件,但是這裏gyp並不是二進制可執行文件,而是一個shell文件,查看文件內容,我們發現實際執行的是python gyp_main.py。所以查看cobalt的python調用流,實際就是找從開始編譯到調用gyp_main.py的中間過程。

(2),爲了方便理解,我們第一次可以不用讀每一個py文件,只需要修改如下的腳本,就能打印傳進gyp的參數,

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/cobalt/build/gyp_cobalt

  parser.add_argument('-v', '--verbose', dest='verbose_count',
                      default=2, action='count',       ##這裏0改2
                      help='Verbose level (multiple times for more).')

然後執行如下命令:

cobalt/build/gyp_cobalt -C qa linux-x64x11 –v

就能看到打印了gyp的輸入參數

cobalt/build/gyp_cobalt -C qa linux-x64x11 -v

Loading platform configuration for "linux-x64x11".
Searching for ApplicationConfiguration in /home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/x64x11/cobalt
Searching for ApplicationConfiguration in /home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/shared/cobalt
Found ApplicationConfiguration: CobaltLinuxConfiguration in /home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/shared/cobalt/configuration.py
Using platform-specific ApplicationConfiguration for cobalt.
Building config: qa
Retrieving build number from /home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/cobalt/build/build.id
Build Number: 205289
GYP arguments: ['--format=ninja,qtcreator_ninja-linux-x64x11', '--depth=/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src', '--toplevel-dir=/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src', '-DCC_HOST=/home/xiaoshixiu/starboard-toolchains/x86_64-linux-gnu-clang-chromium-298539-1/llvm-build/Release+Asserts/bin/clang', '-Dhost_os=linux', '-Dstarboard_path=starboard/linux/x64x11', '-DOS=starboard', '-Dstarboard_platform_name=linux-x64x11', '-Goutput_dir=out', '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/build/base_configuration.gypi', '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/build/common.gypi', '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/x64x11/gyp_configuration.gypi', '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/cobalt/build/cobalt_configuration.gypi', '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/x64x11/cobalt/configuration.gypi', '-Denable_vr=0', '-Dcobalt_version=205289', '-Duse_tsan=0', '-Dcobalt_config=qa', '-Dcobalt_enable_jit=1', '-Dclang=1', '-Dcobalt_fastbuild=0', '-Duse_asan=0', '-Djavascript_engine=v8', '-Dinclude_path_platform_deploy_gypi=starboard/build/default_no_deploy.gypi', '-Dcustom_media_session_client=0', '-Duse_openssl=1', '-Dasan_symbolizer_path=', '-Gqtcreator_session_name_prefix=cobalt', '-Gconfig=linux-x64x11_qa', '/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/cobalt/build/all.gyp']
Done.

有了上述gyp參數,我們就可以直接找第一個gyp文件,也就是all.gyp,然後依照dependence就可以找到整個工程的編譯順序了。

(3)雖然可以直接得到gyp的輸入參數,但是我希望知道具體每一個參數的讀取方法以及參數值的原始位置,我現在詳細分析:
① gyp_cobalt –C參數,我們知道-C參數後面接上build type,也就是debug,devel,qa,gold,那這幾個參數是在哪裏保存的呢,我們可以看下面的文件:

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/tools/config.py

  DEBUG = 'debug'
  DEVEL = 'devel'
  GOLD = 'gold'
  QA = 'qa'

② gyp_cobalt platform參數,一般在ubuntu上我們配置爲linux-x64x11,但是cobalt怎麼知道有哪些平臺的呢,可以看看下面的文件:

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/tools/platform.py

這個文件裏我們可以知道兩點:1,cobalt判斷支持平臺的方法是搜索starboard下面的文件夾,尋找包含以下文件的目錄:

_PLATFORM_FILES = [
    'gyp_configuration.gypi',
    'gyp_configuration.py',
    'starboard_platform.gyp',
    'configuration_public.h',
    'atomic_public.h',
    'thread_types_public.h',
]

然後將目錄路徑的最後一級結點和倒數第二級結點組合,也就組成平臺名,通常是操作系統-系統架構+圖形架構,例如linux-x64x11。

③從平臺中獲取配置文件,以linux-x64x11爲例,如果我們指定了這個平臺,cobalt會從指定文件中讀取配置內容,可以看下面這個文件:

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/tools/build.py

在_LoadPlatformConfig(platform_name) 函數中可以看到通過下面的文件來獲取配置:

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/linux/x64x11/gyp_configuration.py

然後這個類繼承瞭如下share目錄的配置,

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/linux/shared/gyp_configuration.py

而share目錄的配置繼承了平臺配置,

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/platform_configuration.py

綜上所述,gyp的輸入參數基本都可以從上述三個文件中獲取。

這裏我們舉幾個例子

A:首先是編譯鏈參數,具體類和成員是
/src/starboard/linux/shared/gyp_configuration.py文件中的
GetEnvironmentVariables函數
這裏Call過程我們不分析,直接放Call的最後地點,如下

def _GetClangInstallPath(clang_spec):
  return os.path.join(
      _GetClangBasePath(clang_spec), 'llvm-build', 'Release+Asserts')

所以最後的結果是DCC_HOST=/home/xiaoshixiu/starboard-toolchains/x86_64-linux-gnu-clang-chromium-298539-1/llvm-build/Release+Asserts/bin/clang,可以看到最後的結果連接了是home的user目錄的編譯鏈,這個編譯鏈是自動創建的。

B:然後我們可以找下gyp的include文件,這些文件將被第一個gyp文件所包含。我們可以在如下文件中找到gypi include規則。

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/gyp_runner.py

首先

‘-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/build/base_configuration.gypi‘,

 '-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/build/common.gypi'

這兩個文件是和平臺無關的,無論什麼平臺都要包含。

然後可以在如下文件中找到平臺配置

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/platform_configuration.py

平臺配置文件使用如下規則:return [os.path.join(platform_info.path, ‘gyp_configuration.gypi’)],也就是只需要在對應平臺的目錄下找到gyp_configuration.gypi即可。Linux-x64x11對應的是:

'-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/x64x11/gyp_configuration.gypi'

接下來是應用配置,指定這些頭文件的腳本在如下文件中:

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/linux/shared/cobalt/configuration.py

而此文件同樣引用瞭如下文件

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/cobalt/build/cobalt_configuration.py

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/application_configuration.py

所以最後通過上述兩個文件的GetPostIncludes方法,將頭文件搜索到。搜索規則是
1、直接引用
'-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/cobalt/build/cobalt_configuration.gypi'
2,在平臺下找到cobalt目錄,然後在cobalt目錄下找configuration.gypi文件,如果找得到就添加到頭文件列表中,注意在不同的平臺中這個文件不一定都有,從內容上看它和平臺配置是有一定的重合的,而且應用名不一定爲cobalt。

'-I/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/starboard/linux/x64x11/cobalt/configuration.gypi'

④,接下來我們討論下宏配置。
我們可以發現gyp輸入參數的宏和平臺配置文件gypi有一定的重合,說明這些是默認的平臺配置。在下面文件中可以發現定義了variables變量。

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/platform_configuration.py

variables = {
        'clang': use_clang,
        # Whether to build with clang's Address Sanitizer instrumentation.
        'use_asan': use_asan,
        # Whether to build with clang's Thread Sanitizer instrumentation.
        'use_tsan': use_tsan,
        # Which JavaScript engine to use.  Currently, both SpiderMonkey 45 and
        # V8 are supported.  Note that V8 can only be used on platforms that
        # support JIT.
        'javascript_engine': 'mozjs-45',
        # Disable JIT and run in interpreter-only mode by default. It can be
        # set to 1 to run in JIT mode.  For SpiderMonkey in particular, we
        # have found that disabling JIT often results in faster JavaScript
        # execution and lower memory usage.  Setting this to 0 for engine that
        # requires JIT, or 1 on a platform that does not support JIT, is a
        # usage error.
        'cobalt_enable_jit': 0,
        # TODO: Remove these compatibility variables.
        'cobalt_config': config_name,
        'cobalt_fastbuild': 0,
        'custom_media_session_client': 0,
        'enable_vr': 0,
}

然後這些變量被傳到下面文件的

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/gyp_runner.py

中的configuration_variables。最後附加到gyp的參數args中。另外也可以在

https://cobalt.googlesource.com/cobalt/+/refs/heads/19.lts.stable/src/starboard/build/gyp_runner.py

中找到common_variables和generator_variables,包含了如下參數:

 common_variables = {
        'OS': 'starboard',
        'CC_HOST': os.environ.get('CC_HOST', os.environ.get('CC', '')),
        'host_os': _GetHostOS(),
        'starboard_path': os.path.relpath(platform.Get(platform_name).path,
                                          source_tree_dir),
        'starboard_platform_name': platform_name,
    }
    _AppendVariables(common_variables, self.common_args)
    # Append generator variables.
    generator_variables = {
        # Set the output folder name; affects all generators but MSVS.
        'output_dir': 'out',
    }

⑤,我們可以畫個uml來初步表達上述python執行流程:
在這裏插入圖片描述
3、GYP Dependency Flow
分析了GYP的輸入參數,接下來我們分析gyp文件的依賴樹以及不同gyp和gypi的作用。
①,首先分析第一個GYP文件,也就是’/home/xiaoshixiu/workhome/cobalt/cobalt_19_lts_5/cobalt/src/cobalt/build/all.gyp’,我這裏用uml把依賴圖畫出來:
在這裏插入圖片描述
當然我沒有畫出cobalt的其他依賴,只是把從cobalt到starboard的依賴畫了出來。我們可以發現,帶有configuration的gyp/gypi文件都是python腳本執行時動態指定的,而帶有platform的gyp/gypi文件都是在文件中指定依賴的。這樣我們可以大致分類爲,對cobalt的feature進行配置的參數在configuration的gyp/gypi中,而對cobalt的代碼源文件進行配置的參數在platform的gyp/gypi中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章