Initial commit: Go 1.23 release state

This commit is contained in:
Vorapol Rinsatitnon
2024-09-21 23:49:08 +10:00
commit 17cd57a668
13231 changed files with 3114330 additions and 0 deletions

57
misc/ios/README Normal file
View File

@@ -0,0 +1,57 @@
Go on iOS
=========
To run the standard library tests, run all.bash as usual, but with the compiler
set to the clang wrapper that invokes clang for iOS. For example, this command runs
all.bash on the iOS emulator:
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
If CC_FOR_TARGET is not set when the toolchain is built (make.bash or all.bash), CC
can be set on the command line. For example,
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC=$(go env GOROOT)/misc/ios/clangwrap.sh go build
Setting CC is not necessary if the toolchain is built with CC_FOR_TARGET set.
To use the go tool to run individual programs and tests, put $GOROOT/bin into PATH to ensure
the go_ios_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests:
export PATH=$GOROOT/bin:$PATH
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 go test archive/tar
The go_ios_exec wrapper uses GOARCH to select the emulator (amd64) or the device (arm64).
However, further setup is required to run tests or programs directly on a device.
First make sure you have a valid developer certificate and have setup your device properly
to run apps signed by your developer certificate. Then install the libimobiledevice and
ideviceinstaller tools from https://www.libimobiledevice.org/. Use the HEAD versions from
source; the stable versions have bugs that prevents the Go exec wrapper to install and run
apps.
Second, the Go exec wrapper must be told the developer account signing identity, the team
id and a provisioned bundle id to use. They're specified with the environment variables
GOIOS_DEV_ID, GOIOS_TEAM_ID and GOIOS_APP_ID. The detect.go program in this directory will
attempt to auto-detect suitable values. Run it as
go run detect.go
which will output something similar to
export GOIOS_DEV_ID="iPhone Developer: xxx@yyy.zzz (XXXXXXXX)"
export GOIOS_APP_ID=YYYYYYYY.some.bundle.id
export GOIOS_TEAM_ID=ZZZZZZZZ
If you have multiple devices connected, specify the device UDID with the GOIOS_DEVICE_ID
variable. Use `idevice_id -l` to list all available UDIDs. Then, setting GOARCH to arm64
will select the device:
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
Note that the go_darwin_$GOARCH_exec wrapper uninstalls any existing app identified by
the bundle id before installing a new app. If the uninstalled app is the last app by
the developer identity, the device might also remove the permission to run apps from
that developer, and the exec wrapper will fail to install the new app. To avoid that,
install another app with the same developer identity but with a different bundle id.
That way, the permission to install apps is held on to while the primary app is
uninstalled.

23
misc/ios/clangwrap.sh Executable file
View File

@@ -0,0 +1,23 @@
#!/bin/sh
# This script configures clang to target the iOS simulator. If you'd like to
# build for real iOS devices, change SDK to "iphoneos" and PLATFORM to "ios".
# This uses the latest available iOS SDK, which is recommended. To select a
# specific SDK, run 'xcodebuild -showsdks' to see the available SDKs and replace
# iphonesimulator with one of them.
SDK=iphonesimulator
PLATFORM=ios-simulator
if [ "$GOARCH" == "arm64" ]; then
CLANGARCH="arm64"
else
CLANGARCH="x86_64"
fi
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
CLANG=`xcrun --sdk $SDK --find clang`
exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -m${PLATFORM}-version-min=12.0 "$@"

133
misc/ios/detect.go Normal file
View File

