In January 2021 we will introduce a 10 GB quota for project repositories. Higher limits for individual projects will be available on request. Please see https://doku.lrz.de/display/PUBLIC/GitLab for more information.

macros.cmake 19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
MACRO(ADD_PIPELINE_REGISTRATION IncludeFile ClassName)
    LIST(APPEND PipelineRegistrationIncludeFiles ${IncludeFile})
    LIST(APPEND PipelineRegistrationClassNames ${ClassName})
ENDMACRO(ADD_PIPELINE_REGISTRATION)

MACRO(WRITE_PIPELINE_REGISTRATION FileName)
    MESSAGE(STATUS "* Generating pipeline registration header: ${FileName}")
    SET(PipelineRegistrationSource "// WARNING: This file is automatically generated by CMake, do not modify!\n\n" )

    LIST(APPEND PipelineRegistrationSource "// Include Pipeline Headers:\n" )
    FOREACH(IncludeFile ${PipelineRegistrationIncludeFiles})
        LIST(APPEND PipelineRegistrationSource "#include \"${IncludeFile}\"\n" )
    ENDFOREACH()
    
15
    LIST(APPEND PipelineRegistrationSource "\n// Instantiate templated PipelineRegistrars to register the pipelines.\n" )
16
    FOREACH(ClassName ${PipelineRegistrationClassNames})
17
        LIST(APPEND PipelineRegistrationSource "template class campvis::PipelineRegistrar<${ClassName}>\;\n" )
18 19
    ENDFOREACH()

20
    LIST(APPEND PipelineRegistrationSource "\n" )
21 22 23 24

    FILE(WRITE ${FileName} ${PipelineRegistrationSource})
ENDMACRO(WRITE_PIPELINE_REGISTRATION)

25 26
MACRO(PARSE_HEADER_FOR_PIPELINE FileName)
    FILE(READ ${FileName} content)
27 28 29 30 31

    # Build a regex matching pipeline declarations and extracting their names
    SET(NameRegex "[A-Za-z0-9_]+")
    SET(FullyQualifiedNameRegex "(::)?(${NameRegex}::)*${NameRegex}")
    SET(BaseClassListRegex "((public|private|protected)( virtual)? ${FullyQualifiedNameRegex}, )*")
32
    SET(NamespaceRegex "namespace (${NameRegex}) {")
33 34
    SET(ClassRegex "class (${NameRegex}) ?: ${BaseClassListRegex}public ${FullyQualifiedNameRegex}Pipeline")

35 36 37 38 39 40 41 42 43
    # Find the namespace nesting of this class (very simplified parsing)
    SET(FullNamespace "")
    STRING(REGEX MATCHALL ${NamespaceRegex} namespaces ${content})
    FOREACH(n ${namespaces})
        # Extract namespace name and concatenate
        STRING(REGEX REPLACE ${NamespaceRegex} "\\1" RESULT ${n})
        SET(FullNamespace "${FullNamespace}${RESULT}::")
    ENDFOREACH()

44
    # Find all class definitions inheriting from a Pipeline
45
    STRING(REGEX MATCHALL ${ClassRegex} matches ${content})
46 47 48
    
    FOREACH(m ${matches})
        # Extract class name and register
49
        STRING(REGEX REPLACE ${ClassRegex} "\\1" RESULT ${m})
50
        ADD_PIPELINE_REGISTRATION(${FileName} "${FullNamespace}${RESULT}")
51 52 53
    ENDFOREACH()
ENDMACRO(PARSE_HEADER_FOR_PIPELINE)

54 55 56 57 58 59 60 61 62 63 64 65
MACRO(ADD_SCRIPTED_PIPELINE_REGISTRATION ScriptFile PipelineName)
    LIST(APPEND ScriptedPipelineRegistrationScriptFiles ${ScriptFile})
    LIST(APPEND ScriptedPipelineRegistrationPipelineNames ${PipelineName})
ENDMACRO(ADD_SCRIPTED_PIPELINE_REGISTRATION)

MACRO(WRITE_SCRIPTED_PIPELINE_REGISTRATION FileName)
    MESSAGE(STATUS "* Generating scripted pipeline registration header: ${FileName}")
    SET(PipelineRegistrationSource "// WARNING: This file is automatically generated by CMake, do not modify!\n\n" )

    LIST(APPEND PipelineRegistrationSource "// Include required headers:\n"
                                           "#include \"scripting/scriptedpipelineregistrar.h\"\n")

