mirror of
https://gitlab.com/eql/EQL5.git
synced 2025-12-06 02:30:31 -08:00
129 lines
5.3 KiB
HTML
129 lines
5.3 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Debugging</title>
|
|
<meta charset="utf-8">
|
|
<link rel="stylesheet" href="style.css" type="text/css">
|
|
<style>
|
|
pre { color: black; background-color: #F4F4F4; }
|
|
code { color: black; }
|
|
.input { color: blue; }
|
|
</style>
|
|
</head>
|
|
<div style="width: 600px; margin: 20px;">
|
|
<h2>Debugging</h2>
|
|
This is a simple <b>tutorial</b> using the top-level processing Qt events:
|
|
<pre> $ <span class="input">eql5 -qtpl</span></pre>
|
|
<br>
|
|
<h3>Example 1: Error on REPL (trivial)</h3>
|
|
<pre>
|
|
|
|
EQL-USER[1]> <span class="input">(/ 0)</span>
|
|
|
|
Condition of type: DIVISION-BY-ZERO
|
|
|
|
Available restarts:
|
|
|
|
1. (RESTART-TOPLEVEL) Go back to Top-Level REPL.
|
|
2. (RESTART-QT-EVENTS) Restart Qt event processing.
|
|
|
|
** BREAK [LEVEL 2]>
|
|
</pre>
|
|
<img src="debug-dialog.png" alt="debug dialog">
|
|
<p>Note that all debug input is handled in a debug dialog, <b>not</b> in the console window.</p>
|
|
<p>So, either type the restart number in the dialog</p>
|
|
<pre><span class="input"> :r1</span></pre>or just click Cancel / hit Escape, which will always choose <code>:r1</code>.
|
|
<p>Type <code>:h</code> for all available debug options.</p>
|
|
<p>Both restarts will have the same effect here, see note at bottom.</p>
|
|
<br>
|
|
<h3>Example 2: Error during Qt event processing</h3>
|
|
Start calculator example:
|
|
<pre> $ <span class="input">eql5 -qtpl examples/X-extras/calculator</span></pre>
|
|
<br>
|
|
Let's run this function:
|
|
<pre> EQL-USER[1]> <span class="input">(clc:auto "42 ? blah")</span></pre>
|
|
<br>
|
|
This will output 2 errors, without breaking into the debugger:
|
|
<pre>
|
|
|
|
[EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"
|
|
|
|
[EQL:err] QINVOKE-METHOD NIL NIL "animateClick" (400)
|
|
</pre>
|
|
<p><b>Note</b>: After eventual print output (like the above), you won't see a fresh top-level prompt.<br>Don't get confused by this, as you can continue to enter commands.</p>
|
|
<br>
|
|
Now make EQL errors break into the debugger:
|
|
<pre> EQL-USER[2]> <span class="input">(setf eql:*break-on-errors* t)</span></pre>
|
|
<br>
|
|
Run our function again:
|
|
<pre>
|
|
|
|
EQL-USER[3]> <span class="input">(clc:auto "42 ? blah")</span>
|
|
|
|
Condition of type: SIMPLE-CONDITION
|
|
|
|
[EQL:err] QFIND-CHILD #<QDialog "" 0x39737d0 [1]> "?"
|
|
|
|
Available restarts:
|
|
|
|
1. (CONTINUE) Return from BREAK.
|
|
2. (RESTART-QT-EVENTS) Restart Qt event processing.
|
|
|
|
** BREAK [LEVEL 1]>
|
|
</pre>
|
|
<img src="debug-dialog.png" alt="debug dialog">
|
|
<p>Now there are 2 possible restarts:</p>
|
|
<pre><span class="input"> :r1</span></pre>
|
|
<code>(CONTINUE)</code> will continue execution, which will break on the next error, then finish our function.
|
|
<pre><span class="input"> :r2</span></pre>
|
|
<code>(RESTART-QT-EVENTS)</code> will abort execution, returning to the REPL immediately.
|
|
<br><br>
|
|
<hr>
|
|
<br><br>
|
|
<h3>Notes</h3>
|
|
There is one situation where interactive debugging won't work, and this is in code inside an (overridden)
|
|
<pre> "paintEvent(QPaintEvent*)"</pre> function, as this may cause recursive paint events and segfaults.
|
|
<br>
|
|
<br> <br>
|
|
To exit instantly from EQL during debugging (on nasty errors), just type
|
|
<pre><span class="input"> :qq</span> / <span class="input">:exit</span></pre> in the debug dialog (or REPL).
|
|
<p>Optionally you can also directly abort (see respective C function) by typing:</p>
|
|
<pre><span class="input"> :qa</span> / <span class="input">:abort</span></pre>
|
|
<br><p>On simple <code>read</code> errors on the REPL (e.g. non-existing packages, non-external symbols), the debugger will not be entered (as this would cause an unrecoverable <code>break</code>, since <code>read</code> runs in its own thread here); instead, the erroneous input string will be returned as-is.</p>
|
|
<br><p>The conflicting case</p>
|
|
<pre>
|
|
(RESTART-TOPLEVEL)
|
|
(RESTART-QT-EVENTS)</pre>
|
|
is resolved automatically (<code>RESTART-QT-EVENTS</code> would block the REPL in this case).
|
|
<br>
|
|
<br>
|
|
<br>
|
|
<h3>Tips</h3>
|
|
You might want to put this in your <code>~/.eclrc</code> file:
|
|
<pre>
|
|
|
|
#+eql
|
|
(setf eql:*qtpl* t ; same as -qtpl
|
|
eql:*break-on-errors* t)
|
|
</pre>
|
|
<br><br>
|
|
For running ECL / EQL through <code>gdb</code> (debugger), put this in your <code>~/.gdbinit</code> file:
|
|
<pre>
|
|
|
|
handle SIGPWR nostop noprint
|
|
handle SIGXCPU nostop noprint
|
|
</pre>
|
|
<br>
|
|
<p>You may find</p>
|
|
<pre> (qproperties object &optional (depth 1))</pre>
|
|
<p>very convenient for debugging, as it prints the current state of the interesting object.</p>
|
|
<br>
|
|
<p>In order to automatically switch the REPL to a given package after loading a file, add this line:</p>
|
|
<pre> (qlater (lambda () (in-package :my-package)))</pre>
|
|
<br>
|
|
<p>If you use ECL readline (see <code>~/.eql5/lib/ecl-readline.lisp</code>, to be compiled manually after running EQL5 for the first time / updating ECL):<br>After entering <code>:qq</code> (quitting the top-level), the console/shell should always be reset (but you won't probably see the command while typing it; an <code>alias</code> might help):</p>
|
|
<pre> $ <span class="input">reset</span></pre>
|
|
<br>
|
|
<br>
|
|
</div>
|
|
</html>
|