@@ -0,0 +1,133 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// detect attempts to autodetect the correct
// values of the environment variables
// used by go_ios_exec.
// detect shells out to ideviceinfo, a third party program that can
// be obtained by following the instructions at
// https://github.com/libimobiledevice/libimobiledevice.
package main
import (
"bytes"
"crypto/x509"
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
udids := getLines(exec.Command("idevice_id", "-l"))
if len(udids) == 0 {
fail("no udid found; is a device connected?")
}
mps := detectMobileProvisionFiles(udids)
if len(mps) == 0 {
fail("did not find mobile provision matching device udids %q", udids)
}
fmt.Println("# Available provisioning profiles below.")
fmt.Println("# NOTE: Any existing app on the device with the app id specified by GOIOS_APP_ID")
fmt.Println("# will be overwritten when running Go programs.")
for _, mp := range mps {
fmt.Println()
f, err := os.CreateTemp("", "go_ios_detect_")
check(err)
fname := f.Name()
defer os.Remove(fname)
out := output(parseMobileProvision(mp))
_, err = f.Write(out)
check(err)
check(f.Close())
cert, err := plistExtract(fname, "DeveloperCertificates:0")
check(err)
pcert, err := x509.ParseCertificate(cert)
check(err)
fmt.Printf("export GOIOS_DEV_ID=\"%s\"\n", pcert.Subject.CommonName)
appID, err := plistExtract(fname, "Entitlements:application-identifier")
check(err)
fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
check(err)
fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
}
}
func detectMobileProvisionFiles(udids [][]byte) []string {
cmd := exec.Command("mdfind", "-name", ".mobileprovision")
lines := getLines(cmd)
var files []string
for _, line := range lines {
if len(line) == 0 {
continue
}
xmlLines := getLines(parseMobileProvision(string(line)))
matches := 0
for _, udid := range udids {
for _, xmlLine := range xmlLines {
if bytes.Contains(xmlLine, udid) {
matches++
}
}
}
if matches == len(udids) {
files = append(files, string(line))
}
}
return files
}
func parseMobileProvision(fname string) *exec.Cmd {
return exec.Command("security", "cms", "-D", "-i", string(fname))
}
func plistExtract(fname string, path string) ([]byte, error) {
out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
if err != nil {
return nil, err
}
return bytes.TrimSpace(out), nil
}
func getLines(cmd *exec.Cmd) [][]byte {
out := output(cmd)
lines := bytes.Split(out, []byte("\n"))
// Skip the empty line at the end.
if len(lines[len(lines)-1]) == 0 {
lines = lines[:len(lines)-1]
}
return lines
}
func output(cmd *exec.Cmd) []byte {
out, err := cmd.Output()
if err != nil {
fmt.Println(strings.Join(cmd.Args, "\n"))
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
return out
}
func check(err error) {
if err != nil {
fail(err.Error())
}
}
func fail(msg string, v ...interface{}) {
fmt.Fprintf(os.Stderr, msg, v...)
fmt.Fprintln(os.Stderr)
os.Exit(1)
}

366
misc/ios/go_ios_exec.go Normal file
View File

@@ -0,0 +1,366 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This program can be used as go_ios_$GOARCH_exec by the Go tool. It executes
// binaries on the iOS Simulator using the XCode toolchain.
package main
import (
"fmt"
"go/build"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"syscall"
)
const debug = false
var tmpdir string
var (
devID string
appID string
teamID string
bundleID string
deviceID string
)
// lock is a file lock to serialize iOS runs. It is global to avoid the
// garbage collector finalizing it, closing the file and releasing the
// lock prematurely.
var lock *os.File
func main() {
log.SetFlags(0)
log.SetPrefix("go_ios_exec: ")
if debug {
log.Println(strings.Join(os.Args, " "))
}
if len(os.Args) < 2 {
log.Fatal("usage: go_ios_exec a.out")
}
// For compatibility with the old builders, use a fallback bundle ID
bundleID = "golang.gotest"
exitCode, err := runMain()
if err != nil {
log.Fatalf("%v\n", err)
}
os.Exit(exitCode)
}
func runMain() (int, error) {
var err error
tmpdir, err = os.MkdirTemp("", "go_ios_exec_")
if err != nil {
return 1, err
}
if !debug {
defer os.RemoveAll(tmpdir)
}
appdir := filepath.Join(tmpdir, "gotest.app")
os.RemoveAll(appdir)
if err := assembleApp(appdir, os.Args[1]); err != nil {
return 1, err
}
// This wrapper uses complicated machinery to run iOS binaries. It
// works, but only when running one binary at a time.
// Use a file lock to make sure only one wrapper is running at a time.
//
// The lock file is never deleted, to avoid concurrent locks on distinct
// files with the same path.
lockName := filepath.Join(os.TempDir(), "go_ios_exec-"+deviceID+".lock")
lock, err = os.OpenFile(lockName, os.O_CREATE|os.O_RDONLY, 0666)
if err != nil {
return 1, err
}
if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); err != nil {
return 1, err
}
err = runOnSimulator(appdir)
if err != nil {
return 1, err
}
return 0, nil
}
func runOnSimulator(appdir string) error {
if err := installSimulator(appdir); err != nil {
return err
}
return runSimulator(appdir, bundleID, os.Args[2:])
}
func assembleApp(appdir, bin string) error {
if err := os.MkdirAll(appdir, 0755); err != nil {
return err
}
if err := cp(filepath.Join(appdir, "gotest"), bin); err != nil {
return err
}
pkgpath, err := copyLocalData(appdir)
if err != nil {
return err
}
entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
if err := os.WriteFile(entitlementsPath, []byte(entitlementsPlist()), 0744); err != nil {
return err
}
if err := os.WriteFile(filepath.Join(appdir, "Info.plist"), []byte(infoPlist(pkgpath)), 0744); err != nil {
return err
}
if err := os.WriteFile(filepath.Join(appdir, "ResourceRules.plist"), []byte(resourceRules), 0744); err != nil {
return err
}
return nil
}
func installSimulator(appdir string) error {
cmd := exec.Command(
"xcrun", "simctl", "install",
"booted", // Install to the booted simulator.
appdir,
)
if out, err := cmd.CombinedOutput(); err != nil {
os.Stderr.Write(out)
return fmt.Errorf("xcrun simctl install booted %q: %v", appdir, err)
}
return nil
}
func runSimulator(appdir, bundleID string, args []string) error {
xcrunArgs := []string{"simctl", "spawn",
"booted",
appdir + "/gotest",
}
xcrunArgs = append(xcrunArgs, args...)
cmd := exec.Command("xcrun", xcrunArgs...)
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("xcrun simctl launch booted %q: %v", bundleID, err)
}
return nil
}
func copyLocalDir(dst, src string) error {
if err := os.Mkdir(dst, 0755); err != nil {
return err
}
d, err := os.Open(src)
if err != nil {
return err
}
defer d.Close()
fi, err := d.Readdir(-1)
if err != nil {
return err
}
for _, f := range fi {
if f.IsDir() {
if f.Name() == "testdata" {
if err := cp(dst, filepath.Join(src, f.Name())); err != nil {
return err
}
}
continue
}
if err := cp(dst, filepath.Join(src, f.Name())); err != nil {
return err
}
}
return nil
}
func cp(dst, src string) error {
out, err := exec.Command("cp", "-a", src, dst).CombinedOutput()
if err != nil {
os.Stderr.Write(out)
}
return err
}
func copyLocalData(dstbase string) (pkgpath string, err error) {
cwd, err := os.Getwd()
if err != nil {
return "", err
}
finalPkgpath, underGoRoot, err := subdir()
if err != nil {
return "", err
}
cwd = strings.TrimSuffix(cwd, finalPkgpath)
// Copy all immediate files and testdata directories between
// the package being tested and the source root.
pkgpath = ""
for _, element := range strings.Split(finalPkgpath, string(filepath.Separator)) {
if debug {
log.Printf("copying %s", pkgpath)
}
pkgpath = filepath.Join(pkgpath, element)
dst := filepath.Join(dstbase, pkgpath)
src := filepath.Join(cwd, pkgpath)
if err := copyLocalDir(dst, src); err != nil {
return "", err
}
}
if underGoRoot {
// Copy timezone file.
//
// Typical apps have the zoneinfo.zip in the root of their app bundle,
// read by the time package as the working directory at initialization.
// As we move the working directory to the GOROOT pkg directory, we
// install the zoneinfo.zip file in the pkgpath.
err := cp(
filepath.Join(dstbase, pkgpath),
filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
)
if err != nil {
return "", err
}
// Copy src/runtime/textflag.h for (at least) Test386EndToEnd in
// cmd/asm/internal/asm.
runtimePath := filepath.Join(dstbase, "src", "runtime")
if err := os.MkdirAll(runtimePath, 0755); err != nil {
return "", err
}
err = cp(
filepath.Join(runtimePath, "textflag.h"),
filepath.Join(cwd, "src", "runtime", "textflag.h"),
)
if err != nil {
return "", err
}
}
return finalPkgpath, nil
}
// subdir determines the package based on the current working directory,
// and returns the path to the package source relative to $GOROOT (or $GOPATH).
func subdir() (pkgpath string, underGoRoot bool, err error) {
cwd, err := os.Getwd()
if err != nil {
return "", false, err
}
cwd, err = filepath.EvalSymlinks(cwd)
if err != nil {
log.Fatal(err)
}
goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
if err != nil {
return "", false, err
}
if strings.HasPrefix(cwd, goroot) {
subdir, err := filepath.Rel(goroot, cwd)
if err != nil {
return "", false, err
}
return subdir, true, nil
}
for _, p := range filepath.SplitList(build.Default.GOPATH) {
pabs, err := filepath.EvalSymlinks(p)
if err != nil {
return "", false, err
}
if !strings.HasPrefix(cwd, pabs) {
continue
}
subdir, err := filepath.Rel(pabs, cwd)
if err == nil {
return subdir, false, nil
}
}
return "", false, fmt.Errorf(
"working directory %q is not in either GOROOT(%q) or GOPATH(%q)",
cwd,
runtime.GOROOT(),
build.Default.GOPATH,
)
}
func infoPlist(pkgpath string) string {
return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key><string>golang.gotest</string>
<key>CFBundleSupportedPlatforms</key><array><string>iPhoneOS</string></array>
<key>CFBundleExecutable</key><string>gotest</string>
<key>CFBundleVersion</key><string>1.0</string>
<key>CFBundleShortVersionString</key><string>1.0</string>
<key>CFBundleIdentifier</key><string>` + bundleID + `</string>
<key>CFBundleResourceSpecification</key><string>ResourceRules.plist</string>
<key>LSRequiresIPhoneOS</key><true/>
<key>CFBundleDisplayName</key><string>gotest</string>
<key>GoExecWrapperWorkingDirectory</key><string>` + pkgpath + `</string>
</dict>
</plist>
`
}
func entitlementsPlist() string {
return `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>keychain-access-groups</key>
<array><string>` + appID + `</string></array>
<key>get-task-allow</key>
<true/>
<key>application-identifier</key>
<string>` + appID + `</string>
<key>com.apple.developer.team-identifier</key>
<string>` + teamID + `</string>
</dict>
</plist>
`
}
const resourceRules = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>rules</key>
<dict>
<key>.*</key>
<true/>
<key>Info.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<integer>10</integer>
</dict>
<key>ResourceRules.plist</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<integer>100</integer>
</dict>
</dict>
</dict>
</plist>
`