{"id":2502,"date":"2020-01-12T11:47:43","date_gmt":"2020-01-12T08:47:43","guid":{"rendered":"http:\/\/demensdeum.com\/blog\/?p=2502"},"modified":"2024-12-16T22:32:30","modified_gmt":"2024-12-16T19:32:30","slug":"porting-cpp-sdl-app-on-android","status":"publish","type":"post","link":"https:\/\/demensdeum.com\/blog\/pt\/2020\/01\/12\/porting-cpp-sdl-app-on-android\/","title":{"rendered":"Portando um aplicativo C++ SDL para Android"},"content":{"rendered":"<p>Neste post descreverei minha experi\u00eancia de portar um prot\u00f3tipo de editor 3D <a href=\"https:\/\/gitlab.com\/demensdeum\/cube-art-project-bootstrap\" target=\"_blank\" rel=\" noopener noreferrer\">Cube Art Project<\/a>no Android.<br \/>Primeiro, vejamos o resultado; um editor com um cursor de cubo 3D vermelho est\u00e1 sendo executado no emulador:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-2509\" src=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2020\/01\/emulator.png\" alt=\"\" width=\"460\" height=\"265\" srcset=\"https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2020\/01\/emulator.png 959w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2020\/01\/emulator-300x173.png 300w, https:\/\/demensdeum.com\/blog\/wp-content\/uploads\/2020\/01\/emulator-768x442.png 768w\" sizes=\"auto, (max-width: 460px) 100vw, 460px\" \/><\/p>\n<p>Para uma montagem bem-sucedida, voc\u00ea deve fazer o seguinte:<\/p>\n<ol>\n<li>Instale o Android SDK e o NDK mais recentes (quanto mais recente a vers\u00e3o do NDK, melhor).<\/li>\n<li>Baixe o c\u00f3digo-fonte do SDL2 e pegue o modelo de l\u00e1 para construir o aplicativo Android.<\/li>\n<li>Adicione imagem SDL e misturador SDL \u00e0 montagem.<\/li>\n<li>Adicionar as bibliotecas do meu mecanismo de jogo e kit de ferramentas, suas depend\u00eancias (GLM, JSON para C++ moderno)<\/li>\n<li>Adaptar arquivos assembly para Gradle.<\/li>\n<li>Adaptar c\u00f3digo C++ para compatibilidade com Android, altera\u00e7\u00f5es nos componentes dependentes da plataforma afetados (OpenGL ES, inicializa\u00e7\u00e3o de contexto gr\u00e1fico)<\/li>\n<li>Crie e teste o projeto no emulador.<\/li>\n<\/ol>\n<h3>Modelo de projeto<\/h3>\n<p>Carregando fontes SDL, SDL Image, SDL Mixer:<br \/><a href=\"https:\/\/www.libsdl.org\/download-2.0.php\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/www.libsdl.org\/download-2.0.php<\/a><br \/>\nA pasta docs cont\u00e9m instru\u00e7\u00f5es detalhadas para trabalhar com o modelo de projeto Android; copie o diret\u00f3rio android-project para uma pasta separada, crie um link simb\u00f3lico ou copie a pasta SDL para android-project\/app\/jni.<br \/>Substitu\u00edmos o identificador correto pelo sinalizador avd, iniciamos o emulador Android no diret\u00f3rio Sdk:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>cd ~\/Android\/Sdk\/emulator\n.\/emulator -avd Pixel_2_API_24\n\n<\/code><\/pre>\n<\/div>\n<p>Especifique os caminhos no script, monte o projeto:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>rm -rf app\/build || true\nexport ANDROID_HOME=\/home\/demensdeum\/Android\/Sdk\/\nexport ANDROID_NDK_HOME=\/home\/demensdeum\/Android\/android-ndk-r21-beta2\/\n.\/gradlew clean build\n.\/gradlew installDebug\n\n<\/code><\/pre>\n<\/div>\n<p>O modelo de projeto SDL com c\u00f3digo C do arquivo deve ser montado<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>android-sdl-test-app\/cube-art-project-android\/app\/jni\/src\/YourSourceHere.c\n\n<\/code><\/pre>\n<\/div>\n<h3>Depend\u00eancias<\/h3>\n<p>Baixe o c\u00f3digo-fonte em arquivos para SDL_image, SDL_mixer:<br \/><a href=\"https:\/\/www.libsdl.org\/projects\/SDL_image\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/www.libsdl.org\/projects\/SDL_image\/<\/a><br \/>\n<a href=\"https:\/\/www.libsdl.org\/projects\/SDL_mixer\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/www.libsdl.org\/projects\/SDL_mixer\/<\/a><\/p>\n<p>Carregando as depend\u00eancias do seu projeto, por exemplo minhas bibliotecas compartilhadas:<br \/><a href=\"https:\/\/gitlab.com\/demensdeum\/FlameSteelCore\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FlameSteelCore\/<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/FlameSteelCommonTraits\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FlameSteelCommonTraits<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/FlameSteelBattleHorn\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FlameSteelBattleHorn<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/FlameSteelEngineGameToolkit\/\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FlameSteelEngineGameToolkit\/<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/FlameSteelEngineGameToolkitFSGL\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FlameSteelEngineGameToolkitFSGL<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/FSGL\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/FSGL<\/a><br \/>\n<a href=\"https:\/\/gitlab.com\/demensdeum\/cube-art-project\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/cube-art-project<\/a><\/p>\n<p>Fazemos upload de tudo isso para app\/jni, cada \u201cm\u00f3dulo\u201d em uma pasta separada, por exemplo app\/jni\/FSGL. A seguir, voc\u00ea tem a op\u00e7\u00e3o de encontrar geradores funcionais para os arquivos Application.mk e Android.mk, n\u00e3o os encontrei, mas talvez haja uma solu\u00e7\u00e3o simples baseada no CMake. Siga os links e comece a se familiarizar com o formato de arquivo assembly para Android NDK:<br \/><a href=\"https:\/\/developer.android.com\/ndk\/guides\/application_mk\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ndk\/guides\/application_mk<\/a><br \/>\n<a href=\"https:\/\/developer.android.com\/ndk\/guides\/android_mk\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ndk\/guides\/android_mk<\/a><\/p>\n<p>Voc\u00ea tamb\u00e9m deve ler sobre diferentes implementa\u00e7\u00f5es de APP_STL no NDK:<br \/><a href=\"https:\/\/developer.android.com\/ndk\/guides\/cpp-support.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ndk\/guides\/cpp-support.html<\/a><\/p>\n<p>Ap\u00f3s a familiariza\u00e7\u00e3o, criamos um arquivo Android.mk para cada \u201cm\u00f3dulo\u201d, seguido de um exemplo de arquivo assembly da biblioteca compartilhada Cube-Art-Project:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>LOCAL_PATH := $(call my-dir)\ninclude $(CLEAR_VARS)\n\nAPP_STL := c++_static\nAPP_CPPFLAGS := -fexceptions\nLOCAL_MODULE := CubeArtProject\nLOCAL_C_INCLUDES := $(LOCAL_PATH)\/src $(LOCAL_PATH)\/..\/include $(LOCAL_PATH)\/..\/include\/FlameSteelCommonTraits\/src\/FlameSteelCommonTraits\nLOCAL_EXPORT_C_INCLUDES = $(LOCAL_PATH)\/src\/\n\ndefine walk\n$(wildcard $(1)) $(foreach e, $(wildcard $(1)\/*), $(call walk, $(e)))\nendef\n\nALLFILES = $(call walk, $(LOCAL_PATH)\/src)\nFILE_LIST := $(filter %.cpp, $(ALLFILES))\n$(info CubeArtProject source code files list)\n$(info $(FILE_LIST))\nLOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)\/%=%)\n\nLOCAL_SHARED_LIBRARIES += FlameSteelCore\nLOCAL_SHARED_LIBRARIES += FlameSteelBattleHorn\nLOCAL_SHARED_LIBRARIES += FlameSteelCommonTraits\nLOCAL_SHARED_LIBRARIES += FlameSteelEngineGameToolkit\nLOCAL_SHARED_LIBRARIES += FlameSteelEngineGameToolkitFSGL\nLOCAL_SHARED_LIBRARIES += FSGL\nLOCAL_SHARED_LIBRARIES += SDL2\nLOCAL_SHARED_LIBRARIES += SDL2_image\n\nLOCAL_LDFLAGS := -static-libstdc++\ninclude $(BUILD_SHARED_LIBRARY)\n\n<\/code><\/pre>\n<\/div>\n<p>Qualquer usu\u00e1rio experiente do CMake entender\u00e1 essa configura\u00e7\u00e3o desde as primeiras linhas, os formatos s\u00e3o muito semelhantes, o Android.mk n\u00e3o possui GLOB_RECURSIVE, ent\u00e3o voc\u00ea deve procurar recursivamente os arquivos de origem usando a fun\u00e7\u00e3o walk.<\/p>\n<p>Alteramos Application.mk, Android.mk para criar c\u00f3digo C++ e n\u00e3o C:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>APP_ABI := armeabi-v7a arm64-v8a x86 x86_64\nAPP_PLATFORM=android-16\nAPP_STL := c++_static\nAPP_CPPFLAGS := -fexceptions\n\n<\/code><\/pre>\n<\/div>\n<p>Renomeie YourSourceHere.c -> YourSourceHere.cpp, fa\u00e7a grep nas entradas, altere o caminho na montagem, por exemplo:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>app\/jni\/src\/Android.mk:LOCAL_SRC_FILES := YourSourceHere.cpp\n\n<\/code><\/pre>\n<\/div>\n<p>Em seguida, tente construir o projeto, se voc\u00ea encontrar erros do compilador sobre a aus\u00eancia de cabe\u00e7alhos, verifique a exatid\u00e3o dos caminhos em Android.mk; Se houver erros do vinculador como \u201crefer\u00eancia indefinida\u201d, verifique se os arquivos de c\u00f3digo-fonte nos assemblies est\u00e3o especificados corretamente. As listas podem ser rastreadas especificando $(info $(FILE_LIST)) no arquivo Android.mk; N\u00e3o se esque\u00e7a do mecanismo de liga\u00e7\u00e3o dupla, usando m\u00f3dulos na chave LOCAL_SHARED_LIBRARIES e liga\u00e7\u00e3o correta atrav\u00e9s de LD, por exemplo para FSGL:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>LOCAL_LDLIBS := -lEGL -lGLESv2\n\n<\/code><\/pre>\n<\/div>\n<h3>Adapta\u00e7\u00e3o e lan\u00e7amento<\/h3>\n<p>Tive que mudar algumas coisas, por exemplo, remover o GLEW das compila\u00e7\u00f5es para iOS e Android, renomear algumas das chamadas OpenGL, adicionar o postfix EOS (glGenVertexArrays -> glGenVertexArraysOES), incluir uma macro para as fun\u00e7\u00f5es de depura\u00e7\u00e3o modernas ausentes , a cereja do bolo \u00e9 a inclus\u00e3o impl\u00edcita de cabe\u00e7alhos GLES2 indicando macro GL_GLEXT_PROTOTYPES 1:<\/p>\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>#define GL_GLEXT_PROTOTYPES 1\n#include \"SDL_opengles2.h\"\n\n<\/code><\/pre>\n<\/div>\n<p>Tamb\u00e9m observei uma tela preta nas primeiras inicializa\u00e7\u00f5es com um erro do tipo \u201cE\/libEGL: validar_display:255 erro 3008 (EGL_BAD_DISPLAY)\u201d, alterei a inicializa\u00e7\u00e3o da janela SDL, o perfil OpenGL e tudo funcionou:<\/p >\n<div class=\"hcb_wrap\">\n<pre class=\"prism line-numbers lang-unknown\" data-lang=\"unknown\"><code>SDL_DisplayMode mode;\nSDL_GetDisplayMode(0,0,&mode);\nint width = mode.w;\nint height = mode.h;\n\nwindow = SDL_CreateWindow(\n            title,\n            0,\n            0,\n            width,\n            height,\n            SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE\n        );\n\nSDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES );\n<\/code><\/pre>\n<\/div>\n<p>No emulador, o aplicativo \u00e9 instalado por padr\u00e3o com o \u00edcone SDL e o nome &#8220;Jogo&#8221;.<\/p>\n<p>S\u00f3 tenho que explorar a possibilidade de gerar automaticamente arquivos assembly baseados no CMake, ou migrar assemblies de todas as plataformas para Gradle; no entanto, o CMake continua sendo a escolha de fato para o desenvolvimento cont\u00ednuo de C++.<\/p>\n<h3>C\u00f3digo fonte<\/h3>\n<p><a href=\"https:\/\/gitlab.com\/demensdeum\/android-sdl-test-app\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/android- sdl-test-app<\/a><br \/><a href=\"https:\/\/gitlab.com\/demensdeum\/android-sdl-test-app\/tree\/master\/cube-art-project-android\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/gitlab.com\/demensdeum\/android-sdl-test-app\/tree\/master\/cube-art-project-android<\/a><\/p>\n<h3>Fontes<\/h3>\n<p><a href=\"https:\/\/developer.android.com\/ndk\/guides\/cpp-support.html\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ ndk\/guides\/cpp-support.html<\/a><br \/><a href=\"https:\/\/developer.android.com\/ndk\/guides\/application_mk\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ndk\/guides\/application_mk<\/a><br \/>\n<a href=\"https:\/\/developer.android.com\/ndk\/guides\/android_mk\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/developer.android.com\/ndk\/guides\/android_mk<\/a><br \/>\n<a href=\"https:\/\/lazyfoo.net\/tutorials\/SDL\/52_hello_mobile\/android_windows\/index.php\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/lazyfoo.net\/tutorials\/SDL\/52_hello_mobile\/android_windows\/index.php<\/a><br \/>\n<a href=\"https:\/\/medium.com\/androiddevelopers\/getting-started-with-c-and-android-native-activities-2213b402ffff\" target=\"_blank\" rel=\"noopener noreferrer\">https:\/\/medium.com\/androiddevelopers\/getting-started-with-c-and-android-native-activities-2213b402ffff<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neste post descreverei minha experi\u00eancia de portar um prot\u00f3tipo de editor 3D Cube Art Projectno Android.Primeiro, vejamos o resultado; um editor com um cursor de cubo 3D vermelho est\u00e1 sendo executado no emulador: Para uma montagem bem-sucedida, voc\u00ea deve fazer o seguinte: Instale o Android SDK e o NDK mais recentes (quanto mais recente a<a class=\"more-link\" href=\"https:\/\/demensdeum.com\/blog\/pt\/2020\/01\/12\/porting-cpp-sdl-app-on-android\/\">Continue reading <span class=\"screen-reader-text\">&#8220;Portando um aplicativo C++ SDL para Android&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[61,52],"tags":[37,124,145,146,77,147,148],"class_list":["post-2502","post","type-post","status-publish","format-standard","hentry","category-techie","category-tutorials","tag-android","tag-c","tag-cpp","tag-opengl-es","tag-sdl","tag-sdl-image","tag-sdl-mixer","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"pt","enabled_languages":["en","ru","zh","de","fr","ja","pt"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"ru":{"title":true,"content":true,"excerpt":false},"zh":{"title":true,"content":true,"excerpt":false},"de":{"title":true,"content":true,"excerpt":false},"fr":{"title":true,"content":true,"excerpt":false},"ja":{"title":true,"content":true,"excerpt":false},"pt":{"title":true,"content":true,"excerpt":false}}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2502","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=2502"}],"version-history":[{"count":31,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2502\/revisions"}],"predecessor-version":[{"id":3923,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/2502\/revisions\/3923"}],"wp:attachment":[{"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=2502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=2502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demensdeum.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=2502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}