最近经常编译许多不同版本的V8,用来做漏洞复现和研究学习,但是由于python和jinjia版本较高,经常出现同一个报错,这里写个通用解决方式。

报错信息

基本报错如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ninja: Entering directory `out/x64_9.5.172.21.release'
[209/1834] ACTION //src/inspector:protocol_generated_sources(//build/toolchain/linux:clang_x64)
FAILED: gen/src/inspector/protocol/Forward.h gen/src/inspector/protocol/Protocol.cpp gen/src/inspector/protocol/Protocol.h gen/src/inspector/protocol/Console.cpp gen/src/inspector/protocol/Console.h gen/src/inspector/protocol/Debugger.cpp gen/src/inspector/protocol/Debugger.h gen/src/inspector/protocol/HeapProfiler.cpp gen/src/inspector/protocol/HeapProfiler.h gen/src/inspector/protocol/Profiler.cpp gen/src/inspector/protocol/Profiler.h gen/src/inspector/protocol/Runtime.cpp gen/src/inspector/protocol/Runtime.h gen/src/inspector/protocol/Schema.cpp gen/src/inspector/protocol/Schema.h gen/include/inspector/Debugger.h gen/include/inspector/Runtime.h gen/include/inspector/Schema.h
python3 ../../third_party/inspector_protocol/code_generator.py --jinja_dir ../../third_party/ --output_base gen/src/inspector --config ../../src/inspector/inspector_protocol_config.json --inspector_protocol_dir ///third_party/inspector_protocol
Traceback (most recent call last):
File "/home/loorain/v8/v8/out/x64_9.5.172.21.release/../../third_party/inspector_protocol/code_generator.py", line 702, in <module>
main()
File "/home/loorain/v8/v8/out/x64_9.5.172.21.release/../../third_party/inspector_protocol/code_generator.py", line 584, in main
jinja_env = initialize_jinja_env(jinja_dir, config.protocol.output, config)
File "/home/loorain/v8/v8/out/x64_9.5.172.21.release/../../third_party/inspector_protocol/code_generator.py", line 190, in initialize_jinja_env
import jinja2
File "/home/loorain/v8/v8/third_party/jinja2/__init__.py", line 33, in <module>
from jinja2.environment import Environment, Template
File "/home/loorain/v8/v8/third_party/jinja2/environment.py", line 16, in <module>
from jinja2.defaults import BLOCK_START_STRING, \
File "/home/loorain/v8/v8/third_party/jinja2/defaults.py", line 32, in <module>
from jinja2.tests import TESTS as DEFAULT_TESTS
File "/home/loorain/v8/v8/third_party/jinja2/tests.py", line 13, in <module>
from collections import Mapping
ImportError: cannot import name 'Mapping' from 'collections' (/usr/lib/python3.10/collections/__init__.py)
[226/1834] CXX obj/torque_base/implementation-visitor.o
ninja: build stopped: subcommand failed.

主要问题就是**ImportError: cannot import name 'Mapping' from 'collections'**,查询资料可以确定问题主要是py版本导致的问题。

这个问题是由于 jinja2 模块在 Python 3.10 中无法正常导入 Mapping 类导致的。Python 3.10 已将 Mapping 类从 collections 模块移到了 collections.abc 模块,而你的代码可能是基于较早版本的 Python,仍然从 collections 中导入 Mapping

解决方法

方法一

问题主要是因为python版本较高导致的,因此编译时选用低于python3.10的python进行编译,就能解决。最好使用3.9或更早的小版本。

方法二

虽然换版本可以解决,不过像我这种懒人很讨厌配多个环境,所以可以手动更改v8代码。

这里我写了两个脚本,一个用于编译前更改代码,一个用于编译后恢复代码

更改 jinja2collections 引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

# 这里改成自己的tests.py路径,在报错信息中可以看到
JINJA2_TESTS_PY="/home/loorain/v8/v8/third_party/jinja2/tests.py"

# 检查文件是否存在
if [ ! -f "$JINJA2_TESTS_PY" ]; then
echo "文件 $JINJA2_TESTS_PY 不存在。请检查路径是否正确。"
exit 1
fi

# 备份原始文件
cp "$JINJA2_TESTS_PY" "$JINJA2_TESTS_PY.bak"
echo "已备份文件为 $JINJA2_TESTS_PY.bak"

# 使用sed命令替换collections导入为collections.abc
sed -i 's/from collections import Mapping/from collections.abc import Mapping/' "$JINJA2_TESTS_PY"
echo "已修改 $JINJA2_TESTS_PY 文件,将 'from collections import Mapping' 替换为 'from collections.abc import Mapping'"

恢复 jinja2 的原始 collections 引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash

# 更改路径位置
JINJA2_TESTS_PY="/home/loorain/v8/v8/third_party/jinja2/tests.py"
JINJA2_TESTS_PY_BAK="$JINJA2_TESTS_PY.bak"

# 检查备份文件是否存在
if [ ! -f "$JINJA2_TESTS_PY_BAK" ]; then
echo "备份文件 $JINJA2_TESTS_PY_BAK 不存在。无法恢复。"
exit 1
fi

# 恢复备份文件
cp "$JINJA2_TESTS_PY_BAK" "$JINJA2_TESTS_PY"
echo "已恢复 $JINJA2_TESTS_PY 文件为备份版本"

# 删除备份文件(如果你希望保留备份文件,可以注释掉这行)
rm "$JINJA2_TESTS_PY_BAK"
echo "已删除备份文件 $JINJA2_TESTS_PY_BAK"