찾다
백엔드 개발GolangEmacs에서 Golang 디버깅 마스터하기

소개

저는 Golang으로 개발을 시작한 이후로 디버거를 실제로 사용하지 않았습니다. 대신 나는 내 코드를 검증하기 위해 순진하게 fmt.Print 문을 모든 곳에 추가했습니다. 인쇄 문과 로그는 첫 번째 디버깅 본능일 수도 있지만 정교한 런타임 동작과 (물론!) 재현이 불가능해 보이는 복잡한 동시성 문제로 인해 크고 복잡한 코드 기반을 처리할 때 종종 부족합니다.

보다 복잡한 프로젝트 작업을 시작한 후(예: https://github.com/cloudoperators/heureka) delve(Golang 디버거)에 대해 더 자세히 살펴보고 Emacs가 무엇을 제공하는지 확인해야 했습니다. 그것과 상호 작용합니다. Go 생태계는 뛰어난 디버깅 도구를 제공하지만 이를 편안한 개발 워크플로에 통합하는 것은 어려울 수 있습니다.

이번 게시물에서는 Emacs, Delve 및 dape의 강력한 조합에 대해 자세히 설명하겠습니다. 이러한 도구를 함께 사용하면 Emacs의 유명한 유연성과 확장성을 유지하면서 기존 IDE를 모방하는(종종 능가하는) 디버깅 환경을 만들 수 있습니다.

다음과 같은 결과를 기대할 수 있습니다.

  • dape를 사용하여 Delve 설정 및 구성
  • 표준 애플리케이션과 Ginkgo 테스트를 모두 디버그합니다(현재 제가 사용하고 있는 것이 이것이죠?)
  • Emacs 전용 사용자 정의로 디버깅 작업 흐름을 최적화하세요

개발 환경 설정

이 게시물에서는 여러분이 이미 Emacs 경험을 갖고 있으며 이제 패키지를 구성하고 작은 Elisp 스니펫을 작성하는 방법을 알고 있다고 가정합니다. 저는 개인적으로 Straight.el을 패키지 관리자로 사용하고,minimal-emacs.d를 최소 바닐라 Emacs 구성으로 사용하고(나만의 사용자 정의와 함께), dape를 디버그 어댑터 클라이언트로, eglot을 LSP 클라이언트로 사용합니다.

필수 Emacs 패키지

Emacs 29 사용자의 경우 eglot이 내장되어 있습니다. Gopls에 대한 eglot 구성 및 일부 고급 Gopls 설정을 확인하세요. 먼저 dape를 추가하겠습니다.

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))

고 모드:

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))

필수 Go 도구 설치

LSP 서버인 Delve와 gopls를 설치하세요.

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest

또한 제가 가끔 사용하는 다른 도구도 많이 있습니다.

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest

그런 다음 해당 Emacs 패키지를 구성해야 합니다.

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)

데이프 구성

dap 대신 dape를 사용하는 특별한 이유는 없습니다. 내가 여전히 MinEmacs를 사용하고 있을 때 그것은 그것의 일부였고 나는 그것에 익숙해졌습니다. 문서에 따르면:

  • Dape는 launch.json 파일을 지원하지 않습니다. 프로젝트별 구성이 필요한 경우 dir-locals 및 dape-command를 사용하세요.
  • Dape는 사용자가 옵션을 사용하여 기존 구성에 PLIST 항목을 수정하거나 추가할 수 있도록 하여 미니버퍼 내의 인체공학성을 향상시킵니다.
  • 마법도 없고 ${workspaceFolder}와 같은 특수 변수도 없습니다. 대신 새 세션을 시작하기 전에 함수와 변수가 해결됩니다.
  • vscode가 존재하지 않는 경우 Emacs에서 디버그 어댑터 구성이 어떻게 구현될지 상상해 봅니다.

