From 82aff110b7e53cb2ee9ecefc2c1f977c2b7efbf8 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Thu, 1 Feb 2018 17:08:01 +0300 Subject: [PATCH] cmake: allow providing list of extra modules paths --- CMakeLists.txt | 2 +- cmake/OpenCVModule.cmake | 175 ++++++++++++++++++++++++++++------------------- cmake/OpenCVUtils.cmake | 54 ++++++++++++--- modules/CMakeLists.txt | 2 +- 4 files changed, 152 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66f03de..68c9546 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,7 +497,7 @@ ocv_include_directories(${OPENCV_CONFIG_FILE_INCLUDE_DIR}) # ---------------------------------------------------------------------------- # Path for additional modules # ---------------------------------------------------------------------------- -set(OPENCV_EXTRA_MODULES_PATH "" CACHE PATH "Where to look for additional OpenCV modules") +set(OPENCV_EXTRA_MODULES_PATH "" CACHE PATH "Where to look for additional OpenCV modules (can be ;-separated list of paths)") # ---------------------------------------------------------------------------- # Autodetect if we are in a GIT repository diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 6eeba30..46e1ca5 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -251,57 +251,118 @@ macro(ocv_module_disable module) return() # leave the current folder endmacro() +# gather acceptable locations and generate names for them +# if folder contains CMakeLists.txt - it is accepted, +# otherwise all first-level subfolders containing CMakeLists.txt are accepted. +# Usage: _glob_locations( [ ...]) +function(_glob_locations out_paths out_names) + foreach(path ${ARGN}) + message(STATUS "Inspect: ${path}") + list(LENGTH paths before) + get_filename_component(path "${path}" ABSOLUTE) + # Either module itself + if(NOT path STREQUAL CMAKE_CURRENT_SOURCE_DIR AND EXISTS "${path}/CMakeLists.txt") + get_filename_component(name "${path}" NAME) + list(APPEND paths "${path}") + list(APPEND names "${name}") + else() + # Either flat collection of modules + file(GLOB subdirs RELATIVE "${path}" "${path}/*") + foreach(subdir ${subdirs}) + message(STATUS "Inspect: ${path}/${subdir}") + if(EXISTS "${path}/${subdir}/CMakeLists.txt") + list(APPEND paths "${path}/${subdir}") + list(APPEND names "${subdir}") + endif() + endforeach() + endif() + list(LENGTH paths after) + if(before EQUAL after) + message(SEND_ERROR "No modules has been found: ${path}") + endif() + endforeach() + # Return + set(${out_paths} ${paths} PARENT_SCOPE) + set(${out_names} ${names} PARENT_SCOPE) +endfunction() + +# Calls 'add_subdirectory' for each location. +# Note: both input lists should have same length. +# Usage: _add_modules_1( ) +function(_add_modules_1 paths names) + list(LENGTH ${paths} len) + if(len EQUAL 0) + return() + endif() + list(LENGTH ${names} len_verify) + if(NOT len EQUAL len_verify) + message(FATAL_ERROR "Bad configuration! ${len} != ${len_verify}") + endif() + math(EXPR len "${len} - 1") + foreach(i RANGE ${len}) + list(GET ${paths} ${i} path) + list(GET ${names} ${i} name) + message(STATUS "First pass: ${name} => ${path}") + include("${path}/cmake/init.cmake" OPTIONAL) + add_subdirectory("${path}" "${CMAKE_CURRENT_BINARY_DIR}/.firstpass/${name}") + endforeach() +endfunction() + +# Calls 'add_subdirectory' for each module name. +# Usage: _add_modules_2([ ...]) +function(_add_modules_2) + foreach(m ${ARGN}) + set(the_module "${m}") + if(BUILD_opencv_world AND m STREQUAL "opencv_world" + OR NOT BUILD_opencv_world + OR NOT OPENCV_MODULE_${m}_IS_PART_OF_WORLD) + if(NOT m MATCHES "^opencv_") + message(WARNING "Incorrect module name: ${m}") + endif() + string(REGEX REPLACE "^opencv_" "" name "${m}") + message(STATUS "Second pass: ${name} => ${OPENCV_MODULE_${m}_LOCATION}") + add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${name}") + endif() + endforeach() +endfunction() + +# Check if list of input items is unique. +# Usage: _assert_uniqueness( [ ...]) +function(_assert_uniqueness msg) + ocv_get_duplicates(dups ${ARGN}) + if(dups) + foreach(e ${ARGN}) + list(FIND dups "${e}" idx) + if(NOT idx EQUAL -1) + set(prefix " > ") + else() + set(prefix " ") + endif() + message("${prefix}${e}") + endforeach() + message(FATAL_ERROR "${msg}") + endif() +endfunction() + # collect modules from specified directories # NB: must be called only once! -macro(ocv_glob_modules) +# Usage: ocv_glob_modules(
[ ...]) +macro(ocv_glob_modules main_root) if(DEFINED OPENCV_INITIAL_PASS) message(FATAL_ERROR "OpenCV has already loaded its modules. Calling ocv_glob_modules second time is not allowed.") endif() - set(__directories_observed "") # collect modules set(OPENCV_INITIAL_PASS ON) + _glob_locations(__main_paths __main_names ${main_root}) + _glob_locations(__extra_paths __extra_names ${ARGN}) + _assert_uniqueness("Duplicated modules LOCATIONS has been found" ${__main_paths} ${__extra_paths}) + _assert_uniqueness("Duplicated modules NAMES has been found" ${__main_names} ${__extra_names}) set(OPENCV_PROCESSING_EXTRA_MODULES 0) - foreach(__path ${ARGN}) - if("${__path}" STREQUAL "EXTRA") - set(OPENCV_PROCESSING_EXTRA_MODULES 1) - else() - get_filename_component(__path "${__path}" ABSOLUTE) - - list(FIND __directories_observed "${__path}" __pathIdx) - if(__pathIdx GREATER -1) - message(FATAL_ERROR "The directory ${__path} is observed for OpenCV modules second time.") - endif() - list(APPEND __directories_observed "${__path}") - - set(__count 0) - file(GLOB __ocvmodules RELATIVE "${__path}" "${__path}/*") - if(__ocvmodules) - list(SORT __ocvmodules) - foreach(mod ${__ocvmodules}) - get_filename_component(__modpath "${__path}/${mod}" ABSOLUTE) - if(EXISTS "${__modpath}/CMakeLists.txt") - - list(FIND __directories_observed "${__modpath}" __pathIdx) - if(__pathIdx GREATER -1) - message(FATAL_ERROR "The module from ${__modpath} is already loaded.") - endif() - list(APPEND __directories_observed "${__modpath}") - - add_subdirectory("${__modpath}" "${CMAKE_CURRENT_BINARY_DIR}/${mod}/.${mod}") - - if (DEFINED OPENCV_MODULE_opencv_${mod}_LOCATION) - math(EXPR __count "${__count} + 1") - endif() - endif() - endforeach() - endif() - if (OPENCV_PROCESSING_EXTRA_MODULES AND ${__count} LESS 1) - message(SEND_ERROR "No extra modules found in folder: ${__path}\nPlease provide path to 'opencv_contrib/modules' folder.") - endif() - endif() - endforeach() - ocv_clear_vars(__ocvmodules __directories_observed __path __modpath __pathIdx) + _add_modules_1(__main_paths __main_names) + set(OPENCV_PROCESSING_EXTRA_MODULES 1) + _add_modules_1(__extra_paths __extra_names) + ocv_clear_vars(__main_names __extra_names __main_paths __extra_paths) # resolve dependencies __ocv_resolve_dependencies() @@ -309,35 +370,7 @@ macro(ocv_glob_modules) # create modules set(OPENCV_INITIAL_PASS OFF PARENT_SCOPE) set(OPENCV_INITIAL_PASS OFF) - if(${BUILD_opencv_world}) - foreach(m ${OPENCV_MODULES_BUILD}) - set(the_module "${m}") - if("${m}" STREQUAL opencv_world) - add_subdirectory("${OPENCV_MODULE_opencv_world_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/world") - elseif(NOT OPENCV_MODULE_${m}_IS_PART_OF_WORLD AND NOT ${m} STREQUAL opencv_world) - message(STATUS "Processing module ${m}...") - if(m MATCHES "^opencv_") - string(REGEX REPLACE "^opencv_" "" __shortname "${m}") - add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${__shortname}") - else() - message(WARNING "Check module name: ${m}") - add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${m}") - endif() - endif() - endforeach() - else() - foreach(m ${OPENCV_MODULES_BUILD}) - set(the_module "${m}") - if(m MATCHES "^opencv_") - string(REGEX REPLACE "^opencv_" "" __shortname "${m}") - add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${__shortname}") - else() - message(WARNING "Check module name: ${m}") - add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" "${CMAKE_CURRENT_BINARY_DIR}/${m}") - endif() - endforeach() - endif() - unset(__shortname) + _add_modules_2(${OPENCV_MODULES_BUILD}) endmacro() diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 1a4d1cb..c0bbac7 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -116,18 +116,39 @@ macro(_ocv_fix_target target_var) endif() endmacro() -function(ocv_is_opencv_directory result_var dir) - get_filename_component(__abs_dir "${dir}" ABSOLUTE) - if("${__abs_dir}" MATCHES "^${OpenCV_SOURCE_DIR}" - OR "${__abs_dir}" MATCHES "^${OpenCV_BINARY_DIR}" - OR (OPENCV_EXTRA_MODULES_PATH AND "${__abs_dir}" MATCHES "^${OPENCV_EXTRA_MODULES_PATH}")) - set(${result_var} 1 PARENT_SCOPE) + +# check if "sub" (file or dir) is below "dir" +function(is_subdir res dir sub ) + get_filename_component(dir "${dir}" ABSOLUTE) + get_filename_component(sub "${sub}" ABSOLUTE) + file(TO_CMAKE_PATH "${dir}" dir) + file(TO_CMAKE_PATH "${sub}" sub) + set(dir "${dir}/") + string(LENGTH "${dir}" len) + string(LENGTH "${sub}" len_sub) + if(NOT len GREATER len_sub) + string(SUBSTRING "${sub}" 0 ${len} prefix) + endif() + if(prefix AND prefix STREQUAL dir) + set(${res} TRUE PARENT_SCOPE) else() - set(${result_var} 0 PARENT_SCOPE) + set(${res} FALSE PARENT_SCOPE) endif() endfunction() +function(ocv_is_opencv_directory result_var dir) + set(result FALSE) + foreach(parent ${OpenCV_SOURCE_DIR} ${OpenCV_BINARY_DIR} ${OPENCV_EXTRA_MODULES_PATH}) + is_subdir(result "${parent}" "${dir}") + if(result) + break() + endif() + endforeach() + set(${result_var} ${result} PARENT_SCOPE) +endfunction() + + # adds include directories in such a way that directories from the OpenCV source tree go first function(ocv_include_directories) ocv_debug_message("ocv_include_directories( ${ARGN} )") @@ -688,7 +709,7 @@ endif() # NOT DEFINED CMAKE_ARGC # EXCLUSIVE: break after first successful condition # # Usage: -# ocv_build_features_string(out [EXLUSIVE] [IF feature THEN title] ... [ELSE title]) +# ocv_build_features_string(out [EXCLUSIVE] [IF feature THEN title] ... [ELSE title]) # function(ocv_build_features_string out) set(result) @@ -807,6 +828,23 @@ macro(ocv_list_pop_front LST VAR) endif() endmacro() +# Get list of duplicates in the list of input items. +# ocv_get_duplicates( [ ...]) +function(ocv_get_duplicates res) + if(ARGC LESS 2) + message(FATAL_ERROR "Invalid call to ocv_get_duplicates") + endif() + set(lst ${ARGN}) + list(SORT lst) + set(prev_item) + foreach(item ${lst}) + if(item STREQUAL prev_item) + list(APPEND dups ${item}) + endif() + set(prev_item ${item}) + endforeach() + set(${res} ${dups} PARENT_SCOPE) +endfunction() # simple regex escaping routine (does not cover all cases!!!) macro(ocv_regex_escape var regex) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index edbfe1a..6a80040 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -4,7 +4,7 @@ if(NOT OPENCV_MODULES_PATH) set(OPENCV_MODULES_PATH "${CMAKE_CURRENT_SOURCE_DIR}") endif() -ocv_glob_modules(${OPENCV_MODULES_PATH} EXTRA ${OPENCV_EXTRA_MODULES_PATH}) +ocv_glob_modules(${OPENCV_MODULES_PATH} ${OPENCV_EXTRA_MODULES_PATH}) # build lists of modules to be documented set(OPENCV_MODULES_MAIN "") -- 2.7.4