github.com/sagernet/sing-box@v1.9.0-rc.20/cmd/internal/build_shared/sdk.go (about) 1 package build_shared 2 3 import ( 4 "go/build" 5 "os" 6 "path/filepath" 7 "runtime" 8 "sort" 9 "strconv" 10 "strings" 11 12 "github.com/sagernet/sing-box/log" 13 "github.com/sagernet/sing/common" 14 E "github.com/sagernet/sing/common/exceptions" 15 "github.com/sagernet/sing/common/rw" 16 "github.com/sagernet/sing/common/shell" 17 ) 18 19 var ( 20 androidSDKPath string 21 androidNDKPath string 22 ) 23 24 func FindSDK() { 25 searchPath := []string{ 26 "$ANDROID_HOME", 27 "$HOME/Android/Sdk", 28 "$HOME/.local/lib/android/sdk", 29 "$HOME/Library/Android/sdk", 30 } 31 for _, path := range searchPath { 32 path = os.ExpandEnv(path) 33 if rw.FileExists(filepath.Join(path, "licenses", "android-sdk-license")) { 34 androidSDKPath = path 35 break 36 } 37 } 38 if androidSDKPath == "" { 39 log.Fatal("android SDK not found") 40 } 41 if !findNDK() { 42 log.Fatal("android NDK not found") 43 } 44 45 javaVersion, err := shell.Exec("java", "--version").ReadOutput() 46 if err != nil { 47 log.Fatal(E.Cause(err, "check java version")) 48 } 49 if !strings.Contains(javaVersion, "openjdk 17") { 50 log.Fatal("java version should be openjdk 17") 51 } 52 53 os.Setenv("ANDROID_HOME", androidSDKPath) 54 os.Setenv("ANDROID_SDK_HOME", androidSDKPath) 55 os.Setenv("ANDROID_NDK_HOME", androidNDKPath) 56 os.Setenv("NDK", androidNDKPath) 57 os.Setenv("PATH", os.Getenv("PATH")+":"+filepath.Join(androidNDKPath, "toolchains", "llvm", "prebuilt", runtime.GOOS+"-x86_64", "bin")) 58 } 59 60 func findNDK() bool { 61 const fixedVersion = "26.2.11394342" 62 const versionFile = "source.properties" 63 if fixedPath := filepath.Join(androidSDKPath, "ndk", fixedVersion); rw.FileExists(filepath.Join(fixedPath, versionFile)) { 64 androidNDKPath = fixedPath 65 return true 66 } 67 ndkVersions, err := os.ReadDir(filepath.Join(androidSDKPath, "ndk")) 68 if err != nil { 69 return false 70 } 71 versionNames := common.Map(ndkVersions, os.DirEntry.Name) 72 if len(versionNames) == 0 { 73 return false 74 } 75 sort.Slice(versionNames, func(i, j int) bool { 76 iVersions := strings.Split(versionNames[i], ".") 77 jVersions := strings.Split(versionNames[j], ".") 78 for k := 0; k < len(iVersions) && k < len(jVersions); k++ { 79 iVersion, _ := strconv.Atoi(iVersions[k]) 80 jVersion, _ := strconv.Atoi(jVersions[k]) 81 if iVersion != jVersion { 82 return iVersion > jVersion 83 } 84 } 85 return true 86 }) 87 for _, versionName := range versionNames { 88 currentNDKPath := filepath.Join(androidSDKPath, "ndk", versionName) 89 if rw.FileExists(filepath.Join(androidSDKPath, versionFile)) { 90 androidNDKPath = currentNDKPath 91 log.Warn("reproducibility warning: using NDK version " + versionName + " instead of " + fixedVersion) 92 return true 93 } 94 } 95 return false 96 } 97 98 var GoBinPath string 99 100 func FindMobile() { 101 goBin := filepath.Join(build.Default.GOPATH, "bin") 102 if runtime.GOOS == "windows" { 103 if !rw.FileExists(filepath.Join(goBin, "gobind.exe")) { 104 log.Fatal("missing gomobile installation") 105 } 106 } else { 107 if !rw.FileExists(filepath.Join(goBin, "gobind")) { 108 log.Fatal("missing gomobile installation") 109 } 110 } 111 GoBinPath = goBin 112 }