diff options
author | Ayke van Laethem <[email protected]> | 2021-08-10 21:35:52 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2021-08-12 21:19:24 +0200 |
commit | f57e9622fdb650f14a48cc327db01c216cd0d9c6 (patch) | |
tree | 1bda50a5662f0571e17a8363a6470b8555e244cf | |
parent | c25a7cc7477a5fc58d68e125ec2cf62836f23fe2 (diff) | |
download | tinygo-f57e9622fdb650f14a48cc327db01c216cd0d9c6.tar.gz tinygo-f57e9622fdb650f14a48cc327db01c216cd0d9c6.zip |
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.
-rw-r--r-- | loader/goroot.go | 2 | ||||
-rw-r--r-- | main_test.go | 86 | ||||
-rw-r--r-- | src/runtime/nonhosted.go | 48 | ||||
-rw-r--r-- | src/runtime/runtime_wasm_js.go | 5 | ||||
-rw-r--r-- | src/syscall/syscall_nonhosted.go (renamed from src/syscall/syscall_baremetal.go) | 20 | ||||
-rw-r--r-- | src/syscall/tables_nonhosted.go (renamed from src/syscall/tables_baremetal.go) | 2 |
6 files changed, 126 insertions, 37 deletions
diff --git a/loader/goroot.go b/loader/goroot.go index 6770d0458..8f0acf1b8 100644 --- a/loader/goroot.go +++ b/loader/goroot.go @@ -208,7 +208,7 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides // with the TinyGo version. This is the case on some targets. func needsSyscallPackage(buildTags []string) bool { 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 } } diff --git a/main_test.go b/main_test.go index 2c1b2f864..a502115e4 100644 --- a/main_test.go +++ b/main_test.go @@ -162,15 +162,15 @@ func runPlatTests(target string, tests []string, t *testing.T) { 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" { t.Run("filesystem.go", func(t *testing.T) { t.Parallel() 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" { 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. binary := filepath.Join(tmpdir, "test") err = runBuild("./"+path, binary, &options) @@ -242,37 +278,31 @@ func runTestWithConfig(name, target string, t *testing.T, options compileopts.Op return } - // Run the test. - runComplete := make(chan struct{}) + // Create the test command, taking care of emulators etc. var cmd *exec.Cmd - ranTooLong := false - if target == "" { + if len(spec.Emulator) == 0 { 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 { - cmd = exec.Command(binary) - } else { - args := append(spec.Emulator[1:], binary) - cmd = exec.Command(spec.Emulator[0], args...) + args := append(spec.Emulator[1:], binary) + cmd = exec.Command(spec.Emulator[0], args...) + } + if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" { + // Allow reading from the current directory. + cmd.Args = append(cmd.Args, "--dir=.") + for _, v := range environmentVars { + cmd.Args = append(cmd.Args, "--env", v) } - - if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" { - // Allow reading from the current directory. - cmd.Args = append(cmd.Args, "--dir=.") - for _, v := range environmentVars { - cmd.Args = append(cmd.Args, "--env", v) - } - cmd.Args = append(cmd.Args, cmdArgs...) - } else { + cmd.Args = append(cmd.Args, cmdArgs...) + } else { + if !needsEnvInVars { + cmd.Args = append(cmd.Args, cmdArgs...) // works on qemu-aarch64 etc cmd.Env = append(cmd.Env, environmentVars...) } } + + // Run the test. + runComplete := make(chan struct{}) + ranTooLong := false stdout := &bytes.Buffer{} cmd.Stdout = stdout cmd.Stderr = os.Stderr diff --git a/src/runtime/nonhosted.go b/src/runtime/nonhosted.go new file mode 100644 index 000000000..61f5023df --- /dev/null +++ b/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:]) + } +} diff --git a/src/runtime/runtime_wasm_js.go b/src/runtime/runtime_wasm_js.go index b39aef0a5..f4335e121 100644 --- a/src/runtime/runtime_wasm_js.go +++ b/src/runtime/runtime_wasm_js.go @@ -15,11 +15,6 @@ func _start() { run() } -//go:linkname syscall_runtime_envs syscall.runtime_envs -func syscall_runtime_envs() []string { - return nil -} - var handleEvent func() //go:linkname setEventHandler syscall/js.setEventHandler diff --git a/src/syscall/syscall_baremetal.go b/src/syscall/syscall_nonhosted.go index 4f0c6e530..885738e4a 100644 --- a/src/syscall/syscall_baremetal.go +++ b/src/syscall/syscall_nonhosted.go @@ -1,4 +1,4 @@ -// +build baremetal +// +build baremetal js package syscall @@ -47,8 +47,24 @@ const ( O_CLOEXEC = 0 ) +func runtime_envs() []string + 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) { diff --git a/src/syscall/tables_baremetal.go b/src/syscall/tables_nonhosted.go index 47a536bff..a78eb75fb 100644 --- a/src/syscall/tables_baremetal.go +++ b/src/syscall/tables_nonhosted.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build baremetal nintendoswitch +// +build baremetal nintendoswitch js package syscall |