main.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package main
  2. import (
  3. "flag"
  4. "os"
  5. "os/exec"
  6. "path/filepath"
  7. "strconv"
  8. "strings"
  9. _ "github.com/sagernet/gomobile"
  10. "github.com/sagernet/sing-box/cmd/internal/build_shared"
  11. "github.com/sagernet/sing-box/log"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. "github.com/sagernet/sing/common/rw"
  14. "github.com/sagernet/sing/common/shell"
  15. )
  16. var (
  17. debugEnabled bool
  18. target string
  19. platform string
  20. // withTailscale bool
  21. )
  22. func init() {
  23. flag.BoolVar(&debugEnabled, "debug", false, "enable debug")
  24. flag.StringVar(&target, "target", "android", "target platform")
  25. flag.StringVar(&platform, "platform", "", "specify platform")
  26. // flag.BoolVar(&withTailscale, "with-tailscale", false, "build tailscale for iOS and tvOS")
  27. }
  28. func main() {
  29. flag.Parse()
  30. build_shared.FindMobile()
  31. switch target {
  32. case "android":
  33. buildAndroid()
  34. case "apple":
  35. buildApple()
  36. }
  37. }
  38. var (
  39. sharedFlags []string
  40. debugFlags []string
  41. sharedTags []string
  42. darwinTags []string
  43. // memcTags []string
  44. notMemcTags []string
  45. debugTags []string
  46. )
  47. func init() {
  48. sharedFlags = append(sharedFlags, "-trimpath")
  49. sharedFlags = append(sharedFlags, "-buildvcs=false")
  50. currentTag, err := build_shared.ReadTag()
  51. if err != nil {
  52. currentTag = "unknown"
  53. }
  54. sharedFlags = append(sharedFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -s -w -buildid= -checklinkname=0")
  55. debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag+" -X internal/godebug.defaultGODEBUG=multipathtcp=0 -checklinkname=0")
  56. sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_naive_outbound", "with_clash_api", "badlinkname", "tfogo_checklinkname0")
  57. darwinTags = append(darwinTags, "with_dhcp", "grpcnotrace")
  58. // memcTags = append(memcTags, "with_tailscale")
  59. sharedTags = append(sharedTags, "with_tailscale", "ts_omit_logtail", "ts_omit_ssh", "ts_omit_drive", "ts_omit_taildrop", "ts_omit_webclient", "ts_omit_doctor", "ts_omit_capture", "ts_omit_kube", "ts_omit_aws", "ts_omit_synology", "ts_omit_bird")
  60. notMemcTags = append(notMemcTags, "with_low_memory")
  61. debugTags = append(debugTags, "debug")
  62. }
  63. type AndroidBuildConfig struct {
  64. AndroidAPI int
  65. OutputName string
  66. Tags []string
  67. }
  68. func filterTags(tags []string, exclude ...string) []string {
  69. excludeMap := make(map[string]bool)
  70. for _, tag := range exclude {
  71. excludeMap[tag] = true
  72. }
  73. var result []string
  74. for _, tag := range tags {
  75. if !excludeMap[tag] {
  76. result = append(result, tag)
  77. }
  78. }
  79. return result
  80. }
  81. func checkJavaVersion() {
  82. var javaPath string
  83. javaHome := os.Getenv("JAVA_HOME")
  84. if javaHome == "" {
  85. javaPath = "java"
  86. } else {
  87. javaPath = filepath.Join(javaHome, "bin", "java")
  88. }
  89. javaVersion, err := shell.Exec(javaPath, "--version").ReadOutput()
  90. if err != nil {
  91. log.Fatal(E.Cause(err, "check java version"))
  92. }
  93. if !strings.Contains(javaVersion, "openjdk 17") {
  94. log.Fatal("java version should be openjdk 17")
  95. }
  96. }
  97. func getAndroidBindTarget() string {
  98. if platform != "" {
  99. return platform
  100. } else if debugEnabled {
  101. return "android/arm64"
  102. }
  103. return "android"
  104. }
  105. func buildAndroidVariant(config AndroidBuildConfig, bindTarget string) {
  106. args := []string{
  107. "bind",
  108. "-v",
  109. "-o", config.OutputName,
  110. "-target", bindTarget,
  111. "-androidapi", strconv.Itoa(config.AndroidAPI),
  112. "-javapkg=io.nekohasekai",
  113. "-libname=box",
  114. }
  115. if !debugEnabled {
  116. args = append(args, sharedFlags...)
  117. } else {
  118. args = append(args, debugFlags...)
  119. }
  120. args = append(args, "-tags", strings.Join(config.Tags, ","))
  121. args = append(args, "./experimental/libbox")
  122. command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
  123. command.Stdout = os.Stdout
  124. command.Stderr = os.Stderr
  125. err := command.Run()
  126. if err != nil {
  127. log.Fatal(err)
  128. }
  129. copyPath := filepath.Join("..", "sing-box-for-android", "app", "libs")
  130. if rw.IsDir(copyPath) {
  131. copyPath, _ = filepath.Abs(copyPath)
  132. err = rw.CopyFile(config.OutputName, filepath.Join(copyPath, config.OutputName))
  133. if err != nil {
  134. log.Fatal(err)
  135. }
  136. log.Info("copied ", config.OutputName, " to ", copyPath)
  137. }
  138. }
  139. func buildAndroid() {
  140. build_shared.FindSDK()
  141. checkJavaVersion()
  142. bindTarget := getAndroidBindTarget()
  143. // Build main variant (SDK 23)
  144. mainTags := append([]string{}, sharedTags...)
  145. // mainTags = append(mainTags, memcTags...)
  146. if debugEnabled {
  147. mainTags = append(mainTags, debugTags...)
  148. }
  149. buildAndroidVariant(AndroidBuildConfig{
  150. AndroidAPI: 23,
  151. OutputName: "libbox.aar",
  152. Tags: mainTags,
  153. }, bindTarget)
  154. // Build legacy variant (SDK 21, no naive outbound)
  155. legacyTags := filterTags(sharedTags, "with_naive_outbound")
  156. // legacyTags = append(legacyTags, memcTags...)
  157. if debugEnabled {
  158. legacyTags = append(legacyTags, debugTags...)
  159. }
  160. buildAndroidVariant(AndroidBuildConfig{
  161. AndroidAPI: 21,
  162. OutputName: "libbox-legacy.aar",
  163. Tags: legacyTags,
  164. }, bindTarget)
  165. }
  166. func buildApple() {
  167. var bindTarget string
  168. if platform != "" {
  169. bindTarget = platform
  170. } else if debugEnabled {
  171. bindTarget = "ios"
  172. } else {
  173. bindTarget = "ios,iossimulator,tvos,tvossimulator,macos"
  174. }
  175. args := []string{
  176. "bind",
  177. "-v",
  178. "-target", bindTarget,
  179. "-libname=box",
  180. "-tags-not-macos=with_low_memory",
  181. "-iosversion=15.0",
  182. "-macosversion=13.0",
  183. "-tvosversion=17.0",
  184. }
  185. //if !withTailscale {
  186. // args = append(args, "-tags-macos="+strings.Join(memcTags, ","))
  187. //}
  188. if !debugEnabled {
  189. args = append(args, sharedFlags...)
  190. } else {
  191. args = append(args, debugFlags...)
  192. }
  193. tags := append(sharedTags, darwinTags...)
  194. //if withTailscale {
  195. // tags = append(tags, memcTags...)
  196. //}
  197. if debugEnabled {
  198. tags = append(tags, debugTags...)
  199. }
  200. args = append(args, "-tags", strings.Join(tags, ","))
  201. args = append(args, "./experimental/libbox")
  202. command := exec.Command(build_shared.GoBinPath+"/gomobile", args...)
  203. command.Stdout = os.Stdout
  204. command.Stderr = os.Stderr
  205. err := command.Run()
  206. if err != nil {
  207. log.Fatal(err)
  208. }
  209. copyPath := filepath.Join("..", "sing-box-for-apple")
  210. if rw.IsDir(copyPath) {
  211. targetDir := filepath.Join(copyPath, "Libbox.xcframework")
  212. targetDir, _ = filepath.Abs(targetDir)
  213. os.RemoveAll(targetDir)
  214. os.Rename("Libbox.xcframework", targetDir)
  215. log.Info("copied to ", targetDir)
  216. }
  217. }