cmd/gomobile: use new -pkgdir flag
The go command now has a -pkgdir flag, which specifies a directory for all install output, including the standard library. Use it to build the mobile compilers under $GOMOBILE, so that targets like the iOS simulator (darwin/386) do not conflict with system targets. The result is we no longer need GOROOT to be writable. The iOS simulator now works with gomobile bind. Fixes golang/go#11342. Change-Id: I0bc6378e0cb82e3175b2a1efe355e3ce39533649 Reviewed-on: https://go-review.googlesource.com/12303 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
parent
d709f21793
commit
9300366e65
|
@ -62,7 +62,7 @@ For documentation, see 'go help build'.
|
|||
}
|
||||
|
||||
func runBind(cmd *command) error {
|
||||
cleanup, err := envInit()
|
||||
cleanup, err := buildEnvInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -43,25 +43,19 @@ func goIOSBind(pkg *build.Package) error {
|
|||
return err
|
||||
}
|
||||
|
||||
armPath, err := goIOSBindArchive(name, mainFile, darwinArmEnv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
arm64Path, err := goIOSBindArchive(name, mainFile, darwinArm64Env)
|
||||
if err != nil {
|
||||
return err
|
||||
cmd := exec.Command("xcrun", "lipo", "-create")
|
||||
|
||||
// TODO(crawshaw): Build in parallel.
|
||||
for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} {
|
||||
arch := archClang(getenv(env, "GOARCH"))
|
||||
path, err := goIOSBindArchive(name, mainFile, env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("darwin-%s: %v", arch, err)
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "-arch", arch, path)
|
||||
}
|
||||
|
||||
cmd := exec.Command(
|
||||
"xcrun", "lipo",
|
||||
"-create",
|
||||
"-arch", "arm",
|
||||
armPath,
|
||||
"-arch", "arm64",
|
||||
arm64Path,
|
||||
"-o", buildO,
|
||||
)
|
||||
// TODO(crawshaw): arch i386/x86_64 for iOS simulator
|
||||
cmd.Args = append(cmd.Args, "-o", buildO)
|
||||
if buildX {
|
||||
printcmd(strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
@ -73,8 +67,6 @@ func goIOSBind(pkg *build.Package) error {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO(crawshaw): seq.h
|
||||
|
||||
// Copy header file next to output archive.
|
||||
return copyFile(
|
||||
filepath.Join(buildO[:len(buildO)-2]+".h"),
|
||||
|
@ -90,23 +82,15 @@ func goIOSBindArchive(name, path string, env []string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
// Build env suitable for invoking $CC.
|
||||
cmd := exec.Command("go", "env", "GOGCCFLAGS")
|
||||
cmd.Env = environ(env)
|
||||
ccflags, err := cmd.Output()
|
||||
if err != nil {
|
||||
panic(err) // the Go tool must work by now
|
||||
}
|
||||
env = append([]string{fmt.Sprintf("CCFLAGS=%q", string(ccflags))}, env...)
|
||||
|
||||
obj := "gobind-" + name + "-" + arch + ".o"
|
||||
cmd = exec.Command(
|
||||
cmd := exec.Command(
|
||||
getenv(env, "CC"),
|
||||
"-I", ".",
|
||||
"-g", "-O2",
|
||||
"-o", obj,
|
||||
"-c", "Go"+strings.Title(name)+".m",
|
||||
)
|
||||
cmd.Args = append(cmd.Args, strings.Split(getenv(env, "CGO_CFLAGS"), " ")...)
|
||||
cmd.Dir = filepath.Join(tmpdir, "objc")
|
||||
cmd.Env = env
|
||||
if buildX {
|
||||
|
@ -138,16 +122,6 @@ func goIOSBindArchive(name, path string, env []string) (string, error) {
|
|||
return archive, nil
|
||||
}
|
||||
|
||||
func getenv(env []string, key string) string {
|
||||
prefix := key + "="
|
||||
for _, kv := range env {
|
||||
if strings.HasPrefix(kv, prefix) {
|
||||
return kv[len(prefix):]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var iosBindTmpl = template.Must(template.New("ios.go").Parse(`
|
||||
package main
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ For documentation, see 'go help build'.
|
|||
}
|
||||
|
||||
func runBuild(cmd *command) (err error) {
|
||||
cleanup, err := envInit()
|
||||
cleanup, err := buildEnvInit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -198,9 +198,10 @@ func init() {
|
|||
|
||||
func goBuild(src string, env []string, args ...string) error {
|
||||
cmd := exec.Command(
|
||||
`go`,
|
||||
`build`,
|
||||
`-tags=`+strconv.Quote(strings.Join(ctx.BuildTags, ",")),
|
||||
"go",
|
||||
"build",
|
||||
"-pkgdir="+pkgdir(env),
|
||||
"-tags="+strconv.Quote(strings.Join(ctx.BuildTags, ",")),
|
||||
)
|
||||
if buildV {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
|
@ -213,8 +214,7 @@ func goBuild(src string, env []string, args ...string) error {
|
|||
}
|
||||
cmd.Args = append(cmd.Args, args...)
|
||||
cmd.Args = append(cmd.Args, src)
|
||||
cmd.Env = []string{"CGO_ENABLED=1"}
|
||||
cmd.Env = append(cmd.Env, env...)
|
||||
cmd.Env = append([]string{}, env...)
|
||||
buf := new(bytes.Buffer)
|
||||
buf.WriteByte('\n')
|
||||
if buildV {
|
||||
|
|
|
@ -6,7 +6,9 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -16,17 +18,14 @@ var (
|
|||
gomobilepath string // $GOPATH/pkg/gomobile
|
||||
ndkccpath string // $GOPATH/pkg/gomobile/android-{{.NDK}}
|
||||
|
||||
androidArmEnv []string
|
||||
darwinArmEnv []string
|
||||
darwinArm64Env []string
|
||||
androidArmEnv []string
|
||||
darwin386Env []string
|
||||
darwinAmd64Env []string
|
||||
)
|
||||
|
||||
func envInit() (cleanup func(), err error) {
|
||||
cwd, err = os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func buildEnvInit() (cleanup func(), err error) {
|
||||
// Find gomobilepath.
|
||||
gopath := goEnv("GOPATH")
|
||||
for _, p := range filepath.SplitList(gopath) {
|
||||
|
@ -56,38 +55,9 @@ func envInit() (cleanup func(), err error) {
|
|||
return nil, errors.New("toolchain out of date, run `gomobile init`")
|
||||
}
|
||||
|
||||
// Setup the cross-compiler environments.
|
||||
|
||||
// TODO(crawshaw): Remove ndkccpath global.
|
||||
ndkccpath = filepath.Join(gomobilepath, "android-"+ndkVersion)
|
||||
ndkccbin := filepath.Join(ndkccpath, "arm", "bin")
|
||||
|
||||
androidEnv := []string{
|
||||
"CC=" + filepath.Join(ndkccbin, "arm-linux-androideabi-gcc"),
|
||||
"CXX=" + filepath.Join(ndkccbin, "arm-linux-androideabi-g++"),
|
||||
`GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0"`,
|
||||
if err := envInit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
androidArmEnv = append([]string{
|
||||
"GOOS=android",
|
||||
"GOARCH=arm",
|
||||
"GOARM=7",
|
||||
}, androidEnv...)
|
||||
|
||||
// TODO(jbd): Remove clangwrap.sh dependency by implementing clangwrap.sh
|
||||
// in Go in this package.
|
||||
goroot := goEnv("GOROOT")
|
||||
iosEnv := []string{
|
||||
"CC=" + filepath.Join(goroot, "misc/ios/clangwrap.sh"),
|
||||
"CCX=" + filepath.Join(goroot, "misc/ios/clangwrap.sh"),
|
||||
}
|
||||
darwinArmEnv = append([]string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=arm",
|
||||
}, iosEnv...)
|
||||
darwinArm64Env = append([]string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=arm64",
|
||||
}, iosEnv...)
|
||||
|
||||
// We need a temporary directory when assembling an apk/app.
|
||||
if buildN {
|
||||
|
@ -105,6 +75,119 @@ func envInit() (cleanup func(), err error) {
|
|||
return func() { removeAll(tmpdir) }, nil
|
||||
}
|
||||
|
||||
func envInit() (err error) {
|
||||
// TODO(crawshaw): cwd only used by ctx.Import, which can take "."
|
||||
cwd, err = os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup the cross-compiler environments.
|
||||
|
||||
// TODO(crawshaw): Remove ndkccpath global.
|
||||
ndkccpath = filepath.Join(gomobilepath, "android-"+ndkVersion)
|
||||
ndkccbin := filepath.Join(ndkccpath, "arm", "bin")
|
||||
|
||||
exe := ""
|
||||
if goos == "windows" {
|
||||
exe = ".exe"
|
||||
}
|
||||
androidArmEnv = []string{
|
||||
"GOOS=android",
|
||||
"GOARCH=arm",
|
||||
"GOARM=7",
|
||||
"CC=" + filepath.Join(ndkccbin, "arm-linux-androideabi-gcc"+exe),
|
||||
"CXX=" + filepath.Join(ndkccbin, "arm-linux-androideabi-g++"+exe),
|
||||
"CGO_ENABLED=1",
|
||||
}
|
||||
|
||||
if runtime.GOOS != "darwin" {
|
||||
return nil
|
||||
}
|
||||
|
||||
clang, cflags, err := envClang("iphoneos")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
darwinArmEnv = []string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=arm",
|
||||
"GOARM=7",
|
||||
"CC=" + clang,
|
||||
"CXX=" + clang,
|
||||
"CGO_CFLAGS=" + cflags + " -arch " + archClang("arm"),
|
||||
"CGO_LDFLAGS=" + cflags + " -arch " + archClang("arm"),
|
||||
"CGO_ENABLED=1",
|
||||
}
|
||||
darwinArm64Env = []string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=arm64",
|
||||
"CC=" + clang,
|
||||
"CXX=" + clang,
|
||||
"CGO_CFLAGS=" + cflags + " -arch " + archClang("arm64"),
|
||||
"CGO_LDFLAGS=" + cflags + " -arch " + archClang("arm64"),
|
||||
"CGO_ENABLED=1",
|
||||
}
|
||||
|
||||
clang, cflags, err = envClang("iphonesimulator")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
darwin386Env = []string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=386",
|
||||
"CC=" + clang,
|
||||
"CXX=" + clang,
|
||||
"CGO_CFLAGS=" + cflags + " -mios-simulator-version-min=6.1 -arch " + archClang("386"),
|
||||
"CGO_LDFLAGS=" + cflags + " -mios-simulator-version-min=6.1 -arch " + archClang("386"),
|
||||
"CGO_ENABLED=1",
|
||||
}
|
||||
darwinAmd64Env = []string{
|
||||
"GOOS=darwin",
|
||||
"GOARCH=amd64",
|
||||
"CC=" + clang,
|
||||
"CXX=" + clang,
|
||||
"CGO_CFLAGS=" + cflags + " -mios-simulator-version-min=6.1 -arch x86_64",
|
||||
"CGO_LDFLAGS=" + cflags + " -mios-simulator-version-min=6.1 -arch x86_64",
|
||||
"CGO_ENABLED=1",
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func envClang(sdkName string) (clang, cflags string, err error) {
|
||||
cmd := exec.Command("xcrun", "--sdk", sdkName, "--find", "clang")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("xcrun --find: %v\n%s", err, out)
|
||||
}
|
||||
clang = strings.TrimSpace(string(out))
|
||||
|
||||
cmd = exec.Command("xcrun", "--sdk", sdkName, "--show-sdk-path")
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("xcrun --show-sdk-path: %v\n%s", err, out)
|
||||
}
|
||||
sdk := strings.TrimSpace(string(out))
|
||||
|
||||
return clang, "-isysroot " + sdk, nil
|
||||
}
|
||||
|
||||
func archClang(goarch string) string {
|
||||
switch goarch {
|
||||
case "arm":
|
||||
return "armv7"
|
||||
case "arm64":
|
||||
return "arm64"
|
||||
case "386":
|
||||
return "i386"
|
||||
case "amd64":
|
||||
return "x86_64"
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown GOARCH: %q", goarch))
|
||||
}
|
||||
}
|
||||
|
||||
// environ merges os.Environ and the given "key=value" pairs.
|
||||
// If a key is in both os.Environ and kv, kv takes precedence.
|
||||
func environ(kv []string) []string {
|
||||
|
@ -140,3 +223,17 @@ func environ(kv []string) []string {
|
|||
}
|
||||
return new
|
||||
}
|
||||
|
||||
func getenv(env []string, key string) string {
|
||||
prefix := key + "="
|
||||
for _, kv := range env {
|
||||
if strings.HasPrefix(kv, prefix) {
|
||||
return kv[len(prefix):]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func pkgdir(env []string) string {
|
||||
return gomobilepath + "/pkg_" + getenv(env, "GOOS") + "_" + getenv(env, "GOARCH")
|
||||
}
|
||||
|
|
|
@ -116,9 +116,13 @@ func runInit(cmd *command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if err := envInit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Install standard libraries for cross compilers.
|
||||
start := time.Now()
|
||||
if err := installAndroid(); err != nil {
|
||||
if err := installStd(androidArmEnv); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := installDarwin(); err != nil {
|
||||
|
@ -140,56 +144,45 @@ func runInit(cmd *command) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func installAndroid() error {
|
||||
exe := ""
|
||||
if goos == "windows" {
|
||||
exe = ".exe"
|
||||
}
|
||||
ndkccbin := filepath.Join(ndkccpath, "arm", "bin")
|
||||
androidEnv := []string{
|
||||
`CC=` + filepath.Join(ndkccbin, "arm-linux-androideabi-gcc"+exe),
|
||||
`CXX=` + filepath.Join(ndkccbin, "arm-linux-androideabi-g++"+exe),
|
||||
}
|
||||
return installStd("android", "arm", androidEnv)
|
||||
}
|
||||
|
||||
func installDarwin() error {
|
||||
if goos != "darwin" {
|
||||
return nil // Only build iOS compilers on OS X.
|
||||
}
|
||||
cc := filepath.Join(goEnv("GOROOT"), "misc/ios/clangwrap.sh")
|
||||
darwinEnv := []string{`CC=` + cc, `CXX=` + cc}
|
||||
if err := installStd("darwin", "arm", darwinEnv); err != nil {
|
||||
if err := installStd(darwinArmEnv); err != nil {
|
||||
return err
|
||||
}
|
||||
return installStd("darwin", "arm64", darwinEnv)
|
||||
if err := installStd(darwinArm64Env); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO(crawshaw): darwin/386 for the iOS simulator?
|
||||
if err := installStd(darwinAmd64Env, "-tags=ios"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func installStd(tOS, tArch string, env []string) error {
|
||||
func installStd(env []string, args ...string) error {
|
||||
tOS := getenv(env, "GOOS")
|
||||
tArch := getenv(env, "GOARCH")
|
||||
if buildV {
|
||||
fmt.Fprintf(os.Stderr, "\n# Building standard library for %s/%s.\n", tOS, tArch)
|
||||
}
|
||||
removeAll(filepath.Join(goEnv("GOROOT"), "pkg", tOS+"_"+tArch))
|
||||
envpath := os.Getenv("PATH")
|
||||
if buildN {
|
||||
envpath = "$PATH"
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "install")
|
||||
cmd := exec.Command("go", "install", "-pkgdir="+pkgdir(env))
|
||||
cmd.Args = append(cmd.Args, args...)
|
||||
if buildV {
|
||||
cmd.Args = append(cmd.Args, "-v")
|
||||
}
|
||||
if buildX {
|
||||
cmd.Args = append(cmd.Args, "-x")
|
||||
}
|
||||
cmd.Args = append(cmd.Args, "std")
|
||||
cmd.Env = []string{
|
||||
`PATH=` + envpath,
|
||||
`GOOS=` + tOS,
|
||||
`GOARCH=` + tArch,
|
||||
`CGO_ENABLED=1`,
|
||||
}
|
||||
cmd.Env = []string{"PATH=" + envpath}
|
||||
cmd.Env = append(cmd.Env, env...)
|
||||
if tArch == "arm" {
|
||||
cmd.Env = append(cmd.Env, "GOARM=7")
|
||||
}
|
||||
if buildX {
|
||||
printcmd("%s", strings.Join(cmd.Env, " ")+" "+strings.Join(cmd.Args, " "))
|
||||
}
|
||||
|
@ -295,8 +288,8 @@ func goVersion() ([]byte, error) {
|
|||
}
|
||||
// TODO(crawshaw): this is a crude test for Go 1.5. After release,
|
||||
// remove this and check it is not an old release version.
|
||||
if !bytes.Contains(buildHelp, []byte("-toolexec")) {
|
||||
return nil, fmt.Errorf("installed Go tool does not support -toolexec")
|
||||
if !bytes.Contains(buildHelp, []byte("-pkgdir")) {
|
||||
return nil, fmt.Errorf("installed Go tool does not support -pkgdir")
|
||||
}
|
||||
return exec.Command(gobin, "version").CombinedOutput()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue