host:ubuntu12.04,gcc4.6,glibc2.15
target: x86, ia32,gcc4.9, glibc2.20
编译v8的时候,先编译host程序,然后用host程序产生一些文件,最后再编译target程序。
这里提示运行host程序mksnapshot时,找不到libstdc++.so.6里面GLIBCXX_3.4.20版本的某个符号:
CXX(target) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.target/v8_nosnapshot/src/snapshot/snapshot-empty.o
AR(host) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/tools/gyp/libv8_nosnapshot.a
CXX(host) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/mksnapshot/src/snapshot/mksnapshot.o
AR(target) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.target/tools/gyp/libv8_nosnapshot.a
AR(host) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/testing/libgtest.a
LINK(host) /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot
ACTION tools_gyp_v8_gyp_v8_snapshot_target_run_mksnapshot /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.target/v8_snapshot/geni/snapshot.cc
ACTION tools_gyp_v8_gyp_v8_snapshot_host_run_mksnapshot /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/v8_snapshot/geni/snapshot.cc
/disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot: /usr/lib/i386-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot)
/disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot: /usr/lib/i386-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot)
make[2]: *** [/disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.target/v8_snapshot/geni/snapshot.cc] Error 1
make[2]: *** Waiting for unfinished jobs....
先看看mksnapshot到底缺少哪一个符号,使用objdump -C -T out/ia32.release/mksnapshot | grep GLIBCXX_3.4.20:
shuyin.wsy@localhost:/disk7/shuyin.wsy/codebase_host/vm/v8$ objdump -C -T out/ia32.release/mksnapshot | grep GLIBCXX_3.4.20
00000000 DF *UND* 00000000 GLIBCXX_3.4.20 std::__throw_out_of_range_fmt(char const*, ...)
-C是将c++的符号解码为用户可以看明白的符号;-T显示dynamic-syms,nm --dynamic也可以显示动态符号,但是objdump -T的带有符号版本,更方便。
编译的时候没问题,也连接成功了,但是运行时出现了问题,可能是host程序链接了target的动态库,验证一下:
shuyin.wsy@localhost:/disk7/shuyin.wsy/codebase_host/vm/v8$ objdump -C -T /lib/i386-linux-gnu/libc.so.6 | grep GLIBCXX_3.4.20
shuyin.wsy@localhost:/disk7/shuyin.wsy/codebase_host/vm/v8$ objdump -C -T /disk7/shuyin.wsy/codebase_host/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/sysroot/usr/lib/libstdc++.so.6 | grep GLIBCXX_3.4.20
000a3490 g DF .text 000000d0 GLIBCXX_3.4.20 std::__throw_out_of_range_fmt(char const*, ...)
0004a390 g DF .text 00000012 GLIBCXX_3.4.20 std::get_new_handler()
000a4780 g DF .text 000000e9 GLIBCXX_3.4.20 std::regex_error::regex_error(std::regex_constants::error_type)
00000000 g DO *ABS* 00000000 GLIBCXX_3.4.20 GLIBCXX_3.4.20
00049b10 g DF .text 00000014 GLIBCXX_3.4.20 std::get_terminate()
00049b90 g DF .text 00000014 GLIBCXX_3.4.20 std::get_unexpected()
确认是链接了target的动态库,可能是使用ld时指定了错误的参数(-Lsome_target_libdir);可能是环境变量里面有问题(比如LIBRARY_PATH=some_target_libdir:${LIBRARY_PATH});也可能是使用了target的i686-linux-gnu-g++(i686-linux-gnu-g++设置LIBRARY_PATH环境变量,包含了target动态库的路径,然后调用collect程序,collect程序再去调用ld)。
经过分析,排出前两种可能,给build/gyp/pylib/gyp/generator/make.py打如下patch,可以在连接mksnapshot的时候报错,把命令打出来:
diff --git a/build/gyp/pylib/gyp/generator/make.py b/build/gyp/pylib/gyp/generator/ma
index 786b4e0..fd3bf65 100644
--- a/build/gyp/pylib/gyp/generator/make.py
+++ b/build/gyp/pylib/gyp/generator/make.py
@@ -142,7 +142,7 @@ cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.
# special "figure out circular dependencies" flags around the entire
# input list during linking.
quiet_cmd_link = LINK($(TOOLSET)) $@
-cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start
+cmd_link = $(error $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl
# We support two kinds of shared objects (.so):
# 1) shared_library, which is just bundling together many dependent libraries连接mksnapshot的命令为:
/disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-g++ -B/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/binutils/Linux_x64/Release/bin -pthread -fuse-ld=gold -B/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/binutils/Linux_x64/Release/bin -fuse-ld=gold -B/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/binutils/Linux_x64/Release/bin -m32 -m32 -L/disk7/shuyin.wsy/codebase_host/out/platforms/tablet.cht.intel.eng.x86/host/lib -o /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/mksnapshot -Wl,--start-group /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/mksnapshot/src/snapshot/mksnapshot.o /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/tools/gyp/libv8_base.a /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/tools/gyp/libv8_nosnapshot.a /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/tools/gyp/libv8_libplatform.a /disk7/shuyin.wsy/codebase_host/vm/v8/out/ia32.release/obj.host/tools/gyp/libv8_libbase.a -Wl,--end-group -ldl -lrt -licui18n -licuuc -licudata.确实是使用了target的i686-linux-gnu-g++。
由于v8使用gyp编译,先要熟悉一下编译流程,首先分析出build/gyp/pylib/gyp/generator/make.py文件的GenerateOutput函数是产生Makefile文件的,在里面raise,看看python是怎么调用的:
Traceback (most recent call last):
File "build/gyp/gyp_main.py", line 16, in
sys.exit(gyp.script_main())
File "build/gyp/pylib/gyp/__init__.py", line 545, in script_main
return main(sys.argv[1:])
File "build/gyp/pylib/gyp/__init__.py", line 538, in main
return gyp_main(args)
File "build/gyp/pylib/gyp/__init__.py", line 523, in gyp_main
generator.GenerateOutput(flat_list, targets, data, params)
File "build/gyp/pylib/gyp/generator/make.py", line 2074, in GenerateOutput
raise()然后gyp的工作流程就是:
1、Makefile里面调用build/gyp/gyp:
build/gyp/gyp --generator-output="$(OUTDIR)" build/all.gyp \
-Ibuild/standalone.gypi --depth=. \
-Dv8_target_arch=$(V8_TARGET_ARCH) \
$(if $(findstring $(CXX_TARGET_ARCH),$(V8_TARGET_ARCH)), \
-Dtarget_arch=$(V8_TARGET_ARCH),) \
$(if $(findstring optdebug,$@),-Dv8_optimized_debug=1,) \
-S$(suffix $(basename $@))$(suffix $@) $(GYPFLAGS)2、build/gyp/gyp里面执行了build/gyp/gyp_main.py,将所有参数传递过去了:
#!/bin/sh
set -e
base=$(dirname "$0")
exec python "${base}/gyp_main.py" "$@"
3、build/gyp/gyp_main.py调用了build/gyp/pylib/gyp/__init__.py的函数:
if __name__ == '__main__':
sys.exit(gyp.script_main())4、build/gyp/pylib/gyp/__init__.py中执行gyp_main函数,使用parser处理build/gyp/gyp的输入参数,从build/standalone.gypi的json数据里面获得CC,CXX,CC.host,CXX.host的默认值:
['clang==1 and ((OS!="mac" and OS!="ios") or clang_xcode==0) '
'and OS!="win" and "
'make_global_settings': [
['CC', '
['CXX', '
['CC.host', '$(CC)'],
['CXX.host', '$(CXX)'],
],
}],
也就是make.py里面的data[build_file]的数据,在make.py中打印make_global_settings_array:
[['CC', '/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang'], ['CXX', '/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang++'], ['CC.host', '$(CC)'], ['CXX.host', '$(CXX)']]
经过make.py中如下代码的处理:
for key, value in make_global_settings_array:
if re.match('.*_wrapper', key):
continue
if value[0] != '$':
value = '$(abspath %s)' % value
wrapper = wrappers.get(key)
if wrapper:
value = '%s %s' % (wrapper, value)
del wrappers[key]
if key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
make_global_settings += (
'ifneq (,$(filter $(origin %s), undefined default))\n' % key)
# Let gyp-time envvars win over global settings.
env_key = key.replace('.', '_') # CC.host -> CC_host
if env_key in os.environ:
value = os.environ[env_key]
make_global_settings += ' %s = %s\n' % (key, value)
make_global_settings += 'endif\n'
else:
make_global_settings += '%s ?= %s\n' % (key, value)
环境变量里有CC和CXX,分别为/disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-gcc,/disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-g++;环境变量里没有CC_host, CXX_host,所以生成的部分Makefile为:
ifneq (,$(filter $(origin CC), undefined default))
CC = /disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-gcc
endif
ifneq (,$(filter $(origin CXX), undefined default))
CXX = /disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-g++
endif
ifneq (,$(filter $(origin CC.host), undefined default))
CC.host = $(CC)
endif
ifneq (,$(filter $(origin CXX.host), undefined default))
CXX.host = $(CXX)
endif这四个if都是满足条件的,所以:
CC.host = CC = /disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-gcc
CXX.host = CXX = /disk7/shuyin.wsy/codebase_host/xmake/prebuilts/gcc/linux-x86/x86/i686-linux-gnu-4.9-glibc-2.20/bin/i686-linux-gnu-g++在编译v8之前,指定环境变量CC_host和CXX_host即可:
CC_host="$${YUNOS_ROOT}/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang"
CXX_host="$${YUNOS_ROOT}/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang++"
另外,在target为arm的一个分支上:
build/standalone.gypi得到的数据为:
['clang!=1 and host_clang==1 and target_arch!="ia32" and target_arch!="x64"', {
'make_global_settings': [
['CC.host', '
['CXX.host', '
],
}],
make.py中make_global_settings_array为:
[['CC.host', '/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang'], ['CXX.host', '/disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang++']]输出的部分Makefile为:
ifneq (,$(filter $(origin CC.host), undefined default))
CC.host = $(abspath /disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang)
endif
ifneq (,$(filter $(origin CXX.host), undefined default))
CXX.host = $(abspath /disk7/shuyin.wsy/codebase_host/vm/v8/third_party/llvm-build/Release+Asserts/bin/clang++)
endif