在 Linux 上构建适用于 iOS 的 C++ SDL 应用程序

在这篇文章中,我将描述在 Linux 上为 iOS 构建 C++ SDL 应用程序的过程,在没有付费 Apple Developer 订阅的情况下签署 ipa 存档,以及在没有越狱的情况下使用 macOS 将其安装在干净的设备 (iPad) 上。< /p>

首先,让我们安装 Linux 的构建工具链:
https://github.com/tpoechtrager/cctools-port

需要从存储库下载工具链,然后按照Godot Engine网站上的说明完成安装:
https://docs.godotengine.org/ru/latest/development/compiling/cross-compiling_for_ios_on_linux.html

目前,您需要下载 Xcode dmg 并从那里复制 sdk 来构建 cctools-port。此阶段在 macOS 上更容易完成;只需从已安装的 Xcode 复制必要的 sdk 文件即可。成功编译后,终端将包含交叉编译器工具链的路径。

接下来您可以开始构建适用于 iOS 的 SDL 应用程序。让我们打开 cmake 并添加必要的更改来构建 C++ 代码:

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)

现在您可以使用 cmake 和 make 进行编译,但不要忘记将 $PATH 添加到交叉编译器工具链:


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

为了与框架和SDL正确链接,我们将它们编写在cmake中,例如游戏Space Jaguar的依赖项:


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"
)

就我而言,SDL、SDL_Image、SDL_mixer 库预先在 macOS 上的 Xcode 中编译以进行静态链接;从 Xcode 复制的框架。还添加了 libclang_rt.ios.a 库,其中包括特定于 iOS 的运行时调用,例如 isOSVersionAtLeast。包含一个用于 OpenGL ES 的宏,禁用移动版本中不支持的功能,类似于 Android。

解决所有构建问题后,您应该获得 ARM 的已组装二进制文件。接下来,让我们考虑在没有越狱的设备上运行组装的二进制文件。

在 macOS 上,安装 Xcode,在 Apple 门户上注册,无需支付开发者计划费用。在Xcode中添加帐户->首选项->帐户、创建空白应用程序并在真实设备上构建。在组装过程中,设备将被添加到免费的开发者帐户中。组装并启动后,您需要构建存档才能执行此操作,选择 Generic iOS Device and Product ->档案。构建存档后,从中提取embedded.mobileprovision和PkgInfo文件。从设备的构建日志中,找到具有正确签名密钥的 codesign 行、扩展名为 app.xcent 的授权文件的路径,将其复制。

从压缩包中复制.app文件夹,将压缩包中的二进制文件替换为Linux中交叉编译器编译的二进制文件(例如SpaceJaguar.app/SpaceJaguar),然后将必要的资源添加到.app中,检查存档中 .app 中的 PkgInfo 和Embedded.mobileprovision 文件的完整性,如有必要,请再次复制。我们使用协同设计命令 – 重新签名 .app codesign 需要输入密钥进行签名,即权利文件的路径(可以使用 .plist 扩展名重命名)

重新签名后,创建一个 Payload 文件夹,将扩展名为 .app 的文件夹移动到那里,在根目录中创建一个包含 Payload 的 zip 存档,并使用 .ipa 扩展名重命名该存档。之后,在 Xcode 中,打开设备列表并将新的 ipa 拖放到设备的应用程序列表中;通过 Apple Configurator 2 安装不适用于此方法。如果重新签名正确完成,则具有新二进制文件的应用程序将安装在具有 7 天证书的 iOS 设备(例如 iPad)上,这对于测试期来说足够了。

来源

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

将 C++ SDL 应用程序移植到 Android

在这篇文章中,我将描述我移植 3D 编辑器原型的经验 Android 上的 Cube Art Project
首先,让我们看看模拟器中运行的结果;带有红色 3D 立方体光标的编辑器:

