我一直与Philip Guo的excellent series一起关注CPython的内部结构,并一直在GDB中浏览解释器的代码。不幸的是,当我单步执行代码,不按顺序执行指令(例如一系列赋值操作,没什么花哨的东西)时,GDB似乎跳了很多。
据我了解,这是由于编译器优化所致。实际上,CPython的configure
文件似乎默认为-O2
。在使用./configure
和make
编译Python 2.7.15时,情况就是这样:
gcc -pthread -c -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Modules/python.o ./Modules/python.c
gcc -pthread -c -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/acceler.o Parser/acceler.c
gcc -pthread -c -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c
gcc -pthread -c -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/listnode.o Parser/listnode.c
...
我尝试通过不进行优化而通过./configure CFLAGS="-g -O0"
进行配置并再次使用make
进行编译来解决此问题(请注意,将每一行从-fno-strict-aliasing -g -O2
更改为-fno-strict-aliasing -g -O0
):
gcc -pthread -c -fno-strict-aliasing -g -O0 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Modules/python.o ./Modules/python.c
gcc -pthread -c -fno-strict-aliasing -g -O0 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/acceler.o Parser/acceler.c
gcc -pthread -c -fno-strict-aliasing -g -O0 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/grammar1.o Parser/grammar1.c
gcc -pthread -c -fno-strict-aliasing -g -O0 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include -DPy_BUILD_CORE -o Parser/listnode.o Parser/listnode.c
...
不幸的是,当我单步执行代码时,GDB仍然跳来跳去。为了完整起见,这是我与GDB一起运行的命令:
gdb --args ./python test.py
test.py
的内容只是一些基本的算术和打印函数,它们实际上并不相关。
我对这些步骤中至少一个的理解必须是不完整的。我是否将优化标志设置不正确? GDB是否由于其他原因在指令之间跳转?任何建议将不胜感激。谢谢!
答案 0 :(得分:1)
tl; dr:您需要configure
设置--with-pydebug
。
在-O3
之后的命令行上有一个-O2
,因此将-O2
更改为-O0
并没有任何好处。 -O3
仍然会覆盖它。您需要找出-O3
的来源并将其删除。
如果您查看生成的Makefile
,应该会看到类似这样的内容:
# Compiler options
OPT= -DNDEBUG -g -fwrapv -O3 -Wall
# ...
# Avoid assigning CFLAGS, LDFLAGS, etc. so users can use them on the
# command line to append to these values without stomping the pre-set
# values.
PY_CFLAGS= $(BASECFLAGS) $(OPT) $(CONFIGURE_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS)
您当然可以编辑生成的Makefile
,将-O3
更改为-O0
。但是,如果您查看configure
脚本和Makefile.pre
的内部,则可以看到它的来源:它是默认值,在这种情况下仅被替换:
case $ac_cv_prog_cc_g in
yes)
if test "$Py_DEBUG" = 'true' ; then
# Optimization messes up debuggers, so turn it off for
# debug builds.
if "$CC" -v --help 2>/dev/null |grep -- -Og > /dev/null; then
OPT="-g -Og -Wall"
else
OPT="-g -O0 -Wall"
fi
else
OPT="-g $WRAP -O3 -Wall"
fi
;;
这还会为gcc
以外的其他编译器设置正确的标志。
但是,--with-pydebug
的主要作用是启用Py_DEBUG
,如果您正在对CPython进行源调试,则可能需要启用{{3}},但这与-O0
是分开的。是您真正要问的问题。因此,据我所知,如果只想要 -O0
,您唯一可以做的就是编辑Makefile
(或提出一些复杂的env变量集和configure
参数引诱它进行调试构建,但随后未启用Py_DEBUG
)。