66
    LIST(APPEND PipelineRegistrationSource "\nnamespace campvis {\n" )
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    LIST(APPEND PipelineRegistrationSource "\t\t// Instantiate templated ScriptedPipelineRegistrars to register pipelines.\n" )

    WHILE(ScriptedPipelineRegistrationPipelineNames)
        LIST(GET ScriptedPipelineRegistrationPipelineNames 0 PipelineName)
        LIST(REMOVE_AT ScriptedPipelineRegistrationPipelineNames 0)

        LIST(GET ScriptedPipelineRegistrationScriptFiles 0 ScriptFile)
        LIST(REMOVE_AT ScriptedPipelineRegistrationScriptFiles 0)

        LIST(APPEND PipelineRegistrationSource "\t\tchar ${PipelineName}PipelineId[] = \"${PipelineName}\"\;\n"
                                               "\t\tchar ${PipelineName}PipelineScript[] = \"${ScriptFile}\"\;\n"
                                               "\t\ttemplate class ScriptedPipelineRegistrar"
                                               "<IdentifiableLuaPipeline<${PipelineName}PipelineId>, "
                                               "${PipelineName}PipelineScript>\;\n")
    ENDWHILE(ScriptedPipelineRegistrationPipelineNames)

83
    LIST(APPEND PipelineRegistrationSource "}\n" )
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108

    FILE(WRITE ${FileName} ${PipelineRegistrationSource})
ENDMACRO(WRITE_SCRIPTED_PIPELINE_REGISTRATION)

MACRO(PARSE_SCRIPT_FOR_PIPELINE FileName)
    FILE(READ ${FileName} content)

    # Build a regex matching pipeline declarations and extracting their names
    SET(DeclarationRegex "pipeline = campvis.newPipeline\\(\"([A-Za-z0-9_]+)\"\\)")

    # Find all pipeline declarations
    STRING(REGEX MATCHALL ${DeclarationRegex} matches ${content})
    LIST(LENGTH matches MatchCount)

    IF(MatchCount LESS 1)
        MESSAGE(WARNING "No pipelines found in script '${FileName}'")
    ELSEIF(MatchCount GREATER 1)
        MESSAGE(WARNING "Script '${FileName}' defines multiple pipelines; ignoring")
    ELSE(MatchCount LESS 1)
        # Extract pipeline name and register
        STRING(REGEX REPLACE ${DeclarationRegex} "\\1" RESULT ${matches})
        ADD_SCRIPTED_PIPELINE_REGISTRATION(${FileName} ${RESULT})
    ENDIF(MatchCount LESS 1)
ENDMACRO(PARSE_SCRIPT_FOR_PIPELINE)

109
MACRO(INCLUDE_MODULE ModuleDirectory ModuleListFile)
110
    STRING(TOUPPER ${ModuleDirectory} ModuleDirectoryUpper)
111 112
    SET(ThisModDir ${ModulesDir}/${ModuleDirectory})

113
    # if module is not enabled, load .cmake file for the first time to gather module status and other meta information
114
    IF(NOT DEFINED CAMPVIS_BUILD_MODULE_${ModDirUpper})
115 116 117 118 119
        # add a CMake option for building this module
        OPTION(CAMPVIS_BUILD_MODULE_${ModDirUpper}  "Build Module ${ModDir} (${ThisModStatus})" OFF)
        
        SET(ModuleEnabled FALSE)
        INCLUDE(${ModuleListFile})
120 121 122 123
        
        IF(NOT DEFINED ThisModExternalDependencies)
            SET(ThisModExternalDependencies FALSE)
        ENDIF(NOT DEFINED ThisModExternalDependencies)
124 125 126 127 128 129 130 131 132 133 134 135 136 137
            
        # enable module if module status matches CAMPVIS_DEFAULT_ENABLED_MODULES
        IF(${CAMPVIS_DEFAULT_ENABLED_MODULES} STREQUAL "STABLE_NO_DEPENDENCIES" AND ThisModStatus STREQUAL STABLE AND NOT ThisModExternalDependencies)
            SET(CAMPVIS_BUILD_MODULE_${ModDirUpper} ON CACHE BOOL "Build Module ${ModDir} (${ThisModStatus})" FORCE)
        ENDIF()
        IF(${CAMPVIS_DEFAULT_ENABLED_MODULES} STREQUAL "STABLE_WITH_EXTERNAL_DEPENDENCIES" AND ThisModStatus STREQUAL STABLE)
            SET(CAMPVIS_BUILD_MODULE_${ModDirUpper} ON CACHE BOOL "Build Module ${ModDir} (${ThisModStatus})" FORCE)
        ENDIF()
        IF(${CAMPVIS_DEFAULT_ENABLED_MODULES} STREQUAL "TESTING" AND (ThisModStatus STREQUAL STABLE OR ThisModStatus STREQUAL TESTING))
            SET(CAMPVIS_BUILD_MODULE_${ModDirUpper} ON CACHE BOOL "Build Module ${ModDir} (${ThisModStatus})" FORCE)
        ENDIF()
        IF(${CAMPVIS_DEFAULT_ENABLED_MODULES} STREQUAL "ALL")
            SET(CAMPVIS_BUILD_MODULE_${ModDirUpper} ON CACHE BOOL "Build Module ${ModDir} (${ThisModStatus})" FORCE)
        ENDIF()
