From dc75976ec5b6fa6ad9b2452f3b6f48ae30a26ad0 Mon Sep 17 00:00:00 2001 From: WildCat Date: Wed, 22 Dec 2021 14:39:06 +0800 Subject: [PATCH 01/19] Add parallel build --- .gitignore | 6 + cmd/gomobile/bind_iosapp.go | 359 +++++++++++++++++++----------------- go.sum | 2 + 3 files changed, 202 insertions(+), 165 deletions(-) diff --git a/.gitignore b/.gitignore index 87baa6455..2b7614a89 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,9 @@ example/bind/android/gradlew* example/bind/android/gradle example/bind/android/build example/bind/android/app/build + +vendor +build/ +.gitignore +cmd/gomobile/gomobile +.vscode/launch.json diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index bf0f37db6..0257e67cb 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -8,10 +8,12 @@ import ( "errors" "fmt" "io" + "log" "os/exec" "path/filepath" "strconv" "strings" + "sync" "text/template" "golang.org/x/tools/go/packages" @@ -45,182 +47,35 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) var frameworkDirs []string frameworkArchCount := map[string]int{} - for _, t := range targets { - // Catalyst support requires iOS 13+ - v, _ := strconv.ParseFloat(buildIOSVersion, 64) - if t.platform == "maccatalyst" && v < 13.0 { - return errors.New("catalyst requires -iosversion=13 or higher") - } - - outDir := filepath.Join(tmpdir, t.platform) - outSrcDir := filepath.Join(outDir, "src") - gobindDir := filepath.Join(outSrcDir, "gobind") - - // Run gobind once per platform to generate the bindings - cmd := exec.Command( - gobind, - "-lang=go,objc", - "-outdir="+outDir, - ) - cmd.Env = append(cmd.Env, "GOOS="+platformOS(t.platform)) - cmd.Env = append(cmd.Env, "CGO_ENABLED=1") - tags := append(buildTags[:], platformTags(t.platform)...) - cmd.Args = append(cmd.Args, "-tags="+strings.Join(tags, ",")) - if bindPrefix != "" { - cmd.Args = append(cmd.Args, "-prefix="+bindPrefix) - } - for _, p := range pkgs { - cmd.Args = append(cmd.Args, p.PkgPath) - } - if err := runCmd(cmd); err != nil { - return err - } - - env := appleEnv[t.String()][:] - sdk := getenv(env, "DARWIN_SDK") - - frameworkDir := filepath.Join(tmpdir, t.platform, sdk, title+".framework") - frameworkDirs = append(frameworkDirs, frameworkDir) - frameworkArchCount[frameworkDir] = frameworkArchCount[frameworkDir] + 1 - - fileBases := make([]string, len(pkgs)+1) - for i, pkg := range pkgs { - fileBases[i] = bindPrefix + strings.Title(pkg.Name) - } - fileBases[len(fileBases)-1] = "Universe" - - // Add the generated packages to GOPATH for reverse bindings. - gopath := fmt.Sprintf("GOPATH=%s%c%s", outDir, filepath.ListSeparator, goEnv("GOPATH")) - env = append(env, gopath) - - if err := writeGoMod(outDir, t.platform, t.arch); err != nil { - return err - } + targetBuildResultMutex := &sync.Mutex{} - // Run `go mod tidy` to force to create go.sum. - // Without go.sum, `go build` fails as of Go 1.16. - if modulesUsed { - if err := goModTidyAt(outSrcDir, env); err != nil { - return err - } - } + var waitGroup sync.WaitGroup + waitGroup.Add(len(targets)) - path, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) - if err != nil { - return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err) - } - - versionsDir := filepath.Join(frameworkDir, "Versions") - versionsADir := filepath.Join(versionsDir, "A") - titlePath := filepath.Join(versionsADir, title) - if frameworkArchCount[frameworkDir] > 1 { - // Not the first static lib, attach to a fat library and skip create headers - fatCmd := exec.Command( - "xcrun", - "lipo", path, titlePath, "-create", "-output", titlePath, - ) - if err := runCmd(fatCmd); err != nil { - return err - } - continue - } + for _, target := range targets { + go func(target targetInfo, targetBuildResultMutex *sync.Mutex) { + defer waitGroup.Done() - versionsAHeadersDir := filepath.Join(versionsADir, "Headers") - if err := mkdir(versionsAHeadersDir); err != nil { - return err - } - if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { - return err - } - if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { - return err - } - if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { - return err - } + log.Println("start building for target", target) - lipoCmd := exec.Command( - "xcrun", - "lipo", path, "-create", "-o", titlePath, - ) - if err := runCmd(lipoCmd); err != nil { - return err - } - - // Copy header file next to output archive. - var headerFiles []string - if len(fileBases) == 1 { - headerFiles = append(headerFiles, title+".h") - err := copyFile( - filepath.Join(versionsAHeadersDir, title+".h"), - filepath.Join(gobindDir, bindPrefix+title+".objc.h"), - ) - if err != nil { - return err - } - } else { - for _, fileBase := range fileBases { - headerFiles = append(headerFiles, fileBase+".objc.h") - err := copyFile( - filepath.Join(versionsAHeadersDir, fileBase+".objc.h"), - filepath.Join(gobindDir, fileBase+".objc.h"), - ) - if err != nil { - return err - } - } - err := copyFile( - filepath.Join(versionsAHeadersDir, "ref.h"), - filepath.Join(gobindDir, "ref.h"), - ) - if err != nil { - return err - } - headerFiles = append(headerFiles, title+".h") - err = writeFile(filepath.Join(versionsAHeadersDir, title+".h"), func(w io.Writer) error { - return appleBindHeaderTmpl.Execute(w, map[string]interface{}{ - "pkgs": pkgs, "title": title, "bases": fileBases, - }) - }) + err, frameworkDir := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) if err != nil { - return err + log.Fatalf("%v", err) + return } - } - if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { - return err - } - if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { - return err - } - err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { - _, err := w.Write([]byte(appleBindInfoPlist)) - return err - }) - if err != nil { - return err - } + targetBuildResultMutex.Lock() + frameworkDirs = append(frameworkDirs, frameworkDir) + frameworkArchCount[frameworkDir] = frameworkArchCount[frameworkDir] + 1 + targetBuildResultMutex.Unlock() - var mmVals = struct { - Module string - Headers []string - }{ - Module: title, - Headers: headerFiles, - } - err = writeFile(filepath.Join(versionsADir, "Modules", "module.modulemap"), func(w io.Writer) error { - return appleModuleMapTmpl.Execute(w, mmVals) - }) - if err != nil { - return err - } - err = symlink(filepath.Join("Versions/Current/Modules"), filepath.Join(frameworkDir, "Modules")) - if err != nil { - return err - } + log.Println("finish building for target", target) + }(target, targetBuildResultMutex) } + waitGroup.Wait() + // Finally combine all frameworks to an XCFramework xcframeworkArgs := []string{"-create-xcframework"} @@ -258,6 +113,180 @@ func goAppleBindArchive(name string, env []string, gosrc string) (string, error) return archive, nil } +func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, frameworkDir string) { + // Catalyst support requires iOS 13+ + v, _ := strconv.ParseFloat(buildIOSVersion, 64) + if t.platform == "maccatalyst" && v < 13.0 { + return errors.New("catalyst requires -iosversion=13 or higher"), "" + } + + outDir := filepath.Join(tmpdir, t.platform, t.arch) // adding arch + outSrcDir := filepath.Join(outDir, "src") + gobindDir := filepath.Join(outSrcDir, "gobind") + + // Run gobind once per platform to generate the bindings + cmd := exec.Command( + gobindCommandPath, + "-lang=go,objc", + "-outdir="+outDir, + ) + cmd.Env = append(cmd.Env, "GOOS="+platformOS(t.platform)) + cmd.Env = append(cmd.Env, "CGO_ENABLED=1") + tags := append(buildTags[:], platformTags(t.platform)...) + cmd.Args = append(cmd.Args, "-tags="+strings.Join(tags, ",")) + if bindPrefix != "" { + cmd.Args = append(cmd.Args, "-prefix="+bindPrefix) + } + for _, p := range pkgs { + cmd.Args = append(cmd.Args, p.PkgPath) + } + if err := runCmd(cmd); err != nil { + return err, "" + } + + env := appleEnv[t.String()][:] + sdk := getenv(env, "DARWIN_SDK") + + frameworkDir = filepath.Join(tmpdir, t.platform, t.arch+"_framework", sdk, title+".framework") + + fileBases := make([]string, len(pkgs)+1) + for i, pkg := range pkgs { + fileBases[i] = bindPrefix + strings.Title(pkg.Name) + } + fileBases[len(fileBases)-1] = "Universe" + + // Add the generated packages to GOPATH for reverse bindings. + gopath := fmt.Sprintf("GOPATH=%s%c%s", outDir, filepath.ListSeparator, goEnv("GOPATH")) + env = append(env, gopath) + + if err := writeGoMod(outDir, t.platform, t.arch); err != nil { + return err, "" + } + + // Run `go mod tidy` to force to create go.sum. + // Without go.sum, `go build` fails as of Go 1.16. + if modulesUsed { + if err := goModTidyAt(outSrcDir, env); err != nil { + return err, "" + } + } + + path, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) + if err != nil { + return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), "" + } + + versionsDir := filepath.Join(frameworkDir, "Versions") + versionsADir := filepath.Join(versionsDir, "A") + titlePath := filepath.Join(versionsADir, title) + //if frameworkArchCount[frameworkDir] > 1 { + // // Not the first static lib, attach to a fat library and skip create headers + // fatCmd := exec.Command( + // "xcrun", + // "lipo", path, titlePath, "-create", "-output", titlePath, + // ) + // if err := runCmd(fatCmd); err != nil { + // return err, "" + // } + // continue + //} + + versionsAHeadersDir := filepath.Join(versionsADir, "Headers") + if err := mkdir(versionsAHeadersDir); err != nil { + return err, "" + } + if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { + return err, "" + } + if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { + return err, "" + } + if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { + return err, "" + } + + lipoCmd := exec.Command( + "xcrun", + "lipo", path, "-create", "-o", titlePath, + ) + if err := runCmd(lipoCmd); err != nil { + return err, "" + } + + // Copy header file next to output archive. + var headerFiles []string + if len(fileBases) == 1 { + headerFiles = append(headerFiles, title+".h") + err := copyFile( + filepath.Join(versionsAHeadersDir, title+".h"), + filepath.Join(gobindDir, bindPrefix+title+".objc.h"), + ) + if err != nil { + return err, "" + } + } else { + for _, fileBase := range fileBases { + headerFiles = append(headerFiles, fileBase+".objc.h") + err := copyFile( + filepath.Join(versionsAHeadersDir, fileBase+".objc.h"), + filepath.Join(gobindDir, fileBase+".objc.h"), + ) + if err != nil { + return err, "" + } + } + err := copyFile( + filepath.Join(versionsAHeadersDir, "ref.h"), + filepath.Join(gobindDir, "ref.h"), + ) + if err != nil { + return err, "" + } + headerFiles = append(headerFiles, title+".h") + err = writeFile(filepath.Join(versionsAHeadersDir, title+".h"), func(w io.Writer) error { + return appleBindHeaderTmpl.Execute(w, map[string]interface{}{ + "pkgs": pkgs, "title": title, "bases": fileBases, + }) + }) + if err != nil { + return err, "" + } + } + + if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { + return err, "" + } + if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { + return err, "" + } + err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { + _, err := w.Write([]byte(appleBindInfoPlist)) + return err + }) + if err != nil { + return err, "" + } + + var mmVals = struct { + Module string + Headers []string + }{ + Module: title, + Headers: headerFiles, + } + err = writeFile(filepath.Join(versionsADir, "Modules", "module.modulemap"), func(w io.Writer) error { + return appleModuleMapTmpl.Execute(w, mmVals) + }) + if err != nil { + return err, "" + } + err = symlink(filepath.Join("Versions/Current/Modules"), filepath.Join(frameworkDir, "Modules")) + if err != nil { + return err, "" + } + return err, frameworkDir +} + var appleBindHeaderTmpl = template.Must(template.New("apple.h").Parse(` // Objective-C API for talking to the following Go packages // diff --git a/go.sum b/go.sum index d4d3ebf1e..5d710d232 100644 --- a/go.sum +++ b/go.sum @@ -36,3 +36,5 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +robpike.io/ivy v0.1.9 h1:iZN9ddmhd1Hr8MJrMZFCu6MqFiAPtoj37HAmrCzkyno= +robpike.io/ivy v0.1.9/go.mod h1:6B/DGaft5rvYiF7MgCTiZAAvH5W7vtu0eS2BW77updo= From 46290163b95915eeb9a240cd32ec021ba10bccdd Mon Sep 17 00:00:00 2001 From: WildCat Date: Wed, 22 Dec 2021 16:08:11 +0800 Subject: [PATCH 02/19] Finish major part --- cmd/gomobile/bind_iosapp.go | 102 ++++++++++++++---------------------- 1 file changed, 39 insertions(+), 63 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 0257e67cb..27edab5e2 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "log" + "os" "os/exec" "path/filepath" "strconv" @@ -19,6 +20,13 @@ import ( "golang.org/x/tools/go/packages" ) +type archBuildResult struct { + libraryPath string + headerPath string + + targetInfo +} + func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { var name string var title string @@ -45,8 +53,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) return err } - var frameworkDirs []string - frameworkArchCount := map[string]int{} + var buildResults []archBuildResult targetBuildResultMutex := &sync.Mutex{} var waitGroup sync.WaitGroup @@ -58,15 +65,14 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) log.Println("start building for target", target) - err, frameworkDir := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) + err, buildResult := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) if err != nil { log.Fatalf("%v", err) return } targetBuildResultMutex.Lock() - frameworkDirs = append(frameworkDirs, frameworkDir) - frameworkArchCount[frameworkDir] = frameworkArchCount[frameworkDir] + 1 + buildResults = append(buildResults, *buildResult) targetBuildResultMutex.Unlock() log.Println("finish building for target", target) @@ -79,12 +85,13 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) // Finally combine all frameworks to an XCFramework xcframeworkArgs := []string{"-create-xcframework"} - for _, dir := range frameworkDirs { - xcframeworkArgs = append(xcframeworkArgs, "-framework", dir) + for _, buildResult := range buildResults { + xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) } xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) cmd := exec.Command("xcodebuild", xcframeworkArgs...) + log.Println("running: xcodebuild", strings.Join(xcframeworkArgs, " ")) err = runCmd(cmd) return err } @@ -113,11 +120,11 @@ func goAppleBindArchive(name string, env []string, gosrc string) (string, error) return archive, nil } -func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, frameworkDir string) { +func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, buildResult *archBuildResult) { // Catalyst support requires iOS 13+ v, _ := strconv.ParseFloat(buildIOSVersion, 64) if t.platform == "maccatalyst" && v < 13.0 { - return errors.New("catalyst requires -iosversion=13 or higher"), "" + return errors.New("catalyst requires -iosversion=13 or higher"), nil } outDir := filepath.Join(tmpdir, t.platform, t.arch) // adding arch @@ -141,13 +148,15 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa cmd.Args = append(cmd.Args, p.PkgPath) } if err := runCmd(cmd); err != nil { - return err, "" + log.Fatalln(err) + os.Exit(1) + return err, nil } env := appleEnv[t.String()][:] sdk := getenv(env, "DARWIN_SDK") - frameworkDir = filepath.Join(tmpdir, t.platform, t.arch+"_framework", sdk, title+".framework") + frameworkDir := filepath.Join(tmpdir, t.platform, t.arch+"_framework", sdk, title+".framework") fileBases := make([]string, len(pkgs)+1) for i, pkg := range pkgs { @@ -160,57 +169,29 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa env = append(env, gopath) if err := writeGoMod(outDir, t.platform, t.arch); err != nil { - return err, "" + return err, nil } // Run `go mod tidy` to force to create go.sum. // Without go.sum, `go build` fails as of Go 1.16. if modulesUsed { if err := goModTidyAt(outSrcDir, env); err != nil { - return err, "" + return err, nil } } - path, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) + staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) if err != nil { - return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), "" + return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), nil } versionsDir := filepath.Join(frameworkDir, "Versions") versionsADir := filepath.Join(versionsDir, "A") - titlePath := filepath.Join(versionsADir, title) - //if frameworkArchCount[frameworkDir] > 1 { - // // Not the first static lib, attach to a fat library and skip create headers - // fatCmd := exec.Command( - // "xcrun", - // "lipo", path, titlePath, "-create", "-output", titlePath, - // ) - // if err := runCmd(fatCmd); err != nil { - // return err, "" - // } - // continue - //} + //titlePath := filepath.Join(versionsADir, title) versionsAHeadersDir := filepath.Join(versionsADir, "Headers") if err := mkdir(versionsAHeadersDir); err != nil { - return err, "" - } - if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { - return err, "" - } - if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { - return err, "" - } - if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { - return err, "" - } - - lipoCmd := exec.Command( - "xcrun", - "lipo", path, "-create", "-o", titlePath, - ) - if err := runCmd(lipoCmd); err != nil { - return err, "" + return err, nil } // Copy header file next to output archive. @@ -222,7 +203,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, bindPrefix+title+".objc.h"), ) if err != nil { - return err, "" + return err, nil } } else { for _, fileBase := range fileBases { @@ -232,7 +213,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, fileBase+".objc.h"), ) if err != nil { - return err, "" + return err, nil } } err := copyFile( @@ -240,7 +221,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, "ref.h"), ) if err != nil { - return err, "" + return err, nil } headerFiles = append(headerFiles, title+".h") err = writeFile(filepath.Join(versionsAHeadersDir, title+".h"), func(w io.Writer) error { @@ -249,22 +230,12 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa }) }) if err != nil { - return err, "" + return err, nil } } - if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { - return err, "" - } if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { - return err, "" - } - err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { - _, err := w.Write([]byte(appleBindInfoPlist)) - return err - }) - if err != nil { - return err, "" + return err, nil } var mmVals = struct { @@ -278,13 +249,18 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa return appleModuleMapTmpl.Execute(w, mmVals) }) if err != nil { - return err, "" + return err, nil } err = symlink(filepath.Join("Versions/Current/Modules"), filepath.Join(frameworkDir, "Modules")) if err != nil { - return err, "" + return err, nil + } + frameworkHeaderPath := filepath.Join(frameworkDir, "Versions", "A", "Headers") + return err, &archBuildResult{ + headerPath: frameworkHeaderPath, + libraryPath: staticLibPath, + targetInfo: t, } - return err, frameworkDir } var appleBindHeaderTmpl = template.Must(template.New("apple.h").Parse(` From 272f05554ab318bf24250217b4b769e7c99c6578 Mon Sep 17 00:00:00 2001 From: WildCat Date: Wed, 22 Dec 2021 16:44:14 +0800 Subject: [PATCH 03/19] Embed libs first --- cmd/gomobile/bind.go | 4 +-- cmd/gomobile/bind_iosapp.go | 71 +++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index efbc89699..4dd2d9d30 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -189,8 +189,8 @@ func writeFile(filename string, generate func(io.Writer) error) error { fmt.Fprintf(os.Stderr, "write %s\n", filename) } - if err := mkdir(filepath.Dir(filename)); err != nil { - return err + if errMkDirErr := mkdir(filepath.Dir(filename)); errMkDirErr != nil { + return errMkDirErr } if buildN { diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 27edab5e2..f0d8cb701 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -27,6 +27,11 @@ type archBuildResult struct { targetInfo } +type xcframeworkPayload struct { + libraryPath string + headerPath string +} + func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { var name string var title string @@ -85,17 +90,79 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) // Finally combine all frameworks to an XCFramework xcframeworkArgs := []string{"-create-xcframework"} + // for _, buildResult := range buildResults { + // xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) + // } + + xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) + + simulatorPayload := simulatorFrameworkPayload(buildResults, "iossimulator") + if simulatorPayload != nil { + xcframeworkArgs = append(xcframeworkArgs, "-library", simulatorPayload.libraryPath, "-headers", simulatorPayload.headerPath) + } + catalystPayload := simulatorFrameworkPayload(buildResults, "maccatalyst") + if catalystPayload != nil { + xcframeworkArgs = append(xcframeworkArgs, "-library", catalystPayload.libraryPath, "-headers", catalystPayload.headerPath) + } + for _, buildResult := range buildResults { - xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) + if !isPlatformNameSimulatorOrCatalyst(buildResult.platform) { + xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) + } } - xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) cmd := exec.Command("xcodebuild", xcframeworkArgs...) log.Println("running: xcodebuild", strings.Join(xcframeworkArgs, " ")) err = runCmd(cmd) return err } +func isPlatformNameSimulatorOrCatalyst(platformName string) bool { + return platformName == "iossimulator" || platformName == "maccatalyst" +} + +func simulatorFrameworkPayload(buildResults []archBuildResult, platformName string) *xcframeworkPayload { + if !isPlatformNameSimulatorOrCatalyst(platformName) { + log.Fatalf("unsupported platform %q", platformName) + return nil + } + + var filteredStaticLibPaths []string + for _, buildResult := range buildResults { + if buildResult.platform == platformName { + filteredStaticLibPaths = append(filteredStaticLibPaths, buildResult.libraryPath) + } + } + + if len(filteredStaticLibPaths) == 0 { + return nil + } else if len(filteredStaticLibPaths) == 1 { + return &xcframeworkPayload{ + headerPath: buildResults[0].headerPath, + libraryPath: buildResults[0].libraryPath, + } + } + + outputPath := filepath.Dir(filepath.Dir(filteredStaticLibPaths[0])) + "/" + "univesal.a" + if err := lipoCreate(outputPath, filteredStaticLibPaths); err != nil { + log.Fatalln(err) + } + + return &xcframeworkPayload{ + headerPath: buildResults[0].headerPath, + libraryPath: outputPath, + } +} + +func lipoCreate(outputPath string, libPaths []string) error { + args := []string{"lipo", "-create"} + args = append(args, libPaths...) + args = append(args, "-output", outputPath) + cmd := exec.Command("xcrun", args...) + log.Println("running: lipo", strings.Join(args, " ")) + return runCmd(cmd) +} + const appleBindInfoPlist = ` From e6059854c59952251b8a418235d98cf443c08aeb Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 11:38:19 +0800 Subject: [PATCH 04/19] Rollback to merge frameworks --- cmd/gomobile/bind.go | 7 +- cmd/gomobile/bind_iosapp.go | 145 ++++++++++++++++++------------------ 2 files changed, 79 insertions(+), 73 deletions(-) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index 4dd2d9d30..074b3b463 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -185,12 +185,15 @@ func copyFile(dst, src string) error { } func writeFile(filename string, generate func(io.Writer) error) error { + fmt.Println("write file:", filename) if buildV { fmt.Fprintf(os.Stderr, "write %s\n", filename) } - if errMkDirErr := mkdir(filepath.Dir(filename)); errMkDirErr != nil { - return errMkDirErr + dirToMake := filepath.Dir(filename) + fmt.Println("dirToMake:", dirToMake) + if err := mkdir(dirToMake); err != nil { + fmt.Println(err) } if buildN { diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index f0d8cb701..e636cd660 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -21,8 +21,10 @@ import ( ) type archBuildResult struct { - libraryPath string - headerPath string + libraryPath string + headerPath string + titlePath string + frameworkPath string targetInfo } @@ -59,6 +61,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } var buildResults []archBuildResult + var platformBuildResults = make(map[string][]archBuildResult) targetBuildResultMutex := &sync.Mutex{} var waitGroup sync.WaitGroup @@ -78,6 +81,10 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) targetBuildResultMutex.Lock() buildResults = append(buildResults, *buildResult) + if platformBuildResults[target.platform] == nil { + platformBuildResults[target.platform] = []archBuildResult{} + } + platformBuildResults[target.platform] = append(platformBuildResults[target.platform], *buildResult) targetBuildResultMutex.Unlock() log.Println("finish building for target", target) @@ -90,79 +97,31 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) // Finally combine all frameworks to an XCFramework xcframeworkArgs := []string{"-create-xcframework"} - // for _, buildResult := range buildResults { - // xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) - // } - - xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) - - simulatorPayload := simulatorFrameworkPayload(buildResults, "iossimulator") - if simulatorPayload != nil { - xcframeworkArgs = append(xcframeworkArgs, "-library", simulatorPayload.libraryPath, "-headers", simulatorPayload.headerPath) - } - catalystPayload := simulatorFrameworkPayload(buildResults, "maccatalyst") - if catalystPayload != nil { - xcframeworkArgs = append(xcframeworkArgs, "-library", catalystPayload.libraryPath, "-headers", catalystPayload.headerPath) + refinedBuildResults := []archBuildResult{} + + // Merge binary for single target + for _, buildResults := range platformBuildResults { + if len(buildResults) == 2 { + mergeArchsForSinglePlatform(buildResults[0].titlePath, buildResults[1].titlePath) + refinedBuildResults = append(refinedBuildResults, buildResults[0]) + } else if len(buildResults) == 1 { + refinedBuildResults = append(refinedBuildResults, buildResults[0]) + } else { + log.Fatalln("unexpected number of build results", len(buildResults)) + } } - for _, buildResult := range buildResults { - if !isPlatformNameSimulatorOrCatalyst(buildResult.platform) { - xcframeworkArgs = append(xcframeworkArgs, "-library", buildResult.libraryPath, "-headers", buildResult.headerPath) - } + for _, result := range refinedBuildResults { + xcframeworkArgs = append(xcframeworkArgs, "-framework", result.frameworkPath) } + xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) cmd := exec.Command("xcodebuild", xcframeworkArgs...) log.Println("running: xcodebuild", strings.Join(xcframeworkArgs, " ")) err = runCmd(cmd) return err } -func isPlatformNameSimulatorOrCatalyst(platformName string) bool { - return platformName == "iossimulator" || platformName == "maccatalyst" -} - -func simulatorFrameworkPayload(buildResults []archBuildResult, platformName string) *xcframeworkPayload { - if !isPlatformNameSimulatorOrCatalyst(platformName) { - log.Fatalf("unsupported platform %q", platformName) - return nil - } - - var filteredStaticLibPaths []string - for _, buildResult := range buildResults { - if buildResult.platform == platformName { - filteredStaticLibPaths = append(filteredStaticLibPaths, buildResult.libraryPath) - } - } - - if len(filteredStaticLibPaths) == 0 { - return nil - } else if len(filteredStaticLibPaths) == 1 { - return &xcframeworkPayload{ - headerPath: buildResults[0].headerPath, - libraryPath: buildResults[0].libraryPath, - } - } - - outputPath := filepath.Dir(filepath.Dir(filteredStaticLibPaths[0])) + "/" + "univesal.a" - if err := lipoCreate(outputPath, filteredStaticLibPaths); err != nil { - log.Fatalln(err) - } - - return &xcframeworkPayload{ - headerPath: buildResults[0].headerPath, - libraryPath: outputPath, - } -} - -func lipoCreate(outputPath string, libPaths []string) error { - args := []string{"lipo", "-create"} - args = append(args, libPaths...) - args = append(args, "-output", outputPath) - cmd := exec.Command("xcrun", args...) - log.Println("running: lipo", strings.Join(args, " ")) - return runCmd(cmd) -} - const appleBindInfoPlist = ` @@ -187,7 +146,19 @@ func goAppleBindArchive(name string, env []string, gosrc string) (string, error) return archive, nil } +func mergeArchsForSinglePlatform(from string, to string) error { + fatCmd := exec.Command( + "xcrun", + "lipo", from, to, "-create", "-output", to, + ) + if err := runCmd(fatCmd); err != nil { + return err + } + return nil +} + func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, buildResult *archBuildResult) { + log.Println("build for target:", t) // Catalyst support requires iOS 13+ v, _ := strconv.ParseFloat(buildIOSVersion, 64) if t.platform == "maccatalyst" && v < 13.0 { @@ -223,7 +194,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa env := appleEnv[t.String()][:] sdk := getenv(env, "DARWIN_SDK") - frameworkDir := filepath.Join(tmpdir, t.platform, t.arch+"_framework", sdk, title+".framework") + frameworkDir := filepath.Join(tmpdir, t.platform, sdk, title+"_"+t.arch+".framework") fileBases := make([]string, len(pkgs)+1) for i, pkg := range pkgs { @@ -247,6 +218,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa } } + // staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) if err != nil { return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), nil @@ -254,12 +226,29 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa versionsDir := filepath.Join(frameworkDir, "Versions") versionsADir := filepath.Join(versionsDir, "A") - //titlePath := filepath.Join(versionsADir, title) - + titlePath := filepath.Join(versionsADir, title) versionsAHeadersDir := filepath.Join(versionsADir, "Headers") if err := mkdir(versionsAHeadersDir); err != nil { return err, nil } + if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { + return err, nil + } + if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { + return err, nil + } + if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { + return err, nil + } + + log.Println("staticLibPath:" + staticLibPath) + lipoCmd := exec.Command( + "xcrun", + "lipo", staticLibPath, "-create", "-o", titlePath, + ) + if err := runCmd(lipoCmd); err != nil { + return err, nil + } // Copy header file next to output archive. var headerFiles []string @@ -301,10 +290,22 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa } } + if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { + return err, nil + } + if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { return err, nil } + err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { + _, err := w.Write([]byte(appleBindInfoPlist)) + return err + }) + if err != nil { + return err, nil + } + var mmVals = struct { Module string Headers []string @@ -324,9 +325,11 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa } frameworkHeaderPath := filepath.Join(frameworkDir, "Versions", "A", "Headers") return err, &archBuildResult{ - headerPath: frameworkHeaderPath, - libraryPath: staticLibPath, - targetInfo: t, + headerPath: frameworkHeaderPath, + libraryPath: staticLibPath, + titlePath: titlePath, + targetInfo: t, + frameworkPath: frameworkDir, } } From 7a4f454e11fd7cbfa3d5c07dc27e8536dee90f8a Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 11:48:04 +0800 Subject: [PATCH 05/19] Finish parallel build --- cmd/gomobile/bind_iosapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index e636cd660..03c087fe3 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -194,7 +194,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa env := appleEnv[t.String()][:] sdk := getenv(env, "DARWIN_SDK") - frameworkDir := filepath.Join(tmpdir, t.platform, sdk, title+"_"+t.arch+".framework") + frameworkDir := filepath.Join(tmpdir, t.platform, sdk, t.arch, title+".framework") fileBases := make([]string, len(pkgs)+1) for i, pkg := range pkgs { From 7a9d5b05045de17ab8983819d159c05922e20c49 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:17:28 +0800 Subject: [PATCH 06/19] Remove unused field --- cmd/gomobile/bind_iosapp.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 03c087fe3..9553b5e27 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -21,19 +21,12 @@ import ( ) type archBuildResult struct { - libraryPath string - headerPath string titlePath string frameworkPath string targetInfo } -type xcframeworkPayload struct { - libraryPath string - headerPath string -} - func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { var name string var title string @@ -323,10 +316,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa if err != nil { return err, nil } - frameworkHeaderPath := filepath.Join(frameworkDir, "Versions", "A", "Headers") return err, &archBuildResult{ - headerPath: frameworkHeaderPath, - libraryPath: staticLibPath, titlePath: titlePath, targetInfo: t, frameworkPath: frameworkDir, From ab56776ff18e0b4a3d877ea988d1514235f9eea2 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:17:59 +0800 Subject: [PATCH 07/19] Recover bind --- cmd/gomobile/bind.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index 074b3b463..efbc89699 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -185,15 +185,12 @@ func copyFile(dst, src string) error { } func writeFile(filename string, generate func(io.Writer) error) error { - fmt.Println("write file:", filename) if buildV { fmt.Fprintf(os.Stderr, "write %s\n", filename) } - dirToMake := filepath.Dir(filename) - fmt.Println("dirToMake:", dirToMake) - if err := mkdir(dirToMake); err != nil { - fmt.Println(err) + if err := mkdir(filepath.Dir(filename)); err != nil { + return err } if buildN { From 83860d52196381ceec8ae12e904777313ef00bc8 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:19:58 +0800 Subject: [PATCH 08/19] Remove unnecessary logs --- cmd/gomobile/bind_iosapp.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 9553b5e27..6de651448 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "log" "os" "os/exec" "path/filepath" @@ -64,11 +63,9 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) go func(target targetInfo, targetBuildResultMutex *sync.Mutex) { defer waitGroup.Done() - log.Println("start building for target", target) - err, buildResult := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) if err != nil { - log.Fatalf("%v", err) + fmt.Errorf("%v", err) return } @@ -80,8 +77,6 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) platformBuildResults[target.platform] = append(platformBuildResults[target.platform], *buildResult) targetBuildResultMutex.Unlock() - log.Println("finish building for target", target) - }(target, targetBuildResultMutex) } @@ -100,7 +95,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } else if len(buildResults) == 1 { refinedBuildResults = append(refinedBuildResults, buildResults[0]) } else { - log.Fatalln("unexpected number of build results", len(buildResults)) + fmt.Errorf("unexpected number of build results", len(buildResults)) } } @@ -110,7 +105,6 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) xcframeworkArgs = append(xcframeworkArgs, "-output", buildO) cmd := exec.Command("xcodebuild", xcframeworkArgs...) - log.Println("running: xcodebuild", strings.Join(xcframeworkArgs, " ")) err = runCmd(cmd) return err } @@ -151,7 +145,6 @@ func mergeArchsForSinglePlatform(from string, to string) error { } func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, buildResult *archBuildResult) { - log.Println("build for target:", t) // Catalyst support requires iOS 13+ v, _ := strconv.ParseFloat(buildIOSVersion, 64) if t.platform == "maccatalyst" && v < 13.0 { @@ -179,7 +172,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa cmd.Args = append(cmd.Args, p.PkgPath) } if err := runCmd(cmd); err != nil { - log.Fatalln(err) + fmt.Errorf("%v", err) os.Exit(1) return err, nil } @@ -234,7 +227,6 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa return err, nil } - log.Println("staticLibPath:" + staticLibPath) lipoCmd := exec.Command( "xcrun", "lipo", staticLibPath, "-create", "-o", titlePath, From 0572ebcc29614dc1491849958a596813ccc887a0 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:22:00 +0800 Subject: [PATCH 09/19] Recovert gitignore and go.sum --- .gitignore | 8 +------- go.sum | 4 +--- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 2b7614a89..d6c0fcdb4 100644 --- a/.gitignore +++ b/.gitignore @@ -24,10 +24,4 @@ example/bind/android/local.properties example/bind/android/gradlew* example/bind/android/gradle example/bind/android/build -example/bind/android/app/build - -vendor -build/ -.gitignore -cmd/gomobile/gomobile -.vscode/launch.json +example/bind/android/app/build \ No newline at end of file diff --git a/go.sum b/go.sum index 5d710d232..dc4559231 100644 --- a/go.sum +++ b/go.sum @@ -35,6 +35,4 @@ golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -robpike.io/ivy v0.1.9 h1:iZN9ddmhd1Hr8MJrMZFCu6MqFiAPtoj37HAmrCzkyno= -robpike.io/ivy v0.1.9/go.mod h1:6B/DGaft5rvYiF7MgCTiZAAvH5W7vtu0eS2BW77updo= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= \ No newline at end of file From b4ff38497a96813ffa1b305fbc38a7589136b93b Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:23:09 +0800 Subject: [PATCH 10/19] Add empty line at the end --- .gitignore | 2 +- go.sum | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d6c0fcdb4..87baa6455 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ example/bind/android/local.properties example/bind/android/gradlew* example/bind/android/gradle example/bind/android/build -example/bind/android/app/build \ No newline at end of file +example/bind/android/app/build diff --git a/go.sum b/go.sum index dc4559231..d4d3ebf1e 100644 --- a/go.sum +++ b/go.sum @@ -35,4 +35,4 @@ golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= \ No newline at end of file +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 6e4c23ba23586abc075161606c7e3c199f1805ca Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:24:29 +0800 Subject: [PATCH 11/19] Remove unused comment --- cmd/gomobile/bind_iosapp.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 6de651448..1f65c586d 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -204,7 +204,6 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa } } - // staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) if err != nil { return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), nil From 45c426714eb65ef5927fb37705e354d4d5b23aaa Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 12:36:30 +0800 Subject: [PATCH 12/19] Clean up --- cmd/gomobile/bind_iosapp.go | 63 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 1f65c586d..58500adfb 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "os" "os/exec" "path/filepath" "strconv" @@ -59,13 +58,15 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) var waitGroup sync.WaitGroup waitGroup.Add(len(targets)) + var parallelBuildError error + for _, target := range targets { go func(target targetInfo, targetBuildResultMutex *sync.Mutex) { defer waitGroup.Done() - err, buildResult := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) + buildResult, err := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) if err != nil { - fmt.Errorf("%v", err) + parallelBuildError = fmt.Errorf("cannot build %s [%s]: %v", target.platform, target.arch, err) return } @@ -82,6 +83,10 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) waitGroup.Wait() + if parallelBuildError != nil { + return parallelBuildError + } + // Finally combine all frameworks to an XCFramework xcframeworkArgs := []string{"-create-xcframework"} @@ -95,10 +100,14 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } else if len(buildResults) == 1 { refinedBuildResults = append(refinedBuildResults, buildResults[0]) } else { - fmt.Errorf("unexpected number of build results", len(buildResults)) + err = fmt.Errorf("unexpected number of build results: %v", len(buildResults)) } } + if err != nil { + return err + } + for _, result := range refinedBuildResults { xcframeworkArgs = append(xcframeworkArgs, "-framework", result.frameworkPath) } @@ -144,11 +153,11 @@ func mergeArchsForSinglePlatform(from string, to string) error { return nil } -func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (err error, buildResult *archBuildResult) { +func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Package, title string, name string, modulesUsed bool) (buildResult *archBuildResult, err error) { // Catalyst support requires iOS 13+ v, _ := strconv.ParseFloat(buildIOSVersion, 64) if t.platform == "maccatalyst" && v < 13.0 { - return errors.New("catalyst requires -iosversion=13 or higher"), nil + return nil, errors.New("catalyst requires -iosversion=13 or higher") } outDir := filepath.Join(tmpdir, t.platform, t.arch) // adding arch @@ -172,9 +181,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa cmd.Args = append(cmd.Args, p.PkgPath) } if err := runCmd(cmd); err != nil { - fmt.Errorf("%v", err) - os.Exit(1) - return err, nil + return nil, err } env := appleEnv[t.String()][:] @@ -193,20 +200,20 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa env = append(env, gopath) if err := writeGoMod(outDir, t.platform, t.arch); err != nil { - return err, nil + return nil, err } // Run `go mod tidy` to force to create go.sum. // Without go.sum, `go build` fails as of Go 1.16. if modulesUsed { if err := goModTidyAt(outSrcDir, env); err != nil { - return err, nil + return nil, err } } staticLibPath, err := goAppleBindArchive(name+"-"+t.platform+"-"+t.arch, env, outSrcDir) if err != nil { - return fmt.Errorf("%s/%s: %v", t.platform, t.arch, err), nil + return nil, fmt.Errorf("%s/%s: %v", t.platform, t.arch, err) } versionsDir := filepath.Join(frameworkDir, "Versions") @@ -214,16 +221,16 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa titlePath := filepath.Join(versionsADir, title) versionsAHeadersDir := filepath.Join(versionsADir, "Headers") if err := mkdir(versionsAHeadersDir); err != nil { - return err, nil + return nil, err } if err := symlink("A", filepath.Join(versionsDir, "Current")); err != nil { - return err, nil + return nil, err } if err := symlink("Versions/Current/Headers", filepath.Join(frameworkDir, "Headers")); err != nil { - return err, nil + return nil, err } if err := symlink(filepath.Join("Versions/Current", title), filepath.Join(frameworkDir, title)); err != nil { - return err, nil + return nil, err } lipoCmd := exec.Command( @@ -231,7 +238,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa "lipo", staticLibPath, "-create", "-o", titlePath, ) if err := runCmd(lipoCmd); err != nil { - return err, nil + return nil, err } // Copy header file next to output archive. @@ -243,7 +250,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, bindPrefix+title+".objc.h"), ) if err != nil { - return err, nil + return nil, err } } else { for _, fileBase := range fileBases { @@ -253,7 +260,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, fileBase+".objc.h"), ) if err != nil { - return err, nil + return nil, err } } err := copyFile( @@ -261,7 +268,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa filepath.Join(gobindDir, "ref.h"), ) if err != nil { - return err, nil + return nil, err } headerFiles = append(headerFiles, title+".h") err = writeFile(filepath.Join(versionsAHeadersDir, title+".h"), func(w io.Writer) error { @@ -270,16 +277,16 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa }) }) if err != nil { - return err, nil + return nil, err } } if err := mkdir(filepath.Join(versionsADir, "Resources")); err != nil { - return err, nil + return nil, err } if err := symlink("Versions/Current/Resources", filepath.Join(frameworkDir, "Resources")); err != nil { - return err, nil + return nil, err } err = writeFile(filepath.Join(frameworkDir, "Resources", "Info.plist"), func(w io.Writer) error { @@ -287,7 +294,7 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa return err }) if err != nil { - return err, nil + return nil, err } var mmVals = struct { @@ -301,17 +308,17 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa return appleModuleMapTmpl.Execute(w, mmVals) }) if err != nil { - return err, nil + return nil, err } err = symlink(filepath.Join("Versions/Current/Modules"), filepath.Join(frameworkDir, "Modules")) if err != nil { - return err, nil + return nil, err } - return err, &archBuildResult{ + return &archBuildResult{ titlePath: titlePath, targetInfo: t, frameworkPath: frameworkDir, - } + }, err } var appleBindHeaderTmpl = template.Must(template.New("apple.h").Parse(` From 1b903c74b694baa0218c2b1996b8868753df0d45 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sat, 1 Jan 2022 20:55:14 +0800 Subject: [PATCH 13/19] Remove build result array --- cmd/gomobile/bind_iosapp.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 58500adfb..9a7508751 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -51,7 +51,6 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) return err } - var buildResults []archBuildResult var platformBuildResults = make(map[string][]archBuildResult) targetBuildResultMutex := &sync.Mutex{} @@ -71,7 +70,6 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } targetBuildResultMutex.Lock() - buildResults = append(buildResults, *buildResult) if platformBuildResults[target.platform] == nil { platformBuildResults[target.platform] = []archBuildResult{} } From 50d954c8a2dd2b0bd72545ac4279ef51533ce2b8 Mon Sep 17 00:00:00 2001 From: WildCat Date: Sun, 2 Jan 2022 17:27:44 +0800 Subject: [PATCH 14/19] Fix build result of merged FAT binary --- cmd/gomobile/bind_iosapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 9a7508751..a7b479530 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -94,7 +94,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) for _, buildResults := range platformBuildResults { if len(buildResults) == 2 { mergeArchsForSinglePlatform(buildResults[0].titlePath, buildResults[1].titlePath) - refinedBuildResults = append(refinedBuildResults, buildResults[0]) + refinedBuildResults = append(refinedBuildResults, buildResults[1]) } else if len(buildResults) == 1 { refinedBuildResults = append(refinedBuildResults, buildResults[0]) } else { From 594b595c2da6c3465f7b2fcfb4804918dda40ea6 Mon Sep 17 00:00:00 2001 From: WildCat Date: Fri, 21 Jan 2022 06:59:26 +0800 Subject: [PATCH 15/19] address review feedbacks --- cmd/gomobile/bind_iosapp.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index a7b479530..3c5098f5b 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -21,8 +21,6 @@ import ( type archBuildResult struct { titlePath string frameworkPath string - - targetInfo } func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { @@ -52,7 +50,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } var platformBuildResults = make(map[string][]archBuildResult) - targetBuildResultMutex := &sync.Mutex{} + var targetBuildResultMutex sync.Mutex var waitGroup sync.WaitGroup waitGroup.Add(len(targets)) @@ -60,7 +58,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) var parallelBuildError error for _, target := range targets { - go func(target targetInfo, targetBuildResultMutex *sync.Mutex) { + go func(target targetInfo) { defer waitGroup.Done() buildResult, err := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) @@ -70,13 +68,13 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } targetBuildResultMutex.Lock() + defer targetBuildResultMutex.Unlock() if platformBuildResults[target.platform] == nil { platformBuildResults[target.platform] = []archBuildResult{} } platformBuildResults[target.platform] = append(platformBuildResults[target.platform], *buildResult) - targetBuildResultMutex.Unlock() - }(target, targetBuildResultMutex) + }(target) } waitGroup.Wait() @@ -314,7 +312,6 @@ func buildTargetArch(t targetInfo, gobindCommandPath string, pkgs []*packages.Pa } return &archBuildResult{ titlePath: titlePath, - targetInfo: t, frameworkPath: frameworkDir, }, err } From 6d124e1540e213530a84414d1437062c3e6e6f04 Mon Sep 17 00:00:00 2001 From: WildCat Date: Fri, 21 Jan 2022 07:05:36 +0800 Subject: [PATCH 16/19] simplify slice append case --- cmd/gomobile/bind_iosapp.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 3c5098f5b..4be25a44d 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -69,9 +69,6 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) targetBuildResultMutex.Lock() defer targetBuildResultMutex.Unlock() - if platformBuildResults[target.platform] == nil { - platformBuildResults[target.platform] = []archBuildResult{} - } platformBuildResults[target.platform] = append(platformBuildResults[target.platform], *buildResult) }(target) From fd0e9491da4415266824a6cf0d555422f05c15b6 Mon Sep 17 00:00:00 2001 From: WildCat Date: Fri, 21 Jan 2022 07:53:22 +0800 Subject: [PATCH 17/19] Add parallelism limit --- cmd/gomobile/bind.go | 13 ++++++++++++- cmd/gomobile/bind_iosapp.go | 18 ++++++++++++------ cmd/gomobile/build.go | 3 +++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go index efbc89699..72fe2ae9c 100644 --- a/cmd/gomobile/bind.go +++ b/cmd/gomobile/bind.go @@ -126,10 +126,13 @@ func runBind(cmd *command) error { case isAndroidPlatform(targets[0].platform): return goAndroidBind(gobind, pkgs, targets) case isApplePlatform(targets[0].platform): + if buildWorkerError := validateBuildWorkers(buildWorkers); buildWorkerError != nil { + return buildWorkerError + } if !xcodeAvailable() { return fmt.Errorf("-target=%q requires Xcode", buildTarget) } - return goAppleBind(gobind, pkgs, targets) + return goAppleBind(gobind, pkgs, targets, buildWorkers) default: return fmt.Errorf(`invalid -target=%q`, buildTarget) } @@ -321,3 +324,11 @@ func areGoModulesUsed() (bool, error) { } return true, nil } + +func validateBuildWorkers(workers int) error { + if workers < 1 { + return fmt.Errorf("invalid workers %d: must be >= 1", workers) + } else { + return nil + } +} diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 4be25a44d..8fd5f956c 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -23,7 +23,7 @@ type archBuildResult struct { frameworkPath string } -func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error { +func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo, buildWorkers int) error { var name string var title string @@ -55,15 +55,20 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) var waitGroup sync.WaitGroup waitGroup.Add(len(targets)) - var parallelBuildError error + var parallelBuildErrorBuffer = make(chan error, len(targets)) + semophore := make(chan struct{}, buildWorkers) for _, target := range targets { go func(target targetInfo) { - defer waitGroup.Done() + semophore <- struct{}{} + defer func() { + <-semophore + waitGroup.Done() + }() buildResult, err := buildTargetArch(target, gobind, pkgs, title, name, modulesUsed) if err != nil { - parallelBuildError = fmt.Errorf("cannot build %s [%s]: %v", target.platform, target.arch, err) + parallelBuildErrorBuffer <- fmt.Errorf("cannot build %s [%s]: %v", target.platform, target.arch, err) return } @@ -75,9 +80,10 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo) } waitGroup.Wait() + close(parallelBuildErrorBuffer) - if parallelBuildError != nil { - return parallelBuildError + for buildErr := range parallelBuildErrorBuffer { + return buildErr } // Finally combine all frameworks to an XCFramework diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go index bd65f1c1a..f7f0eee1e 100644 --- a/cmd/gomobile/build.go +++ b/cmd/gomobile/build.go @@ -14,6 +14,7 @@ import ( "os" "os/exec" "regexp" + "runtime" "strconv" "strings" @@ -243,6 +244,7 @@ var ( buildTarget string // -target buildTrimpath bool // -trimpath buildWork bool // -work + buildWorkers int // -j buildBundleID string // -bundleid buildIOSVersion string // -iosversion buildAndroidAPI int // -androidapi @@ -262,6 +264,7 @@ func addBuildFlags(cmd *command) { cmd.flag.BoolVar(&buildI, "i", false, "") cmd.flag.BoolVar(&buildTrimpath, "trimpath", false, "") cmd.flag.Var(&buildTags, "tags", "") + cmd.flag.IntVar(&buildWorkers, "j", runtime.NumCPU(), "") } func addBuildFlagsNVXWork(cmd *command) { From cfbbb6f70c5ea20ebd5be2eba0d7c49d8ac37f37 Mon Sep 17 00:00:00 2001 From: WildCat Date: Fri, 21 Jan 2022 08:01:36 +0800 Subject: [PATCH 18/19] Small fix --- cmd/gomobile/bind_iosapp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 8fd5f956c..47b79dfd1 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -55,7 +55,7 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo, var waitGroup sync.WaitGroup waitGroup.Add(len(targets)) - var parallelBuildErrorBuffer = make(chan error, len(targets)) + parallelBuildErrorBuffer := make(chan error, len(targets)) semophore := make(chan struct{}, buildWorkers) for _, target := range targets { From faf4e940650a19f37d887b0bb4ef712a27f52177 Mon Sep 17 00:00:00 2001 From: WildCat Date: Fri, 21 Jan 2022 08:02:44 +0800 Subject: [PATCH 19/19] Fix typo --- cmd/gomobile/bind_iosapp.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go index 47b79dfd1..6e9bef3ab 100644 --- a/cmd/gomobile/bind_iosapp.go +++ b/cmd/gomobile/bind_iosapp.go @@ -56,13 +56,13 @@ func goAppleBind(gobind string, pkgs []*packages.Package, targets []targetInfo, waitGroup.Add(len(targets)) parallelBuildErrorBuffer := make(chan error, len(targets)) - semophore := make(chan struct{}, buildWorkers) + semaphore := make(chan struct{}, buildWorkers) for _, target := range targets { go func(target targetInfo) { - semophore <- struct{}{} + semaphore <- struct{}{} defer func() { - <-semophore + <-semaphore waitGroup.Done() }()