Skip to content

Instantly share code, notes, and snippets.

@horsley
Created December 23, 2020 08:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save horsley/db13fd63b6cc07899c3a09112d0b2612 to your computer and use it in GitHub Desktop.
Save horsley/db13fd63b6cc07899c3a09112d0b2612 to your computer and use it in GitHub Desktop.
Xcode 12.3 golang script for xcframework convertion
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
)
var (
archRegex = regexp.MustCompile(`\(for architecture ([^)]*)\)`)
archMap = map[string]string{
"armv7": "ios",
"armv7s": "ios",
"arm64": "ios",
"i386": "simulator",
"x86_64": "simulator",
}
)
func main() {
if len(os.Args) < 2 {
fmt.Println(filepath.Base(os.Args[0]), "xxx.framework")
return
}
oldFrameworkPath := os.Args[1]
//stage 1 find fat binary
if !strings.HasSuffix(oldFrameworkPath, ".framework") {
fmt.Println("not a framework!")
return
}
fatName := strings.Replace(filepath.Base(oldFrameworkPath), ".framework", "", 1)
fatPath := filepath.Join(oldFrameworkPath, fatName)
fatArch := make([]string, 0, 5)
fatInfo := syncRunCmd("file", fatPath)
archMatches := archRegex.FindAllStringSubmatch(fatInfo, -1)
if len(archMatches) <= 1 {
fmt.Println("multi architecture fat binary not found")
return
}
fmt.Println(fatPath, "found fat binary")
fmt.Println("\n", fatInfo)
for _, a := range archMatches {
fatArch = append(fatArch, a[1])
}
//stage 2 make seperate thin bin, copy framework for seperate platform
tmp := filepath.Join(os.TempDir(), fmt.Sprint(time.Now().Unix()))
fmt.Println("tmp dir:", tmp)
platformBin := make(map[string][]string)
for _, arch := range fatArch {
platform, ok := archMap[arch]
if !ok {
fmt.Println("platform not define for arch:", arch)
return
}
platformFramework := filepath.Join(tmp, platform, filepath.Base(oldFrameworkPath))
if _, err := os.Stat(platformFramework); err != nil && os.IsNotExist(err) {
os.MkdirAll(filepath.Dir(platformFramework), 0755)
fmt.Println("make copy:", platformFramework)
fmt.Println(syncRunCmd("cp", "-r", oldFrameworkPath, platformFramework))
platformBin[platformFramework] = make([]string, 0, 3)
}
seperateBin := filepath.Join(tmp, platform, arch, fatName)
os.MkdirAll(filepath.Dir(seperateBin), 0755)
fmt.Println(syncRunCmd("lipo", fatPath, "-thin", arch, "-output", seperateBin))
platformBin[platformFramework] = append(platformBin[platformFramework], seperateBin)
}
//stage 3 combine bin by platform, save in framework dir
xcframworkParam := make([]string, 0, 2*len(fatArch)+3)
xcframworkParam = append(xcframworkParam, "-create-xcframework")
for framework, bin := range platformBin {
lipoParam := []string{"-create", "-output", filepath.Join(framework, fatName)}
lipoParam = append(lipoParam, bin...)
fmt.Println("lipo", lipoParam)
fmt.Println(syncRunCmd("lipo", lipoParam...))
xcframworkParam = append(xcframworkParam, "-framework", framework)
}
//stage 4 make xcframework
xcframworkParam = append(xcframworkParam, "-output", strings.Replace(oldFrameworkPath, ".framework", ".xcframework", 1))
fmt.Println("xcodebuild", xcframworkParam)
fmt.Println(syncRunCmd("xcodebuild", xcframworkParam...))
}
func syncRunCmd(cmd string, args ...string) string {
rst, err := exec.Command(cmd, args...).CombinedOutput()
if err != nil {
return err.Error()
}
return string(rst)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment