Commit e1551c26 authored by Artur Grunau's avatar Artur Grunau

Implement a dependency system for CAMPVis modules

There used to be no way to specify what other modules each module
required in order to work. This led to either compilation or linker
errors that were often not easy to understand.

Introduce a new module-level CMake variable, ThisModDependencies, that a
module can set in its CMake file to indicate what other modules need to
be enabled for it to compile and work properly. If defined,
ThisModDependencies should be a list of strings — the names of required
modules.

Once all available modules have been analysed, the collected dependency
information is used to activate (if necessary) the dependencies of every
enabled module. Transitive and circular dependencies are already
supported in this initial version of our module dependency system.

Unfortunately, when a module gets enabled in the CMake GUI, its
dependencies are only resolved once the Configure button is clicked and
CMake runs again. This is a limitation of CMake in that all
configuration happens offline and it's not possible to react to value
changes immediately.

References #144
parent 0c73f0f7
......@@ -36,6 +36,53 @@ MACRO(PARSE_HEADER_FOR_PIPELINE FileName)
ENDFOREACH()
ENDMACRO(PARSE_HEADER_FOR_PIPELINE)
MACRO(INCLUDE_MODULE ModuleDirectory ModuleListFile)
LIST(APPEND CampvisEnabledModules ${ModuleDirectory})
SET(ThisModDir ${ModulesDir}/${ModuleDirectory})
# load .cmake file
INCLUDE(${ModuleListFile})
# merge module settings into global settings
LIST(APPEND CampvisModulesDefinitions ${ThisModDefinitions})
LIST(APPEND CampvisModulesIncludeDirs ${ThisModIncludeDirs})
LIST(APPEND CampvisModulesExternalLibs ${ThisModExternalLibs})
LIST(APPEND CampvisModulesLinkDirectories ${ThisModLinkDirectories})
LIST(APPEND CampvisModulesSources ${ThisModSources})
LIST(APPEND CampvisModulesHeaders ${ThisModHeaders})
LIST(APPEND CampvisModulesCoreSources ${ThisModCoreSources})
LIST(APPEND CampvisModulesCoreHeaders ${ThisModCoreHeaders})
LIST(APPEND CampvisExternalDllsDebug ${ThisModExternalDllsDebug})
LIST(APPEND CampvisExternalDllsRelease ${ThisModExternalDllsRelease})
# save dependencies in a variable to resolve them later
SET(${ModuleDirectory}ModDependencies ${ThisModDependencies})
# add shader directory to deployment list
LIST(APPEND CampvisShaderDirectories ${ThisModShaderDirectories})
# add definition that this module is activated
LIST(APPEND CampvisGlobalDefinitions -DCAMPVIS_HAS_MODULE_${ModuleDirectoryUpper})
# parse all header files for pipeline classes to add them to the pipeline registration
FOREACH(HeaderFile ${ThisModHeaders})
PARSE_HEADER_FOR_PIPELINE("modules/${HeaderFile}")
ENDFOREACH()
# unset module settings to avoid duplicates if module cmake file misses sth.
UNSET(ThisModDefinitions)
UNSET(ThisModIncludeDirs)
UNSET(ThisModExternalLibs)
UNSET(ThisModLinkDirectories)
UNSET(ThisModSources)
UNSET(ThisModHeaders)
UNSET(ThisModCoreSources)
UNSET(ThisModCoreHeaders)
UNSET(ThisModExternalDllsDebug)
UNSET(ThisModExternalDllsRelease)
UNSET(ThisModShaderDirectories)
UNSET(ThisModDependencies)
ENDMACRO(INCLUDE_MODULE)
# copy and pasted from Voreen...
......@@ -214,4 +261,4 @@ MACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR Files BasePath RemovePathPrefixes)
# MESSAGE(STATUS "${f} -> ${f_cat}")
ENDFOREACH()
ENDMACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR)
\ No newline at end of file
ENDMACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR)
......@@ -8,60 +8,22 @@ MESSAGE(STATUS "Detecting installed modules:")
SET(ModulesDir ${CampvisHome}/modules)
LIST_SUBDIRECTORIES(ModDirs ${ModulesDir} false)
# remove CMake and SVN realated directories from list
# remove CMake and SVN related directories from list
LIST(REMOVE_ITEM ModDirs CMakeFiles campvis-modules.dir .svn)
# go through each subdirectory
FOREACH(ModDir ${ModDirs})
# check whether module.cmake file exists
# check whether module.cmake file exists
SET(ModFile ${ModulesDir}/${ModDir}/${ModDir}.cmake)
IF(EXISTS ${ModFile})
STRING(TOLOWER ${ModDir} ModDirLower)
STRING(TOUPPER ${ModDir} ModDirUpper)
LIST(APPEND CampvisModules ${ModDir})
# check whether the option to build this very module exists and is checked
IF(CAMPVIS_BUILD_MODULE_${ModDirUpper})
MESSAGE(STATUS "* Found Module '${ModDir}' : ENABLED")
SET(ThisModDir ${ModulesDir}/${ModDir})
# load .cmake file
INCLUDE(${ModFile})
# merge module settings into global settings
LIST(APPEND CampvisModulesDefinitions ${ThisModDefinitions})
LIST(APPEND CampvisModulesIncludeDirs ${ThisModIncludeDirs})
LIST(APPEND CampvisModulesExternalLibs ${ThisModExternalLibs})
LIST(APPEND CampvisModulesLinkDirectories ${ThisModLinkDirectories})
LIST(APPEND CampvisModulesSources ${ThisModSources})
LIST(APPEND CampvisModulesHeaders ${ThisModHeaders})
LIST(APPEND CampvisModulesCoreSources ${ThisModCoreSources})
LIST(APPEND CampvisModulesCoreHeaders ${ThisModCoreHeaders})
LIST(APPEND CampvisExternalDllsDebug ${ThisModExternalDllsDebug})
LIST(APPEND CampvisExternalDllsRelease ${ThisModExternalDllsRelease})
# add shader directory to deployment list
LIST(APPEND CampvisShaderDirectories ${ThisModShaderDirectories})
# add definition that this module is activated
LIST(APPEND CampvisGlobalDefinitions -DCAMPVIS_HAS_MODULE_${ModDirUpper})
# parse all header files for pipeline classes to add them to the pipeline registration
FOREACH(HeaderFile ${ThisModHeaders})
PARSE_HEADER_FOR_PIPELINE("modules/${HeaderFile}")
ENDFOREACH()
# unset module settings to avoid duplicates if module cmake file misses sth.
UNSET(ThisModDefinitions)
UNSET(ThisModIncludeDirs)
UNSET(ThisModExternalLibs)
UNSET(ThisModLinkDirectories)
UNSET(ThisModSources)
UNSET(ThisModHeaders)
UNSET(ThisModCoreSources)
UNSET(ThisModCoreHeaders)
UNSET(ThisModExternalDllsDebug)
UNSET(ThisModExternalDllsRelease)
UNSET(ThisModShaderDirectories)
INCLUDE_MODULE(${ModDir} ${ModFile})
ELSE()
MESSAGE(STATUS "* Found Module '${ModDir}'")
ENDIF(CAMPVIS_BUILD_MODULE_${ModDirUpper})
......@@ -77,5 +39,31 @@ FOREACH(ModDir ${ModDirs})
ENDFOREACH(ModDir ${ModDirs})
# Iterate over all enabled modules and their dependencies.
# A WHILE loop is used here because FOREACH doesn't see changes to the list it processes.
# As a result, transitive dependencies would require several CMake runs to be resolved.
WHILE(CampvisEnabledModules)
LIST(GET CampvisEnabledModules 0 Mod)
LIST(REMOVE_AT CampvisEnabledModules 0)
FOREACH(Dep ${${Mod}ModDependencies})
# Check if the dependency exists
LIST(FIND CampvisModules ${Dep} DepExists)
STRING(TOUPPER ${Dep} DepUpper)
IF(DepExists EQUAL -1)
MESSAGE(WARNING "Dependency '${Dep}' of module '${Mod}' not found!")
ELSEIF(NOT CAMPVIS_BUILD_MODULE_${DepUpper})
# Enable the dependency if required
MESSAGE(STATUS "Enabling module '${Dep}' (required by '${Mod}')")
SET(CAMPVIS_BUILD_MODULE_${DepUpper} ON CACHE BOOL "Build Module ${Dep} (required by ${Mod})" FORCE)
SET(ModFile ${ModulesDir}/${Dep}/${Dep}.cmake)
INCLUDE_MODULE(${Dep} ${ModFile})
ENDIF(DepExists EQUAL -1)
ENDFOREACH(Dep ${${Mod}ModDependencies})
UNSET(${Mod}ModDependencies)
ENDWHILE(CampvisEnabledModules)
SET(ModulesDirsParsed TRUE)
ENDIF(NOT ModulesDirsParsed)
......@@ -15,4 +15,4 @@ FILE(GLOB ThisModHeaders RELATIVE ${ModulesDir}
)
SET(ThisModShaderDirectories "modules/vis/glsl")
SET(ThisModDependencies devil)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment