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  }