baremetal,wasm: support command line params and environment variables
This is mainly useful to be able to run `tinygo test`, for example: tinygo test -target=cortex-m-qemu -v math This is not currently supported, but will be in the future.
Этот коммит содержится в:
родитель
c25a7cc747
коммит
f57e9622fd
6 изменённых файлов: 126 добавлений и 37 удалений
|
@ -208,7 +208,7 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides
|
||||||
// with the TinyGo version. This is the case on some targets.
|
// with the TinyGo version. This is the case on some targets.
|
||||||
func needsSyscallPackage(buildTags []string) bool {
|
func needsSyscallPackage(buildTags []string) bool {
|
||||||
for _, tag := range buildTags {
|
for _, tag := range buildTags {
|
||||||
if tag == "baremetal" || tag == "darwin" || tag == "nintendoswitch" || tag == "wasi" {
|
if tag == "baremetal" || tag == "darwin" || tag == "nintendoswitch" || tag == "tinygo.wasm" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
64
main_test.go
64
main_test.go
|
@ -162,15 +162,15 @@ func runPlatTests(target string, tests []string, t *testing.T) {
|
||||||
runTest(name, target, t, nil, nil)
|
runTest(name, target, t, nil, nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
t.Run("env.go", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
runTest("env.go", target, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
||||||
|
})
|
||||||
if target == "" || target == "wasi" {
|
if target == "" || target == "wasi" {
|
||||||
t.Run("filesystem.go", func(t *testing.T) {
|
t.Run("filesystem.go", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTest("filesystem.go", target, t, nil, nil)
|
runTest("filesystem.go", target, t, nil, nil)
|
||||||
})
|
})
|
||||||
t.Run("env.go", func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
runTest("env.go", target, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if target == "" || target == "wasi" || target == "wasm" {
|
if target == "" || target == "wasi" || target == "wasm" {
|
||||||
t.Run("rand.go", func(t *testing.T) {
|
t.Run("rand.go", func(t *testing.T) {
|
||||||
|
@ -233,6 +233,42 @@ func runTestWithConfig(name, target string, t *testing.T, options compileopts.Op
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Determine whether we're on a system that supports environment variables
|
||||||
|
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||||
|
// WebAssembly in the browser). If we're on a system without an environment,
|
||||||
|
// we need to pass command line arguments and environment variables through
|
||||||
|
// global variables (built into the binary directly) instead of the
|
||||||
|
// conventional way.
|
||||||
|
spec, err := compileopts.LoadTarget(target)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("failed to load target spec:", err)
|
||||||
|
}
|
||||||
|
needsEnvInVars := spec.GOOS == "js"
|
||||||
|
for _, tag := range spec.BuildTags {
|
||||||
|
if tag == "baremetal" {
|
||||||
|
needsEnvInVars = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needsEnvInVars {
|
||||||
|
runtimeGlobals := make(map[string]string)
|
||||||
|
if len(cmdArgs) != 0 {
|
||||||
|
runtimeGlobals["osArgs"] = strings.Join(cmdArgs, "\x00")
|
||||||
|
}
|
||||||
|
if len(environmentVars) != 0 {
|
||||||
|
runtimeGlobals["osEnv"] = strings.Join(environmentVars, "\x00")
|
||||||
|
}
|
||||||
|
if len(runtimeGlobals) != 0 {
|
||||||
|
// This sets the global variables like they would be set with
|
||||||
|
// `-ldflags="-X=runtime.osArgs=first\x00second`.
|
||||||
|
// The runtime package has two variables (osArgs and osEnv) that are
|
||||||
|
// both strings, from which the parameters and environment variables
|
||||||
|
// are read.
|
||||||
|
options.GlobalValues = map[string]map[string]string{
|
||||||
|
"runtime": runtimeGlobals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build the test binary.
|
// Build the test binary.
|
||||||
binary := filepath.Join(tmpdir, "test")
|
binary := filepath.Join(tmpdir, "test")
|
||||||
err = runBuild("./"+path, binary, &options)
|
err = runBuild("./"+path, binary, &options)
|
||||||
|
@ -242,26 +278,14 @@ func runTestWithConfig(name, target string, t *testing.T, options compileopts.Op
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the test.
|
// Create the test command, taking care of emulators etc.
|
||||||
runComplete := make(chan struct{})
|
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
ranTooLong := false
|
|
||||||
if target == "" {
|
|
||||||
cmd = exec.Command(binary)
|
|
||||||
cmd.Env = append(cmd.Env, environmentVars...)
|
|
||||||
cmd.Args = append(cmd.Args, cmdArgs...)
|
|
||||||
} else {
|
|
||||||
spec, err := compileopts.LoadTarget(target)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("failed to load target spec:", err)
|
|
||||||
}
|
|
||||||
if len(spec.Emulator) == 0 {
|
if len(spec.Emulator) == 0 {
|
||||||
cmd = exec.Command(binary)
|
cmd = exec.Command(binary)
|
||||||
} else {
|
} else {
|
||||||
args := append(spec.Emulator[1:], binary)
|
args := append(spec.Emulator[1:], binary)
|
||||||
cmd = exec.Command(spec.Emulator[0], args...)
|
cmd = exec.Command(spec.Emulator[0], args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
|
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
|
||||||
// Allow reading from the current directory.
|
// Allow reading from the current directory.
|
||||||
cmd.Args = append(cmd.Args, "--dir=.")
|
cmd.Args = append(cmd.Args, "--dir=.")
|
||||||
|
@ -270,9 +294,15 @@ func runTestWithConfig(name, target string, t *testing.T, options compileopts.Op
|
||||||
}
|
}
|
||||||
cmd.Args = append(cmd.Args, cmdArgs...)
|
cmd.Args = append(cmd.Args, cmdArgs...)
|
||||||
} else {
|
} else {
|
||||||
|
if !needsEnvInVars {
|
||||||
|
cmd.Args = append(cmd.Args, cmdArgs...) // works on qemu-aarch64 etc
|
||||||
cmd.Env = append(cmd.Env, environmentVars...)
|
cmd.Env = append(cmd.Env, environmentVars...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the test.
|
||||||
|
runComplete := make(chan struct{})
|
||||||
|
ranTooLong := false
|
||||||
stdout := &bytes.Buffer{}
|
stdout := &bytes.Buffer{}
|
||||||
cmd.Stdout = stdout
|
cmd.Stdout = stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
|
|
48
src/runtime/nonhosted.go
Обычный файл
48
src/runtime/nonhosted.go
Обычный файл
|
@ -0,0 +1,48 @@
|
||||||
|
// +build baremetal js
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// This file is for non-hosted environments, that don't support command line
|
||||||
|
// parameters or environment variables. To still be able to run certain tests,
|
||||||
|
// command line parameters and environment variables can be passed to the binary
|
||||||
|
// by setting the variables `runtime.osArgs` and `runtime.osEnv`, both of which
|
||||||
|
// are strings separated by newlines.
|
||||||
|
//
|
||||||
|
// The primary use case is `tinygo test`, which takes some parameters (such as
|
||||||
|
// -test.v).
|
||||||
|
|
||||||
|
var env []string
|
||||||
|
|
||||||
|
//go:linkname syscall_runtime_envs syscall.runtime_envs
|
||||||
|
func syscall_runtime_envs() []string {
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
var osArgs string
|
||||||
|
var osEnv string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if osArgs != "" {
|
||||||
|
s := osArgs
|
||||||
|
start := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == 0 {
|
||||||
|
args = append(args, s[start:i])
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args = append(args, s[start:])
|
||||||
|
}
|
||||||
|
|
||||||
|
if osEnv != "" {
|
||||||
|
s := osEnv
|
||||||
|
start := 0
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] == 0 {
|
||||||
|
env = append(env, s[start:i])
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env = append(env, s[start:])
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,11 +15,6 @@ func _start() {
|
||||||
run()
|
run()
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname syscall_runtime_envs syscall.runtime_envs
|
|
||||||
func syscall_runtime_envs() []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var handleEvent func()
|
var handleEvent func()
|
||||||
|
|
||||||
//go:linkname setEventHandler syscall/js.setEventHandler
|
//go:linkname setEventHandler syscall/js.setEventHandler
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build baremetal
|
// +build baremetal js
|
||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
|
@ -47,8 +47,24 @@ const (
|
||||||
O_CLOEXEC = 0
|
O_CLOEXEC = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func runtime_envs() []string
|
||||||
|
|
||||||
func Getenv(key string) (value string, found bool) {
|
func Getenv(key string) (value string, found bool) {
|
||||||
return "", false // stub
|
env := runtime_envs()
|
||||||
|
for _, keyval := range env {
|
||||||
|
// Split at '=' character.
|
||||||
|
var k, v string
|
||||||
|
for i := 0; i < len(keyval); i++ {
|
||||||
|
if keyval[i] == '=' {
|
||||||
|
k = keyval[:i]
|
||||||
|
v = keyval[i+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k == key {
|
||||||
|
return v, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func Open(path string, mode int, perm uint32) (fd int, err error) {
|
func Open(path string, mode int, perm uint32) (fd int, err error) {
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build baremetal nintendoswitch
|
// +build baremetal nintendoswitch js
|
||||||
|
|
||||||
package syscall
|
package syscall
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче