Build cocos2d-x games for iOS on Windows and debug C++ on iPhone
This tutorial shows how to build a cocos2d-x game for iOS on Windows, install it on your iPhone, debug its C++ code with breakpoints and produce an .ipa for the App Store. It works for both 3.x and 4.x. The engine source compiles along with your game as subprojects, and you don’t need to change the engine. You need an Apple Developer account, an iPhone and a USB cable, and you need to have installed KXBuild.
3.x and 4.x differences
The two major versions keep their iOS projects in different places. Where later commands differ, pick the one for your version.
| Engine version | iOS project | App target |
|---|---|---|
| 3.x | proj.ios_mac\MyGame.xcodeproj, created with the project |
MyGame-mobile |
| 4.x | build-xcode\MyGame.xcodeproj, generated when you run doctor |
MyGame |
A 3.x project also has a MyGame-desktop target, which is the macOS version. iOS uses only MyGame-mobile. For 4.x, cocos2d-x ships only a CMakeLists.txt, and the Xcode project has to be generated by CMake. That happens when you run doctor.
Install the engine and create a project
If you already have a project, open its root folder in VS Code with File > Open Folder… or drag the folder into VS Code, and skip to the next section. Otherwise, create one as follows.
Download the engine archive from the cocos2d-x website, extract it, and run setup.py in the engine folder to set up the cocos command. setup.py and the cocos command in 3.x and 4.0 both need Python 2.7.
1cd D:\cocos2d-x-4.0
2python setup.py
setup.py writes environment variables. When it finishes, close the terminal and open a new one before creating the project.
1cd D:\work
2cocos new MyGame -l cpp -p com.example.mygame -d .
-p is the package name. Use the Bundle ID you registered in your developer account. For a Lua project, replace -l cpp with -l lua. Keep the project in a short path such as D:\work. The engine folder nests deeply, and a deep path easily runs into path-too-long errors on Windows.
Open the project and run doctor
In VS Code, open the project root D:\work\MyGame with File > Open Folder….
The first time you open the project, run doctor. It checks the cocos2d-x environment and prepares the iOS project. For 4.x, this is also when the Xcode project is generated in the build-xcode folder. Use either of these.
- VS Code extension. In the title bar of the KXBuild view, open the ··· menu and run Doctor (fix environment).
- Command line. Run the command below.
1kxbuild doctor D:\work\MyGame
When doctor finishes, the KXBuild view lists the MyGame project and its targets. The engine’s own projects may be listed too. Click the MyGame project node to set it as the startup project.
C++ code gets completion, go to definition and error checking in VS Code. See Code completion and indexing. For Lua and JS scripts, install the matching VS Code extensions.
Run on your iPhone
Your keychain folder needs an Apple Development certificate and a Development provisioning profile that includes this iPhone’s UDID. For how to get and place them, see Certificates and signing.
Connect the iPhone with a cable, unlock it and tap Trust in the Trust This Computer prompt, then turn on Developer Mode in Settings > Privacy & Security > Developer Mode. The iPhone restarts once. For drivers and iPhone settings, see Set up your device.
Check that the Build configuration node in the KXBuild view shows Debug, select the iPhone and press F5. KXBuild builds, signs, installs and launches the game, then attaches the debugger. For a 3.x project, pick MyGame-mobile when asked for a target.
The first build compiles the whole engine and takes a while. Later builds only compile the files you changed. The first time you debug on a given iOS version, KXBuild also downloads its device symbols. It’s a few GB, but only once.
Output from log() and CCLOG in the game appears in the KXBuild Console channel of the VS Code Output panel, and the build log in the KXBuild channel. Open the Output panel with Ctrl+Shift+U and switch channels from the dropdown at the top right.
Debug C++ with breakpoints
In Classes\HelloWorldScene.cpp, click to the left of a line number inside HelloWorld::init to add a breakpoint, then press F5. The game stops on that line after it launches. The Variables panel on the left expands this and local variables, and the Call Stack panel shows the full call chain down into the engine. The engine source is compiled with your game, so you can step into engine functions.
A few techniques come up often when debugging game code.
- Functions called every frame. A plain breakpoint in a function like
update(float dt)stops constantly. Right-click and choose “Add Conditional Breakpoint…” with a condition such as_score > 100, or choose “Add Logpoint…” to print values without stopping. - C++ exceptions. While debugging, check C++ Throw in the Breakpoints panel. The debugger stops on the line that throws.
- Crashes.
EXC_BAD_ACCESSusually means accessing a node that has already been released. Reproduce it once with the Debug configuration. The debugger stops where it crashes, and you can walk up the call stack to find what is holding the dangling pointer.
Lua and JS scripts use the engine’s own debugging tools, which don’t interfere with C++ breakpoints. For the full guide to breakpoints, LLDB commands and crash reports, see Debug iOS apps on Windows with LLDB, breakpoints and crash logs.
After changing assets or code
After changing C++ code, press F5. KXBuild only recompiles the files you changed.
For images, sounds and config files in the Resources folder, 3.x and 4.x behave differently.
| Engine version | Changed existing files | Added or deleted files |
|---|---|---|
| 3.x | Press F5 | Press F5 |
| 4.x | Press F5 | Run doctor once, then press F5 |
In 4.x, the lists of resources and source files are written into build-xcode when the Xcode project is generated. New images and new .cpp files only get into build-xcode after you run doctor again. Otherwise you get missing resources at runtime or undefined symbols at link time. When you create new .cpp and .h files, add them to the GAME_SOURCE and GAME_HEADER lists in CMakeLists.txt first, then run doctor.
build-xcode is regenerated every time you run doctor, so don’t change project settings in it by hand. Put settings you want to keep in CMakeLists.txt.
Check frame rate and CPU on the device
The FPS stats in the bottom-left corner of the game come from the engine itself. To see overall load and dropped frames, sample with kxdevice. Switch to a Release build before measuring. Debug builds aren’t optimized, so the numbers come out low.
1kxdevice instruments sysmon -i 1
sysmon prints the device’s overall CPU usage once a second. For dropped frames, memory growth and hot functions, use fluidity, allocations and stackshot. See Performance profiling. Common hot spots in cocos2d-x games are creating nodes every frame, too many draw calls because large images aren’t packed into sprite sheets, and file reads or writes inside update.
Build a Release .ipa
Before submitting, your keychain folder needs an Apple Distribution certificate and an App Store provisioning profile. The game’s icons and launch images are in proj.ios_mac\ios for both 3.x and 4.x, and you can edit the icons with the Asset Catalog Editor. Use either of these.
- VS Code extension. Switch to Release in the Build configuration node of the KXBuild view, then run
KXBuild: Buildfrom the Command Palette. - Command line. In the project root, run the command for your engine version.
For a 3.x project, run this.
1kxbuild build .\proj.ios_mac\MyGame.xcodeproj -c Release -t MyGame-mobile
For a 4.x project, run this.
1kxbuild build .\build-xcode\MyGame.xcodeproj -c Release -t MyGame
If the project’s Release configuration doesn’t specify a distribution certificate, add -D CODE_SIGN_IDENTITY="Apple Distribution" on the command line to override it for this build. Each upload to App Store Connect needs a higher build number than the last, which you can set on the command line with -D CURRENT_PROJECT_VERSION=2.
When the build finishes, the .ipa is in the build folder next to the .xcodeproj. For uploading to App Store Connect, testing on TestFlight and submitting for review, see Release and App Store submission. For the full walkthrough, see Publish to the App Store on Windows, from .ipa upload to review.
FAQ
The cocos command or setup.py reports SyntaxError. You’re running Python 3. Install Python 2.7 and run setup.py again with it.
The 4.x project doesn’t show up in the KXBuild view. build-xcode hasn’t been generated yet. Run doctor once.
The command line reports target not found. The app target is MyGame-mobile in 3.x and MyGame in 4.x.
File name too long or file not found. Move the project to a short path such as D:\work\MyGame and run doctor again.
A 4.x game can’t find newly added images at runtime. Run doctor again after adding resources. See the previous section.
Breakpoints don’t stop, or you only see assembly. Check that the build configuration is Debug, and wait for the device symbols download on your first debug session to finish.
Signing or install errors. Look up the message in 16 common iOS code signing and .ipa install errors, and how to fix them.
The game quits right after launch. Reproduce it with the Debug configuration and F5, and see which line the debugger stops on. For device logs and crash reports, see Troubleshooting.