我正在用C++构建一个在Python中使用的模块。我的流程分为三个步骤:我将各个C++源代码编译成对象,创建库,然后运行setup.py脚本来编译.pyx->.cpp->.so,同时引用我刚刚创建的库。
我知道我可以用Cython setup.py一步完成所有的事情,这就是我曾经做过的事情。将其分成多个步骤的原因是我想让C++代码自己演化,在这种情况下,我将只使用Cython/python中的编译后的库。
因此,当没有bug时,这个流工作得很好。问题是我试图找到一个段错误的来源,所以我想得到调试符号,这样我就可以运行gdb (我在OSX10.14上安装了gdb,这很痛苦,但它很有效)。
我有一个makefile,它执行以下操作。
步骤1:编译单个C++源文件
所有的文件都是用最小标志编译的,但是-g是存在的:
gcc -mmacosx-version-min=10.7 -stdlib=libc++ -std=c++14 -c -g -O0 -I ./csrc -o /Users/colinww/system-model/build/data_buffer.o csrc/data_buffer.cpp我认为即使在这里也有一个问题:当我执行nm -pa data_buffer.o时,我看不到调试符号。此外,我还得到了:
(base) cmac-2:system-model colinww$ dsymutil build/data_buffer.o
warning: no debug symbols in executable (-arch x86_64)步骤2:编译cython源代码
makefile包含以下代码行
cd $(CSRC_DIR) && CC=$(CC) CXX=$(CXX) python3 setup_csrc.py build_ext --build-lib $(BUILD)setup.py的相关部分包括
....
....
....
compile_args = ['-stdlib=libc++', '-std=c++14', '-O0', '-g']
link_args = ['-stdlib=libc++', '-g']
....
....
....
Extension("circbuf",
["circbuf.pyx"],
language="c++",
libraries=["cpysim"],
include_dirs = ['../build'],
library_dirs=['../build'],
extra_compile_args=compile_args,
extra_link_args=link_args),
....
....
....
ext = cythonize(extensions,
gdb_debug=True,
compiler_directives={'language_level': '3'})
setup(ext_modules=ext,
cmdclass={'build_ext': build_ext},
include_dirs=[np.get_include()])当它运行时,它会生成一堆编译/链接命令,比如
gcc -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I/Users/colinww/anaconda3/include -arch x86_64 -I/Users/colinww/anaconda3/include -arch x86_64 -I. -I../build -I/Users/colinww/anaconda3/lib/python3.7/site-packages/numpy/core/include -I/Users/colinww/anaconda3/include/python3.7m -c circbuf.cpp -o build/temp.macosx-10.7-x86_64-3.7/circbuf.o -stdlib=libc++ -std=c++14 -O0 -g和
g++ -bundle -undefined dynamic_lookup -L/Users/colinww/anaconda3/lib -arch x86_64 -L/Users/colinww/anaconda3/lib -arch x86_64 -arch x86_64 build/temp.macosx-10.7-x86_64-3.7/circbuf.o -L../build -lcpysim -o /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so -stdlib=libc++ -g在这两个命令中,都有-g标志。
步骤3:运行调试器
最后,我使用gdb运行我的程序
(base) cmac-2:sim colinww$ gdb python3
(gdb) run system_sim.py它输出了大量与系统文件相关的东西(似乎是无关的),最后运行我的程序,当它出现段错误时:
Thread 2 received signal SIGSEGV, Segmentation fault.
0x0000000a4585469e in cpysim::DataBuffer<double>::Write(long, long, double) () from /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so
(gdb) info local
No symbol table info available.
(gdb) where
#0 0x0000000a4585469e in cpysim::DataBuffer<double>::Write(long, long, double) () from /Users/colinww/system-model/build/circbuf.cpython-37m-darwin.so
#1 0x0000000a458d6276 in cpysim::ChannelFilter::Filter(long, long, long) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#2 0x0000000a458b0d29 in __pyx_pf_6chfilt_6ChFilt_4filter(__pyx_obj_6chfilt_ChFilt*, long, long, long) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#3 0x0000000a458b0144 in __pyx_pw_6chfilt_6ChFilt_5filter(_object*, _object*, _object*) () from /Users/colinww/system-model/build/chfilt.cpython-37m-darwin.so
#4 0x000000010002f1b8 in _PyMethodDef_RawFastCallKeywords ()
#5 0x000000010003be64 in _PyMethodDescr_FastCallKeywords ()正如我上面提到的,我认为问题从最初的编译步骤开始。这与cython无关,我只是从命令行调用gcc,传递-g标志。
(base) cmac-2:system-model colinww$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin感谢您的帮助,谢谢!
更新
我删除了gcc标签,并将其更改为clang。因此,我想我现在很困惑,如果苹果用别名gcc来敲钟,这不是意味着在“那种模式”下,它应该表现得像gcc一样(而且,暗示,有人肯定是这样的)。
更新2
因此,我永远不能让调试符号出现在调试器中,我不得不求助于许多有趣的if-printf语句,但问题是索引变量变得未定义。所以感谢所有的建议,但问题或多或少已经解决了(直到下一次)。谢谢!
发布于 2019-06-28 08:17:01
macOS链接器不会像其他Unixen链接器那样将调试信息链接到最终的二进制文件中。相反,它将调试信息保留在.o文件中,并将“调试映射”写入二进制文件,告诉调试器如何查找和链接从.o文件读取的调试信息。当您剥离二进制文件时,调试映射将被剥离。
因此,您必须确保在最后一个链接之后不会移动或删除.o文件,并且在调试之前不会剥离正在调试的二进制文件。
您可以通过执行以下操作来检查调试映射是否存在:
$ nm -ap <PATH_TO_BINARY> | grep OSO您应该看到如下所示的输出:
000000005d152f51 - 03 0001 OSO /Path/To/Build/Folder/SomeFile.o
如果您没有看到可执行文件可能被剥离了。如果.o文件不在附近,那么就是有人比他们应该清理的更早地清理了您的构建文件夹。
我也不知道gdb是否知道如何读取macOS上的调试映射。如果存在调试映射条目和.o文件,您可以尝试lldb,看看是否可以找到调试信息。如果可以,那么这很可能是gdb-on-macOS的问题。如果OSO和.o文件都存在,那么我猜不到的地方出了问题,也许值得向http://bugreporter.apple.com提交一个bug。
https://stackoverflow.com/questions/56688359
复制相似问题