Linux to iOS C++ Cross Compile

In this article I will describe the build process of C++ SDL iOS app on Linux, resign ipa file without a paid subscription to Apple Developer Program and installation on a clean device (iPad) via macOS without Jailbreak.

First, install the build toolchain in Linux:
https://github.com/tpoechtrager/cctools-port

Toolchain needs to be downloaded from the repository, follow instructions on the site of Godot Engine to complete the installation:
https://docs.godotengine.org/ru/latest/development/compiling/cross-compiling_for_ios_on_linux.html

At this point you need to download Xcode dmg and copy ios sdk to build cctools-port. This stage is easier to pass on MacOS, simply copy of Xcode installed sdk necessary files. After successful build, the terminal will show a path to crosscompiler bin directory.

You can then proceed to the build of SDL applications for iOS. Open cmake and add the necessary changes for C ++ build code:


SET(CMAKE_SYSTEM_NAME Darwin)
SET(CMAKE_C_COMPILER arm-apple-darwin11-clang)
SET(CMAKE_CXX_COMPILER arm-apple-darwin11-clang++)
SET(CMAKE_LINKER arm-apple-darwin11-ld)

Now you can build using cmake and make, but do not forget to register to the $PATH of crosscompiler bin directory:



PATH=$PATH:~/Sources/cctools-port/usage_examples/ios_toolchain/target/bin

For correct linking with frameworks and SDL add them to cmake, Space Jaguar games depending for example:



