Support for compound modules, support for contrib_world
authorMaksim Shabunin <maksim.shabunin@itseez.com>
Mon, 19 Jan 2015 15:03:29 +0000 (18:03 +0300)
committerMaksim Shabunin <maksim.shabunin@itseez.com>
Tue, 10 Feb 2015 15:30:05 +0000 (18:30 +0300)
apps/createsamples/CMakeLists.txt
apps/traincascade/CMakeLists.txt
cmake/OpenCVGenPkgconfig.cmake
cmake/OpenCVModule.cmake
cmake/OpenCVUtils.cmake
doc/CMakeLists.txt
modules/java/CMakeLists.txt
modules/python/common.cmake
platforms/ios/build_framework.py

index 591a0b8..8acd288 100644 (file)
@@ -35,5 +35,5 @@ if(INSTALL_CREATE_DISTRIB)
     install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
   endif()
 else()
-  install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
+  install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
 endif()
index 59d4817..78101c0 100644 (file)
@@ -35,5 +35,5 @@ if(INSTALL_CREATE_DISTRIB)
     install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
   endif()
 else()
-  install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
+  install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
 endif()
index fa57db9..a8686e8 100644 (file)
@@ -37,6 +37,7 @@ ocv_list_reverse(OpenCV_EXTRA_COMPONENTS)
 #build the list of components
 set(OpenCV_LIB_COMPONENTS_ "")
 foreach(CVLib ${OpenCV_LIB_COMPONENTS})
+  if (TARGET ${CVLib})
   get_target_property(libpath ${CVLib} LOCATION_${CMAKE_BUILD_TYPE})
   get_filename_component(libname "${libpath}" NAME)
 
@@ -52,6 +53,7 @@ foreach(CVLib ${OpenCV_LIB_COMPONENTS})
   endif()
 
   set(OpenCV_LIB_COMPONENTS_ "${OpenCV_LIB_COMPONENTS_} \${exec_prefix}/${installDir}/${libname}")
+  endif()
 endforeach()
 
 # add extra dependencies required for OpenCV
index fa02919..90068de 100644 (file)
@@ -19,6 +19,8 @@
 # OPENCV_MODULE_${the_module}_PRIVATE_REQ_DEPS
 # OPENCV_MODULE_${the_module}_PRIVATE_OPT_DEPS
 # OPENCV_MODULE_${the_module}_IS_PART_OF_WORLD
+# OPENCV_MODULE_${the_module}_CUDA_OBJECTS - compiled CUDA objects list
+# OPENCV_MODULE_${the_module}_CHILDREN - list of submodules for compound modules
 # HAVE_${the_module} - for fast check of module availability
 
 # To control the setup of the module you could also set:
@@ -26,6 +28,7 @@
 # OPENCV_MODULE_TYPE - STATIC|SHARED - set to force override global settings for current module
 # OPENCV_MODULE_IS_PART_OF_WORLD - ON|OFF (default ON) - should the module be added to the opencv_world?
 # BUILD_${the_module}_INIT - ON|OFF (default ON) - initial value for BUILD_${the_module}
+# OPENCV_MODULE_CHILDREN - list of submodules
 
 # The verbose template for OpenCV module:
 #
@@ -158,13 +161,9 @@ macro(ocv_add_module _name)
     endif()
 
     # add self to the world dependencies
