diff --git a/cmake/OpenCVDetectAndroidSDK.cmake b/cmake/OpenCVDetectAndroidSDK.cmake index 85c103e002..60832f0e59 100644 --- a/cmake/OpenCVDetectAndroidSDK.cmake +++ b/cmake/OpenCVDetectAndroidSDK.cmake @@ -228,23 +228,16 @@ macro(add_android_project target path) project(${target}) set(android_proj_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/.build") - # get project sources - file(GLOB_RECURSE android_proj_files RELATIVE "${path}" "${path}/res/*" "${path}/src/*") - + # project sources + set(__src_glob "${path}/res/*" "${path}/src/*") if(NOT android_proj_IGNORE_MANIFEST) - list(APPEND android_proj_files ${ANDROID_MANIFEST_FILE}) + list(APPEND __src_glob "${path}/${ANDROID_MANIFEST_FILE}") endif() - # copy sources out from the build tree - set(android_proj_file_deps "") - foreach(f ${android_proj_files}) - add_custom_command( - OUTPUT "${android_proj_bin_dir}/${f}" - COMMAND ${CMAKE_COMMAND} -E copy_if_different "${path}/${f}" "${android_proj_bin_dir}/${f}" - MAIN_DEPENDENCY "${path}/${f}" - COMMENT "Copying ${f}") - list(APPEND android_proj_file_deps "${path}/${f}" "${android_proj_bin_dir}/${f}") - endforeach() + ocv_copyfiles_append_dir(SRC_COPY "${path}" "${android_proj_bin_dir}" ${__src_glob}) + ocv_copyfiles_add_forced_target(${target}_copy_src SRC_COPY "Copy project sources: ${target}") + + set(android_proj_file_deps ${target}_copy_src "${OPENCV_DEPHELPER}/${target}_copy_src") set(android_proj_lib_deps_commands "") set(android_proj_target_files ${ANDROID_PROJECT_FILES}) @@ -261,10 +254,11 @@ macro(add_android_project target path) add_custom_command( OUTPUT ${android_proj_target_files} COMMAND ${CMAKE_COMMAND} -E remove ${android_proj_target_files} + "${android_proj_bin_dir}/bin/${ANDROID_MANIFEST_FILE}" # avoid warning about sub-projects COMMAND ${ANDROID_EXECUTABLE} --silent update project --path "${android_proj_bin_dir}" --target "${android_proj_sdk_target}" --name "${target}" ${android_proj_lib_deps_commands} - MAIN_DEPENDENCY "${android_proj_bin_dir}/${ANDROID_MANIFEST_FILE}" - DEPENDS "${path}/${ANDROID_MANIFEST_FILE}" + WORKING_DIRECTORY "${android_proj_bin_dir}" + DEPENDS ${android_proj_file_deps} COMMENT "Updating Android project at ${path}. SDK target: ${android_proj_sdk_target}" ) @@ -272,7 +266,6 @@ macro(add_android_project target path) # build native part file(GLOB_RECURSE android_proj_jni_files "${path}/jni/*.c" "${path}/jni/*.h" "${path}/jni/*.cpp" "${path}/jni/*.hpp") - ocv_list_filterout(android_proj_jni_files "\\\\.svn") if(android_proj_jni_files AND EXISTS ${path}/jni/Android.mk AND NOT DEFINED JNI_LIB_NAME) # find local module name in Android.mk file to build native lib @@ -310,36 +303,44 @@ macro(add_android_project target path) list(APPEND android_proj_extra_deps "${OpenCV_BINARY_DIR}/bin/classes.jar.dephelper" opencv_java) endif() add_custom_command( - OUTPUT "${android_proj_bin_dir}/bin/${target}-debug.apk" - COMMAND ${ANT_EXECUTABLE} -q -noinput -k debug -Djava.target=1.6 -Djava.source=1.6 - COMMAND ${CMAKE_COMMAND} -E touch "${android_proj_bin_dir}/bin/${target}-debug.apk" # needed because ant does not update the timestamp of updated apk - WORKING_DIRECTORY "${android_proj_bin_dir}" - MAIN_DEPENDENCY "${android_proj_bin_dir}/${ANDROID_MANIFEST_FILE}" - DEPENDS ${android_proj_extra_deps} ${android_proj_file_deps} ${JNI_LIB_NAME}) + OUTPUT "${android_proj_bin_dir}/bin/${target}-debug.apk" + COMMAND ${ANT_EXECUTABLE} -q -noinput -k debug -Djava.target=1.6 -Djava.source=1.6 + COMMAND ${CMAKE_COMMAND} -E touch "${android_proj_bin_dir}/bin/${target}-debug.apk" # needed because ant does not update the timestamp of updated apk + WORKING_DIRECTORY "${android_proj_bin_dir}" + DEPENDS ${android_proj_extra_deps} ${android_proj_file_deps} ${JNI_LIB_NAME} + COMMENT "Generating ${target}-debug.apk" + ) unset(JNI_LIB_NAME) add_custom_target(${target} ALL SOURCES "${android_proj_bin_dir}/bin/${target}-debug.apk" ) + + set(_native_deps "") if(NOT android_proj_IGNORE_JAVA) - add_dependencies(${target} opencv_java) + set(_native_deps opencv_java) endif() if(android_proj_native_deps) - add_dependencies(${target} ${android_proj_native_deps}) + list(APPEND _native_deps ${android_proj_native_deps}) + endif() + if(_native_deps) + add_dependencies(${target} ${_native_deps}) endif() - if (android_proj_COPY_LIBS OR ANDROID_EXAMPLES_WITH_LIBS) - message(STATUS "Android project with libs: " ${target}) - add_custom_target( - ${target}_copy_libs - COMMAND ${CMAKE_COMMAND} -DSRC_DIR=${OpenCV_BINARY_DIR}/lib -DDST_DIR=${android_proj_bin_dir}/libs -P ${OpenCV_SOURCE_DIR}/cmake/copyAndroidLibs.cmake - WORKING_DIRECTORY ${OpenCV_BINARY_DIR}/lib - ) + if((android_proj_COPY_LIBS OR ANDROID_EXAMPLES_WITH_LIBS) AND _native_deps) + message(STATUS "Android project with native libs: " ${target} " (" ${_native_deps} ")") + + ocv_copyfiles_append_dir(NATIVE_COPY "${OpenCV_BINARY_DIR}/lib" "${android_proj_bin_dir}/libs" "${OpenCV_BINARY_DIR}/lib/*.so") + ocv_copyfiles_add_target(${target}_copy_libs NATIVE_COPY "Copy native libs for project: ${target}" ${_native_deps}) + add_dependencies(${target} ${target}_copy_libs) + if (ANDROID_EXAMPLES_WITH_LIBS) - add_dependencies(${target}_copy_libs "${OpenCV_BINARY_DIR}/bin/classes.jar.dephelper" opencv_java) + add_dependencies(${target}_copy_libs opencv_java) endif() endif() + # There is some strange problem with concurrent Android .APK builds: + # /tools/ant/build.xml:781: Problem reading /bin/classes.jar' if(__android_project_chain) add_dependencies(${target} ${__android_project_chain}) endif() @@ -348,15 +349,22 @@ macro(add_android_project target path) # put the final .apk to the OpenCV's bin folder add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${android_proj_bin_dir}/bin/${target}-debug.apk" "${OpenCV_BINARY_DIR}/bin/${target}.apk") if(INSTALL_ANDROID_EXAMPLES AND "${target}" MATCHES "^example-") - #apk - install(FILES "${OpenCV_BINARY_DIR}/bin/${target}.apk" DESTINATION "samples" COMPONENT samples) get_filename_component(sample_dir "${path}" NAME) + # apk + install(FILES "${OpenCV_BINARY_DIR}/bin/${target}.apk" DESTINATION "samples" COMPONENT samples) + # clear "external" project files (need to remove files generated by 'android' tool) + set(external_target_files ${ANDROID_PROJECT_FILES}) + ocv_list_add_prefix(external_target_files "\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}/") + install(CODE " +MESSAGE(STATUS \"Cleaning generated project files from Android sample install directory: ${sample_dir}\") +FOREACH(f ${ANDROID_PROJECT_FILES}) + FILE(REMOVE \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}/\${f}\") +ENDFOREACH() +" COMPONENT samples) #java part - list(REMOVE_ITEM android_proj_files ${ANDROID_MANIFEST_FILE}) - foreach(f ${android_proj_files} ${ANDROID_MANIFEST_FILE}) - get_filename_component(install_subdir "${f}" PATH) - install(FILES "${android_proj_bin_dir}/${f}" DESTINATION "samples/${sample_dir}/${install_subdir}" COMPONENT samples) - endforeach() + install(DIRECTORY "${android_proj_bin_dir}/res" DESTINATION "samples/${sample_dir}" COMPONENT samples) + install(DIRECTORY "${android_proj_bin_dir}/src" DESTINATION "samples/${sample_dir}" COMPONENT samples) + install(FILES "${android_proj_bin_dir}/${ANDROID_MANIFEST_FILE}" DESTINATION "samples/${sample_dir}" COMPONENT samples) #jni part + eclipse files file(GLOB_RECURSE jni_files RELATIVE "${path}" "${path}/jni/*" "${path}/.cproject") ocv_list_filterout(jni_files "\\\\.svn") @@ -368,11 +376,15 @@ macro(add_android_project target path) if(android_proj_lib_deps_commands) set(inst_lib_opt " --library ../../sdk/java") endif() - install(CODE "EXECUTE_PROCESS(COMMAND ${ANDROID_EXECUTABLE} --silent update project --path . --target \"${android_proj_sdk_target}\" --name \"${target}\" ${inst_lib_opt} - WORKING_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}\" - )" COMPONENT samples) - #empty 'gen' - install(CODE "MAKE_DIRECTORY(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}/gen\")" COMPONENT samples) + install(CODE " +MESSAGE(STATUS \"Fixing Android library reference for sample: ${sample_dir}\") +EXECUTE_PROCESS( + COMMAND ${ANDROID_EXECUTABLE} --silent update project --path . --target \"${android_proj_sdk_target}\" --name \"${target}\" ${inst_lib_opt} + WORKING_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}\" +) +" COMPONENT samples) + # empty 'gen' + install(CODE "FILE(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/samples/${sample_dir}/gen\")" COMPONENT samples) endif() endif() endmacro() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 60662536f6..dd41f822b9 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -522,6 +522,45 @@ endmacro() if(NOT DEFINED CMAKE_ARGC) # Guard CMake standalone invocations +# Use this option carefully, CMake's install() will install symlinks instead of real files +# It is fine for development, but should not be used by real installations +set(__symlink_default OFF) # preprocessing is required for old CMake like 2.8.12 +if(DEFINED ENV{BUILD_USE_SYMLINKS}) + set(__symlink_default $ENV{BUILD_USE_SYMLINKS}) +endif() +OCV_OPTION(BUILD_USE_SYMLINKS "Use symlinks instead of files copying during build (and !!INSTALL!!)" (${__symlink_default}) IF (UNIX OR DEFINED __symlink_default)) + +if(CMAKE_VERSION VERSION_LESS "3.2") + macro(ocv_cmake_byproducts var_name) + set(${var_name}) # nothing + endmacro() +else() + macro(ocv_cmake_byproducts var_name) + set(${var_name} BYPRODUCTS ${ARGN}) + endmacro() +endif() + +set(OPENCV_DEPHELPER "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/dephelper" CACHE INTERNAL "") +file(MAKE_DIRECTORY ${OPENCV_DEPHELPER}) + +if(BUILD_USE_SYMLINKS) + set(__file0 "${CMAKE_CURRENT_LIST_FILE}") + set(__file1 "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/symlink_test") + if(NOT IS_SYMLINK "${__file1}") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${__file0}" "${__file1}" + RESULT_VARIABLE SYMLINK_RESULT) + if(NOT SYMLINK_RESULT EQUAL 0) + file(REMOVE "${__file1}") + endif() + if(NOT IS_SYMLINK "${__file1}") + set(BUILD_USE_SYMLINKS 0 CACHE INTERNAL "") + endif() + endif() + if(NOT BUILD_USE_SYMLINKS) + message(STATUS "Build symlinks are not available (disabled)") + endif() +endif() + set(OPENCV_BUILD_INFO_STR "" CACHE INTERNAL "") function(ocv_output_status msg) message(STATUS "${msg}") @@ -1269,3 +1308,81 @@ set(${var_name} \"${${var_name}}\") ") endforeach() endmacro() + +macro(ocv_copyfiles_append_file list_var src dst) + list(LENGTH ${list_var} __id) + list(APPEND ${list_var} ${__id}) + set(${list_var}_SRC_${__id} "${src}") + set(${list_var}_DST_${__id} "${dst}") +endmacro() + +macro(ocv_copyfiles_append_dir list_var src dst) + set(__glob ${ARGN}) + list(LENGTH ${list_var} __id) + list(APPEND ${list_var} ${__id}) + set(${list_var}_SRC_${__id} "${src}") + set(${list_var}_DST_${__id} "${dst}") + set(${list_var}_MODE_${__id} "COPYDIR") + if(__glob) + set(${list_var}_GLOB_${__id} ${__glob}) + endif() +endmacro() + +macro(ocv_copyfiles_make_config_string content_var list_var) + set(var_name "${list_var}") + set(${content_var} "${${content_var}} +set(${var_name} \"${${var_name}}\") +") + foreach(__id ${${list_var}}) + set(${content_var} "${${content_var}} +set(${list_var}_SRC_${__id} \"${${list_var}_SRC_${__id}}\") +set(${list_var}_DST_${__id} \"${${list_var}_DST_${__id}}\") +") + if(DEFINED ${list_var}_MODE_${__id}) + set(${content_var} "${${content_var}}set(${list_var}_MODE_${__id} \"${${list_var}_MODE_${__id}}\")\n") + endif() + if(DEFINED ${list_var}_GLOB_${__id}) + set(${content_var} "${${content_var}}set(${list_var}_GLOB_${__id} \"${${list_var}_GLOB_${__id}}\")\n") + endif() + endforeach() +endmacro() + +macro(ocv_copyfiles_make_config_file filename_var list_var) + ocv_copyfiles_make_config_string(${list_var}_CONFIG ${list_var}) + set(${filename_var} "${CMAKE_CURRENT_BINARY_DIR}/copyfiles-${list_var}.cmake") + file(WRITE "${${filename_var}}" "${${list_var}_CONFIG}") +endmacro() + +macro(ocv_copyfiles_add_forced_target target list_var comment_str) + ocv_copyfiles_make_config_file(CONFIG_FILE ${list_var}) + ocv_cmake_byproducts(__byproducts BYPRODUCTS "${OPENCV_DEPHELPER}/${target}") + add_custom_target(${target} + ${__byproducts} # required for add_custom_target() by ninja + COMMAND ${CMAKE_COMMAND} + "-DCONFIG_FILE:PATH=${CONFIG_FILE}" + "-DCOPYLIST_VAR:STRING=${list_var}" + "-DDEPHELPER=${OPENCV_DEPHELPER}/${target}" + -P "${OpenCV_SOURCE_DIR}/cmake/copy_files.cmake" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "${comment_str}" + DEPENDS "${OpenCV_SOURCE_DIR}/cmake/copy_files.cmake" + # ninja warn about file(WRITE): "${SRC_COPY_CONFIG_FILE}" + ) +endmacro() + +macro(ocv_copyfiles_add_target target list_var comment_str) + set(deps ${ARGN}) + ocv_copyfiles_make_config_file(CONFIG_FILE ${list_var}) + add_custom_command(OUTPUT "${OPENCV_DEPHELPER}/${target}" + COMMAND ${CMAKE_COMMAND} + "-DCONFIG_FILE:PATH=${CONFIG_FILE}" + "-DCOPYLIST_VAR:STRING=${list_var}" + "-DDEPHELPER=${OPENCV_DEPHELPER}/${target}" + -P "${OpenCV_SOURCE_DIR}/cmake/copy_files.cmake" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "${comment_str}" + DEPENDS "${OpenCV_SOURCE_DIR}/cmake/copy_files.cmake" ${deps} + # ninja warn about file(WRITE): "${SRC_COPY_CONFIG_FILE}" + ) + add_custom_target(${target} DEPENDS "${OPENCV_DEPHELPER}/${target}") +endmacro() diff --git a/cmake/copyAndroidLibs.cmake b/cmake/copyAndroidLibs.cmake deleted file mode 100644 index 4e9e17f4c1..0000000000 --- a/cmake/copyAndroidLibs.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# helper file for Android samples build - -file(GLOB_RECURSE LIBS RELATIVE ${SRC_DIR} "*.so") - -foreach(l ${LIBS}) - message(STATUS " Copying: ${l} ...") - execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SRC_DIR}/${l} ${DST_DIR}/${l}) -endforeach() diff --git a/cmake/copy_files.cmake b/cmake/copy_files.cmake new file mode 100644 index 0000000000..2613eee99b --- /dev/null +++ b/cmake/copy_files.cmake @@ -0,0 +1,109 @@ +include("${CONFIG_FILE}") +set(prefix "COPYFILES: ") + +set(use_symlink 0) +if(IS_SYMLINK "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/symlink_test") + set(use_symlink 1) +endif() + +set(update_dephelper 0) +if(DEFINED DEPHELPER AND NOT EXISTS "${DEPHELPER}") + set(update_dephelper 1) +endif() + +set(__state "") + +macro(copy_file_ src dst prefix) + string(REPLACE "${CMAKE_BINARY_DIR}/" "" dst_name "${dst}") + set(local_update 0) + if(NOT EXISTS "${dst}") + set(local_update 1) + endif() + if(use_symlink) + if(local_update OR NOT IS_SYMLINK "${dst}") + message("${prefix}Symlink: '${dst_name}' ...") + endif() + get_filename_component(target_path "${dst}" PATH) + file(MAKE_DIRECTORY "${target_path}") + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dst} + RESULT_VARIABLE SYMLINK_RESULT) + if(NOT SYMLINK_RESULT EQUAL 0) + #message("Symlink failed, fallback to 'copy'") + set(use_symlink 0) + endif() + endif() + if(NOT use_symlink) + if("${src}" IS_NEWER_THAN "${dst}" OR IS_SYMLINK "${dst}") + file(REMOVE "${dst}") # configure_file(COPYONLY) doesn't update timestamp sometimes + set(local_update 1) + endif() + if(local_update) + message("${prefix}Copying: '${dst_name}' ...") + configure_file(${src} ${dst} COPYONLY) + else() + #message("${prefix}Up-to-date: '${dst_name}'") + endif() + endif() + if(local_update) + set(update_dephelper 1) + endif() + file(TIMESTAMP "${dst}" dst_t UTC) + set(__state "${__state}${dst_t} ${dst}\n") +endmacro() + +if(NOT DEFINED COPYLIST_VAR) + set(COPYLIST_VAR "COPYLIST") +endif() +list(LENGTH ${COPYLIST_VAR} __length) +message("${prefix}... ${__length} entries (${COPYLIST_VAR})") +foreach(id ${${COPYLIST_VAR}}) + set(src "${${COPYLIST_VAR}_SRC_${id}}") + set(dst "${${COPYLIST_VAR}_DST_${id}}") + if(NOT EXISTS ${src}) + message(FATAL_ERROR "Source file/dir is missing: ${src} (${CONFIG_FILE})") + endif() + set(_mode "COPYFILE") + if(DEFINED ${COPYLIST_VAR}_MODE_${id}) + set(_mode "${${COPYLIST_VAR}_MODE_${id}}") + endif() + if(_mode STREQUAL "COPYFILE") + #message("... COPY ${src} => ${dst}") + copy_file_("${src}" "${dst}" "${prefix} ") + elseif(_mode STREQUAL "COPYDIR") + get_filename_component(src_name "${src}" NAME) + get_filename_component(src_path "${src}" PATH) + get_filename_component(src_name2 "${src_path}" NAME) + + set(src_glob "${src}/*") + if(DEFINED ${COPYLIST_VAR}_GLOB_${id}) + set(src_glob "${${COPYLIST_VAR}_GLOB_${id}}") + endif() + file(GLOB_RECURSE _files RELATIVE "${src}" ${src_glob}) + list(LENGTH _files __length) + message("${prefix} ... directory '.../${src_name2}/${src_name}' with ${__length} files") + foreach(f ${_files}) + if(NOT EXISTS "${src}/${f}") + message(FATAL_ERROR "COPY ERROR: Source file is missing: ${src}/${f}") + endif() + copy_file_("${src}/${f}" "${dst}/${f}" "${prefix} ") + endforeach() + endif() +endforeach() + +set(STATE_FILE "${CONFIG_FILE}.state") +if(EXISTS "${STATE_FILE}") + file(READ "${STATE_FILE}" __prev_state) +else() + set(__prev_state "") +endif() +if(NOT "${__state}" STREQUAL "${__prev_state}") + file(WRITE "${STATE_FILE}" "${__state}") + message("${prefix}Updated!") + set(update_dephelper 1) +endif() + +if(NOT update_dephelper) + message("${prefix}All files are up-to-date.") +elseif(DEFINED DEPHELPER) + file(WRITE "${DEPHELPER}" "") +endif()