cmd/gomobile: add modulemaps to framework bundles for simpler imports

Modulemaps allow users to use the import directives without
providing the specific header file but by using a module name
in Objective-C and Swift.

  gomobile bind -target=ios golang.org/x/mobile/example/bind/hello

Add the generated framework to an Xcode project. You will be able
to import the library header and use the library by importing hello
in Swift.

  import hello
  // ...
  hello.GoHelloGreetings("burcu");

In Objective-C, you will be able to import with the module name
similarly by using the import directive below.

  #import hello

This CL also enables Go bindings to be used from Swift without an
Objective-C bridging header.

Fixes golang/go#12422

Change-Id: I7c60349caad100861d0b642ddfa873d7ada47598
Reviewed-on: https://go-review.googlesource.com/15044
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go
index 12c2bba..1b9b097 100644
--- a/cmd/gomobile/bind_iosapp.go
+++ b/cmd/gomobile/bind_iosapp.go
@@ -93,7 +93,24 @@
 	if err := symlink("Versions/Current/Resources", buildO+"/Resources"); err != nil {
 		return err
 	}
-	return ioutil.WriteFile(buildO+"/Resources/Info.plist", []byte(iosBindInfoPlist), 0666)
+	if err := ioutil.WriteFile(buildO+"/Resources/Info.plist", []byte(iosBindInfoPlist), 0666); err != nil {
+		return err
+	}
+
+	var mmVals = struct {
+		Module string
+		Header string
+	}{
+		Module: name,
+		Header: strings.Title(name) + ".h",
+	}
+	err = writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w io.Writer) error {
+		return iosModuleMapTmpl.Execute(w, mmVals)
+	})
+	if err != nil {
+		return err
+	}
+	return symlink("Versions/Current/Modules", buildO+"/Modules")
 }
 
 const iosBindInfoPlist = `<?xml version="1.0" encoding="UTF-8"?>
@@ -104,6 +121,11 @@
     </plist>
 `
 
+var iosModuleMapTmpl = template.Must(template.New("iosmmap").Parse(`framework module "{{.Module}}" {
+    header "{{.Header}}"
+    export *
+}`))
+
 func goIOSBindArchive(name, path string, env []string) (string, error) {
 	arch := getenv(env, "GOARCH")
 	archive := filepath.Join(tmpdir, name+"-"+arch+".a")