#!/usr/bin/env python
import third_party
from util import run, root_path, build_path, build_mode
import os
import re
import sys
from distutils.spawn import find_executable
def main():
os.chdir(root_path) # 1. 改变到当前目录 `cd ../..`
third_party.fix_symlinks() # 2. 建立起 第三方项目与根项目相关的软连接
third_party.download_gn()
third_party.download_clang_format()
third_party.download_clang()
third_party.maybe_download_sysroot()
write_lastchange()
mode = build_mode(default=None) # 确认 deno脚本的等级模式
if mode is not None: # 这里主要就是 mode == default == Node
gn_gen(mode)
else:
gn_gen("release")
gn_gen("debug")
- third_party 第三方包, 或 下载对应
- write_lastchange
- util > build_mode
- gn_gen
如果filename
不存在, 就写入contents
def write_if_not_exists(filename, contents):
if not os.path.exists(filename):
with open(filename, "w+") as f:
f.write(contents)
如有需要,标上变化Change的标签
def write_lastchange():
write_if_not_exists(
"build/util/LASTCHANGE",
"LASTCHANGE=c42e4ddbb7973bfb0c57a49ab6bf6dc432baad7e-\n")
write_if_not_exists("build/util/LASTCHANGE.committime", "1535518087")
# TODO 我们应该调用以下脚本,但它似乎会导致
# 每次提交都要重建。
# run([
# sys.executable, "build/util/lastchange.py", "-o",
# "build/util/LASTCHANGE", "--source-dir", root_path, "--filter="
# ])
是否在字符串中, 匹配到下面文本.
# 如果在 args.gn 中找到此文本,我们假设它未经过手工编辑。
gn_args_header = [
"# This file is automatically generated by tools/setup.py.",
"# REMOVE THIS LINE to preserve any changes you make.", ""
]
def gn_args_are_generated(lines):
for line in lines:
if re.match("^\s*#.*REMOVE THIS LINE", line):
return True
return False
- 不存在文件, 自然都是 否定的
- 存在, 返回 参数+是否手工
def read_gn_args(args_filename):
if not os.path.exists(args_filename):
return (None, False) # 没有内容, 不是手工修改的
with open(args_filename) as f:
lines = f.read().splitlines()
args = [l.strip() for l in lines if not re.match("^\s*(#|$)", l)]
hand_edited = not gn_args_are_generated(lines)
return (args, hand_edited)
写入, gn 参数-args
到 args_filename
def write_gn_args(args_filename, args):
assert not gn_args_are_generated(args) # 没有标题 -> 手工制作。
lines = gn_args_header + args
assert gn_args_are_generated(lines) # 用标题 -> 生成。
# 确保 args.gn 存在的目录。
dir = os.path.dirname(args_filename)
if not os.path.isdir(dir):
os.makedirs(dir)
with open(args_filename, "w") as f:
f.write("\n".join(lines) + "\n")
获取 gn 需要的参数
TODO 详解 ?
def generate_gn_args(mode):
out = []
if mode == "release":
out += ["is_official_build=true"]
elif mode == "debug":
pass
else:
print "Bad mode {}. Use 'release' or 'debug' (default)" % mode
sys.exit(1)
if "DENO_BUILD_ARGS" in os.environ:
out += os.environ["DENO_BUILD_ARGS"].split()
# 检查 ccache 或 sccache 是否在路径中,如果是,我们设置 cc_wrapper。
cc_wrapper = find_executable("ccache") or find_executable("sccache")
if cc_wrapper:
out += ['cc_wrapper="%s"' % cc_wrapper]
# 要使 cc_wrapper 在Windows上运行,我们需要选择自己的工具链
# 通过覆盖'custom_toolchain'和'host_toolchain'。
# TODO:有没有办法在没有 args.gn 的情况下使用它?
if os.name == "nt":
tc = "//build_extra/toolchain/win:win_clang_x64"
out += ['custom_toolchain="%s"' % tc, 'host_toolchain="%s"' % tc]
return out
find_executable
返回是否能在shell使用
GN 生成
deno第三方包-V8-使用的构建系统是Ninja,而 GN 是用来生成
.ninja
文件的工具。
GN 被包含在 depot_tools 中
def gn_gen(mode):
os.environ["DENO_BUILD_MODE"] = mode
# 我们不是直接使用 gn gen --args 而是写入 args.gn 文件。
# 这是为了避免在传递命令行参数时,会覆盖, 引起 quoting/escaping 并发症
args_filename = os.path.join(build_path(), "args.gn") # 根据构建模式,返回参数文件路径
# 检查 args.gn 是否存在,以及它是自动生成还是手工制作。
existing_gn_args, hand_edited = read_gn_args(args_filename)
# 如果 args.gn 不是手工制作的,那就重新生成它。
if hand_edited:
print "%s: Using gn options from hand edited '%s'." % (mode,
args_filename)
gn_args = existing_gn_args
else:
print "%s: Writing gn options to '%s'." % (mode, args_filename)
gn_args = generate_gn_args(mode) # 生成的参数
if gn_args != existing_gn_args:
write_gn_args(args_filename, gn_args) # 写入
for line in gn_args:
print " " + line # 调试展示
# 运行 gn
run([third_party.gn_path, "gen", build_path()],
env=third_party.google_env()) # 整合环境变量
- build_path 构建路径确认
- read_gn_args
- third_party
- gn_path
- google_env 整合环境变量
- generate_gn_args
- write_gn_args
if __name__ == '__main__':
sys.exit(main())