-    # add to world only extra modules (ON) or only main modules (OFF)
-    set(__expected_extra 0)
-    if (OPENCV_EXTRA_WORLD)
-        set(__expected_extra 1)
-    endif()
-    if((NOT DEFINED OPENCV_MODULE_IS_PART_OF_WORLD AND NOT OPENCV_MODULE_${the_module}_CLASS STREQUAL "BINDINGS"
-        AND __expected_extra EQUAL OPENCV_PROCESSING_EXTRA_MODULES)
+    if((NOT DEFINED OPENCV_MODULE_IS_PART_OF_WORLD
+        AND NOT OPENCV_MODULE_${the_module}_CLASS STREQUAL "BINDINGS"
+        AND NOT OPENCV_PROCESSING_EXTRA_MODULES)
         OR OPENCV_MODULE_IS_PART_OF_WORLD
         )
       set(OPENCV_MODULE_${the_module}_IS_PART_OF_WORLD ON CACHE INTERNAL "")
@@ -179,7 +178,8 @@ macro(ocv_add_module _name)
       set(OPENCV_MODULES_DISABLED_USER ${OPENCV_MODULES_DISABLED_USER} "${the_module}" CACHE INTERNAL "List of OpenCV modules explicitly disabled by user")
     endif()
 
-    # TODO: add submodules if any
+    # add submodules if any
+    set(OPENCV_MODULE_${the_module}_CHILDREN "${OPENCV_MODULE_CHILDREN}" CACHE INTERNAL "List of ${the_module} submodules")
 
     # stop processing of current file
     return()
@@ -306,27 +306,42 @@ endfunction()
 # sort modules by dependencies
 function(__ocv_sort_modules_by_deps __lst)
   ocv_list_sort(${__lst})
-  set(${__lst}_ORDERED ${${__lst}} CACHE INTERNAL "")
-  set(__result "")
-  foreach (m ${${__lst}})
-    list(LENGTH __result __lastindex)
-    set(__index ${__lastindex})
-    foreach (__d ${__result})
-      set(__deps "${OPENCV_MODULE_${__d}_DEPS}")
-      if(";${__deps};" MATCHES ";${m};")
-        list(FIND __result "${__d}" __i)
-        if(__i LESS "${__index}")
-          set(__index "${__i}")
+  set(input ${${__lst}})
+  set(result "")
+  while(input)
+    list(LENGTH input length_before)
+    foreach (m ${input})
+      # check if module is in the result already
+      if (NOT ";${result};" MATCHES ";${m};")
+        # scan through module dependencies...
+        set(unresolved_deps_found FALSE)
+        foreach (d ${OPENCV_MODULE_${m}_CHILDREN} ${OPENCV_MODULE_${m}_DEPS})
+          # ... which are not already in the result and are enabled
+          if ((NOT ";${result};" MATCHES ";${d};") AND HAVE_${d})
+            set(unresolved_deps_found TRUE)
+            break()
+          endif()
+        endforeach()
+        # chek if all dependencies for this module has been resolved
+        if (NOT unresolved_deps_found)
+          list(APPEND result ${m})
+          list(REMOVE_ITEM input ${m})
         endif()
       endif()
     endforeach()
-    if(__index STREQUAL __lastindex)
-      list(APPEND __result "${m}")
-    else()
-      list(INSERT __result ${__index} "${m}")
+    list(LENGTH input length_after)
+    # check for infinite loop or unresolved dependencies
+    if (NOT length_after LESS length_before)
+      message(WARNING "Unresolved dependencies or loop in dependency graph (${length_after})\n"
+        "Processed ${__lst}: ${${__lst}}\n"
+        "Good modules: ${result}\n"
+        "Bad modules: ${input}"
+      )
+      list(APPEND result ${input})
+      break()
     endif()
-  endforeach()
-  set(${__lst} "${__result}" PARENT_SCOPE)
+  endwhile()
+  set(${__lst} "${result}" PARENT_SCOPE)
 endfunction()
 
 # resolve dependensies
@@ -645,9 +660,43 @@ macro(_ocv_create_module)
     get_native_precompiled_header(${the_module} precomp.hpp)
   endif()
 
+  set(sub_objs "")
+  set(sub_links "")
+  set(cuda_objs "")
+  if (DEFINED OPENCV_MODULE_${the_module}_CHILDREN)
+    status("Complex module ${the_module}")
+    foreach (m ${OPENCV_MODULE_${the_module}_CHILDREN})
+      if (BUILD_${m} AND TARGET ${m}_object) # ambigous?
+        get_target_property(_sub_links ${m} LINK_LIBRARIES)
+        list(APPEND sub_objs $<TARGET_OBJECTS:${m}_object>)
+        list(APPEND sub_links ${_sub_links})
+        status("    + ${m}")
+      else()
+        status("    - ${m}")
+      endif()
+      list(APPEND cuda_objs ${OPENCV_MODULE_${m}_CUDA_OBJECTS})
+    endforeach()
+  endif()
+
   ocv_add_library(${the_module} ${OPENCV_MODULE_TYPE} ${OPENCV_MODULE_${the_module}_HEADERS} ${OPENCV_MODULE_${the_module}_SOURCES}
     "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cvconfig.h" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/opencv2/opencv_modules.hpp"
-    ${${the_module}_pch})
+    ${${the_module}_pch} ${sub_objs})
+
+  if (cuda_objs)
+    target_link_libraries(${the_module} ${cuda_objs})
+  endif()
+
+  # TODO: is it needed?
+  if (sub_links)
+    ocv_list_filterout(sub_links "^opencv_")
+    ocv_list_unique(sub_links)
+    target_link_libraries(${the_module} ${sub_links})
+  endif()
+
+  unset(sub_objs)
+  unset(sub_links)
+  unset(cuda_objs)
+
   if(NOT the_module STREQUAL opencv_ts)
     set_target_properties(${the_module} PROPERTIES COMPILE_DEFINITIONS OPENCV_NOSTL)
   endif()