为了成功组装,您必须执行以下操作:

  1. 安装最新的 Android SDK 和 NDK(NDK 版本越新越好)。
  2. 下载 SDL2 源代码,从那里获取模板来构建 Android 应用程序。
  3. 将 SDL Image、SDL Mixer 添加到程序集中。
  4. 添加我的游戏引擎和工具包的库及其依赖项(GLM、现代 C++ 的 JSON)
  5. 调整 Gradle 的程序集文件。
  6. 调整 C++ 代码以与 Android 兼容,更改受影响的平台相关组件(OpenGL ES、图形上下文初始化)
  7. 在模拟器上构建并测试项目。

项目模板

加载源SDL、SDL Image、SDL Mixer:
https://www.libsdl.org/download-2.0.php
docs 文件夹包含使用 android 项目模板的详细说明;将 android-project 目录复制到单独的文件夹,创建符号链接或将 SDL 文件夹复制到 android-project/app/jni。
我们用正确的标识符替换 avd 标志,从 Sdk:

目录启动 android 模拟器

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

在脚本中指定路径,组装项目:

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

应使用文件中的 C 代码组装 SDL 项目模板

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

依赖项

下载SDL_image、SDL_mixer的源代码:
https://www.libsdl.org/projects/SDL_image/
https://www.libsdl.org/projects/SDL_mixer/

加载项目的依赖项,例如我的共享库:
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

我们将所有这些上传到 app/jni,每个“模块”放入一个单独的文件夹,例如 app/jni/FSGL。接下来,您可以选择查找 Application.mk 和 Android.mk 文件的工作生成器,我没有找到它们,但也许有一个基于 CMake 的简单解决方案。点击链接并开始熟悉 Android NDK 的程序集文件格式:
https://developer.android.com/ndk/guides/application_mk
https://developer.android.com/ndk/guides/android_mk

您还应该了解 NDK 中不同的 APP_STL 实现:
https://developer.android.com/ndk/guides/cpp-support.html

熟悉后,我们为每个“模块”创建一个 Android.mk 文件,然后是共享库 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 用户都会从第一行开始理解这个配置,格式非常相似,Android.mk 缺少 GLOB_RECURSIVE,所以你必须使用 walk 函数递归搜索源文件。

我们更改 Application.mk、Android.mk 来构建 C++ 而不是 C 代码:

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

重命名YourSourceHere.c -> YourSourceHere.cpp,grep条目,更改程序集中的路径,例如:

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

接下来,尝试构建项目,如果编译器看到缺少标头的错误,请检查 Android.mk 中路径的正确性;如果链接器出现“未定义引用”等错误,请检查程序集中的源代码文件是否指定正确;可以通过在 Android.mk 文件中指定 $(info $(FILE_LIST)) 来跟踪列表。不要忘记双重链接机制,使用 LOCAL_SHARED_LIBRARIES 键中的模块并通过 LD 进行正确链接,例如 FSGL:

LOCAL_LDLIBS := -lEGL -lGLESv2

适应和启动

我必须改变一些东西,例如,从 iOS 和 Android 的构建中删除 GLEW,重命名一些 OpenGL 调用,添加 EOS 后缀(glGenVertexArrays -> glGenVertexArraysOES),包含用于缺少的现代调试功能的宏,锦上添花的是隐式包含指示宏的 GLES2 标头GL_GLEXT_PROTOTYPES 1:

#define GL_GLEXT_PROTOTYPES 1
#include "SDL_opengles2.h"

我还观察到第一次启动时出现黑屏,并出现类似“E/libEGL: validate_display:255 error 3008 (EGL_BAD_DISPLAY)”的错误,更改了 SDL 窗口的初始化、OpenGL 配置文件,一切正常:

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 );

在模拟器上,应用程序默认安装为 SDL 图标和名称“Game”。

我只需探索基于CMake自动生成程序集文件的可能性,或者将所有平台的程序集迁移到Gradle即可;然而,CMake 仍然是正在进行的 C++ 开发的事实上的选择。

源代码

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

来源

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