138
    ENDIF(NOT DEFINED CAMPVIS_BUILD_MODULE_${ModDirUpper})
139 140
    
    # if module is enabled, load .cmake file for the second time, this time also parsing its build instructions
141
    IF(${CAMPVIS_BUILD_MODULE_${ModDirUpper}})
142 143 144 145 146 147 148 149 150 151 152 153 154 155
        SET(ModuleEnabled TRUE)
        INCLUDE(${ModuleListFile})
        
        LIST(APPEND CampvisEnabledModules ${ModuleDirectory})

        # 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})
156 157 158
        LIST(APPEND CampvisModulesApplicationSources ${ThisModApplicationSources})
        LIST(APPEND CampvisModulesApplicationHeaders ${ThisModApplicationHeaders})
        LIST(APPEND CampvisModulesApplicationToBeMocced ${ThisModApplicationToBeMocced})
159 160 161 162 163 164 165 166 167 168 169
        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})
170
    ENDIF(${CAMPVIS_BUILD_MODULE_${ModDirUpper}})
171 172 173 174 175 176 177 178 179 180

    # 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)
181 182 183
    UNSET(CampvisApplicationSources)
    UNSET(CampvisApplicationHeaders)
    UNSET(CampvisApplicationToBeMocced)
184 185 186 187
    UNSET(ThisModExternalDllsDebug)
    UNSET(ThisModExternalDllsRelease)
    UNSET(ThisModShaderDirectories)
    UNSET(ThisModDependencies)
188 189 190
    UNSET(ThisModStatus)
    UNSET(ThisModExternalDependencies)
    UNSET(ModuleEnabled)
191
ENDMACRO(INCLUDE_MODULE)
192

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
MACRO(RESOLVE_MODULE_DEPENDENCIES)
    # 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)
ENDMACRO(RESOLVE_MODULE_DEPENDENCIES)

MACRO(SET_DEFAULT_MODULES DefaultModules)
    # Only enable default modules on the first CMake run
    IF(NOT DEFAULT_CAMPVIS_MODULES_SET)
        FOREACH(Mod ${DefaultModules})
            # Check if the module exists
            LIST(FIND CampvisModules ${Mod} ModExists)
            STRING(TOUPPER ${Mod} ModUpper)

            IF(ModExists EQUAL -1)
                MESSAGE(WARNING "Default module '${Mod}' not found!")
            ELSEIF(NOT CAMPVIS_BUILD_MODULE_${ModUpper})
                # Enable the module if required
                MESSAGE(STATUS "Enabling default module '${Mod}'")
                SET(CAMPVIS_BUILD_MODULE_${ModUpper} ON CACHE BOOL "Build default module ${Mod}" FORCE)
                SET(ModFile ${ModulesDir}/${Mod}/${Mod}.cmake)
                INCLUDE_MODULE(${Mod} ${ModFile})
            ENDIF(ModExists EQUAL -1)
        ENDFOREACH(Mod ${DefaultModules})
    ENDIF(NOT DEFAULT_CAMPVIS_MODULES_SET)

    SET(DEFAULT_CAMPVIS_MODULES_SET 1 CACHE INTERNAL "")
ENDMACRO(SET_DEFAULT_MODULES DefaultModules)
243

244
# copy and pasted from Voreen...
schultezub's avatar
schultezub committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

MACRO(LIST_SUBDIRECTORIES Result Directory AbsolutePath)
  FILE(GLOB sub-dirs RELATIVE ${Directory} ${Directory}/*)
  SET(${Result} "")
  FOREACH(d ${sub-dirs})
    IF(IS_DIRECTORY ${Directory}/${d})
        IF(${AbsolutePath})
            LIST(APPEND ${Result} ${Directory}/${d})
        ELSE()
            LIST(APPEND ${Result} ${d})
        ENDIF()
    ENDIF()
  ENDFOREACH()
  LIST(SORT ${Result})
ENDMACRO(LIST_SUBDIRECTORIES)

261 262 263 264 265 266 267 268 269 270
# Resolve Qt5 DLL locations
MACRO(RESOLVE_QT5_DLL_LOCATIONS Components)
    FOREACH(component ${Components})
        GET_TARGET_PROPERTY(DebugLocation "Qt5::${component}" LOCATION_DEBUG)
        GET_TARGET_PROPERTY(ReleaseLocation "Qt5::${component}" LOCATION)
        LIST(APPEND CampvisExternalDllsDebug ${DebugLocation})
        LIST(APPEND CampvisExternalDllsRelease ${ReleaseLocation})
    ENDFOREACH()    
ENDMACRO(RESOLVE_QT5_DLL_LOCATIONS)

schultezub's avatar
schultezub committed
271 272
# copies the passed debug and release DLLs to bin/Debug and bin/Release, resp.
MACRO(COPY_EXTERNAL_DLLS DebugDLLs ReleaseDLLs failOnError)
273
    MESSAGE(STATUS "* Copying external DLLs")
schultezub's avatar
schultezub committed
274
    
schultezub's avatar
schultezub committed
275
    SET(debug_dir "${CMAKE_BINARY_DIR}/bin/Debug")
schultezub's avatar
schultezub committed
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
    IF(NOT EXISTS ${debug_dir})
        FILE(MAKE_DIRECTORY ${debug_dir})    
    ENDIF()
    FOREACH(dllPath ${${DebugDLLs}})
        IF(EXISTS ${dllPath})
            GET_FILENAME_COMPONENT(dllName ${dllPath} NAME)
            IF(EXISTS ${debug_dir}/${dllName})
                FILE(REMOVE ${debug_dir}/${dllName})
            ENDIF()
            FILE(COPY ${dllPath} DESTINATION ${debug_dir})
        ELSEIF(${failOnError})
            MESSAGE(FATAL_ERROR "Debug DLL not found: ${dllPath}")
        ELSE()
            MESSAGE(WARNING "Debug DLL not found: ${dllPath}")
        ENDIF()
    ENDFOREACH()
    
schultezub's avatar
schultezub committed
293
    SET(release_dir "${CMAKE_BINARY_DIR}/bin/Release")
schultezub's avatar
schultezub committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    IF(NOT EXISTS ${release_dir})
        FILE(MAKE_DIRECTORY ${release_dir})    
    ENDIF()
    FOREACH(dllPath ${${ReleaseDLLs}})
        IF(EXISTS ${dllPath})            
            GET_FILENAME_COMPONENT(dllName ${dllPath} NAME)
            IF(EXISTS ${release_dir}/${dllName})
                FILE(REMOVE ${release_dir}/${dllName})
            ENDIF()
            FILE(COPY ${dllPath} DESTINATION ${release_dir})
        ELSEIF(${failOnError})
            MESSAGE(FATAL_ERROR "Release DLL not found: ${dllPath}")
        ELSE()
            MESSAGE(WARNING "Release DLL not found: ${dllPath}")
        ENDIF()
    ENDFOREACH()
ENDMACRO()

312
MACRO(DEPLOY_DIRECTORY Target DirectoryList)
schultezub's avatar
schultezub committed
313
    MESSAGE(${Target})
314 315
    MESSAGE(${DirectoryList})
    FOREACH(Directory ${DirectoryList})
schultezub's avatar
schultezub committed
316 317
        ADD_CUSTOM_COMMAND(
            TARGET ${Target}
318
            COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_PATH}/${Directory}" "$<TARGET_FILE_DIR:${Target}>/${Directory}"
schultezub's avatar
schultezub committed
319 320
        )
    ENDFOREACH()
321
ENDMACRO(DEPLOY_DIRECTORY)
schultezub's avatar
schultezub committed
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385

# adapted from: http://stackoverflow.com/questions/148570/using-pre-compiled-headers-with-cmake
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
  IF(MSVC)
    GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
    SET(PrecompiledBinary "${CMAKE_CURRENT_BINARY_DIR}/${PrecompiledBasename}.pch")
    SET(Sources ${${SourcesVar}})

    SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
                                PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_OUTPUTS "${PrecompiledBinary}")
    SET_SOURCE_FILES_PROPERTIES(${Sources}
                                PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledBinary}\" /FI\"${PrecompiledBinary}\" /Fp\"${PrecompiledBinary}\""
                                           OBJECT_DEPENDS "${PrecompiledBinary}")  

    # Add precompiled header to SourcesVar
    LIST(APPEND ${SourcesVar} ${PrecompiledSource})
  ENDIF(MSVC)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)

# adapted from: http://www.mail-archive.com/cmake@cmake.org/msg04394.html
MACRO(ADD_GCC_PRECOMPILED_HEADER _targetName _input )

    GET_FILENAME_COMPONENT(_name ${_input} NAME)
    SET(_source "${CMAKE_CURRENT_SOURCE_DIR}/${_input}")
    SET(_outdir "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch")
    MAKE_DIRECTORY(${_outdir})
    SET(_output "${_outdir}/${CMAKE_BUILD_TYPE}.c++")
    STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name)
    SET(_compiler_FLAGS ${${_flags_var_name}})

    GET_TARGET_PROPERTY(_type ${_targetName} TYPE)
    IF(${_type} MATCHES SHARED_LIBRARY)
        LIST(APPEND _compiler_FLAGS "-fPIC")
    ENDIF()

    GET_DIRECTORY_PROPERTY(_directory_flags INCLUDE_DIRECTORIES)
    FOREACH(item ${_directory_flags})
    LIST(APPEND _compiler_FLAGS "-I${item}")
    ENDFOREACH(item)


    GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS)
    LIST(APPEND _compiler_FLAGS ${_directory_flags})

    SEPARATE_ARGUMENTS(_compiler_FLAGS)
    #MESSAGE("_compiler_FLAGS: ${_compiler_FLAGS}")
    #message("${CMAKE_CXX_COMPILER} ${_compiler_FLAGS} -x c++-header -o ${_output} ${_source}")
    ADD_CUSTOM_COMMAND(
        OUTPUT ${_output}
        COMMAND ${CMAKE_CXX_COMPILER}
                                ${_compiler_FLAGS}
                                -x c++-header
                                -o ${_output} ${_source}
        DEPENDS ${_source} )
        ADD_CUSTOM_TARGET(${_targetName}_gch DEPENDS ${_output})
    ADD_DEPENDENCIES(${_targetName} ${_targetName}_gch)
    #SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-include ${_name} -Winvalid-pch -H")
    #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include ${_name} -Winvalid-pch")
    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES
        COMPILE_FLAGS "-include ${_name} -Winvalid-pch"
    )
        
ENDMACRO(ADD_GCC_PRECOMPILED_HEADER)
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430

# Assigns the passed Files to source groups according to their file path.
# The path prefixes as well as dot operators are removed from the path.
# E.g.: path/to/my/file.cpp               =>  path\\to\\my
#       <PathPrefix>/path/to/my/file.cpp  =>  path\\to\\my
#       ../../path/to/my/file.cpp         =>  path\\to\\my
MACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR Files BasePath RemovePathPrefixes)
    FOREACH(f ${${Files}})
        SET(f_cat "")
        
        # extract relative file path
        IF(IS_ABSOLUTE ${f})
            FILE(RELATIVE_PATH f_rel ${BasePath} ${f})
            GET_FILENAME_COMPONENT(f_rel ${f_rel} PATH)
        ELSE()
            GET_FILENAME_COMPONENT(f_rel ${f} PATH)
        ENDIF()
        
        # create source group specifier from rel path
        IF(f_rel)
            # remove ../
            string(REGEX REPLACE "\\.\\./" "" f_cat ${f_rel})
            # remove specified prefixes
            FOREACH(prefix ${${RemovePathPrefixes}})
                IF(f_cat)
                    string(REGEX REPLACE "${prefix}" "" f_cat ${f_cat})
                ENDIF()
            ENDFOREACH()
            
            # convert path separators into source group separators: 
            # path/to/my => path\\to\\my
            IF(f_cat)
                string(REGEX REPLACE "\\\\|/" "\\\\\\\\" f_cat ${f_cat})
            ENDIF()
        ENDIF()
        
        # set extracted source group
        IF(f_cat)
            SOURCE_GROUP("${f_cat}" FILES ${f})
        ELSE()
            SOURCE_GROUP("" FILES ${f})
        ENDIF()
        
#        MESSAGE(STATUS "${f} -> ${f_cat}")
    ENDFOREACH()
431
ENDMACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR)