Ogre 1.9 build for Android with standalone toolchain

Discussion of issues specific to mobile platforms such as iOS, Android, Symbian and Meego.
ayberkozgur
Gnoblar
Posts: 3
Joined: Wed Sep 17, 2014 5:29 pm
Location: Lausanne, Switzerland
x 2

Ogre 1.9 build for Android with standalone toolchain

Post by ayberkozgur »

I recently succeeded in building the SampleBrowser for Android with a standalone toolchain, i.e completely ndk-build-free. My goal in doing this is to install ogre binaries and headers into a standalone toolchain to be used alongside other similar libraries in a much larger project; ndk-build and regular ndks are really not suitable for this. This is tested on Ubuntu 14.04 with android-ndk-r9d with android-14 and OpenCV 3.0-ocl-tp2's android.toolchain.cmake. Any recent OpenCV toolchain file should work. The one in https://github.com/taka-no-me/android-cmake should also work. Steps are:
  1. Create a standalone toolchain (tweak the settings to your needs):

    Code: Select all

    /path-to-ndk-root/build/tools/make-standalone-toolchain.sh \
        --platform=android-14 \
        --install-dir=/target-path-to-standalone-toolchain \
        --toolchain=arm-linux-androideabi-4.8
    
    Be aware that if you don't have write access to the target path, the script will fail silently.
  2. Set the following environment vars (tweak the settings to your needs):

    Code: Select all

    export ANDROID_HOME=/path-to-android-sdk
    export ANDROID_SDK_ROOT=$ANDROID_HOME
    export ANDROID_SDK=$ANDROID_SDK_ROOT
    export ANDROID_STANDALONE_TOOLCHAIN=/path-to-standalone-toolchain
    export ANDROID_NDK_STANDALONE_TOOLCHAIN=$ANDROID_NDK_TOOLCHAIN
    export ANDROID_ABI=armeabi-v7a
    export ANDROID_NATIVE_API_LEVEL=14
    export ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.8
    export PATH=$ANDROID_STANDALONE_TOOLCHAIN/bin:$PATH
    
  3. Make sure that ANDROID_NDK environment variable is unset before proceeding. This is because the OpenCV toolchain looks for a regular NDK as soon as ANDROID_NDK is set. This results in ignoring the standalone toolchain.
  4. Get the AndroidDependencies (required for normal build) and extract them somewhere (not necessarily inside the ogre source directory).
  5. Copy everything except libstdc++.a and libsupc++.a in AndroidDependencies/lib/armeabi-v7a/ to /path-to-standalone-toolchain/sysroot/usr/lib
  6. Copy everything inside AndroidDependencies/include/ to /path-to-standalone-toolchain/sysroot/usr/include, BE CAREFUL zconf.h AND zlib.h ARE ALREADY THERE, DO NOT OVERWRITE BUT BACKUP THE OLD ONES FIRST.
  7. These are not copied to the standalone toolchain but we need them anyway:

    Code: Select all

    cp -r /path-to-ndk-root/sources /path-to-standalone-toolchain/sysroot/usr/share/ndk-sources
    
  8. The following header is searched by ogre inside the regular ndk so we must put a symlink to it inside the standalone toolchain's regular include path in order to not modify any other CMakeLists:

    Code: Select all

    ln -s /path-to-standalone-toolchain/sysroot/usr/share/ndk-sources/android/cpufeatures/cpu-features.h /path-to-standalone-toolchain/sysroot/usr/include/cpu-features.h
    
  9. Replace /path-to-ogre-src/Samples/Browser/CMakeLists.txt content with the following:

    Code: Select all

    #-------------------------------------------------------------------
    # This file is part of the CMake build system for OGRE
    #     (Object-oriented Graphics Rendering Engine)
    # For the latest info, see http://www.ogre3d.org/
    #
    # This file is modified to avoid using ndk-build.
    #
    # The contents of this file are placed in the public domain. Feel
    # free to make use of it in any way you like.
    #-------------------------------------------------------------------
    
    get_property(OGRE_SAMPLES_LIST GLOBAL PROPERTY "OGRE_SAMPLES_LIST")
    
    if (OGRE_STATIC)
            # Find all samples headers, and copy them to a single include folder
            # We do this instead of including every sample in the include_directories directive,
            # because this creates a list that is too long for the MSVC command line sometimes.
            file (GLOB SAMPLES_HEADERS ${OGRE_SOURCE_DIR}/Samples/*/include/*.h)
            foreach(SAMPLE_HEADER_FULLPATH ${SAMPLES_HEADERS})
                    get_filename_component(SAMPLE_HEADER_NAME ${SAMPLE_HEADER_FULLPATH} NAME)
                    configure_file(${SAMPLE_HEADER_FULLPATH} ${OGRE_BINARY_DIR}/Samples/include/${SAMPLE_HEADER_NAME} COPYONLY)
            endforeach(SAMPLE_HEADER_FULLPATH)
            include_directories(
                    ${CMAKE_CURRENT_SOURCE_DIR}/include
                    ${OGRE_BINARY_DIR}/Samples/include)
    
            ogre_add_component_include_dir(Paging)
            ogre_add_component_include_dir(Terrain)
            ogre_add_component_include_dir(Volume)
            ogre_add_component_include_dir(RTShaderSystem)
    else()
            include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
    endif()
    
    if(${ANDROID_NATIVE_API_LEVEL} LESS 14)
            MATH(EXPR ANDROID_SDK_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}+1")
    else()
            SET(ANDROID_SDK_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}")
            SET(SCREEN_SIZE "|screenSize")
    endif()
    
    SET(ANDROID_TARGET "android-${ANDROID_SDK_API_LEVEL}")
    
    #Prepare the Android project files
    SET(NDKOUT "${CMAKE_BINARY_DIR}/SampleBrowserNDK")
    file(MAKE_DIRECTORY "${NDKOUT}")
    file(MAKE_DIRECTORY "${NDKOUT}/assets")
    file(MAKE_DIRECTORY "${NDKOUT}/res")
    file(MAKE_DIRECTORY "${NDKOUT}/libs/${ANDROID_ABI}")
    file(WRITE "${NDKOUT}/default.properties" "target=${ANDROID_TARGET}")
    configure_file("${OGRE_TEMPLATES_DIR}/AndroidManifest.xml.in" "${NDKOUT}/AndroidManifest.xml" @ONLY)
    configure_file("${OGRE_TEMPLATES_DIR}/Android_resources.cfg.in" "${NDKOUT}/assets/resources.cfg" @ONLY)
    configure_file("${OGRE_TEMPLATES_DIR}/samples.cfg.in" "${NDKOUT}/assets/samples.cfg" @ONLY)
    
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/models" DESTINATION "${NDKOUT}/assets")
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/particle" DESTINATION "${NDKOUT}/assets")
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/RTShaderLib" DESTINATION "${NDKOUT}/assets")
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/thumbnails" DESTINATION "${NDKOUT}/assets")
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/packs" DESTINATION "${NDKOUT}/assets")
    file(COPY "${CMAKE_SOURCE_DIR}/Samples/Media/materials" DESTINATION "${NDKOUT}/assets")
    
    file(COPY "${CMAKE_SOURCE_DIR}/SDK/Android/drawable-hdpi" DESTINATION "${NDKOUT}/res")
    file(COPY "${CMAKE_SOURCE_DIR}/SDK/Android/drawable-ldpi" DESTINATION "${NDKOUT}/res")
    file(COPY "${CMAKE_SOURCE_DIR}/SDK/Android/drawable-mdpi" DESTINATION "${NDKOUT}/res")
    file(COPY "${CMAKE_SOURCE_DIR}/SDK/Android/drawable-xhdpi" DESTINATION "${NDKOUT}/res")
    
    #Prepare the build environment for the sample browser library
    include_directories("${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/share/ndk-sources/android/cpufeatures" "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/share/ndk-sources/android/native_app_glue")
    include_directories(${OGRE_SOURCE_DIR}/include)
    include_directories(${OGRE_SOURCE_DIR}/OgreMain/include)
    include_directories(${OGRE_SOURCE_DIR}/RenderSystems/GLES2/include)
    include_directories(${OGRE_SOURCE_DIR}/RenderSystems/GLES2/include/EGL)
    link_directories(${OGRE_BINARY_DIR}/lib)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s -DGL_GLEXT_PROTOTYPES=1 -fexceptions -frtti -D___ANDROID___ -DZZIP_OMIT_CONFIG_H -DINCLUDE_RTSHADER_SYSTEM=1")
    add_library(OgreSampleBrowser MODULE
            ${CMAKE_CURRENT_SOURCE_DIR}/src/SampleBrowser.cpp
            "$ENV{ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/share/ndk-sources/android/cpufeatures/cpu-features.c"
            "$ENV{ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/share/ndk-sources/android/native_app_glue/android_native_app_glue.c"
            )
    target_link_libraries(OgreSampleBrowser
            android log c dl
            EGL GLESv2 zzip z FreeImage freetype OIS
            Plugin_ParticleFXStatic Plugin_OctreeSceneManagerStatic RenderSystem_GLES2Static OgreRTShaderSystemStatic OgreOverlayStatic OgreTerrainStatic OgrePagingStatic OgreVolumeStatic OgreMainStatic
            ${OGRE_SAMPLES_LIST})
    add_dependencies(OgreSampleBrowser ${OGRE_SAMPLES_LIST})
    
    #Copy built lib to the android project's dynamic lib directory
    add_custom_command(
            TARGET OgreSampleBrowser
            POST_BUILD
            COMMAND cp libOgreSampleBrowser.so "${NDKOUT}/libs/${ANDROID_ABI}"
            WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/lib/
            )
    
    #Get build.xml in place so that we can use ant
    add_custom_command(
            TARGET OgreSampleBrowser
            POST_BUILD
            COMMAND "$ENV{ANDROID_SDK}/tools/android" update project --target ${ANDROID_TARGET} --path "${NDKOUT}"
            WORKING_DIRECTORY ${NDKOUT}
            )
    
    #Build apks with ant
    add_custom_command(
            TARGET OgreSampleBrowser
            POST_BUILD
            COMMAND ant debug
            WORKING_DIRECTORY ${NDKOUT}
            )
    
  10. Get the android.toolchain.cmake from somewhere. Ogre's toolchain file will not work as it does not look for standalone toolchains. Build with the following:

    Code: Select all

    mkdir build-android
    cd build-android
    cmake .. -DCMAKE_TOOLCHAIN_FILE=$OpenCV_DIR/android.toolchain.cmake
    make -j 5 OgreSampleBrowser
    
  11. If you are interested in this, please let me know if this worked for you. Also, let me know if building cpu-features and android_native_app_glue like this is a good idea, or is dangerous in some way. If this is safe, I think it would be a good addition to the wiki. Please let me know what you think.
bachnv
Gnoblar
Posts: 3
Joined: Fri Sep 19, 2014 9:10 am

Re: Ogre 1.9 build for Android with standalone toolchain

Post by bachnv »

Dear ayberkozgur,

Thank you very much for your greate work.
I also try to built OGRE from source code.
I follow bellow guide:
>http://www.ogre3d.org/forums/viewtopic.php?f=2&t=80802
However, when I use built lib in my project, I meet bellow error:

Code: Select all

in function RenderingThread::createRenderingWindow():jni/../../../Ogre/include/OgreMain/Android/OgreAPKZipArchive.h:43: error: undefined reference to 'Ogre::EmbeddedZipArchiveFactory::EmbeddedZipArchiveFactory()'
Do you now the cause, and have any solutions or suggestions?