You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下使用Makefile运行Go程序时Ctrl+C优雅退出问题

问题描述

我在Windows 11系统中使用以下Makefile运行Go应用:

build:
    go build -o ./bin/my-service ./cmd/my-service

cls: build
    cmd /c cls

# Run the application
run: cls
    ./bin/my-service

# Clean build artifacts
clean:
    rmdir /s /q bin

执行make run命令后程序能正常启动,但我的Go应用包含如下优雅关闭逻辑:

// 创建WaitGroup等待goroutines完成
var wg sync.WaitGroup

// 创建通道监听系统信号(如Ctrl+C)
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

// 创建可取消的context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 启动需要优雅停止的goroutine
wg.Add(1)
go startGoroutine(ctx, &wg)

// 阻塞直到收到信号(如Ctrl+C)
<-sigChan

cancel()

// 收到信号,处理优雅关闭
fmt.Println("Received shutdown signal, stopping goroutines...")

// 执行必要的清理、停止goroutine等操作

// 等待goroutine完成
log.Println("waiting for wg.wait")
wg.Wait()

time.Sleep(10 * time.Second)

fmt.Println("Shutdown complete")

问题:按下Ctrl+C后,程序会立即终止,10秒休眠和"Shutdown complete"日志会在后台执行并在光标后输出,无法维持程序直到执行完最后一行。但直接用go run main.go运行时,优雅关闭逻辑可正常工作。

我尝试过将Makefile中的run命令替换为cmd /c start /wait "C:\full_path_to_app\my-service.exe",这个方法能正常触发优雅退出,但需要在build命令中指定.exe后缀,且必须使用绝对路径,同时会在新窗口中运行程序,而非当前终端窗口。

请问是否有方法能让make等待程序在按下Ctrl+C后完全退出?


解决方案

问题核心是Windows下的make(如GNU Make)收到Ctrl+C时会直接终止自身及所有子进程,不会等待Go程序完成优雅关闭流程。以下是几种可行的解决办法:

方法1:适配Shell终端的信号转发

如果使用Git Bash、WSL这类类Unix终端,修改Makefile的run目标,让make忽略SIGINT信号,把信号传递给Go程序:

run: cls
    @trap "" INT; ./bin/my-service

trap "" INT会让make不处理Ctrl+C信号,转而传递给子进程,这样Go程序就能捕获信号并执行完整的关闭逻辑。

方法2:用CMD在当前窗口运行并等待

针对Windows原生CMD/PowerShell终端,无需绝对路径和修改build后缀,直接用start /wait并指定空窗口标题,就能在当前窗口运行并等待程序完成:

run: cls
    cmd /c start /wait "" ./bin/my-service

解释:

  • start /wait会等待程序完全退出后才返回
  • 空的""是start命令的窗口标题参数,省略会导致把程序路径识别为标题,进而弹出新窗口
  • Go在Windows下编译时,即使指定输出名为my-service,实际会生成my-service.exe,CMD会自动识别并运行,无需手动加.exe后缀

方法3:PowerShell直接调用

如果默认终端是PowerShell,可直接用PowerShell命令调用程序,它会自动等待程序完成包括优雅关闭在内的所有流程:

run: cls
    powershell -Command "./bin/my-service; exit $LASTEXITCODE"

这样收到Ctrl+C时,PowerShell会把信号传递给Go程序,确保它执行完所有关闭逻辑后再退出。


内容的提问来源于stack exchange,提问作者Quintonn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:38:25