target_link_libraries(
${FSEGT_PROJECT_NAME}
${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/libclang_rt.ios.a
${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/libSDL2.a
${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/libSDL2_mixer.a
${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/libSDL2_image.a
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/CoreServices.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/ImageIO.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/Metal.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/AVFoundation.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/GameController.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/CoreMotion.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/CoreGraphics.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/AudioToolbox.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/CoreAudio.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/QuartzCore.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/OpenGLES.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/UIKit.framework"
"${FLAME_STEEL_PROJECT_ROOT_DIRECTORY}/scripts/buildScripts/ios/resources/libs/Foundation.framework"
)

In my case, SDL library, SDL_Image, SDL_mixer compiled in Xcode on macOS advance for static linking; Frameworks copied from Xcode. Also added libclang_rt.ios.a library, which includes specific runtime iOS calls, e.g. isOSVersionAtLeast. Enabled macros for working with OpenGL ES, disables unsupported features in the mobile platforms, similar to Android.

After the resolving build problems, you must get a binary compiled for the arm. Next, I will describe binary installation and run on the device without Jailbreak.

On macOS make Xcode installation, register on Apple’s website, without having to pay for the development of the program. Add account in Xcode -> Preferences -> Accounts, create an empty application and build for a real device. During assembly, device will be added to a free developer account. After building and running, you need to make an archive of the build, for this select Generic iOS Device and Product -> Archive. By the end of the archive build, copy files called embedded.mobileprovision, PkgInfo. From the build log on the device, find the line codesign with the correct key signature, the path to the file with the extension of entitlements app.xcent, copy it.

Copy the .app from the archive, replace binary in the archive created by cross-compiler in Linux (eg SpaceJaguar.app/SpaceJaguar), further adding to the .app necessary resources to check the safety and PkgInfo embedded.mobileprovision in the .app file from the archive, copy again if needed. Resign .app using codesign command – codesign requires the input argument of the key for the sign, the path to the entitlements file (can be renamed with the extension .plist)

After resign create Payload folder, move to the folder with the .app extension, create a zip file with the Payload directory, rename the file with the extension .ipa. After that, in Xcode, open the list of devices and Drag’n’Drop ipa in the list of device applications; Installation via Apple Configurator 2 for this process does not work. If resign made correctly, a new application is installed with correct binary on iOS device (e.g. iPad) with 7 day certificate for testing period that is sufficient.

References

https://github.com/tpoechtrager/cctools-port
https://docs.godotengine.org/ru/latest/development/compiling/cross-compiling_for_ios_on_linux.html
https://jonnyzzz.com/blog/2018/06/13/link-error-3/
https://stackoverflow.com/questions/6896029/re-sign-ipa-iphone
https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html

Porting C++ SDL Application To Android

In this article I will describe his experience porting 3D editor prototype Cube Art Project on Android.
First, look at the result, the emulator running the editor with 3D cursor red cube:

To build a successful have to do the following:

  1. Install the latest Android SDK and NDK (National Palace of Culture version of the fresher the better).
  2. Download the code SDL2, take out a template to build an application for android.
  3. Add SDL Image, SDL Mixer for assembly.
  4. Add the library of my game engine and toolkit, their dependencies (GLM, JSON for Modern C++)
  5. Adapt the assembly files for Gradle.
  6. Adapt the C ++ code to be compatible with Android, changes were platform specific components (OpenGL ES, the graphics context initialization)
  7. Assemble and test the project on the emulator.

Project Template

Load the source code SDL, SDL Image, SDL Mixer:
https://www.libsdl.org/download-2.0.php
The docs folder contains detailed instructions on working with project android template; copy the directory android-project in a separate folder, make a symlink or copy the SDL folder in android-project / app / jni.
Substitute the correct identifier for avd flag, run the emulator from the Android Sdk directory:


cd ~/Android/Sdk/emulator
./emulator -avd Pixel_2_API_24

Specify the path to the script, pick a project:


rm -rf app/build || true
export ANDROID_HOME=/home/demensdeum/Android/Sdk/
export ANDROID_NDK_HOME=/home/demensdeum/Android/android-ndk-r21-beta2/
./gradlew clean build
./gradlew installDebug

Should meet SDL project template with the code in C from a file


android-sdl-test-app/cube-art-project-android/app/jni/src/YourSourceHere.c

Dependencies

Download the source code archives for SDL_image, SDL_mixer:
https://www.libsdl.org/projects/SDL_image/
https://www.libsdl.org/projects/SDL_mixer/

Load depending on your project, for example, my shared library:
https://gitlab.com/demensdeum/FlameSteelCore/
https://gitlab.com/demensdeum/FlameSteelCommonTraits
https://gitlab.com/demensdeum/FlameSteelBattleHorn
https://gitlab.com/demensdeum/FlameSteelEngineGameToolkit/
https://gitlab.com/demensdeum/FlameSteelEngineGameToolkitFSGL
https://gitlab.com/demensdeum/FSGL
https://gitlab.com/demensdeum/cube-art-project

All of this was discharged into app / jni, each “module” in a separate folder, such as app / jni / FSGL. Next, you have the option to find workers generators Application.mk and Android.mk files, I have not found, but maybe there’s a simple solution based on CMake. Click on a link and start to get acquainted with the format of the build files for Android NDK:

https://developer.android.com/ndk/guides/application_mk
https://developer.android.com/ndk/guides/android_mk

You should also read about different APP_STL implementation NDK:
https://developer.android.com/ndk/guides/cpp-support.html

After reviewing create for each “module” file Android.mk, further example of an assembly file shared library Cube-Art-Project:


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

APP_STL := c++_static
APP_CPPFLAGS := -fexceptions
LOCAL_MODULE := CubeArtProject
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src $(LOCAL_PATH)/../include $(LOCAL_PATH)/../include/FlameSteelCommonTraits/src/FlameSteelCommonTraits
LOCAL_EXPORT_C_INCLUDES = $(LOCAL_PATH)/src/

define walk
  $(wildcard $(1)) $(foreach e, $(wildcard $(1)/*), $(call walk, $(e)))
endef

ALLFILES = $(call walk, $(LOCAL_PATH)/src)
FILE_LIST := $(filter %.cpp, $(ALLFILES))
$(info CubeArtProject source code files list)
$(info $(FILE_LIST))
LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%)

LOCAL_SHARED_LIBRARIES += FlameSteelCore
LOCAL_SHARED_LIBRARIES += FlameSteelBattleHorn
LOCAL_SHARED_LIBRARIES += FlameSteelCommonTraits
LOCAL_SHARED_LIBRARIES += FlameSteelEngineGameToolkit
LOCAL_SHARED_LIBRARIES += FlameSteelEngineGameToolkitFSGL
LOCAL_SHARED_LIBRARIES += FSGL
LOCAL_SHARED_LIBRARIES += SDL2
LOCAL_SHARED_LIBRARIES += SDL2_image

LOCAL_LDFLAGS := -static-libstdc++
include $(BUILD_SHARED_LIBRARY)

CMake any experienced user realizes this configuration with the first string formats are very similar in Android.mk no GLOB_RECURSIVE, so we have to recursively search for source files with walk functions.

Change Application.mk, Android.mk with-but to build C++ instead of C code:


APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_PLATFORM=android-16
APP_STL := c++_static
APP_CPPFLAGS := -fexceptions

Rename YourSourceHere.c -> YourSourceHere.cpp, grep for entry, change the path in the assembly, for example:


app/jni/src/Android.mk:LOCAL_SRC_FILES := YourSourceHere.cpp

Next, try to build the project, if you see an error from the compiler about the absence of Heather, check the correctness of the ways in Android.mk; if mistakes are kind of linker “undefined reference”, check the correctness of indications of source code files in assemblies ottreysit lists possible by specifying $ (info $ (FILE_LIST)) in Android.mk file. Do not forget the double-linking mechanism, with modules in LOCAL_SHARED_LIBRARIES key and correct linking through the LD, for example FSGL:


LOCAL_LDLIBS := -lEGL -lGLESv2

Adaptation And Launching

I had to change some things, for example to remove GLEW of assemblies for iOS and Android, to rename part of OpenGL calls, adding a suffix EOS (glGenVertexArrays -> glGenVertexArraysOES), include macro missing modernistic features debug, the cherry on the cake is the implicit include vulnerability GLES2 Heather indicating macro GL_GLEXT_PROTOTYPES 1 :


#define GL_GLEXT_PROTOTYPES 1
#include "SDL_opengles2.h"

Also, a black screen in the first starts with an error type “E / libEGL: validate_display: 255 error 3008 (EGL_BAD_DISPLAY)”, has changed initialize SDL window, GL profile initialization and it worked:


SDL_DisplayMode mode;
SDL_GetDisplayMode(0,0,&mode);
int width = mode.w;
int height = mode.h;

window = SDL_CreateWindow(
            title,
            0,
            0,
            width,
            height,
            SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE
        );

SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES );

On the default emulator application is installed with the “Game” icon SDL and name.

I needed to explore the possibility of automatically generating assembly files based on CMake, or else migrate assembly for all platforms on Gradle; CMake but remains the de facto choice for the current development in C++.

Source Code

https://gitlab.com/demensdeum/android-sdl-test-app
https://gitlab.com/demensdeum/android-sdl-test-app/tree/master/cube-art-project-android

Sources

https://developer.android.com/ndk/guides/cpp-support.html
https://developer.android.com/ndk/guides/application_mk
https://developer.android.com/ndk/guides/android_mk
https://lazyfoo.net/tutorials/SDL/52_hello_mobile/android_windows/index.php
https://medium.com/androiddevelopers/getting-started-with-c-and-android-native-activities-2213b402ffff

SDL2 – OpenGL ES

I love Panda3D game engine. But right now this engine is very hard to compile and debug on Microsoft Windows operation system. So as I said some time ago, I begin to develop my own graphics library. Right now it’s based on OpenGL ES and SDL2.
In this article I am going to tell how to initialize OpenGL ES context and how SDL2 helps in this task. We are going to show nothing.

King Nothing

First of all you need to install OpenGL ES3 – GLES 3 libraries. This operation is platform dependant, for Ubuntu Linux you can just type sudo apt-get install libgles2-mesa-dev. To work with OpenGL you need to initialize OpenGL context. There is many ways to do that, by using one of libraries – SDL2, GLFW, GLFM etc. Actually there is no one right way to initialize OpenGL context, but I chose SDL2 because it’s cross-platform solution, code will look same for Windows/*nix/HTML5/iOS/Android/etc.

To install sdl2 on Ubuntu use this command sudo apt-get install libsdl2-dev

So here is OpenGL context initialization code with SDL2:

    SDL_Window *window = SDL_CreateWindow(
            "SDL2 - OGLES",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            640,
            480,
            SDL_WINDOW_OPENGL
            );
	    

    SDL_GLContext glContext = SDL_GL_CreateContext(window);

After that, you can use any OpenGL calls in that context.

Here is example code for this article:
https://github.com/demensdeum/OpenGLES3-Experiments/tree/master/3sdl-gles
https://github.com/demensdeum/OpenGLES3-Experiments/blob/master/3sdl-gles/sdlgles.cpp

You can build and test it with command cmake . && make && ./SDLGles