v0.42.0-net.2
Pre-releaseA test build of the TinyGo 0.42 development tree with working host networking over real TLS and working process spawning on hosted linux and macOS. It exists so a downstream project can build and run a program whose release paths are all HTTPS and which shells out to the binaries it installs. It is not an official TinyGo release and it is not built from tinygo-org/tinygo.
This is v0.42.0-net.1 plus a working os/exec.
New in net.2: os/exec starts processes
TinyGo's os package stubbed the process layer out. StartProcess rejected every ProcAttr carrying Dir, Sys or Files — and os/exec always passes three Files — so no command could ever be run; Wait, Kill and Signal returned operation not implemented, and ProcessState was an empty struct whose methods all reported failure. What did exist on linux, a bare fork() followed by execve() with no branch on the return value, was unsound anyway: parent and child both fell into the exec.
- Processes are started with
posix_spawn(3)on hosted linux (musl) and macOS (libSystem), not with a fork. These targets run the threads scheduler and collect with Boehm, so afork()from Go would hand the child a single thread holding whatever locks the other threads owned — malloc's among them — with the collector's stop-the-world signal free to land between the fork and the exec.posix_spawnmoves the clone and the exec inside libc, where no Go code runs in between. ProcAttr.Files,.Dirand.Envall work. Descriptors are laid out withdup2/closefile actions,Dirwithposix_spawn_file_actions_addchdir_np, and a nilEnvinherits the parent's environment, as in upstream Go.Waitreaps withwait4and retries onEINTR, which is routine here rather than exceptional: a thread parked inwait4is exactly the kind the collector has to interrupt.ProcessStateis real. It carries the pid and the actualsyscall.WaitStatus, soexec.ExitErrorreportsexit status N, andExitCode,Exited,Success,SysandStringall work. A killed child is reported as signalled.Kill/Signalwork, and mapESRCHtoos.ErrProcessDone— which is whatexec.CommandContextexpects when its context fires at the same moment the command finishes.- The child gets an empty signal mask. Unlike a handler disposition, a blocked mask survives an
exec, and the spawning thread may be carrying the collector's signal blocked. os.Pipeon macOS now setsFD_CLOEXECon both ends. macOS has nopipe2, so every pipe used to leak into every process started afterwards, and a child holding a duplicate of a write end keeps the pipe from ever reporting end of file — which is exactly howos/execcollects a command's output.- The darwin libSystem stub declares the
posix_spawnfamily, which the minimal macOS SDK omits.
Targets without a process model — baremetal, wasm, Windows — keep exactly the previous stubs.
Carried over from net.1
crypto/tlsis the real one. TinyGo replacescrypto/tlswith a stub whose handshake does nothing, sohttps://produced a plaintext connection wearing the TLS API. On hosted linux and darwin the standard library's owncrypto/tlsis used instead; the stub stays in place for baremetal, wasm and Windows targets.- The host netdev works on macOS.
src/net's raw-socket netdev was linux-only, so a darwin binary reportedNetdev not setfor every dial. It now builds on darwin too, withSO_NOSIGPIPEon every socket. - HTTPS on macOS has trust roots.
crypto/x509's macOS verifier is a stub in TinyGo, sonet/httpsupplies a root pool of its own, read from$SSL_CERT_FILEor from/etc/ssl/cert.pem. weak.runtime_makeStrongFromWeakis implemented, whichcrypto/tls's certificate cache needs to link.- The darwin libSystem stub declares the BSD socket API, which the minimal macOS SDK omits.
Verified
tests/spawnprobe — the process layer asked one piece at a time: output, combined stderr, exit status, cmd.Env, an inherited environment, cmd.Dir, stdin from a pipe, ExtraFiles as descriptor 3, no descriptor leak into an unrelated child, a context deadline killing sleep, a missing binary as os.ErrNotExist, and sixteen concurrent spawns. All twelve checks pass on linux/arm64 and linux/amd64, as does the os package's own test suite, including 200 spawns under continuous garbage collection.
tests/netprobe — TCP, TLS, plain HTTP, HTTPS and DNS — continues to report every layer working, unchanged from net.1.
macOS is verified by CI only. The os package tests, which now cover starting a process, collecting its exit status and honouring Dir and Files, run on the macOS job of this build. No darwin binary from this release has been exercised by hand; run tests/spawnprobe on a Mac before trusting it in anger.
Windows is unchanged and still gets the stubs. A Windows binary built with this toolchain compiles crypto/tls to the no-op handshake, so https:// there is plaintext wearing the TLS API, and os.StartProcess still returns operation not implemented. Only hosted linux and macOS were switched over.
Install
Each tinygo<version>.<os>-<arch>.tar.gz unpacks to a single tinygo/ directory holding bin/, lib/, src/ and targets/.
curl -L -O https://github.com/yohimik/tinygo/releases/download/v0.42.0-net.2/tinygo0.42.0-net.2.linux-amd64.tar.gz
tar xzf tinygo0.42.0-net.2.linux-amd64.tar.gz -C /usr/local/lib
export TINYGOROOT=/usr/local/lib/tinygo
export PATH=$PATH:$TINYGOROOT/bin
tinygo versionTINYGOROOT must point at that directory whenever bin/tinygo is not run from inside it.
A host Go toolchain is required. TinyGo runs go list and reads the standard library from $(go env GOROOT), so a Go toolchain must be installed on the machine that runs tinygo — including when cross-compiling. This build accepts Go 1.25 through 1.27; crypto/tls and os/exec themselves come from that toolchain's GOROOT, which is why the version matters more than usual here.
.deb packages are also attached; they install to /usr/local/lib/tinygo with a symlink at /usr/local/bin/tinygo.
Using it in a Dockerfile instead of the tinygo/tinygo image
Replace the toolchain, not the base image: start from golang:1.27, unpack the tarball, and point TINYGOROOT at it.
FROM golang:1.27
ARG TINYGO_VERSION=0.42.0-net.2
ARG TARGETARCH
RUN curl -fsSL -o /tmp/tinygo.tar.gz \
"https://github.com/yohimik/tinygo/releases/download/v${TINYGO_VERSION}/tinygo${TINYGO_VERSION}.linux-${TARGETARCH}.tar.gz" \
&& tar xzf /tmp/tinygo.tar.gz -C /usr/local/lib \
&& rm /tmp/tinygo.tar.gz
ENV TINYGOROOT=/usr/local/lib/tinygo
ENV PATH="/usr/local/lib/tinygo/bin:${PATH}"Cross-compiling to macOS works from that image with GOOS=darwin GOARCH=arm64 tinygo build ….
macOS caveats
-
A binary from this toolchain now needs macOS 10.15 or later.
posix_spawn_file_actions_addchdir_np, which carriescmd.Dirinto the child, arrived in 10.15, and the libSystem stub declares it unconditionally. The deployment target itself is unchanged (10.12 on amd64, 11.0 on arm64). -
A raw
tls.Dial(…, nil)still fails.crypto/x509's platform verifier is a stub on darwin, and a nilRootCAssends verification straight to it.net/httpsupplies roots for itself, sohttp.Clientoverhttps://is fine; code that dials TLS directly must pass its own pool:pem, _ := os.ReadFile("/etc/ssl/cert.pem") pool := x509.NewCertPool() pool.AppendCertsFromPEM(pem) conn, err := tls.Dial("tcp", host, &tls.Config{ServerName: name, RootCAs: pool})
-
SSL_CERT_FILEoverrides the bundle thatnet/httploads, for a container image or a host without/etc/ssl/cert.pem. -
The resolver is a stub resolver. It reads
/etc/hostsand thenameserverlines of/etc/resolv.conf, and queries them over UDP. It does not use the macOS system resolver, so scoped and split-horizon DNS, mDNS.localnames, and IPv6 nameservers are not supported. It returns one address per name, preferring A over AAAA.
Process-layer caveats, both platforms
ProcAttr.Sysis still rejected.syscall.SysProcAttrasks for thingsposix_spawncannot express —setsid, credentials, a controlling terminal, process groups — soStartProcessreturnssys setting not implementedrather than silently ignoring it.exec.Cmdonly sets it if you do.os.Process.Waitreaps withwait4on the pid directly, so a program that also reaps children itself, or that installs its ownSIGCHLDhandling, may race with it.os/signalis unchanged; this release did not touch signal delivery to the TinyGo process itself.
Source
- Compiler:
yohimik/tinygobranchrelease/net src/netsubmodule:yohimik/netbranchhost-netdev-darwin
Verifying downloads
GitHub records a SHA-256 digest for every asset below. To print them:
gh release view v0.42.0-net.2 --repo yohimik/tinygo --json assets --jq '.assets[] | "\(.digest) \(.name)"'