diff --git a/cmd/gomobile/build.go b/cmd/gomobile/build.go
index 4ea5fc4..c666caf 100644
--- a/cmd/gomobile/build.go
+++ b/cmd/gomobile/build.go
@@ -17,7 +17,6 @@ import (
"os/exec"
"path"
"path/filepath"
- "runtime"
"strconv"
"strings"
)
@@ -327,56 +326,6 @@ func addBuildFlagsNVX(cmd *command) {
cmd.flag.BoolVar(&buildX, "x", false, "")
}
-// TODO(jbd): Build darwin/arm cross compiler during gomobile init.
-
-func goIOSBuild(src string) error {
- // iOS builds are achievable only if the host machine is darwin.
- if runtime.GOOS != "darwin" {
- return nil
- }
-
- goroot := goEnv("GOROOT")
- gopath := goEnv("GOPATH")
- gocmd := exec.Command(
- `go`,
- `build`,
- `-tags=`+strconv.Quote(strings.Join(ctx.BuildTags, ",")))
- if buildV {
- gocmd.Args = append(gocmd.Args, "-v")
- }
- if buildI {
- gocmd.Args = append(gocmd.Args, "-i")
- }
- if buildX {
- gocmd.Args = append(gocmd.Args, "-x")
- }
- gocmd.Args = append(gocmd.Args, src)
- // TODO(jbd): Return a user-friendly error if xcode command line
- // tools are not available.
- gocmd.Stdout = os.Stdout
- gocmd.Stderr = os.Stderr
- gocmd.Env = []string{
- `GOOS=darwin`,
- `GOARCH=arm`, // TODO(jbd): Build for arm64
- `GOARM=7`,
- `CGO_ENABLED=1`,
- `CC=` + filepath.Join(goroot, "misc/ios/clangwrap.sh"), // TODO(jbd): reimplement clangwrap here.
- `CXX=` + filepath.Join(goroot, "misc/ios/clangwrap.sh"),
- `GOROOT=` + goroot,
- `GOPATH=` + gopath,
- }
- if buildX {
- printcmd("%s", strings.Join(gocmd.Env, " ")+" "+strings.Join(gocmd.Args, " "))
- }
- if !buildN {
- gocmd.Env = environ(gocmd.Env)
- if err := gocmd.Run(); err != nil {
- return err
- }
- }
- return nil
-}
-
// goAndroidBuild builds a package.
// If libPath is specified then it builds as a shared library.
func goAndroidBuild(src, libPath string) error {
diff --git a/cmd/gomobile/ios.go b/cmd/gomobile/ios.go
new file mode 100644
index 0000000..aeb041b
--- /dev/null
+++ b/cmd/gomobile/ios.go
@@ -0,0 +1,482 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+// TODO(jbd): iOS builds are achievable only if the host machine is darwin.
+// TODO(jbd): Build darwin/arm cross compiler during gomobile init.
+
+func goIOSBuild(src string) error {
+ dir := "$XCODEPROJ"
+ if !buildN {
+ tmp, err := ioutil.TempDir("", "xcodeproject")
+ if err != nil {
+ return err
+ }
+ dir = tmp
+ }
+ if buildX {
+ printcmd("mkdir %s", dir)
+ }
+
+ layout := map[string][]byte{
+ dir + "/main.xcodeproj/project.pbxproj": []byte(projPbxproj),
+ dir + "/main/Info.plist": []byte(infoPlist),
+ dir + "/main/Images.xcassets/AppIcon.appiconset/Contents.json": []byte(contentsJSON),
+ }
+
+ for dst, v := range layout {
+ if buildX {
+ printcmd("echo \"%s\" > %s", v, dst)
+ }
+ if !buildN {
+ if err := os.MkdirAll(filepath.Dir(dst), 0775|os.ModeDir); err != nil {
+ return err
+ }
+ if err := ioutil.WriteFile(dst, v, 0644); err != nil {
+ return err
+ }
+ }
+ }
+
+ armPath := filepath.Join(dir, "arm")
+ if err := goBuild(src, armPath, []string{
+ `GOOS=darwin`,
+ `GOARCH=arm`,
+ `GOARM=7`,
+ }); err != nil {
+ return err
+ }
+
+ arm64Path := filepath.Join(dir, "arm64")
+ if err := goBuild(src, arm64Path, []string{
+ `GOOS=darwin`,
+ `GOARCH=arm64`,
+ }); err != nil {
+ return err
+ }
+
+ // Apple requires builds to target both darwin/arm and darwin/arm64.
+ // We are using lipo tool to build multiarchitecture binaries.
+ // TODO(jbd): Investigate the new announcements about iO9's fat binary
+ // size limitations are breaking this feature.
+ if buildX {
+ printcmd("xcrun lipo -create %s %s -o %s", armPath, arm64Path, filepath.Join(dir, "main/main"))
+ }
+ if !buildN {
+ err := exec.Command(
+ "xcrun", "lipo",
+ "-create", armPath, arm64Path,
+ "-o", filepath.Join(dir, "main/main"),
+ ).Run()
+ if err != nil {
+ return err
+ }
+ }
+
+ // TODO(jbd): Copy assets.
+ // TODO(jbd): Run xcodebuild and move the build to the desired output directory.
+ // TODO(jbd): Remove the temp dir.
+ return nil
+}
+
+func goBuild(src, o string, env []string) error {
+ goroot := goEnv("GOROOT")
+ gopath := goEnv("GOPATH")
+ cmd := exec.Command(
+ `go`,
+ `build`,
+ `-tags=`+strconv.Quote(strings.Join(ctx.BuildTags, ",")),
+ )
+ if buildV {
+ cmd.Args = append(cmd.Args, "-v")
+ }
+ if buildI {
+ cmd.Args = append(cmd.Args, "-i")
+ }
+ if buildX {
+ cmd.Args = append(cmd.Args, "-x")
+ }
+ cmd.Args = append(cmd.Args, "-o="+o)
+ cmd.Args = append(cmd.Args, src)
+ cmd.Env = append(env, []string{
+ `CGO_ENABLED=1`,
+ `GOROOT=` + goroot,
+ `GOPATH=` + gopath,
+ }...)
+ if buildX {
+ printcmd("%s", strings.Join(cmd.Env, " ")+" "+strings.Join(cmd.Args, " "))
+ }
+ if !buildN {
+ cmd.Env = environ(cmd.Env)
+ return cmd.Run()
+ }
+ return nil
+}
+
+const infoPlist = `
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ main
+ CFBundleIdentifier
+ org.golang.todo.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
+`
+
+const projPbxproj = `// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+/* Begin PBXBuildFile section */
+ 254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 254BB84E1B1FD08900C56DE9 /* Images.xcassets */; };
+ 254BB8681B1FD16500C56DE9 /* main in Resources */ = {isa = PBXBuildFile; fileRef = 254BB8671B1FD16500C56DE9 /* main */; };
+/* End PBXBuildFile section */
+/* Begin PBXFileReference section */
+ 254BB83E1B1FD08900C56DE9 /* main.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = main.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 254BB8421B1FD08900C56DE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 254BB84E1B1FD08900C56DE9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ 254BB8671B1FD16500C56DE9 /* main */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = main; sourceTree = ""; };
+/* End PBXFileReference section */
+/* Begin PBXGroup section */
+ 254BB8351B1FD08900C56DE9 = {
+ isa = PBXGroup;
+ children = (
+ 254BB8401B1FD08900C56DE9 /* main */,
+ 254BB83F1B1FD08900C56DE9 /* Products */,
+ );
+ sourceTree = "";
+ usesTabs = 0;
+ };
+ 254BB83F1B1FD08900C56DE9 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 254BB83E1B1FD08900C56DE9 /* main.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 254BB8401B1FD08900C56DE9 /* main */ = {
+ isa = PBXGroup;
+ children = (
+ 254BB8671B1FD16500C56DE9 /* main */,
+ 254BB84E1B1FD08900C56DE9 /* Images.xcassets */,
+ 254BB8411B1FD08900C56DE9 /* Supporting Files */,
+ );
+ path = main;
+ sourceTree = "";
+ };
+ 254BB8411B1FD08900C56DE9 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ 254BB8421B1FD08900C56DE9 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+/* Begin PBXNativeTarget section */
+ 254BB83D1B1FD08900C56DE9 /* main */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */;
+ buildPhases = (
+ 254BB83C1B1FD08900C56DE9 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = main;
+ productName = main;
+ productReference = 254BB83E1B1FD08900C56DE9 /* main.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+/* Begin PBXProject section */
+ 254BB8361B1FD08900C56DE9 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0630;
+ ORGANIZATIONNAME = Developer;
+ TargetAttributes = {
+ 254BB83D1B1FD08900C56DE9 = {
+ CreatedOnToolsVersion = 6.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 254BB8351B1FD08900C56DE9;
+ productRefGroup = 254BB83F1B1FD08900C56DE9 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 254BB83D1B1FD08900C56DE9 /* main */,
+ );
+ };
+/* End PBXProject section */
+/* Begin PBXResourcesBuildPhase section */
+ 254BB83C1B1FD08900C56DE9 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 254BB8681B1FD16500C56DE9 /* main in Resources */,
+ 254BB84F1B1FD08900C56DE9 /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+/* Begin XCBuildConfiguration section */
+ 254BB85F1B1FD08900C56DE9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 254BB8601B1FD08900C56DE9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.3;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 254BB8621B1FD08900C56DE9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = main/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 254BB8631B1FD08900C56DE9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = main/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+/* Begin XCConfigurationList section */
+ 254BB8391B1FD08900C56DE9 /* Build configuration list for PBXProject "main" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 254BB85F1B1FD08900C56DE9 /* Debug */,
+ 254BB8601B1FD08900C56DE9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 254BB8611B1FD08900C56DE9 /* Build configuration list for PBXNativeTarget "main" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 254BB8621B1FD08900C56DE9 /* Debug */,
+ 254BB8631B1FD08900C56DE9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 254BB8361B1FD08900C56DE9 /* Project object */;
+}
+`
+
+const contentsJSON = `{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
+`