概述
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中。
最后
以上就是悲凉薯片为你收集整理的Cobalt编译流程分析的全部内容,希望文章能够帮你解决Cobalt编译流程分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复