Skip to content

Commit

Permalink
support Go 1.21 for Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Sep 13, 2023
1 parent e5bb80a commit 4b92e97
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 6 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ jobs:
GOARCH=arm64 go run test.go -qemu -args="-test.run=^Test -test.v time"
- name: Test (amd64)
if: ${{ runner.os == 'Linux' || !startsWith(matrix.go, '1.21.') }}
run: |
go run test.go -args="-test.run=^Test -test.v fmt"
go run test.go -args="-test.run=^Test -test.v internal/abi"
Expand All @@ -69,7 +68,9 @@ jobs:
go run test.go -args="-test.run=^Test -test.v math/big"
go run test.go -args="-test.run=^Test -test.v math/bits"
go run test.go -args="-test.run=^Test -test.v math/cmplx"
go run test.go -args="-test.run=^Test -test.v math/rand"
# math/rand's TestDefaultRace doesn't work well by default.
# Set an environment to do the default tests.
GO_RAND_TEST_HELPER_CODE=1 go run test.go -args="-test.run=^Test -test.v math/rand"
go run test.go -args="-test.run=^Test -test.v -test.short runtime"
go run test.go -args="-test.run=^Test -test.v runtime/debug"
go run test.go -args="-test.run=^Test -test.v runtime/internal/atomic"
Expand Down
2 changes: 1 addition & 1 deletion 1.21_linux/math/rand/default_test.go.patch
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
func TestDefaultRace(t *testing.T) {
//--to
func TestDefaultRace(t *testing.T) {
t.Skip("creating a process is not supported in this environment")
t.Skip("os.Getenv and creating processes are not supported in this environment")
5 changes: 5 additions & 0 deletions 1.21_windows/runtime/abi_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func TestFinalizerRegisterABI(t *testing.T) {
//--to
func TestFinalizerRegisterABI(t *testing.T) {
t.Skip("creating a new process with os.Args[0] doesn't work in this environment")
3 changes: 3 additions & 0 deletions 1.21_windows/runtime/cgo/gcc_fatalf.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//--from
#include <stdio.h>
//--to
3 changes: 3 additions & 0 deletions 1.21_windows/runtime/cgo/gcc_libinit.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//--from
#include <stdio.h>
//--to
3 changes: 3 additions & 0 deletions 1.21_windows/runtime/cgo/gcc_libinit_windows.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//--from
#include <stdio.h>
//--to
22 changes: 22 additions & 0 deletions 1.21_windows/runtime/cgo/gcc_windows_amd64.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//--from
#include <stdio.h>
//--to
//--from
static void
threadentry(void *v)
{
//--to
static int getproccount() {
static int proccount = 0;
if (!proccount) {
SYSTEM_INFO info;
GetSystemInfo(&info);
proccount = info.dwNumberOfProcessors;
}
return proccount;
}

static void
threadentry(void *v)
{
SetThreadAffinityMask(GetCurrentThread(), (1<<getproccount())-1);
10 changes: 10 additions & 0 deletions 1.21_windows/runtime/cgo/libcgo.h.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//--from
#include <stdio.h>
//--to
//--append
#define fprintf dummy_fprintf
#define stderr dummy_stderr

// TODO: Use OutputDebugMessage.
#define dummy_fprintf(stream, format, ...)
#define dummy_stderr 2
10 changes: 10 additions & 0 deletions 1.21_windows/runtime/crash_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//--from
func TestRuntimePanic(t *testing.T) {
//--to
func TestRuntimePanic(t *testing.T) {
t.Skip("analyzing output is not supported in this environment")
//--from
func TestG0StackOverflow(t *testing.T) {
//--to
func TestG0StackOverflow(t *testing.T) {
t.Skip("analyzing output is not supported in this environment")
5 changes: 5 additions & 0 deletions 1.21_windows/runtime/malloc_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func TestArenaCollision(t *testing.T) {
//--to
func TestArenaCollision(t *testing.T) {
t.Skip("creating a new process with os.Args[0] doesn't work in this environment")
160 changes: 160 additions & 0 deletions 1.21_windows/runtime/os_windows.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//--from
//go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll"
//--to
//--from
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
//--to
//--from
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
//--to
//go:cgo_import_dynamic runtime._OutputDebugStringW OutputDebugStringW%1 "kernel32.dll"
//--from
_GetConsoleMode,
//--to
//--from
_SetConsoleCtrlHandler,
//--to
//--from
_WriteConsoleW,
//--to
_OutputDebugStringW,
//--from
_timeBeginPeriod,
_timeEndPeriod,
//--to
//--from
m32 := windowsLoadSystemLib(winmmdll[:])
if m32 == 0 {
throw("winmm.dll not found")
}
_timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
_timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
if _timeBeginPeriod == nil || _timeEndPeriod == nil {
throw("timeBegin/EndPeriod not found")
}
//--to
//--from
// We call these all the way here, late in init, so that malloc works
// for the callback functions these generate.
var fn any = ctrlHandler
ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
stdcall2(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)
//--to
//--from
func osRelax(relax bool) uint32 {
if haveHighResTimer {
// If the high resolution timer is available, the runtime uses the timer
// to sleep for short durations. This means there's no need to adjust
// the global clock frequency.
return 0
}

if relax {
return uint32(stdcall1(_timeEndPeriod, 1))
} else {
return uint32(stdcall1(_timeBeginPeriod, 1))
}
}
//--to
func osRelax(relax bool) uint32 {
if haveHighResTimer {
// If the high resolution timer is available, the runtime uses the timer
// to sleep for short durations. This means there's no need to adjust
// the global clock frequency.
return 0
}

throw("not reached")
return 0
}
//--from
func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
const (
_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
_STD_ERROR_HANDLE = ^uintptr(11) // -12
)
var handle uintptr
switch fd {
case 1:
handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
case 2:
handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
default:
// assume fd is real windows handle.
handle = fd
}
isASCII := true
b := (*[1 << 30]byte)(buf)[:n]
for _, x := range b {
if x >= 0x80 {
isASCII = false
break
}
}

if !isASCII {
var m uint32
isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
// If this is a console output, various non-unicode code pages can be in use.
// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
if isConsole {
return int32(writeConsole(handle, buf, n))
}
}
var written uint32
stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
return int32(written)
}
//--to
func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
const (
_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
_STD_ERROR_HANDLE = ^uintptr(11) // -12
)
var handle uintptr
switch fd {
case 1:
handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
case 2:
handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
default:
// assume fd is real windows handle.
handle = fd
}
if fd == 1 || fd == 2 {
// Note that handle is not used anyway.
return int32(writeConsole(handle, buf, n))
}
var written uint32
stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
return int32(written)
}
//--from
func writeConsoleUTF16(handle uintptr, b []uint16) {
l := uint32(len(b))
if l == 0 {
return
}
var written uint32
stdcall5(_WriteConsoleW,
handle,
uintptr(unsafe.Pointer(&b[0])),
uintptr(l),
uintptr(unsafe.Pointer(&written)),
0,
)
return
}
//--to
func writeConsoleUTF16(handle uintptr, b []uint16) {
b = b[:len(b)+1]
b[len(b)-1] = 0
l := uint32(len(b))
if l <= 1 {
return
}
stdcall1(_OutputDebugStringW,
uintptr(unsafe.Pointer(&b[0])),
)
return
}
7 changes: 7 additions & 0 deletions 1.21_windows/runtime/syscall_windows.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//--from
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
//--to
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
if trap == 0 {
panic("trap must not be 0 at SyscallN")
}
5 changes: 5 additions & 0 deletions 1.21_windows/runtime/syscall_windows_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func TestNumCPU(t *testing.T) {
//--to
func TestNumCPU(t *testing.T) {
t.Skip("creating a new process with os.Args[0] doesn't work in this environment")
5 changes: 5 additions & 0 deletions 1.21_windows/sync/mutex_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func TestMutexMisuse(t *testing.T) {
//--to
func TestMutexMisuse(t *testing.T) {
t.Skip("analyzing output is not supported in this environment")
27 changes: 24 additions & 3 deletions test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,31 @@ func createJSON(args []string) (string, error) {
}

func buildTestBinary(jsonPath string, args []string) error {
bin := "test"
// Create a temporary working directory to use a fixed Go version for go.mod.
// go.mod's Go version matters as this might change some Go's behavior (e.g. runtime.TestPanicNil).
tmp, err := os.MkdirTemp("", "hitsumabushi-*")
if err != nil {
return err
}
defer os.RemoveAll(tmp)

cmd := exec.Command("go", "mod", "init", "hitsumabushitest")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = tmp
if err := cmd.Run(); err != nil {
return err
}

wd, err := os.Getwd()
if err != nil {
return err
}
bin := filepath.Join(wd, "test")
if runtime.GOOS == "windows" {
bin += ".exe"
}
cmd := exec.Command("go", "test", "-c", "-vet=off", "-overlay="+jsonPath, "-o="+bin)
cmd = exec.Command("go", "test", "-c", "-vet=off", "-overlay="+jsonPath, "-o="+bin)
cmd.Args = append(cmd.Args, args...)
cmd.Env = append(os.Environ(),
"CGO_ENABLED=1",
Expand All @@ -95,10 +115,11 @@ func buildTestBinary(jsonPath string, args []string) error {
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

cmd.Dir = tmp
if err := cmd.Run(); err != nil {
return err
}

return nil
}

Expand Down

0 comments on commit 4b92e97

Please sign in to comment.