VSCode를 사용해 본 적이 있다면 이 VSCode가 다양한 디버깅 프로필을 저장하기 위해 launch.json을 사용한다는 사실을 이미 알고 계실 것입니다.

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))

이 페이지에 따라 디버깅 구성에서 조정할 수 있는 다양한 필드/속성이 있습니다.

Property Description
name Name for your configuration that appears in the drop down in the Debug viewlet
type Always set to "go". This is used by VS Code to figure out which extension should be used for debugging your code
request Either of launch or attach. Use attach when you want to attach to an already running process
mode For launch requests, either of auto, debug, remote, test, exec. For attach requests, use either local or remote
program Absolute path to the package or file to debug when in debug & test mode, or to the pre-built binary file to debug in exec mode
env Environment variables to use when debugging. Example: { "ENVNAME": "ENVVALUE" }
envFile Absolute path to a file containing environment variable definitions
args Array of command line arguments that will be passed to the program being debugged
showLog Boolean indicating if logs from delve should be printed in the debug console
logOutput Comma separated list of delve components for debug output
buildFlags Build flags to be passed to the Go compiler
remotePath Absolute path to the file being debugged on the remote machine
processId ID of the process that needs debugging (for attach request with local mode)

샘플 애플리케이션

이제 REST API를 구현한 실제 애플리케이션을 디버깅하여 우리가 배운 내용을 실제로 적용해 보겠습니다.

프로젝트 구조

우리의 예는 다음 구조를 가진 작업 관리용 REST API입니다.

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))

핵심 구성요소

핵심 구성요소를 살펴보겠습니다.

작업은 핵심 도메인 모델을 나타냅니다.

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))

TaskStore는 메모리 내 데이터 작업을 처리합니다.

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest

REST API

API는 다음 엔드포인트를 노출합니다.

  • POST /task/create - 새 작업을 생성합니다
  • GET /task/get?id= - ID로 작업을 검색합니다.
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest

섬기는 사람

서버 구현은 다음과 같습니다.

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)

주요 기능을 살펴보겠습니다.

{
    "name": "Launch file",
    "type": "go",
    "request": "launch",
    "mode": "auto",
    "program": "${file}"
}

애플리케이션 구축

서버를 시작해 보겠습니다.

taskapi/
├── go.mod
├── go.sum
├── main.go
├── task_store.go
└── task_test.go

이제 다른 터미널에서 새 작업을 생성하세요:

import (
    "fmt"
)

type Task struct {
    ID          int    `json:"id"`
    Title       string `json:"title"`
    Description string `json:"description"`
    Done        bool   `json:"done"`
}

응답:

type TaskStore struct {
    tasks  map[int]Task
    nextID int
}

func NewTaskStore() *TaskStore {
    return &TaskStore{
        tasks:  make(map[int]Task),
        nextID: 1,
    }
}

가져올 수 있는지 살펴보겠습니다.

// CreateTask stores a given Task internally
func (ts *TaskStore) CreateTask(task Task) Task {
    task.ID = ts.nextID
    ts.tasks[task.ID] = task
    ts.nextID++
    return task
}

// GetTask retrieves a Task by ID
func (ts *TaskStore) GetTask(id int) (Task, error) {
    task, exists := ts.tasks[id]
    if !exists {
        return Task{}, fmt.Errorf("task with id %d not found", id)
    }
    return task, nil
}

// UpdateTask updates task ID with a new Task object
func (ts *TaskStore) UpdateTask(id int, task Task) error {
    if _, exists := ts.tasks[id]; !exists {
        return fmt.Errorf("task with id %d not found", id)
    }
    task.ID = id
    ts.tasks[id] = task
    return nil
}

응답:

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
)

// Server implements a web application for managing tasks
type Server struct {
    store *TaskStore
}

func (s *Server) handleCreateTask(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    createdTask := s.store.CreateTask(task)
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(createdTask)
}

