Spaces:
Sleeping
Sleeping
File size: 10,578 Bytes
739258a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
if(NOT ANDROID_PACKAGE_NAME)
set(ANDROID_PACKAGE_NAME "com.github.stevenlovegrove.pangolin")
endif()
if(NOT ANDROID_DEFERRED_ENTRY_SO)
set(ANDROID_DEFERRED_ENTRY_SO "libpangolin.so")
endif()
# Configure build environment to automatically generate APK's instead of executables.
if(ANDROID AND NOT TARGET apk)
# virtual targets which we'll add apks and push actions to.
add_custom_target( apk )
add_custom_target( push )
add_custom_target( run )
# Reset output directories to be in binary folder (rather than source)
set(LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME})
macro( create_android_manifest_xml filename prog_name package_name activity_name)
file( WRITE ${filename}
"<?xml version=\"1.0\" encoding=\"utf-8\"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"
package=\"${package_name}.${prog_name}\"
android:versionCode=\"1\"
android:versionName=\"1.0\">
<!-- This is the platform API where NativeActivity was introduced. -->
<uses-sdk android:minSdkVersion=\"14\" />
<uses-feature android:glEsVersion=\"0x00020000\" />
<uses-feature android:name=\"android.hardware.camera\" />
<uses-permission android:name=\"android.permission.CAMERA\"/>
<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>
<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>
<!-- This .apk has no Java code itself, so set hasCode to false. -->
<application android:label=\"${activity_name}\" android:hasCode=\"false\">
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name=\"android.app.NativeActivity\"
android:label=\"${activity_name}\"
android:screenOrientation=\"landscape\"
android:configChanges=\"orientation|keyboard|keyboardHidden\"
android:theme=\"@android:style/Theme.NoTitleBar.Fullscreen\"
>
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name=\"android.app.lib_name\"
android:value=\"${prog_name}_start\" />
<intent-filter>
<action android:name=\"android.intent.action.MAIN\" />
<category android:name=\"android.intent.category.LAUNCHER\" />
</intent-filter>
</activity>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->" )
endmacro()
macro( create_bootstrap_library prog_name package_name)
set(bootstrap_cpp "${CMAKE_CURRENT_BINARY_DIR}/${prog_name}_start.cpp" )
file( WRITE ${bootstrap_cpp}
"#include <android/native_activity.h>
#include <android/log.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <cstdio>
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, \"AndroidUtils.cmake\", __VA_ARGS__))
#define LIB_PATH \"/data/data/${package_name}.${prog_name}/lib/\"
void * load_lib(const char * l) {
void * handle = dlopen(l, RTLD_NOW | RTLD_GLOBAL);
if (!handle) LOGE( \"dlopen('%s'): %s\", l, strerror(errno) );
return handle;
}
void ANativeActivity_onCreate(ANativeActivity * app, void * ud, size_t udsize) {
#include \"${prog_name}_shared_load.h\"
// Look for standard entrypoint in user lib
void (*stdentrypoint)(ANativeActivity*, void*, size_t);
*(void **) (&stdentrypoint) = dlsym(load_lib( LIB_PATH \"lib${prog_name}.so\"), \"ANativeActivity_onCreate\");
if (stdentrypoint) {
(*stdentrypoint)(app, ud, udsize);
}else{
// Look for deferred load entry point
void (*exdentrypoint)(ANativeActivity*, void*, size_t, const char*);
*(void **) (&exdentrypoint) = dlsym(load_lib( LIB_PATH \"lib${prog_name}.so\"), \"DeferredNativeActivity_onCreate\");
if (!exdentrypoint) {
// Look in specific shared lib
*(void **) (&exdentrypoint) = dlsym(load_lib( LIB_PATH \"${ANDROID_DEFERRED_ENTRY_SO}\"), \"DeferredNativeActivity_onCreate\");
}
if(exdentrypoint) {
(*exdentrypoint)(app, ud, udsize, LIB_PATH \"lib${prog_name}.so\" );
}else{
LOGE( \"Unable to find compatible entry point\" );
}
}
}" )
add_library( "${prog_name}_start" SHARED ${bootstrap_cpp} )
target_link_libraries( "${prog_name}_start" android log )
add_dependencies( ${prog_name} "${prog_name}_start" )
endmacro()
macro( android_update android_project_name)
# Find which android platforms are available.
execute_process(
COMMAND android list targets -c
OUTPUT_VARIABLE android_target_list
)
# Pick first platform from this list.
string(REGEX MATCH "^[^\n]+" android_target "${android_target_list}" )
message(STATUS "Android Target: ${android_target}")
if( NOT "${android_target}" STREQUAL "" )
# Generate ant build scripts for making APK
execute_process(
COMMAND android update project --name ${android_project_name} --path . --target ${android_target} --subprojects
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
else()
message( FATAL_ERROR "No Android SDK platforms found. Please install an Android platform SDK. On Linux, run 'android'." )
endif()
endmacro()
# Override add_executable to build android .so instead!
macro( add_executable prog_name)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libs/${ANDROID_NDK_ABI_NAME})
add_library( ${prog_name} SHARED ${ARGN} )
# Add required link libs for android
target_link_libraries(${prog_name} log android )
# Create manifest required for APK
create_android_manifest_xml(
"${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml" "${prog_name}"
"${ANDROID_PACKAGE_NAME}" "${prog_name}"
)
# Create library that will launch this program and load shared libs
create_bootstrap_library( ${prog_name} ${ANDROID_PACKAGE_NAME} )
# Generate ant build system for APK
android_update( ${prog_name} )
# Target to invoke ant build system for APK
set( APK_FILE "${CMAKE_CURRENT_BINARY_DIR}/bin/${prog_name}-debug.apk" )
add_custom_command(
OUTPUT ${APK_FILE}
COMMAND ant debug
DEPENDS ${prog_name}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
# Target to install on device
add_custom_target( ${prog_name}-apk
DEPENDS ${APK_FILE}
)
add_dependencies(apk ${prog_name}-apk)
# Target to install on device
add_custom_target( ${prog_name}-push
COMMAND adb install -r ${APK_FILE}
DEPENDS ${APK_FILE}
)
add_dependencies(push ${prog_name}-push)
# install and run on device
add_custom_target( ${prog_name}-run
COMMAND adb shell am start -n ${ANDROID_PACKAGE_NAME}.${prog_name}/android.app.NativeActivity
DEPENDS ${prog_name}-push
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
add_dependencies(run ${prog_name}-run)
# Flag to package dependent libs
set_property(TARGET ${prog_name} APPEND PROPERTY MAKE_APK 1 )
# Clear shared library loading header
file( WRITE "${CMAKE_CURRENT_BINARY_DIR}/${prog_name}_shared_load.h" "")
endmacro()
macro( package_with_target prog_name lib_path )
# Mark lib_path as dependent of prog_name
set_property(TARGET ${prog_name} APPEND PROPERTY IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE ${lib_path} )
# If prog_name is to be packaged, add file copy command to package .so's.
get_target_property( package_dependent_libs ${prog_name} MAKE_APK )
if( package_dependent_libs )
get_filename_component(target_filename ${lib_path} NAME)
file( APPEND ${depend_file} "load_lib(LIB_PATH \"${target_filename}\" );\n")
add_custom_command(TARGET ${prog_name} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${lib_path} "${CMAKE_CURRENT_BINARY_DIR}/libs/${ANDROID_NDK_ABI_NAME}/"
)
endif()
endmacro()
macro( add_to_depend_libs prog_name depend_file lib_name )
# Recursively Process dependents of lib_name
get_target_property(TARGET_LIBS ${lib_name} IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE)
if(NOT TARGET_LIBS)
get_target_property(TARGET_LIBS ${lib_name} IMPORTED_LINK_INTERFACE_LIBRARIES_NOCONFIG)
endif()
if(NOT TARGET_LIBS)
get_target_property(TARGET_LIBS ${lib_name} IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG)
endif()
foreach(SUBLIB ${TARGET_LIBS})
if(SUBLIB)
add_to_depend_libs( ${prog_name} ${depend_file} ${SUBLIB} )
endif()
endforeach()
# Check if lib itself is an external shared library
if("${lib_name}" MATCHES "\\.so$")
package_with_target( ${prog_name} ${lib_name} )
endif()
# Check if lib itself is an internal shared library
get_target_property(TARGET_LIB ${lib_name} LOCATION)
if("${TARGET_LIB}" MATCHES "\\.so$")
package_with_target( ${prog_name} ${TARGET_LIB} )
endif()
endmacro()
macro( target_link_libraries prog_name)
# _target_link_libraries corresponds to original
_target_link_libraries( ${prog_name} ${ARGN} )
# Recursively process dependencies
set(depend_file "${CMAKE_CURRENT_BINARY_DIR}/${prog_name}_shared_load.h" )
foreach( LIB ${ARGN} )
add_to_depend_libs( ${prog_name} ${depend_file} ${LIB} )
endforeach()
endmacro()
endif()
|