在独立的Matlab中调试代码

3
假设我有一个名为foo的函数,它被用于一个独立应用程序中(即使用mcc -m编译成可执行文件),其中有一个重要的中间结果bar。通常,在函数完成后我不需要这个中间结果,因此它不是返回值。但是为了开发和调试目的,能够让这个中间结果可访问是很有用的,我可以使用assignin将中间结果放入某个调试工作区。
现在的问题是,在独立编译中assignin是不可能的,如果代码中有assignin,则mcc会报错。我想做的是只在交互式运行代码时包含assignin,而在编译为独立应用程序时不包含assignin。此外,这样做还可以加快速度,因为在独立应用程序中我不需要中间结果,因此不在独立应用程序中进行assignin可以节省时间和/或内存。在任何其他编程环境中,这都被称为在调试和发布模式下编译。
伪Matlab代码如下:
function res = foo()
  bar = some complicated formula
  if ~standalone
    assignin('debug', 'foo_bar', bar)
  end
  res = some complicated formula involving bar

问题在于我不知道如何表达if ~standalone,首先我不知道如何测试是否处于独立模式,但更重要的是,这需要一些代码结构,实际上会导致mcc完全忽略受保护的代码块并且不尝试编译它,因为assignin不能在独立模式下编译。
顺便说一下,这不仅对中间结果有价值,而且对额外数据收集也有用,其中额外数据将在受保护的块中计算,并通过assignin导出。显然,在独立版本中不应计算此类额外数据,因为它没有任何作用。
在matlab中是否有这样的代码结构可以实现这一点,或者有更好的替代方案?到目前为止,在开发过程中,我只是在注释的代码中进行调整,取消注释和重新注释调试代码。
2个回答

2

不要使用assignin来填充调试工作区,可以使用全局调试结构并将变量存储在同名字段中。所有有效的变量名称也都是有效的结构字段名称。您可以使用全局变量实现此功能,但最好在函数内部使用持久变量来完成。这将适用于编译或非编译代码。

首先,定义一个函数来定义您的调试模式。

function out = isdebugging(value)
%ISDEBUGGING Get or set the global debugging state

persistent state
if isempty(state)
    state = false;
end

switch nargin
    case 0 % Getter
        out = state;
    case 1 % Setter
        state = value;
end

然后是一个用于存储调试值的函数,只有在开启调试模式时才会保存这些值。

function out = debugval(action, name, value)
%DEBUGVAL Stash values for debugging

persistent stash
if isempty(stash)
    stash = struct;
end

% Short-circuit when not in debugging mode to save space
if ~isdebugging()
    return;
end

switch action
    case 'get'
        out = stash.(name);
    case 'getall'
        out = stash;
    case 'set'
        stash.(name) = value;
    case 'list'
        out = fieldnames(stash);
    case 'remove'
        stash = rmfield(stash, name);
    case 'clear'
        stash = struct;
end

默认情况下,调试功能被禁用,因此在编译版本中会短路并不累加值。您可以在交互式Matlab会话中手动启用它,方法是使用isdebugging(true)。这样可以避免检测是否正在运行部署的问题。这也意味着,如果您想测试已编译代码在该上下文中的工作方式,可以在编译应用程序中启用和使用它。您可以使用GUI按钮或环境变量告诉编译应用程序启用调试。
isdebugging()调用可以保护其他代码。但是除了日志输出或值累加之外,我不会过分使用isdebugging()来保护任何东西。您不希望您的调试机制对代码的正确性产生副作用。
还要查看Java的log4j,以了解如何在应用程序中包含运行时可配置的调试输出模型。您可以将其原则应用于Matlab。

1
使用函数isdeployed。当在MCR中运行时,isdeployed为true,在MATLAB中运行时为false。
编辑:当然,这并不能解决编译的问题。你可能需要找到assignin的替代品。

不幸的是,在我的古老版本的Matlab(6.1.0.450)中似乎还没有这个函数,但是如果使用mcc,它会对任何这样的if块进行智能处理并完全忽略它,还是会尝试编译assignin代码,并因此无法编译。 - wich
我自己没有尝试过,但我认为它会编译失败,这就是为什么我添加了编辑的原因。我猜isdeployed的主要用途是像print这样的函数,可以编译,但不会运行。 - Ghaul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接