调试

除了使用调试器(例如 gdb)配合调试构建(见下文)外,SUMO 源代码还在多个位置提供了调试宏,这些宏通常处于停用状态(例如被注释掉)。激活这些宏可以产生详细的程序输出,且可以通过给定参数进行配置。

调试构建#

要在构建过程中生成调试符号,请参阅对应操作系统的构建说明(Linux / Windows / macOS)。对应的二进制文件会带有后缀 D(例如使用 sumoD 代替 sumo)。调试配置定义了一个预处理器宏 _DEBUG,可用于封装特定于调试的代码。对于简单的文本调试,应使用更灵活的本地宏来开启和关闭,详见下文。

本地调试宏#

在 SUMO 中插入可重用调试代码的推荐风格是通过预处理器指令进行封装。具体做法是在源文件开头放置 #define DEBUG_THIS_CODE(最好放在其他 #include#define 宏之后)。调试代码(例如向 std::cout 输出内容)应被包围在以下结构中:

#ifdef DEBUG_THIS_CODE
    ...
#endif

这样,通过(取消)注释 #define DEBUG_THIS_CODE 这一行即可开启或关闭调试。

有时将此与条件结合使用以进行更具体的调试输出会很有用。例如,如果在遍历所有车辆时只需要输出 ID 为 'my_new_ferrari' 的车辆信息,你应该插入相应的调试条件:

#define DEBUG_COND (veh.getID() == "my_new_ferrari")

(位置与 #define DEBUG_THIS_CODE 相同),并将调试代码进一步封装为:

#ifdef DEBUG_THIS_CODE
    if DEBUG_COND {
        ...
    }
#endif

请注意,这假设 veh 是当前正在遍历的车辆的引用。值得一提的是,你也可以定义带参数的调试条件,以获得更大的灵活性。例如:

#define DEBUG_COND(x) (x != 0 && x->getID() == "my_new_ferrari")
    ...
#ifdef DEBUG_THIS_CODE
    if DEBUG_COND(veh_pointer) {
        ...
    }
#endif

调试宏已经存在于多个位置(在实现你自己的宏之前,请查看其中一些):

  • src/microsim/MSLane.cpp
  • src/microsim/MSLink.cpp
  • src/microsim/MSVehicle.cpp
  • src/microsim/lcmodel/MSLCM_LC2013.cpp
  • src/guisim/GUIVehicle.cpp
  • src/guisim/GUILane.cpp

基于选定车辆的调试#

头文件 utils/common/StdDefs.h 提供了字符串 gDebugSelectedVehicle,它始终保存着在 GUI 中最后选定的车辆 ID。如果激活了相应的宏,可以在调试条件中使用它来实现动态调试选择。

调试外部库#

调试符号(.pdb 文件)仅适用于 SUMOLibraries 中包含的部分外部库。要在 Visual Studio 中使用它们,只需将所需符号的路径添加到选项菜单中的“符号文件位置”。操作方法为:转到 工具 > 选项... > 调试 > 符号,并将所需外部库的 .pdb 文件路径作为新位置添加(参见下图示例)。.pdb 文件通常位于每个库的 libbin 目录中。


示例:添加 FOX 调试符号

FOX Toolkit 消息日志#

FOX Toolkit 库使用宏输出不同重要性的调试消息。每条消息都被分配了一个数字级别,并且仅在调试模式下打印。为了接收这些消息,必须向 sumo-guiD 提供命令行参数 -tracelevel <INT>。只有分配的级别低于给定级别的消息才会打印到控制台。