Skip to content

Commit

Permalink
Merge pull request opencv#11200 from alalek:android_refactor_sdk_dete…
Browse files Browse the repository at this point in the history
…ction
  • Loading branch information
alalek committed Apr 5, 2018
2 parents a87a5df + 6abfc67 commit 875b4e2
Show file tree
Hide file tree
Showing 6 changed files with 343 additions and 141 deletions.
48 changes: 33 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ OCV_OPTION(WITH_ITT "Include Intel ITT support" ON
OCV_OPTION(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" NOT (ANDROID OR APPLE_FRAMEWORK) )
OCV_OPTION(BUILD_opencv_apps "Build utility applications (used for example to train classifiers)" (NOT ANDROID AND NOT WINRT) IF (NOT APPLE_FRAMEWORK) )
OCV_OPTION(BUILD_opencv_js "Build JavaScript bindings by Emscripten" OFF )
OCV_OPTION(BUILD_ANDROID_PROJECTS "Build Android projects providing .apk files" ON IF ANDROID )
OCV_OPTION(BUILD_ANDROID_EXAMPLES "Build examples for Android platform" ON IF ANDROID )
OCV_OPTION(BUILD_DOCS "Create build rules for OpenCV Documentation" OFF IF (NOT WINRT AND NOT APPLE_FRAMEWORK))
OCV_OPTION(BUILD_EXAMPLES "Build all examples" OFF )
Expand Down Expand Up @@ -644,14 +645,10 @@ include(cmake/OpenCVFindProtobuf.cmake)

# --- Java Support ---
if(BUILD_JAVA)
include(cmake/OpenCVDetectApacheAnt.cmake)
if(ANDROID)
include(cmake/OpenCVDetectAndroidSDK.cmake)

if(NOT ANDROID_TOOLS_Pkg_Revision GREATER 13)
message(WARNING "OpenCV requires Android SDK tools revision 14 or newer. Otherwise tests and samples will no be compiled.")
endif()
include(cmake/android/OpenCVDetectAndroidSDK.cmake)
else()
include(cmake/OpenCVDetectApacheAnt.cmake)
find_package(JNI)
endif()
endif()
Expand Down Expand Up @@ -1083,18 +1080,39 @@ status(" Non-free algorithms:" OPENCV_ENABLE_NONFREE THEN "YES" ELSE "NO")
# ========================== Android details ==========================
if(ANDROID)
status("")
status(" Android: ")
if(DEFINED ANDROID_NDK_REVISION)
set(__msg "${ANDROID_NDK} (ver ${ANDROID_NDK_REVISION})")
else()
set(__msg "location: ${ANDROID_NDK}")
endif()
status(" Android NDK: " ${__msg})
status(" Android ABI:" ${ANDROID_ABI})
if(BUILD_WITH_STANDALONE_TOOLCHAIN)
status(" NDK toolchain:" "standalone: ${ANDROID_STANDALONE_TOOLCHAIN}")
elseif(BUILD_WITH_ANDROID_NDK OR DEFINED ANDROID_TOOLCHAIN_NAME)
status(" NDK toolchain:" "${ANDROID_TOOLCHAIN_NAME}")
endif()
status(" STL type:" ${ANDROID_STL})
status(" Native API level:" android-${ANDROID_NATIVE_API_LEVEL})
android_get_compatible_target(android_sdk_target_status ${ANDROID_NATIVE_API_LEVEL} ${ANDROID_SDK_TARGET} 11)
status(" SDK target:" "${android_sdk_target_status}")
if(BUILD_WITH_ANDROID_NDK)
status(" Android NDK:" "${ANDROID_NDK} (toolchain: ${ANDROID_TOOLCHAIN_NAME})")
elseif(BUILD_WITH_STANDALONE_TOOLCHAIN)
status(" Android toolchain:" "${ANDROID_STANDALONE_TOOLCHAIN}")
status(" Native API level:" ${ANDROID_NATIVE_API_LEVEL})

if(BUILD_ANDROID_PROJECTS)
status(" Android SDK: " "${ANDROID_SDK} (tools: ${ANDROID_SDK_TOOLS_VERSION} build tools: ${ANDROID_SDK_BUILD_TOOLS_VERSION})")
if(ANDROID_EXECUTABLE)
status(" android tool:" "${ANDROID_EXECUTABLE}")
endif()
else()
status(" Android SDK: " "not used, projects are not built")
endif()
if(DEFINED ANDROID_SDK_COMPATIBLE_TARGET)
status(" SDK target:" "${ANDROID_SDK_COMPATIBLE_TARGET}")
endif()
if(DEFINED ANDROID_PROJECTS_BUILD_TYPE)
if(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "ANT")
status(" Projects build scripts:" "Ant/Eclipse compatible")
elseif(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "ANT")
status(" Projects build scripts:" "Gradle")
endif()
endif()
status(" android tool:" ANDROID_EXECUTABLE THEN "${ANDROID_EXECUTABLE} (${ANDROID_TOOLS_Pkg_Desc})" ELSE NO)
endif()

# ================== Windows RT features ==================
Expand Down
55 changes: 55 additions & 0 deletions cmake/OpenCVUtils.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,61 @@ macro(ocv_path_join result_var P1 P2_)
#message(STATUS "'${P1}' '${P2_}' => '${${result_var}}'")
endmacro()


# Used to parse Android SDK 'source.properties' files
# File lines format:
# - '<var_name>=<value>' (with possible 'space' symbols around '=')
# - '#<any comment>'
# Parsed values are saved into CMake variables:
# - '${var_prefix}_${var_name}'
# Flags:
# - 'CACHE_VAR <var1> <var2>' - put these properties into CMake internal cache
# - 'MSG_PREFIX <msg>' - prefix string for emitted messages
# - flag 'VALIDATE' - emit messages about missing values from required cached variables
# - flag 'WARNING' - emit CMake WARNING instead of STATUS messages
function(ocv_parse_properties_file file var_prefix)
cmake_parse_arguments(PARSE_PROPERTIES_PARAM "VALIDATE;WARNING" "" "CACHE_VAR;MSG_PREFIX" ${ARGN})

set(__msg_type STATUS)
if(PARSE_PROPERTIES_PARAM_WARNING)
set(__msg_type WARNING)
endif()

if(EXISTS "${file}")
set(SOURCE_PROPERTIES_REGEX "^[ ]*([^=:\n\"' ]+)[ ]*=[ ]*(.*)$")
file(STRINGS "${file}" SOURCE_PROPERTIES_LINES REGEX "^[ ]*[^#].*$")
foreach(line ${SOURCE_PROPERTIES_LINES})
if(line MATCHES "${SOURCE_PROPERTIES_REGEX}")
set(__name "${CMAKE_MATCH_1}")
set(__value "${CMAKE_MATCH_2}")
string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" __name ${__name})
if(";${PARSE_PROPERTIES_PARAM_CACHE_VAR};" MATCHES ";${__name};")
set(${var_prefix}_${__name} "${__value}" CACHE INTERNAL "from ${file}")
else()
set(${var_prefix}_${__name} "${__value}" PARENT_SCOPE)
endif()
else()
message(${__msg_type} "${PARSE_PROPERTIES_PARAM_MSG_PREFIX}Can't parse source property: '${line}' (from ${file})")
endif()
endforeach()
if(PARSE_PROPERTIES_PARAM_VALIDATE)
set(__missing "")
foreach(__name ${PARSE_PROPERTIES_PARAM_CACHE_VAR})
if(NOT DEFINED ${var_prefix}_${__name})
list(APPEND __missing ${__name})
endif()
endforeach()
if(__missing)
message(${__msg_type} "${PARSE_PROPERTIES_PARAM_MSG_PREFIX}Can't read properties '${__missing}' from '${file}'")
endif()
endif()
else()
message(${__msg_type} "${PARSE_PROPERTIES_PARAM_MSG_PREFIX}Can't find file: ${file}")
endif()
endfunction()



# rename modules target to world if needed
macro(_ocv_fix_target target_var)
if(BUILD_opencv_world)
Expand Down
210 changes: 210 additions & 0 deletions cmake/android/OpenCVDetectAndroidSDK.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
if(EXISTS "${ANDROID_EXECUTABLE}")
set(ANDROID_SDK_DETECT_QUIET TRUE)
endif()

# fixup for https://github.com/android-ndk/ndk/issues/596
if(DEFINED ANDROID_NDK_REVISION AND ANDROID_NDK_REVISION MATCHES "(1[56])([0-9]+)\\.([^\n]+)\n")
set(ANDROID_NDK_REVISION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
set(ANDROID_NDK_REVISION "${ANDROID_NDK_REVISION}" CACHE INTERNAL "Android NDK revision")
endif()

# https://developer.android.com/studio/command-line/variables.html
ocv_check_environment_variables(ANDROID_SDK_ROOT ANDROID_HOME ANDROID_SDK)

set(__msg_BUILD_ANDROID_PROJECTS "Use BUILD_ANDROID_PROJECTS=OFF to prepare Android project files without building them")

macro(ocv_detect_android_sdk)
if(NOT DEFINED ANDROID_SDK)
if(DEFINED ANDROID_SDK AND EXISTS "${ANDROID_SDK}")
set(ANDROID_SDK "${ANDROID_SDK}" CACHE INTERNAL "Android SDK path")
elseif(DEFINED ANDROID_HOME AND EXISTS "${ANDROID_HOME}")
set(ANDROID_SDK "${ANDROID_HOME}" CACHE INTERNAL "Android SDK path")
elseif(DEFINED ANDROID_SDK_ROOT AND EXISTS "${ANDROID_SDK_ROOT}")
set(ANDROID_SDK "${ANDROID_SDK_ROOT}" CACHE INTERNAL "Android SDK path")
endif()
if(DEFINED ANDROID_SDK)
message(STATUS "Android SDK: using location: ${ANDROID_SDK}")
endif()
endif()
if(NOT DEFINED ANDROID_SDK)
message(FATAL_ERROR "Android SDK: specify path to Android SDK via ANDROID_SDK_ROOT / ANDROID_HOME / ANDROID_SDK variables")
endif()
if(NOT EXISTS "${ANDROID_SDK}")
message(FATAL_ERROR "Android SDK: specified path doesn't exist: ${ANDROID_SDK}")
endif()
endmacro()

macro(ocv_detect_android_sdk_tools)
# https://developer.android.com/studio/releases/sdk-tools.html
if(NOT DEFINED ANDROID_SDK_TOOLS)
if(DEFINED ANDROID_SDK AND EXISTS "${ANDROID_SDK}/tools")
set(ANDROID_SDK_TOOLS "${ANDROID_SDK}/tools" CACHE INTERNAL "Android SDK Tools path")
endif()
endif()
if(NOT DEFINED ANDROID_SDK_TOOLS)
message(FATAL_ERROR "Android SDK Tools: can't automatically find Android SDK Tools. Specify path via ANDROID_SDK_TOOLS variable")
endif()
if(NOT EXISTS "${ANDROID_SDK_TOOLS}")
message(FATAL_ERROR "Android SDK Tools: specified path doesn't exist: ${ANDROID_SDK_TOOLS}")
endif()

if(NOT DEFINED ANDROID_SDK_TOOLS_VERSION)
ocv_parse_properties_file("${ANDROID_SDK_TOOLS}/source.properties"
ANDROID_TOOLS CACHE Pkg_Revision
MSG_PREFIX "Android SDK Tools: "
)

if(NOT DEFINED ANDROID_TOOLS_Pkg_Revision)
message(FATAL_ERROR "Android SDK Tools: Can't determine package version: ANDROID_SDK_TOOLS=${ANDROID_SDK_TOOLS}\n"
"Check specified parameters or force version via 'ANDROID_SDK_TOOLS_VERSION' variable.\n"
"${__msg_BUILD_ANDROID_PROJECTS}")
elseif(NOT ANDROID_SDK_DETECT_QUIET)
set(__info "")
if(DEFINED ANDROID_TOOLS_Pkg_Desc)
set(__info " (description: '${ANDROID_TOOLS_Pkg_Desc}')")
endif()
message(STATUS "Android SDK Tools: ver. ${ANDROID_TOOLS_Pkg_Revision}${__info}")
endif()
set(ANDROID_SDK_TOOLS_VERSION "${ANDROID_TOOLS_Pkg_Revision}" CACHE INTERNAL "Android SDK Tools version")
endif()
if(NOT DEFINED ANDROID_TOOLS_Pkg_Revision)
set(ANDROID_TOOLS_Pkg_Revision "${ANDROID_SDK_TOOLS_VERSION}" CACHE INTERNAL "Android SDK Tools version (deprecated)")
endif()
set(ANDROID_SDK_TOOLS_PATH "${ANDROID_SDK_TOOLS}" CACHE INTERNAL "Android SDK Tools path (deprecated)")
endmacro() # ocv_detect_android_sdk_tools

macro(ocv_detect_android_sdk_build_tools)
# https://developer.android.com/studio/releases/build-tools.html
if(NOT DEFINED ANDROID_SDK_BUILD_TOOLS_VERSION)
if(NOT DEFINED ANDROID_SDK_BUILD_TOOLS)
set(__search_dir ${ANDROID_SDK}/build-tools)
if(NOT EXISTS "${__search_dir}")
message(FATAL_ERROR "Android SDK Build Tools: directory doesn't exist: ${__search_dir} "
"${__msg_BUILD_ANDROID_PROJECTS}")
endif()

if(NOT DEFINED ANDROID_SDK_BUILD_TOOLS_SUBDIR)
file(GLOB __found RELATIVE "${__search_dir}" ${__search_dir}/*)
set(__dirlist "")
set(__selected 0)
set(__versions "")
foreach(d ${__found})
if(IS_DIRECTORY "${__search_dir}/${d}")
list(APPEND __dirlist ${d})
if(d MATCHES "[0-9]+(\\.[0-9]+)*")
list(APPEND __versions "${d}")
endif()
if(__selected VERSION_LESS d)
set(__selected "${d}")
endif()
endif()
endforeach()
if(__selected VERSION_GREATER 0)
set(ANDROID_SDK_BUILD_TOOLS_SUBDIR "${__selected}")
elseif(__dirlist)
set(__versions "")
foreach(d ${__dirlist})
if(EXISTS "${__search_dir}/${d}/source.properties")
ocv_clear_vars(ANDROID_BUILD_TOOLS_Pkg_Revision)
ocv_parse_properties_file("${__search_dir}/${d}/source.properties"
ANDROID_BUILD_TOOLS
MSG_PREFIX "Android SDK Tools: "
)
if(DEFINED ANDROID_BUILD_TOOLS_Pkg_Revision)
list(APPEND __versions "${ANDROID_BUILD_TOOLS_Pkg_Revision}")
if(__selected VERSION_LESS ANDROID_BUILD_TOOLS_Pkg_Revision)
set(ANDROID_SDK_BUILD_TOOLS_SUBDIR "${d}")
set(__selected "${ANDROID_BUILD_TOOLS_Pkg_Revision}")
endif()
endif()
endif()
endforeach()
endif()
if(DEFINED ANDROID_SDK_BUILD_TOOLS_SUBDIR)
set(ANDROID_SDK_BUILD_TOOLS_VERSION "${__selected}" CACHE STRING "Android SDK Build Tools version")
set_property(CACHE ANDROID_SDK_BUILD_TOOLS_VERSION PROPERTY STRINGS ${__versions})
set(ANDROID_SDK_BUILD_TOOLS "${__search_dir}/${d}" CACHE INTERNAL "Android SDK Build Tools path")
message(STATUS "Android SDK Build Tools: ver. ${ANDROID_SDK_BUILD_TOOLS_VERSION} (subdir ${ANDROID_SDK_BUILD_TOOLS_SUBDIR} from ${__dirlist})")
else()
message(FATAL_ERROR "Android SDK Build Tools: autodetection failed. "
"Specify ANDROID_SDK_BUILD_TOOLS_VERSION / ANDROID_SDK_BUILD_TOOLS_SUBDIR / ANDROID_SDK_BUILD_TOOLS variable to bypass autodetection.\n"
"${__msg_BUILD_ANDROID_PROJECTS}")
endif()
endif()
else()
ocv_parse_properties_file("${ANDROID_SDK_BUILD_TOOLS}/source.properties"
ANDROID_BUILD_TOOLS
MSG_PREFIX "Android SDK Tools: "
)
if(NOT DEFINED ANDROID_BUILD_TOOLS_Pkg_Revision)
message(FATAL_ERROR "Android SDK Build Tools: Can't detect version: ANDROID_SDK_BUILD_TOOLS=${ANDROID_SDK_BUILD_TOOLS}\n"
"Specify ANDROID_SDK_BUILD_TOOLS_VERSION variable to bypass autodetection.\n"
"${__msg_BUILD_ANDROID_PROJECTS}")
else()
set(ANDROID_SDK_BUILD_TOOLS_VERSION "${ANDROID_BUILD_TOOLS_Pkg_Revision}" CACHE INTERNAL "Android SDK Build Tools version")
message(STATUS "Android SDK Build Tools: ver. ${ANDROID_SDK_BUILD_TOOLS_VERSION} (ANDROID_SDK_BUILD_TOOLS=${ANDROID_SDK_BUILD_TOOLS})")
endif()
endif() # ANDROID_SDK_BUILD_TOOLS
endif() # ANDROID_SDK_BUILD_TOOLS_VERSION
endmacro() # ocv_detect_android_sdk_build_tools


if(BUILD_ANDROID_PROJECTS)
ocv_detect_android_sdk()
ocv_detect_android_sdk_tools()
ocv_detect_android_sdk_build_tools()

if(ANDROID_SDK_TOOLS_VERSION VERSION_LESS 14)
message(FATAL_ERROR "Android SDK Tools: OpenCV requires Android SDK Tools revision 14 or newer.\n"
"${__msg_BUILD_ANDROID_PROJECTS}")
endif()

if(NOT ANDROID_SDK_TOOLS_VERSION VERSION_LESS 25.3.0)
message(STATUS "Android SDK Tools: Ant (Eclipse) builds are NOT supported by Android SDK")
ocv_update(ANDROID_PROJECTS_SUPPORT_ANT OFF)
if(NOT ANDROID_SDK_BUILD_TOOLS_VERSION VERSION_LESS 26.0.2)
# https://developer.android.com/studio/releases/gradle-plugin.html
message(STATUS "Android SDK Build Tools: Gradle 3.0.0+ builds support is available")
ocv_update(ANDROID_PROJECTS_SUPPORT_GRADLE ON)
endif()
else()
include(${CMAKE_CURRENT_LIST_DIR}/../OpenCVDetectApacheAnt.cmake)
if(ANT_EXECUTABLE AND NOT ANT_VERSION VERSION_LESS 1.7)
message(STATUS "Android SDK Tools: Ant (Eclipse) builds are supported")
ocv_update(ANDROID_PROJECTS_SUPPORT_ANT ON)
endif()
endif()

if(NOT DEFINED ANDROID_PROJECTS_BUILD_TYPE)
if(ANDROID_PROJECTS_SUPPORT_ANT)
ocv_update(ANDROID_PROJECTS_BUILD_TYPE "ANT")
elseif(ANDROID_PROJECTS_SUPPORT_GRADLE)
ocv_update(ANDROID_PROJECTS_BUILD_TYPE "GRADLE")
else()
message(FATAL_ERROR "Android SDK: Can't build Android projects as requested by BUILD_ANDROID_PROJECTS=ON variable.\n"
"${__msg_BUILD_ANDROID_PROJECTS}")
endif()
endif()

if(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "ANT")
message(STATUS "Android SDK Tools: Prepare Android projects for using Ant build scripts (deprecated)")
elseif(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "GRADLE")
message(STATUS "Android SDK Tools: Prepare Android projects for using Gradle 3.0.0+ build scripts")
endif()

else()
message("Android: Projects builds are DISABLED")
macro(add_android_project)
endmacro()
endif() # BUILD_ANDROID_PROJECTS

if(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "ANT")
include(${CMAKE_CURRENT_LIST_DIR}/android_ant_projects.cmake)
elseif(ANDROID_PROJECTS_BUILD_TYPE STREQUAL "GRADLE")
include(${CMAKE_CURRENT_LIST_DIR}/android_gradle_projects.cmake)
elseif(BUILD_ANDROID_PROJECTS)
message(FATAL_ERROR "Internal error")
else()
# TODO
#include(${CMAKE_CURRENT_LIST_DIR}/android_disabled_projects.cmake)
endif()
Loading

0 comments on commit 875b4e2

Please sign in to comment.