@@ -686,6 +735,7 @@ macro(_ocv_create_module)
 
   if((NOT DEFINED OPENCV_MODULE_TYPE AND BUILD_SHARED_LIBS)
       OR (DEFINED OPENCV_MODULE_TYPE AND OPENCV_MODULE_TYPE STREQUAL SHARED))
+    set_target_properties(${the_module} PROPERTIES COMPILE_DEFINITIONS CVAPI_EXPORTS)
     set_target_properties(${the_module} PROPERTIES DEFINE_SYMBOL CVAPI_EXPORTS)
   endif()
 
@@ -696,22 +746,35 @@ macro(_ocv_create_module)
     set_target_properties(${the_module} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:libc /DEBUG")
   endif()
 
-  ocv_install_target(${the_module} EXPORT OpenCVModules
+  ocv_install_target(${the_module} EXPORT OpenCVModules OPTIONAL
     RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs
     LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT libs
     ARCHIVE DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT dev
     )
 
-  # only "public" headers need to be installed
-  if(OPENCV_MODULE_${the_module}_HEADERS AND ";${OPENCV_MODULES_PUBLIC};" MATCHES ";${the_module};")
-    foreach(hdr ${OPENCV_MODULE_${the_module}_HEADERS})
-      string(REGEX REPLACE "^.*opencv2/" "opencv2/" hdr2 "${hdr}")
-      if(NOT hdr2 MATCHES "opencv2/${the_module}/private.*" AND hdr2 MATCHES "^(opencv2/?.*)/[^/]+.h(..)?$" )
-        install(FILES ${hdr} DESTINATION "${OPENCV_INCLUDE_INSTALL_PATH}/${CMAKE_MATCH_1}" COMPONENT dev)
-      endif()
-    endforeach()
-  endif()
+  foreach(m ${OPENCV_MODULE_${the_module}_CHILDREN} ${the_module})
+    # only "public" headers need to be installed
+    if(OPENCV_MODULE_${m}_HEADERS AND ";${OPENCV_MODULES_PUBLIC};" MATCHES ";${m};")
+      foreach(hdr ${OPENCV_MODULE_${m}_HEADERS})
+        string(REGEX REPLACE "^.*opencv2/" "opencv2/" hdr2 "${hdr}")
+        if(NOT hdr2 MATCHES "opencv2/${m}/private.*" AND hdr2 MATCHES "^(opencv2/?.*)/[^/]+.h(..)?$" )
+          install(FILES ${hdr} OPTIONAL DESTINATION "${OPENCV_INCLUDE_INSTALL_PATH}/${CMAKE_MATCH_1}" COMPONENT dev)
+        endif()
+      endforeach()
+    endif()
+  endforeach()
+
   _ocv_add_precompiled_headers(${the_module})
+
+  if (TARGET ${the_module}_object)
+    # copy COMPILE_DEFINITIONS
+    get_target_property(main_defs ${the_module} COMPILE_DEFINITIONS)
+    set_target_properties(${the_module}_object PROPERTIES COMPILE_DEFINITIONS ${main_defs})
+    # use same PCH
+    if (TARGET pch_Generate_${the_module})
+      add_dependencies(${the_module}_object pch_Generate_${the_module} )
+    endif()
+  endif()
 endmacro()
 
 # opencv precompiled headers macro (can add pch to modules and tests)
index 60d862e..40112d5 100644 (file)
@@ -756,6 +756,9 @@ endfunction()
 function(_ocv_append_target_includes target)
   if(DEFINED OCV_TARGET_INCLUDE_DIRS_${target})
     target_include_directories(${target} PRIVATE ${OCV_TARGET_INCLUDE_DIRS_${target}})
+    if (TARGET ${target}_object)
+      target_include_directories(${target}_object PRIVATE ${OCV_TARGET_INCLUDE_DIRS_${target}})
+    endif()
     unset(OCV_TARGET_INCLUDE_DIRS_${target} CACHE)
   endif()
 endfunction()
@@ -780,8 +783,22 @@ function(ocv_add_library target)
       ocv_include_directories(${CUDA_INCLUDE_DIRS})
       ocv_cuda_compile(cuda_objs ${lib_cuda_srcs} ${lib_cuda_hdrs})
     endif()
+    set(OPENCV_MODULE_${target}_CUDA_OBJECTS ${cuda_objs} CACHE INTERNAL "Compiled CUDA object files")
   endif()
 
   add_library(${target} ${ARGN} ${cuda_objs})
+
+  # Add OBJECT library to use in compound modules
+  if (NOT OPENCV_MODULE_${target}_CHILDREN
+      AND NOT OPENCV_MODULE_${target}_CLASS STREQUAL "BINDINGS"
+      AND NOT ${target} STREQUAL "opencv_ts"
+    )
+    set(sources ${ARGN})
+    ocv_list_filterout(sources "\\\\.(cl|inc)$")
+    add_library(${target}_object OBJECT EXCLUDE_FROM_ALL ${sources})
+    set_target_properties(${target}_object PROPERTIES POSITION_INDEPENDENT_CODE True)
+    unset(sources)
+  endif()
+
   _ocv_append_target_includes(${target})
 endfunction()
index cb0d40d..a9d6e22 100644 (file)
@@ -38,7 +38,7 @@ endif(HAVE_DOC_GENERATOR)
 
 if(BUILD_DOCS AND DOXYGEN_FOUND)
   # not documented modules list
-  list(APPEND blacklist "ts" "java" "python2" "python3" "world")
+  list(APPEND blacklist "ts" "java" "python2" "python3" "world" "contrib_world")
 
   # gathering headers
   set(paths_include)
index 25c05bc..8eb2e89 100644 (file)
@@ -242,7 +242,7 @@ else(ANDROID)
   else(WIN32)
     set(JAR_INSTALL_DIR share/OpenCV/java)
   endif(WIN32)
-  install(FILES ${JAR_FILE} DESTINATION ${JAR_INSTALL_DIR} COMPONENT java)
+  install(FILES ${JAR_FILE} OPTIONAL DESTINATION ${JAR_INSTALL_DIR} COMPONENT java)
 endif(ANDROID)
 
 # step 5: build native part
@@ -312,16 +312,16 @@ if(ENABLE_SOLUTION_FOLDERS)
 endif()
 
 if(ANDROID)
-  ocv_install_target(${the_module} EXPORT OpenCVModules
+  ocv_install_target(${the_module} OPTIONAL EXPORT OpenCVModules
           LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT java
           ARCHIVE DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT java)
 else()
   if(NOT INSTALL_CREATE_DISTRIB)
-    ocv_install_target(${the_module} EXPORT OpenCVModules
+    ocv_install_target(${the_module} OPTIONAL EXPORT OpenCVModules
             RUNTIME DESTINATION ${JAR_INSTALL_DIR} COMPONENT java
             LIBRARY DESTINATION ${JAR_INSTALL_DIR} COMPONENT java)
   else()
-    ocv_install_target(${the_module} EXPORT OpenCVModules
+    ocv_install_target(${the_module} OPTIONAL EXPORT OpenCVModules
             RUNTIME DESTINATION ${JAR_INSTALL_DIR}/${OpenCV_ARCH} COMPONENT java
             LIBRARY DESTINATION ${JAR_INSTALL_DIR}/${OpenCV_ARCH} COMPONENT java)
   endif()
index 593fee4..dca4e56 100644 (file)
@@ -20,6 +20,7 @@ ocv_list_filterout(candidate_deps "^opencv_adas$")
 ocv_list_filterout(candidate_deps "^opencv_tracking$")
 ocv_list_filterout(candidate_deps "^opencv_bioinspired$")
 ocv_list_filterout(candidate_deps "^opencv_java$")
+ocv_list_filterout(candidate_deps "^opencv_contrib_world$")
 
 ocv_add_module(${MODULE_NAME} BINDINGS OPTIONAL ${candidate_deps})
 
@@ -113,7 +114,7 @@ else()
 endif()
 
 if(NOT INSTALL_CREATE_DISTRIB)
-  install(TARGETS ${the_module}
+  install(TARGETS ${the_module} OPTIONAL
           ${PYTHON_INSTALL_CONFIGURATIONS}
           RUNTIME DESTINATION ${PYTHON_PACKAGES_PATH} COMPONENT python
           LIBRARY DESTINATION ${PYTHON_PACKAGES_PATH} COMPONENT python
index 0846e0f..1acd2b2 100755 (executable)
@@ -52,7 +52,6 @@ def build_opencv(srcroot, buildroot, target, arch):
     cmakeargs = ("-GXcode " +
                 "-DCMAKE_BUILD_TYPE=Release " +
                 "-DCMAKE_TOOLCHAIN_FILE=%s/platforms/ios/cmake/Toolchains/Toolchain-%s_Xcode.cmake " +
-                "-DBUILD_opencv_world=ON " +
                 "-DCMAKE_C_FLAGS=\"-Wno-implicit-function-declaration\" " +
                 "-DCMAKE_INSTALL_PREFIX=install") % (srcroot, target)
 
@@ -60,7 +59,13 @@ def build_opencv(srcroot, buildroot, target, arch):
         cmakeargs += " -DENABLE_NEON=ON"
 
     if opencv_contrib_path is not None:
-        cmakeargs += " -DOPENCV_EXTRA_MODULES_PATH=%s -DOPENCV_EXTRA_WORLD=ON" % opencv_contrib_path
+        cmakeargs += " -DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON -DOPENCV_EXTRA_MODULES_PATH=%s -DBUILD_opencv_contrib_world=ON" % opencv_contrib_path
+        build_target = "opencv_contrib_world"
+        libname = "libopencv_contrib_world.a"
+    else:
+        cmakeargs += " -DBUILD_opencv_world=ON"
+        build_target = "ALL_BUILD"
+        libname = "libopencv_world.a"
 
     # if cmake cache exists, just rerun cmake to update OpenCV.xcodeproj if necessary
     if os.path.isfile(os.path.join(builddir, "CMakeCache.txt")):
@@ -68,12 +73,12 @@ def build_opencv(srcroot, buildroot, target, arch):
     else:
         execute("cmake %s %s" % (cmakeargs, srcroot))
 
-    for wlib in [builddir + "/modules/world/UninstalledProducts/libopencv_world.a",
-                 builddir + "/lib/Release/libopencv_world.a"]:
+    for wlib in [builddir + "/modules/world/UninstalledProducts/" + libname,
+                 builddir + "/lib/Release/" + libname]:
         if os.path.isfile(wlib):
             os.remove(wlib)
 
-    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 -parallelizeTargets ARCHS=%s -jobs 8 -sdk %s -configuration Release -target ALL_BUILD" % (arch, target.lower()))
+    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 -parallelizeTargets ARCHS=%s -jobs 8 -sdk %s -configuration Release -target %s" % (arch, target.lower(), build_target))
     execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 ARCHS=%s -sdk %s -configuration Release -target install install" % (arch, target.lower()))
     os.chdir(currdir)
 
@@ -81,6 +86,7 @@ def put_framework_together(srcroot, dstroot):
     "constructs the framework directory after all the targets are built"
 
     name = "opencv2" if opencv_contrib_path is None else "opencv2_contrib"
+    libname = "libopencv_world.a" if opencv_contrib_path is None else "libopencv_contrib_world.a"
 
     # find the list of targets (basically, ["iPhoneOS", "iPhoneSimulator"])
     targetlist = glob.glob(os.path.join(dstroot, "build", "*"))
@@ -103,7 +109,7 @@ def put_framework_together(srcroot, dstroot):
     shutil.copytree(tdir0 + "/install/include/opencv2", dstdir + "/Headers")
 
     # make universal static lib
-    wlist = " ".join(["../build/" + t + "/lib/Release/libopencv_world.a" for t in targetlist])
+    wlist = " ".join(["../build/" + t + "/lib/Release/" + libname for t in targetlist])
     execute("lipo -create " + wlist + " -o " + dstdir + "/%s" % name)
 
     # copy Info.plist