| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- // 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.
- package main
- import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "time"
- "golang.org/x/mobile/internal/sdkpath"
- )
- var (
- goos = runtime.GOOS
- goarch = runtime.GOARCH
- )
- var cmdInit = &command{
- run: runInit,
- Name: "init",
- Usage: "[-openal dir]",
- Short: "build OpenAL for Android",
- Long: `
- If a OpenAL source directory is specified with -openal, init will
- build an Android version of OpenAL for use with gomobile build
- and gomobile install.
- `,
- }
- var initOpenAL string // -openal
- func init() {
- cmdInit.flag.StringVar(&initOpenAL, "openal", "", "OpenAL source path")
- }
- func runInit(cmd *command) error {
- gopaths := filepath.SplitList(goEnv("GOPATH"))
- if len(gopaths) == 0 {
- return fmt.Errorf("GOPATH is not set")
- }
- gomobilepath = filepath.Join(gopaths[0], "pkg/gomobile")
- if buildX || buildN {
- fmt.Fprintln(xout, "GOMOBILE="+gomobilepath)
- }
- removeAll(gomobilepath)
- if err := mkdir(gomobilepath); err != nil {
- return err
- }
- if buildN {
- tmpdir = filepath.Join(gomobilepath, "work")
- } else {
- var err error
- tmpdir, err = os.MkdirTemp(gomobilepath, "work-")
- if err != nil {
- return err
- }
- }
- if buildX || buildN {
- fmt.Fprintln(xout, "WORK="+tmpdir)
- }
- defer func() {
- if buildWork {
- fmt.Printf("WORK=%s\n", tmpdir)
- return
- }
- removeAll(tmpdir)
- }()
- // Make sure gobind is up to date.
- if err := goInstall([]string{"golang.org/x/mobile/cmd/gobind@latest"}, nil); err != nil {
- return err
- }
- if buildN {
- initOpenAL = "$OPENAL_PATH"
- } else {
- if initOpenAL != "" {
- var err error
- if initOpenAL, err = filepath.Abs(initOpenAL); err != nil {
- return err
- }
- }
- }
- if err := envInit(); err != nil {
- return err
- }
- start := time.Now()
- if err := installOpenAL(gomobilepath); err != nil {
- return err
- }
- if buildV {
- took := time.Since(start) / time.Second * time.Second
- fmt.Fprintf(os.Stderr, "\nDone, build took %s.\n", took)
- }
- return nil
- }
- func installOpenAL(gomobilepath string) error {
- if initOpenAL == "" {
- return nil
- }
- ndkRoot, err := ndkRoot()
- if err != nil {
- return err
- }
- var cmake string
- if buildN {
- cmake = "cmake"
- } else {
- sdkRoot, err := sdkpath.AndroidHome()
- if err != nil {
- return nil
- }
- cmake, err = exec.LookPath("cmake")
- if err != nil {
- cmakePath := filepath.Join(sdkRoot, "cmake")
- cmakeDir, err := os.Open(cmakePath)
- if err != nil {
- if os.IsNotExist(err) {
- // Skip OpenAL install if the cmake package is not installed.
- return errors.New("cmake was not found in the PATH. Please install it through the Android SDK manager.")
- }
- return err
- }
- defer cmakeDir.Close()
- // There might be multiple versions of CMake installed. Use any one for now.
- cmakeVers, err := cmakeDir.Readdirnames(1)
- if err != nil || len(cmakeVers) == 0 {
- return errors.New("cmake was not found in the PATH. Please install it through the Android SDK manager.")
- }
- cmake = filepath.Join(cmakePath, cmakeVers[0], "bin", "cmake")
- }
- }
- var alTmpDir string
- if buildN {
- alTmpDir = filepath.Join(gomobilepath, "work")
- } else {
- var err error
- alTmpDir, err = os.MkdirTemp(gomobilepath, "openal-release-")
- if err != nil {
- return err
- }
- defer removeAll(alTmpDir)
- }
- for _, f := range []string{"include/AL/al.h", "include/AL/alc.h"} {
- dst := filepath.Join(gomobilepath, f)
- src := filepath.Join(initOpenAL, f)
- if err := copyFile(dst, src); err != nil {
- return err
- }
- }
- for _, arch := range platformArchs("android") {
- t := ndk[arch]
- abi := t.arch
- if abi == "arm" {
- abi = "armeabi"
- }
- make := filepath.Join(ndkRoot, "prebuilt", archNDK(), "bin", "make")
- // Split android-XX to get the api version.
- buildDir := alTmpDir + "/build/" + abi
- if err := mkdir(buildDir); err != nil {
- return err
- }
- cmd := exec.Command(cmake,
- initOpenAL,
- "-DCMAKE_TOOLCHAIN_FILE="+initOpenAL+"/XCompile-Android.txt",
- "-DHOST="+t.ClangPrefix())
- cmd.Dir = buildDir
- tcPath := filepath.Join(ndkRoot, "toolchains", "llvm", "prebuilt", archNDK(), "bin")
- if !buildN {
- orgPath := os.Getenv("PATH")
- cmd.Env = []string{"PATH=" + tcPath + string(os.PathListSeparator) + orgPath}
- }
- if err := runCmd(cmd); err != nil {
- return err
- }
- cmd = exec.Command(make)
- cmd.Dir = buildDir
- if err := runCmd(cmd); err != nil {
- return err
- }
- dst := filepath.Join(gomobilepath, "lib", t.abi, "libopenal.so")
- src := filepath.Join(alTmpDir, "build", abi, "libopenal.so")
- if err := copyFile(dst, src); err != nil {
- return err
- }
- }
- return nil
- }
- func mkdir(dir string) error {
- if buildX || buildN {
- printcmd("mkdir -p %s", dir)
- }
- if buildN {
- return nil
- }
- return os.MkdirAll(dir, 0755)
- }
- func symlink(src, dst string) error {
- if buildX || buildN {
- printcmd("ln -s %s %s", src, dst)
- }
- if buildN {
- return nil
- }
- if goos == "windows" {
- return doCopyAll(dst, src)
- }
- return os.Symlink(src, dst)
- }
- func doCopyAll(dst, src string) error {
- return filepath.Walk(src, func(path string, info os.FileInfo, errin error) (err error) {
- if errin != nil {
- return errin
- }
- prefixLen := len(src)
- if len(path) > prefixLen {
- prefixLen++ // file separator
- }
- outpath := filepath.Join(dst, path[prefixLen:])
- if info.IsDir() {
- return os.Mkdir(outpath, 0755)
- }
- in, err := os.Open(path)
- if err != nil {
- return err
- }
- defer in.Close()
- out, err := os.OpenFile(outpath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, info.Mode())
- if err != nil {
- return err
- }
- defer func() {
- if errc := out.Close(); err == nil {
- err = errc
- }
- }()
- _, err = io.Copy(out, in)
- return err
- })
- }
- func removeAll(path string) error {
- if buildX || buildN {
- printcmd(`rm -r -f "%s"`, path)
- }
- if buildN {
- return nil
- }
- // os.RemoveAll behaves differently in windows.
- // http://golang.org/issues/9606
- if goos == "windows" {
- resetReadOnlyFlagAll(path)
- }
- return os.RemoveAll(path)
- }
- func resetReadOnlyFlagAll(path string) error {
- fi, err := os.Stat(path)
- if err != nil {
- return err
- }
- if !fi.IsDir() {
- return os.Chmod(path, 0666)
- }
- fd, err := os.Open(path)
- if err != nil {
- return err
- }
- defer fd.Close()
- names, _ := fd.Readdirnames(-1)
- for _, name := range names {
- resetReadOnlyFlagAll(path + string(filepath.Separator) + name)
- }
- return nil
- }
- func goEnv(name string) string {
- if val := os.Getenv(name); val != "" {
- return val
- }
- val, err := exec.Command("go", "env", name).Output()
- if err != nil {
- panic(err) // the Go tool was tested to work earlier
- }
- return strings.TrimSpace(string(val))
- }
- func runCmd(cmd *exec.Cmd) error {
- if buildX || buildN {
- dir := ""
- if cmd.Dir != "" {
- dir = "PWD=" + cmd.Dir + " "
- }
- env := strings.Join(cmd.Env, " ")
- if env != "" {
- env += " "
- }
- printcmd("%s%s%s", dir, env, strings.Join(cmd.Args, " "))
- }
- buf := new(bytes.Buffer)
- buf.WriteByte('\n')
- if buildV {
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- } else {
- cmd.Stdout = buf
- cmd.Stderr = buf
- }
- if buildWork {
- if goos == "windows" {
- cmd.Env = append(cmd.Env, `TEMP=`+tmpdir)
- cmd.Env = append(cmd.Env, `TMP=`+tmpdir)
- } else {
- cmd.Env = append(cmd.Env, `TMPDIR=`+tmpdir)
- }
- }
- if !buildN {
- cmd.Env = environ(cmd.Env)
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("%s failed: %v%s", strings.Join(cmd.Args, " "), err, buf)
- }
- }
- return nil
- }
|