func (s *Server) handleGetTask(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodGet {
        http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        return
    }
    id := 0
    fmt.Sscanf(r.URL.Query().Get("id"), "%d", &id)

    task, err := s.store.GetTask(id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(task)
}

단위 테스트

다음은 TaskStore에 대한 몇 가지 단위 테스트(Ginkgo로 작성)입니다.

package main

import (
    "log"
    "net/http"
)

func main() {
    store := NewTaskStore()
    server := &Server{store: store}
    http.HandleFunc("/task/create", server.handleCreateTask)
    http.HandleFunc("/task/get", server.handleGetTask)

    log.Printf("Starting server on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
go build -o taskapi *.go
./taskapi
2024/11/14 07:03:48 Starting server on :8080

Emacs에서는 다음 스크린샷과 같이 ginkgo-run-this-container를 호출합니다.

Mastering Golang Debugging in Emacs

Delve 및 Dape를 사용한 기본 디버깅

Task API를 디버깅하기 위해 다음과 같은 접근 방식이 있습니다.

  • 애플리케이션을 직접 실행하고 디버그할 수 있습니다
  • 실행 중인 프로세스에 연결할 수 있습니다
  • 실행 중인 디버깅 세션에 연결할 수 있습니다

다양한 요청 유형에 대한 옵션은 다음과 같습니다.

요청 모드 필수 선택사항
request mode required optional
launch debug program dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug
test program dlvCwd, env, backend, args, cwd, buildFlags, output, noDebug
exec program dlvCwd, env, backend, args, cwd, noDebug
core program, corefilePath dlvCwd, env
replay traceDirPath dlvCwd, env
attach local processId backend
remote
출시 디버그 프로그램 dlvCwd, env, 백엔드, args, cwd, buildFlags, 출력, noDebug 테스트 프로그램 dlvCwd, env, 백엔드, args, cwd, buildFlags, 출력, noDebug 실행 프로그램 dlvCwd, env, 백엔드, args, cwd, noDebug 코어 프로그램, corefilePath dlvCwd, 환경 재생 traceDirPath dlvCwd, 환경 첨부 로컬 프로세스 ID 백엔드 원격

프로필 1: 애플리케이션 실행

다음은 .dir-locals.el에 대한 첫 번째 디버깅 프로필입니다.

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))

? command-cwd에 다른 값을 사용할 수도 있습니다. 내 경우에는 현재 프로젝트가 아닌 디렉터리에서 디버거를 시작하고 싶었습니다. default-directory는 현재 있는 현재 버퍼의 작업 디렉토리를 보유하는 변수입니다.

디버깅 시작:

  • dape-info를 실행하여 디버깅 정보 표시

Mastering Golang Debugging in Emacs

  • dape-breakpoint-toggle을 사용하여 중단점 만들기:

Mastering Golang Debugging in Emacs

이 프로필로 디버거를 시작한 후 dape-repl 버퍼에 다음이 표시되어야 합니다.

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))

디버깅할 바이너리/파일을 지정하지 않았습니다(.dir-locals.el에 :program "."가 있음). delve는 애플리케이션을 시작하기 전에 바이너리를 자동으로 빌드합니다.

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest

프로필 2: 외부 디버거에 연결

기존 디버깅 세션에 연결하기 위한 프로필을 추가해 보겠습니다.

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest

이제 CLI에서 디버거를 시작해 보겠습니다.

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)

이제 Emacs 내에서 dape를 실행하고 go-attach-taskapi 프로필을 선택할 수 있습니다.

Mastering Golang Debugging in Emacs

프로필 3: 실행 중인 프로세스에 연결

이 시나리오에서는 애플리케이션이 이미 실행 중이지만 여기에 디버거를 연결하려고 합니다. 먼저 애플리케이션을 실행하세요:

{
    "name": "Launch file",
    "type": "go",
    "request": "launch",
    "mode": "auto",
    "program": "${file}"
}

프로세스 ID(PID) 확인:

taskapi/
├── go.mod
├── go.sum
├── main.go
├── task_store.go
└── task_test.go

다른 디버그 프로필을 추가해 보겠습니다.

import (
    "fmt"
)

type Task struct {
    ID          int    `json:"id"`
    Title       string `json:"title"`
    Description string `json:"description"`
    Done        bool   `json:"done"`
}

도우미 기능이 필요합니다:

type TaskStore struct {
    tasks  map[int]Task
    nextID int
}

func NewTaskStore() *TaskStore {
    return &TaskStore{
        tasks:  make(map[int]Task),
        nextID: 1,
    }
}

Mastering Golang Debugging in Emacs

이제 디버거를 시작합니다.

Mastering Golang Debugging in Emacs

이제 다음과 같은 POST 요청을 보내는 경우:

// CreateTask stores a given Task internally
func (ts *TaskStore) CreateTask(task Task) Task {
    task.ID = ts.nextID
    ts.tasks[task.ID] = task
    ts.nextID++
    return task
}

// GetTask retrieves a Task by ID
func (ts *TaskStore) GetTask(id int) (Task, error) {
    task, exists := ts.tasks[id]
    if !exists {
        return Task{}, fmt.Errorf("task with id %d not found", id)
    }
    return task, nil
}

// UpdateTask updates task ID with a new Task object
func (ts *TaskStore) UpdateTask(id int, task Task) error {
    if _, exists := ts.tasks[id]; !exists {
        return fmt.Errorf("task with id %d not found", id)
    }
    task.ID = id
    ts.tasks[id] = task
    return nil
}

디버거는 설정된 중단점에서 자동으로 중지되어야 합니다.

Mastering Golang Debugging in Emacs

Ginkgo 테스트 디버깅

Golang에서 테스트를 디버그할 수 있는 능력은 매우 중요합니다. 은행나무 테스트를 실행하기 위해 다음과 같은 여러 기능이 있는 은행나무 모드를 사용합니다.

Mastering Golang Debugging in Emacs

Mastering Golang Debugging in Emacs

그리고 결과는 다음과 같습니다.

(use-package dape
  :straight t
  :config
  ;; Pulse source line (performance hit)
  (add-hook 'dape-display-source-hook 'pulse-momentary-highlight-one-line)

  ;; To not display info and/or buffers on startup
  ;; (remove-hook 'dape-start-hook 'dape-info)
  (remove-hook 'dape-start-hook 'dape-repl))

Ginkgo용 Dape 구성

Ginkgo 테스트 디버깅을 위한 기본 구성은 다음과 같습니다.

(use-package go-mode
  :straight t
  :mode "\.go\'"
  :hook ((before-save . gofmt-before-save))
  :bind (:map go-mode-map
              ("M-?" . godoc-at-point)
              ("M-." . xref-find-definitions)
              ("M-_" . xref-find-references)
              ;; ("M-*" . pop-tag-mark) ;; Jump back after godef-jump
              ("C-c m r" . go-run))
  :custom
  (gofmt-command "goimports"))

go-test-ginkgo 디버그 프로필을 선택하면 테스트를 디버그할 수 있습니다.

Mastering Golang Debugging in Emacs

이제 구성은 매우 정적이므로 단위 테스트/컨테이너를 미리 선택할 수 없습니다. 어떻게든 -ginkgo.focus 매개변수를 동적으로 만들어야 합니다.

# Install Delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Install gopls
go install golang.org/x/tools/gopls@latest

Mastering Golang Debugging in Emacs

나중에 dape-configs 변수를 살펴보면 다음 값이 표시됩니다.

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/onsi/ginkgo/v2/ginkgo@latest

go install -v golang.org/x/tools/cmd/godoc@latest
go install -v golang.org/x/tools/cmd/goimports@latest
go install -v github.com/stamblerre/gocode@latest
go install -v golang.org/x/tools/cmd/gorename@latest
go install -v golang.org/x/tools/cmd/guru@latest
go install -v github.com/cweill/gotests/...@latest

