在过去的几周里,我已经编写了相当多的程序expl3
,虽然我真的很喜欢所提供 API 的表现力,但调试较大的程序往往非常痛苦。
在许多情况下,我发现各种\xxx_show:
函数对于查询变量的值和查看执行情况非常有用。为了获得更易读的调试输出,\iow_term:x
可以使用其他 I/O 函数。l3basics
还提供了一些内置调试工具来检查未声明变量的分配、错误的算术表达式和其他一些事情,尽管我从未觉得它们很有用。
有时,当扩展出错时,TeX 会因毫无帮助的低级错误消息而中止,而所有这些都不再有帮助。在 TeX 或 LaTeX2e 中使用\tracingmacros
或\tracingcommands
通常可以快速发现问题。
然而,在 中expl3
,跟踪输出几乎总是过于冗长,实际上没有帮助。例如,如果我在示例文档中启用宏跟踪,该文档来自我关于解析平衡组仅在所有cctab
函数之外,我就会得到大约 7600 行日志输出。如果将少数cctab
函数调用包含在跟踪中,日志文件将膨胀到 120k 行!类似的事情也发生在看似无害的函数上,例如函数\xxx_show:
。在数百行代码中滚动只是为了定位您在程序中实际调用的函数之一。
那么,是否有其他工具可以帮助调试程序/软件包代码?或者是否有办法选择性地关闭特定函数集(例如所有内核函数)的跟踪输出?如果没有,未来版本expl3
中是否有计划支持更多调试功能?expl3
答案1
对于评论来说太长,对于答案来说又太模糊;请随意投反对票 ;-)
不幸的是,不行。您列出的选项或多或少就是所有可用的选项。您没有提到的一个选项是使用包中的\traceon
/ ,它允许您有选择地关闭对不感兴趣的代码片段的跟踪(函数是出了名的日志记录 -\traceoff
trace
l3msg
是,因此它们被包裹在 中\conditionally@traceoff
,以便\conditionally@traceon
与 配合使用trace
)。因此,如果您正在调试某些代码,并且您知道其中某些部分正在运行(例如,启动 catcode 表),则可以执行以下操作:
% with \usepackage{trace}
\traceon
% some code to be debugged
\conditionally@traceoff
% log-exhaustive code which you are sure it's working
\conditionally@traceon
% more code to be debugged
\traceoff
但是,整体上并没有太大的改善,因为实际上支持的功能很少trace
(我记得:NFSS、、calc
和xparse
)l3msg
。
内核可以\conditionally@traceoff
可以在这里或那里增加和的出现次数\conditionally@traceon
来改善这种情况,但这是以牺牲一些性能为代价的。另一个主要缺点是,对于仅与扩展一起使用的函数,您根本无法启动或停止跟踪。
一个好的调试工具的这个缺陷不太可能得到解决(至少l3kernel
其他层面上),因为底层 TeX 引擎提供了不调试或太多了调试,它显示的信息仅(容易)在引擎级别获得。
此外,与“通常”的语言略有不同,什么您正在调试的调试工具应该是什么样子。如果您正在调试一些在不可扩展代码中传递的文本,通常\showtokens
或类似的东西真的很有帮助,如果您知道在哪里寻找问题。如果不知道,那么您就回到了\tracingall
。
什么时候我尝试调试一些代码时,我通常会尝试将问题隔离到代码的最小部分,以获得尽可能少的日志记录。在此过程中,我通常会删除所有不属于我的代码(通常是我导致了问题),因此这会大大缩短日志记录。即使在我自己的代码部分中,我也会尽可能将问题精确定位到单个宏调用。
当我无法再缩小问题范围时,我通常会使用\showtokens
宏的参数或\show
控制序列来检查其内容。如果我处于仅扩展的上下文中,那么我会使用类似于的技巧来\msg_expandable_error:nn
制作可扩展的\showtokens
:
\def\eshow#1{\expandafter\@gobble\expandafter{\ERROR <#1>}}
如果这些都不起作用,那么我会去使用\traceon
一些正则表达式来搜索日志(不要尝试通过查看终端中的日志进行调试:你会发现自己无望地上下滚动并忘记你一开始正在搜索什么:-)。
最后,如果问题依赖于扩展技巧(主要是如果你依赖于操纵输入标记流),那么在\traceon
大多数情况下也是无用的,因为它根本不显示标记流。在那些情况下,当所有希望都失去时,我会求助于unravel
(我并不是说它不好,相反,它太好了,小段代码需要数千步才能完成)。\unravel
通常会清楚地向您显示哪里出了问题,但它会先考验您的耐心 ;-)
如果没有其他方法,请停止编写宏,只需编写几段文字进行更改即可;-)