fix(build): support make dev on native Windows (#1886)
This commit is contained in:
@@ -5,6 +5,7 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "apps/backend/**"
|
||||
- "scripts/check-make-shells"
|
||||
- ".github/workflows/backend-tests.yml"
|
||||
- "!**/*.md"
|
||||
- "!**/*.mdx"
|
||||
@@ -13,6 +14,7 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "apps/backend/**"
|
||||
- "scripts/check-make-shells"
|
||||
- ".github/workflows/backend-tests.yml"
|
||||
- "!**/*.md"
|
||||
- "!**/*.mdx"
|
||||
@@ -80,6 +82,13 @@ jobs:
|
||||
- name: Build
|
||||
run: go build -v ./cmd/kandev
|
||||
|
||||
# Assert the run/dev/start-debug targets expand to the right per-shell
|
||||
# command line (native Windows / Git Bash / Unix). The windows-latest job
|
||||
# below compiles Go but never exercises this Make-target dispatch, so a
|
||||
# regression in the OS/MSYSTEM guards would otherwise ship unnoticed.
|
||||
- name: Check Makefile shell dispatch
|
||||
run: make check-make-shells
|
||||
|
||||
- name: Resolve base SHA
|
||||
shell: bash
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
||||
@@ -150,7 +150,15 @@ bootstrap-e2e:
|
||||
|
||||
.PHONY: doctor
|
||||
doctor:
|
||||
# Native Windows (cmd/PowerShell) has no POSIX shell for the bash-only doctor
|
||||
# script. Under Git Bash/MSYS ($(MSYSTEM) is set) it runs fine, so skip only
|
||||
# when OS is Windows_NT AND MSYSTEM is empty — the concatenation equals
|
||||
# "Windows_NT" only in that native case.
|
||||
ifeq ($(OS)$(MSYSTEM),Windows_NT)
|
||||
@echo pre-commit hooks skipped on native Windows - run scripts/doctor from Git Bash to enable
|
||||
else
|
||||
@scripts/doctor
|
||||
endif
|
||||
|
||||
.PHONY: dev
|
||||
dev: doctor
|
||||
|
||||
+48
-14
@@ -9,17 +9,30 @@ LDFLAGS := -s -w
|
||||
|
||||
# Cross-platform commands
|
||||
#
|
||||
# On Windows, GNU Make invokes commands through cmd.exe, which does not
|
||||
# support Unix `NAME=VAL cmd` env-var-prefix syntax. Instead, `set NAME=VAL&`
|
||||
# (single ampersand) chains a subsequent command in the same shell, scoping
|
||||
# the env var to one recipe line — the closest cmd analog to the Unix form.
|
||||
# `EXE` adds the .exe suffix to build outputs; Go does NOT auto-append it
|
||||
# when `-o` is explicit.
|
||||
# Two independent axes decide these variables; conflating them breaks Git
|
||||
# Bash/MSYS, which sets OS=Windows_NT yet runs recipes through sh:
|
||||
#
|
||||
# 1. Executable suffix (EXE) — keyed on $(OS). Go emits a `.exe` for
|
||||
# GOOS=windows regardless of the calling shell, so native cmd/PowerShell
|
||||
# AND Git Bash both need it. Go does NOT auto-append it when `-o` is set.
|
||||
# 2. Shell syntax — keyed on $(OS)$(MSYSTEM). Only native cmd/PowerShell needs
|
||||
# `set NAME=VAL&` (single ampersand chains a command in the same shell,
|
||||
# scoping the env var to one recipe line — the closest cmd analog to the
|
||||
# Unix `NAME=VAL cmd` prefix), backslashed paths, and no `exec`. Under Git
|
||||
# Bash/MSYS $(MSYSTEM) is set (e.g. MINGW64), so the concatenation differs
|
||||
# from "Windows_NT" and recipes take the POSIX branch — matching the shell
|
||||
# they run in. Mirrors the doctor guard in the root Makefile.
|
||||
#
|
||||
# Install GNU Make on Windows with `winget install ezwinports.make` (or via
|
||||
# scoop/chocolatey). Targets that rely on Unix builtins (run, dev,
|
||||
# start-debug, build-cross) remain Unix-only.
|
||||
# scoop/chocolatey). build-cross remains Unix-only — it cross-compiles with
|
||||
# CGO for other OSes, which needs Unix toolchains.
|
||||
ifeq ($(OS),Windows_NT)
|
||||
EXE := .exe
|
||||
else
|
||||
EXE :=
|
||||
endif
|
||||
|
||||
ifeq ($(OS)$(MSYSTEM),Windows_NT)
|
||||
RM = cmd /c del /s /q
|
||||
RMDIR = cmd /c rmdir /s /q
|
||||
# cmd's `mkdir` errors when the dir already exists, unlike Unix `mkdir -p`.
|
||||
@@ -34,7 +47,16 @@ ifeq ($(OS),Windows_NT)
|
||||
GO_LINUX_ARM64 = set CGO_ENABLED=0& set GOOS=linux& set GOARCH=arm64&
|
||||
GO_DARWIN_ARM64 = set CGO_ENABLED=0& set GOOS=darwin& set GOARCH=arm64&
|
||||
GO_DARWIN_AMD64 = set CGO_ENABLED=0& set GOOS=darwin& set GOARCH=amd64&
|
||||
EXE = .exe
|
||||
# Run-target env prefixes and binary invocation. cmd.exe has no `NAME=VAL cmd`
|
||||
# syntax (use `set NAME=VAL&`) and no `exec`; the binary path needs backslashes.
|
||||
DEV_ENV = set KANDEV_DEBUG_PPROF_ENABLED=true&
|
||||
DEBUG_ENV = set KANDEV_DEBUG_PPROF_ENABLED=true& set KANDEV_LOG_LEVEL=debug&
|
||||
EXEC =
|
||||
RUN_BIN = "$(subst /,\,$(BUILD_DIR)/$(BINARY_NAME)$(EXE))"
|
||||
# check-make-shells is a bash script; native cmd.exe can't run its shebang, so
|
||||
# print a skip note instead (mirrors the root Makefile's doctor guard). CI runs
|
||||
# the real check on Linux, and Git Bash/WSL run it locally.
|
||||
CHECK_SHELLS = @echo check-make-shells is bash-only - run it from Git Bash/WSL or the Linux CI
|
||||
# Windows recipes run under cmd.exe, which has no POSIX `if command -v ...; then`
|
||||
# syntax. Neither codesign nor rcodesign ships on Windows anyway, so ad-hoc
|
||||
# signing is a no-op here: darwin/arm64 stays Go-signed at link time, and
|
||||
@@ -51,7 +73,11 @@ else
|
||||
GO_LINUX_ARM64 = CGO_ENABLED=0 GOOS=linux GOARCH=arm64
|
||||
GO_DARWIN_ARM64 = CGO_ENABLED=0 GOOS=darwin GOARCH=arm64
|
||||
GO_DARWIN_AMD64 = CGO_ENABLED=0 GOOS=darwin GOARCH=amd64
|
||||
EXE =
|
||||
DEV_ENV = KANDEV_DEBUG_PPROF_ENABLED=true
|
||||
DEBUG_ENV = KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug
|
||||
EXEC = exec
|
||||
RUN_BIN = ./$(BUILD_DIR)/$(BINARY_NAME)$(EXE)
|
||||
CHECK_SHELLS = @../../scripts/check-make-shells
|
||||
# Ad-hoc sign a darwin Mach-O so Apple Silicon (AMFI) will run it; ad-hoc needs
|
||||
# no Apple identity. Go already ad-hoc-signs darwin/arm64 at link time, so this
|
||||
# is mainly to (a) sign darwin/amd64 too and (b) re-sign uniformly. Prefer
|
||||
@@ -75,7 +101,7 @@ BUILD_TIME := $(shell date -u '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || powershell -c
|
||||
|
||||
LDFLAGS += -X main.Version=$(VERSION) -X main.Commit=$(COMMIT) -X main.BuildTime=$(BUILD_TIME)
|
||||
|
||||
.PHONY: all build build-all build-agentctl build-agentctl-remote build-agentctl-linux build-agentctl-linux-arm64 build-agentctl-darwin-arm64 build-agentctl-darwin-amd64 build-acpdbg acpdbg build-mock-agent build-mock-agent-linux build-preview build-winjob e2e-plugin-package clean run dev start-debug test test-e2e test-sprites-e2e test-lifecycle-goleak lint fmt vet help
|
||||
.PHONY: all build build-all build-agentctl build-agentctl-remote build-agentctl-linux build-agentctl-linux-arm64 build-agentctl-darwin-arm64 build-agentctl-darwin-amd64 build-acpdbg acpdbg build-mock-agent build-mock-agent-linux build-preview build-winjob e2e-plugin-package clean run dev start-debug test test-e2e test-sprites-e2e test-lifecycle-goleak lint fmt vet check-make-shells help
|
||||
|
||||
## Default target
|
||||
all: build
|
||||
@@ -200,17 +226,17 @@ clean:
|
||||
## Run the application
|
||||
run: build
|
||||
@echo "Running $(BINARY_NAME)..."
|
||||
./$(BUILD_DIR)/$(BINARY_NAME)$(EXE) __backend
|
||||
$(RUN_BIN) __backend
|
||||
|
||||
## Run in development mode (with pprof enabled)
|
||||
dev: build
|
||||
@echo "Running $(BINARY_NAME) in development mode..."
|
||||
@KANDEV_DEBUG_PPROF_ENABLED=true exec ./$(BUILD_DIR)/$(BINARY_NAME)$(EXE) __backend
|
||||
@$(DEV_ENV) $(EXEC) $(RUN_BIN) __backend
|
||||
|
||||
## Run in debug mode (pprof + debug logging)
|
||||
start-debug: build
|
||||
@echo "Running $(BINARY_NAME) in debug mode (pprof + debug logging)..."
|
||||
@KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug exec ./$(BUILD_DIR)/$(BINARY_NAME)$(EXE) __backend
|
||||
@$(DEBUG_ENV) $(EXEC) $(RUN_BIN) __backend
|
||||
|
||||
## Run tests
|
||||
test:
|
||||
@@ -227,6 +253,13 @@ test-windows:
|
||||
@echo "Running Windows-sensitive packages..."
|
||||
$(CGO_PREFIX) $(GO) test -tags fts5 -v ./internal/agentctl/server/process/... ./internal/agent/runtime/agentctl/launcher/...
|
||||
|
||||
## Verify run/dev/start-debug expand to the right per-shell command line across
|
||||
## native Windows (cmd), Git Bash/MSYS, and Unix — the Make-target dispatch the
|
||||
## Go CI jobs don't exercise. The harness is a bash script, so it runs under Git
|
||||
## Bash/WSL or the Linux CI; on native cmd/PowerShell it prints a skip note.
|
||||
check-make-shells:
|
||||
$(CHECK_SHELLS)
|
||||
|
||||
## Run E2E tests (real agents, costs money — manual only)
|
||||
## Set agent commands via env vars: E2E_CLAUDE_CODE_COMMAND, E2E_AMP_COMMAND
|
||||
## Enable debug: KANDEV_DEBUG_AGENT_MESSAGES=true KANDEV_DEBUG_LOG_DIR=/tmp/e2e-debug
|
||||
@@ -331,6 +364,7 @@ help:
|
||||
@echo " start-debug Run in debug mode (pprof + debug logging)"
|
||||
@echo " test Run tests (full suite — fails on Windows pending fixture cleanup)"
|
||||
@echo " test-windows Run only the Windows-clean subset (matches CI windows-latest job)"
|
||||
@echo " check-make-shells Assert run/dev/start-debug expand correctly per shell (make -n)"
|
||||
@echo " test-e2e Run E2E adapter tests (real agents, costs money)"
|
||||
@echo " e2e-plugin-package Package the plugin-fixture SDK plugin into .build/kandev-plugin-e2e-1.0.0.tar.gz"
|
||||
@echo " test-lifecycle-goleak Stress-run lifecycle goleak suite (override LIFECYCLE_GOLEAK_COUNT=N)"
|
||||
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env bash
|
||||
# check-make-shells — assert that apps/backend/Makefile's run/dev/start-debug
|
||||
# targets expand to the correct per-shell command line, without running them.
|
||||
#
|
||||
# The Makefile dispatches on two independent axes:
|
||||
# * EXE suffix — keyed on $(OS): any Windows build (native cmd/PowerShell
|
||||
# OR Git Bash) produces kandev.exe.
|
||||
# * shell syntax — keyed on $(OS)$(MSYSTEM): only native cmd/PowerShell uses
|
||||
# `set VAR=VAL&` + backslash path + no exec; Unix and Git
|
||||
# Bash/MSYS use POSIX `VAR=val exec`.
|
||||
# Git Bash is the trap — it sets OS=Windows_NT yet runs recipes through sh, so
|
||||
# it must take the POSIX branch while keeping the .exe suffix. Conflating the
|
||||
# two axes (the pre-fix bug) made Git Bash emit `set VAR=VAL&` into bash, where
|
||||
# the env var is never exported.
|
||||
#
|
||||
# Each shell is simulated deterministically with make's OS=/MSYSTEM=
|
||||
# command-line overrides, so one host checks the dispatch for all three shells
|
||||
# without having to run on each. The harness itself is bash (grep, sed), so it
|
||||
# needs a POSIX shell — it runs in the Linux CI job and under Git Bash/WSL
|
||||
# locally, not from native cmd.exe/PowerShell. Covers the Make-target dispatch
|
||||
# that the backend Go CI jobs don't exercise.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
backend_dir="$(cd "$(dirname "$0")/../apps/backend" && pwd)"
|
||||
|
||||
status=0
|
||||
|
||||
# expect <label> <OS> <MSYSTEM> <target> <expected recipe tail>
|
||||
expect() {
|
||||
local label=$1 os=$2 msys=$3 target=$4 want=$5 got
|
||||
got=$(make -C "$backend_dir" OS="$os" MSYSTEM="$msys" -n "$target" 2>/dev/null \
|
||||
| grep -F __backend \
|
||||
| sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/[[:space:]]\{1,\}/ /g' \
|
||||
|| true)
|
||||
if [ "$got" = "$want" ]; then
|
||||
printf 'ok %-16s %-12s %s\n' "$label" "$target" "$got"
|
||||
else
|
||||
printf 'FAIL %-16s %-12s\n want: %s\n got: %s\n' \
|
||||
"$label" "$target" "$want" "$got"
|
||||
status=1
|
||||
fi
|
||||
}
|
||||
|
||||
# Unix — no .exe, POSIX env-prefix + exec.
|
||||
expect unix '' '' run './bin/kandev __backend'
|
||||
expect unix '' '' dev 'KANDEV_DEBUG_PPROF_ENABLED=true exec ./bin/kandev __backend'
|
||||
expect unix '' '' start-debug 'KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug exec ./bin/kandev __backend'
|
||||
|
||||
# Native Windows (cmd/PowerShell) — .exe, `set VAR=VAL&`, backslash path, no exec.
|
||||
expect windows-native Windows_NT '' run '"bin\kandev.exe" __backend'
|
||||
expect windows-native Windows_NT '' dev 'set KANDEV_DEBUG_PPROF_ENABLED=true& "bin\kandev.exe" __backend'
|
||||
expect windows-native Windows_NT '' start-debug 'set KANDEV_DEBUG_PPROF_ENABLED=true& set KANDEV_LOG_LEVEL=debug& "bin\kandev.exe" __backend'
|
||||
|
||||
# Git Bash/MSYS — .exe suffix but POSIX syntax (recipes run through sh).
|
||||
expect git-bash Windows_NT MINGW64 run './bin/kandev.exe __backend'
|
||||
expect git-bash Windows_NT MINGW64 dev 'KANDEV_DEBUG_PPROF_ENABLED=true exec ./bin/kandev.exe __backend'
|
||||
expect git-bash Windows_NT MINGW64 start-debug 'KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug exec ./bin/kandev.exe __backend'
|
||||
|
||||
if [ "$status" -eq 0 ]; then
|
||||
echo "All Makefile shell-dispatch checks passed (3 shells x 3 targets)."
|
||||
fi
|
||||
exit "$status"
|
||||
Reference in New Issue
Block a user