svaante / dape

Debug Adapter Protocol for Emacs
GNU General Public License v3.0
448 stars 25 forks source link

Configuration to run golang tests under GDB #94

Open ezaquarii opened 4 months ago

ezaquarii commented 4 months ago

Native dlv is not supported on all platforms, but gdb has pretty decent go support that works for most cases.

Here is my snippet that allowed me to debug go test file with a simple C-x C-a d on OpenBSD:

;; .dir-locals.el
((nil . ((dape-configs . ((go-test
              modes (go-mode go-ts-mode)
              command "gdb"
              command-args ("--interpreter=dap")
              command-cwd (file-name-directory (buffer-file-name))
              compile "go test -c -o /tmp/test.bin -gcflags '-N -l'"
              :request "launch"
              :program "/tmp/test.bin"
              :args []
              :stopAtBeginningOfMainSubprogram nil))))))

This probably can benefit from more massaging, but is it something you'd be keen on adding to the release? @svaante

svaante commented 4 months ago

Hey something like this could be fine to add, I am not the biggest fan of assuming "/tmp". Maybe one could use (temporary-file-directory) instead.

Would you mind explaining the need for -gcflags?

And how hard would it be to extend the configuration be able to configure the test selection?

Example for how it's done with dlv:

      ...
      :args
      (lambda ()
           (require 'which-func)
            (if-let* ((file-name (buffer-file-name))
                      ((string-suffix-p "_test.go" file-name))
                      (fn-name (which-function)))
                  `["-test.run"
                      ,(substring-no-properties (concat "^" fn-name "$"))]
               []))))
       ...
ezaquarii commented 4 months ago

Maybe one could use (temporary-file-directory) instead.

Yes. I think it should be used. Hardcoding /tmp is enough for a proof of concept, but not as a way forward.

Would you mind explaining the need for -gcflags?

Debugging optimized code prevents GDB from showing local variables consistently, so I disabled optimizations. There might be more issues that I haven't seen yet.

I'm not 100% sure if this is really necessary, as I can reliabily print local vars from console, but they are not shown in the Local window. Disabling optimizations fixes all glitches.

And how hard would it be to extend the configuration be able to configure the test selection?

The code from dlv should work as out of the box as GDB runs the same test runner binary with the same runtime arguments. The only difference is that dlv compiles the test for you, whle when using gdb I need to compile test runner by hand.

dlv also places binary in /tmp, but I think it randomizes the executable name a bit better.

ezaquarii commented 4 months ago

@svaante what do you think about that?

(require 'which-func)
(defun dape-go-test-name ()
  (if-let* ((file-name (buffer-file-name))
            ((string-suffix-p "_test.go" file-name))
            (fn-name (which-function)))
      `["-test.run" ,(concat "^" (car (split-string (substring-no-properties fn-name))) "$")]
    []))

(defun dape-go-test-binary-name ()
  (concat (temporary-file-directory) "__test.bin"))

(defun dape-go-binary-name ()
  (concat (temporary-file-directory) "__prog.bin"))
;; .dir-locals.el
((nil . ((dape-configs . ((go-gdb-test
               modes (go-mode go-ts-mode)
               command "gdb"
               command-args ("--interpreter=dap")
               command-cwd (lambda () (file-name-directory (buffer-file-name)))
               compile (lambda () (format "go test -c -o %s -gcflags '-N -l'" (dape-go-test-binary-name)))
               :request "launch"
               :program dape-go-test-binary-name
               :args []
               :stopAtBeginningOfMainSubprogram nil)
              (go-gdb
               modes (go-mode go-ts-mode)
               command "gdb"
               command-args ("--interpreter=dap")
               command-cwd dape-command-cwd
               compile (lambda () (format "go build -o %s -gcflags '-N -l'" (dape-go-binary-name)))
               :request "launch"
               :program dape-go-binary-name
               :args []
               :stopAtBeginningOfMainSubprogram nil))))))
svaante commented 4 months ago

Sorry for taking such a long time to respond. but this looks great. I have some small pointers, which would be easier to address in an PR.

Would you mind opening up an PR? For this big change an copyright assignment with FSF is needed (see Contribute in the Readme)