github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/cmd/gomobile/bind_iosapp.go (about)

     1  // Copyright 2015 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"fmt"
     9  	"go/build"
    10  	"io"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"strings"
    14  	"text/template"
    15  )
    16  
    17  func goIOSBind(pkg *build.Package) error {
    18  	binder, err := newBinder(pkg)
    19  	if err != nil {
    20  		return err
    21  	}
    22  	name := binder.pkg.Name()
    23  
    24  	if buildO != "" && !strings.HasSuffix(buildO, ".framework") {
    25  		return fmt.Errorf("static framework name %q missing .framework suffix", buildO)
    26  	}
    27  	if buildO == "" {
    28  		buildO = name + ".framework"
    29  	}
    30  
    31  	if err := binder.GenGo(filepath.Join(tmpdir, "src")); err != nil {
    32  		return err
    33  	}
    34  	mainFile := filepath.Join(tmpdir, "src/iosbin/main.go")
    35  	err = writeFile(mainFile, func(w io.Writer) error {
    36  		return iosBindTmpl.Execute(w, "../go_"+name)
    37  	})
    38  	if err != nil {
    39  		return fmt.Errorf("failed to create the binding package for iOS: %v", err)
    40  	}
    41  	if err := binder.GenObjc(filepath.Join(tmpdir, "objc")); err != nil {
    42  		return err
    43  	}
    44  
    45  	cmd := exec.Command("xcrun", "lipo", "-create")
    46  
    47  	for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} {
    48  		arch := archClang(getenv(env, "GOARCH"))
    49  		path, err := goIOSBindArchive(name, mainFile, env)
    50  		if err != nil {
    51  			return fmt.Errorf("darwin-%s: %v", arch, err)
    52  		}
    53  		cmd.Args = append(cmd.Args, "-arch", arch, path)
    54  	}
    55  
    56  	// Build static framework output directory.
    57  	if err := removeAll(buildO); err != nil {
    58  		return err
    59  	}
    60  	headers := buildO + "/Versions/A/Headers"
    61  	if err := mkdir(headers); err != nil {
    62  		return err
    63  	}
    64  	if err := symlink("A", buildO+"/Versions/Current"); err != nil {
    65  		return err
    66  	}
    67  	if err := symlink("Versions/Current/Headers", buildO+"/Headers"); err != nil {
    68  		return err
    69  	}
    70  	if err := symlink("Versions/Current/"+strings.Title(name), buildO+"/"+strings.Title(name)); err != nil {
    71  		return err
    72  	}
    73  
    74  	cmd.Args = append(cmd.Args, "-o", buildO+"/Versions/A/"+strings.Title(name))
    75  	if err := runCmd(cmd); err != nil {
    76  		return err
    77  	}
    78  
    79  	// Copy header file next to output archive.
    80  	return copyFile(
    81  		headers+"/"+strings.Title(name)+".h",
    82  		tmpdir+"/objc/Go"+strings.Title(name)+".h",
    83  	)
    84  }
    85  
    86  func goIOSBindArchive(name, path string, env []string) (string, error) {
    87  	arch := getenv(env, "GOARCH")
    88  	archive := filepath.Join(tmpdir, name+"-"+arch+".a")
    89  	err := goBuild(path, env, "-buildmode=c-archive", "-tags=ios", "-o", archive)
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  
    94  	obj := "gobind-" + name + "-" + arch + ".o"
    95  	cmd := exec.Command(
    96  		getenv(env, "CC"),
    97  		"-I", ".",
    98  		"-g", "-O2",
    99  		"-o", obj,
   100  		"-c", "Go"+strings.Title(name)+".m",
   101  	)
   102  	cmd.Args = append(cmd.Args, strings.Split(getenv(env, "CGO_CFLAGS"), " ")...)
   103  	cmd.Dir = filepath.Join(tmpdir, "objc")
   104  	cmd.Env = append([]string{}, env...)
   105  	if err := runCmd(cmd); err != nil {
   106  		return "", err
   107  	}
   108  
   109  	cmd = exec.Command("ar", "-q", "-s", archive, obj)
   110  	cmd.Dir = filepath.Join(tmpdir, "objc")
   111  	if err := runCmd(cmd); err != nil {
   112  		return "", err
   113  	}
   114  	return archive, nil
   115  }
   116  
   117  var iosBindTmpl = template.Must(template.New("ios.go").Parse(`
   118  package main
   119  
   120  import (
   121  	_ "github.com/c-darwin/mobile/bind/objc"
   122  	_ "{{.}}"
   123  )
   124  
   125  import "C"
   126  
   127  func main() {}
   128  `))