go install -v github.com/davidrjenni/reftools/cmd/fillstruct@latest
go install -v github.com/fatih/gomodifytags@latest
go install -v github.com/godoctor/godoctor@latest
go install -v github.com/haya14busa/gopkgs/cmd/gopkgs@latest
go install -v github.com/josharian/impl@latest
go install -v github.com/rogpeppe/godef@latest

dape-repl 버퍼에서 디버거(디버그 중심 테스트 프로필 사용)를 시작한 후 다음을 얻습니다.

(use-package ginkgo
  :straight (:type git :host github :repo "garslo/ginkgo-mode")
  :init
  (setq ginkgo-use-pwd-as-test-dir t
        ginkgo-use-default-keys t))

(use-package gotest
  :straight t
  :after go-mode
  :bind (:map go-mode-map
              ("C-c t f" . go-test-current-file)
              ("C-c t t" . go-test-current-test)
              ("C-c t j" . go-test-current-project)
              ("C-c t b" . go-test-current-benchmark)
              ("C-c t c" . go-test-current-coverage)
              ("C-c t x" . go-run)))

(use-package go-guru
  :straight t
  :hook
  (go-mode . go-guru-hl-identifier-mode))

(use-package go-projectile
  :straight t
  :after (projectile go-mode))

(use-package flycheck-golangci-lint
  :straight t
  :hook
  (go-mode . flycheck-golangci-lint-setup))

(use-package go-eldoc
  :straight t
  :hook
  (go-mode . go-eldoc-setup))

(use-package go-tag
  :straight t
  :bind (:map go-mode-map
              ("C-c t a" . go-tag-add)
              ("C-c t r" . go-tag-remove))
  :init (setq go-tag-args (list "-transform" "camelcase")))

(use-package go-fill-struct
  :straight t)

(use-package go-impl
  :straight t)

(use-package go-playground
  :straight t)

?"5개 사양 중 1개"(❶)만 실행되었다는 점에 주목하세요. 이는 ginkgo가 우리가 지정한 컨테이너(❷)에만 집중했다는 의미입니다.

모범 사례 및 팁

디버깅 경험을 통해 다음과 같은 몇 가지 모범 사례를 알게 되었습니다.

  • 디버깅 구성에 버전 제어 사용
  • .dir-locals.el에서 디버그 구성을 유지합니다.
  • 구성에 의미 있는 이름을 사용하세요
  • 프로젝트별 디버깅 도우미 기능 생성
  • 로컬에서 사용자 정의(버퍼별)

리소스 및 참고 자료

  • 마스터의 vscode-go/docs/debugging.md · golang/vscode-go
  • delve/dlv dap-mode 직접 지원 · Issue #318 · emacs-lsp/dap-mode
  • Dape GitHub 저장소
  • Delve 디버거
  • Eglot 문서
  • 은행나무 테스트 프레임워크

위 내용은 Emacs에서 Golang 디버깅 마스터하기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
Golang vs. Python : 장단점Golang vs. Python : 장단점Apr 21, 2025 am 12:17 AM

golangisidealforbuildingscalablesystemsdueToitsefficiencyandconcurrency

Golang 및 C : 동시성 대 원시 속도Golang 및 C : 동시성 대 원시 속도Apr 21, 2025 am 12:16 AM

Golang은 동시성에서 C보다 낫고 C는 원시 속도에서 Golang보다 낫습니다. 1) Golang은 Goroutine 및 Channel을 통해 효율적인 동시성을 달성하며, 이는 많은 동시 작업을 처리하는 데 적합합니다. 2) C 컴파일러 최적화 및 표준 라이브러리를 통해 하드웨어에 가까운 고성능을 제공하며 극도의 최적화가 필요한 애플리케이션에 적합합니다.

Golang을 사용하는 이유는 무엇입니까? 혜택과 장점이 설명되었습니다Golang을 사용하는 이유는 무엇입니까? 혜택과 장점이 설명되었습니다Apr 21, 2025 am 12:15 AM

Golang을 선택하는 이유는 다음과 같습니다. 1) 높은 동시성 성능, 2) 정적 유형 시스템, 3) 쓰레기 수집 메커니즘, 4) 풍부한 표준 라이브러리 및 생태계는 효율적이고 신뢰할 수있는 소프트웨어를 개발하기에 이상적인 선택입니다.

Golang vs. C : 성능 및 속도 비교Golang vs. C : 성능 및 속도 비교Apr 21, 2025 am 12:13 AM

Golang은 빠른 개발 및 동시 시나리오에 적합하며 C는 극도의 성능 및 저수준 제어가 필요한 시나리오에 적합합니다. 1) Golang은 쓰레기 수집 및 동시성 메커니즘을 통해 성능을 향상시키고, 고전성 웹 서비스 개발에 적합합니다. 2) C는 수동 메모리 관리 및 컴파일러 최적화를 통해 궁극적 인 성능을 달성하며 임베디드 시스템 개발에 적합합니다.

Golang은 C보다 빠릅니까? 한계 탐색Golang은 C보다 빠릅니까? 한계 탐색Apr 20, 2025 am 12:19 AM

Golang은 컴파일 시간과 동시 처리에서 더 나은 성능을 발휘하는 반면 C는 달리기 속도 및 메모리 관리에서 더 많은 장점을 가지고 있습니다. 1. 골랑은 빠른 컴파일 속도를 가지고 있으며 빠른 개발에 적합합니다. 2.C는 빠르게 실행되며 성능 크리티컬 애플리케이션에 적합합니다. 3. Golang은 동시 처리에 간단하고 효율적이며 동시 프로그래밍에 적합합니다. 4.C 수동 메모리 관리는 더 높은 성능을 제공하지만 개발 복잡성을 증가시킵니다.

Golang : 웹 서비스에서 시스템 프로그래밍에 이르기까지Golang : 웹 서비스에서 시스템 프로그래밍에 이르기까지Apr 20, 2025 am 12:18 AM

웹 서비스 및 시스템 프로그래밍에서 Golang의 응용 프로그램은 주로 단순성, 효율성 및 동시성에 반영됩니다. 1) 웹 서비스에서 Golang은 강력한 HTTP 라이브러리 및 동시 처리 기능을 통해 고성능 웹 애플리케이션 및 API의 생성을 지원합니다. 2) 시스템 프로그래밍에서 Golang은 운영 체제 개발 및 임베디드 시스템에 적합하기 위해 하드웨어에 가까운 기능 및 C 언어와 호환성을 사용합니다.

Golang vs. C : 벤치 마크 및 실제 성능Golang vs. C : 벤치 마크 및 실제 성능Apr 20, 2025 am 12:18 AM

Golang과 C는 성능 비교에서 고유 한 장점과 단점이 있습니다. 1. Golang은 높은 동시성과 빠른 발전에 적합하지만 쓰레기 수집은 성능에 영향을 줄 수 있습니다. 2.C는 더 높은 성능과 하드웨어 제어를 제공하지만 개발 복잡성이 높습니다. 선택할 때는 프로젝트 요구 사항과 팀 기술을 포괄적 인 방식으로 고려해야합니다.

Golang vs. Python : 비교 분석Golang vs. Python : 비교 분석Apr 20, 2025 am 12:17 AM

Golang은 고성능 및 동시 프로그래밍 시나리오에 적합하지만 Python은 빠른 개발 및 데이터 처리에 적합합니다. 1. Golang은 단순성과 효율성을 강조하며 백엔드 서비스 및 마이크로 서비스에 적합합니다. 2. Python은 간결한 구문 및 풍부한 라이브러리로 유명하며 데이터 과학 및 기계 학습에 적합합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)