在 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

共享库 CMake C++

我最近决定将 FlameSteelFramework 的所有部分设为单独的共享库,然后我将展示 FlameSteelCore

cmake_minimum_required(VERSION 3.5)

project (FlameSteelCore)
set(CMAKE_BUILD_TYPE Release)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)

file(GLOB_RECURSE SOURCE_FILES
    "src/FlameSteelCore/*.cpp"
)

add_library(FlameSteelCore SHARED ${SOURCE_FILES})

install(DIRECTORY "${CMAKE_SOURCE_DIR}/src/FlameSteelCore"
        DESTINATION include/FlameSteelFramework
        FILES_MATCHING
        PATTERN "*.h"
)

install(TARGETS FlameSteelCore DESTINATION lib)

CMake 执行的命令:将 src/FlameSteelCore/ 目录中所有带有 *.cpp 扩展名的文件收集到共享库中,将 src/FlameSteelCore 中带有 *.h 扩展名的所有标头复制到 include/FlameSteelFramework (在我的例子中)这是/usr/local/include/FlameSteelFramework),将共享lib复制到lib目录(/usr/local/lib)
安装后,可能需要更新LD缓存– sudo ldconfig。
要在 Ubuntu 上构建并安装(如果您有正确的构建工具链),只需运行以下命令:

cmake . && make && sudo make install

为了测试安装过程,我将 make 前缀传递到本地文件夹 makeInstallTestPlayground:

cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/demensdeum/makeInstallTestPlayground . && make && make install

参考文献

https: //stackoverflow.com/questions/17511496/how-to-create-a-shared-library-with-cmake
https://stackoverflow.com/questions/6003374/what-is-cmake-equivalent-of-configure-prefix-dir-make-all-install