From 4bfbc64e3f6182b2521a63916ac608a52a08551f Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Wed, 30 Apr 2025 10:31:15 -0700 Subject: [PATCH 1/2] runtime,os: add os.Executable() for Darwin --- src/os/executable_darwin.go | 10 ++++++++++ src/os/executable_other.go | 2 +- src/runtime/os_darwin.go | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/os/executable_darwin.go diff --git a/src/os/executable_darwin.go b/src/os/executable_darwin.go new file mode 100644 index 0000000000..7c65a90c3d --- /dev/null +++ b/src/os/executable_darwin.go @@ -0,0 +1,10 @@ +//go:build darwin + +package os + +// via runtime because we need argc/argv ptrs +func runtime_executable_path() string + +func Executable() (string, error) { + return runtime_executable_path(), nil +} diff --git a/src/os/executable_other.go b/src/os/executable_other.go index 5da50ede18..ce99c13009 100644 --- a/src/os/executable_other.go +++ b/src/os/executable_other.go @@ -1,4 +1,4 @@ -//go:build !linux || baremetal +//go:build (!linux && !darwin) || baremetal package os diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index e7f7b368fb..df5c598807 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -229,3 +229,38 @@ func call_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) int32 //export tinygo_syscall6X func call_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr + +//go:linkname os_runtime_executable_path os.runtime_executable_path +func os_runtime_executable_path() string { + argv := (*unsafe.Pointer)(unsafe.Pointer(main_argv)) + + // skip over argv + argv = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(argv), (uintptr(main_argc)+1)*unsafe.Sizeof(argv))) + + // skip over envv + for (*argv) != nil { + argv = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(argv), unsafe.Sizeof(argv))) + } + + // next string is exe path + argv = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(argv), unsafe.Sizeof(argv))) + + cstr := unsafe.Pointer(*argv) + length := strlen(cstr) + argString := _string{ + length: length, + ptr: (*byte)(cstr), + } + executablePath := *(*string)(unsafe.Pointer(&argString)) + + // strip "executable_path=" prefix if available, it's added after OS X 10.11. + executablePath = stringsTrimPrefix(executablePath, "executable_path=") + return executablePath +} + +func stringsTrimPrefix(s, prefix string) string { + if len(s) >= len(prefix) && s[:len(prefix)] == prefix { + return s[len(prefix):] + } + return s +} From 228bbcb5eee4b318ccf7edfd03398a7b1ad476f7 Mon Sep 17 00:00:00 2001 From: Damian Gryski Date: Wed, 30 Apr 2025 11:36:03 -0700 Subject: [PATCH 2/2] os: handle relative and abs paths in Executable() --- src/os/executable_darwin.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/os/executable_darwin.go b/src/os/executable_darwin.go index 7c65a90c3d..e689db23fb 100644 --- a/src/os/executable_darwin.go +++ b/src/os/executable_darwin.go @@ -6,5 +6,14 @@ package os func runtime_executable_path() string func Executable() (string, error) { - return runtime_executable_path(), nil + p := runtime_executable_path() + if p != "" && p[0] == '/' { + // absolute path + return p, nil + } + cwd, err := Getwd() + if err != nil { + return "", err + } + return joinPath(cwd, p), nil }