11.08., 9:00 - 11:00: Due to updates GitLab will be unavailable for some minutes between 09:00 and 11:00.

macros.cmake 19.2 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 170 171 172 173 174
        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()
175
    ENDIF(${CAMPVIS_BUILD_MODULE_${ModDirUpper}})
176 177 178 179 180 181 182 183 184 185

    # 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)
186 187 188
    UNSET(CampvisApplicationSources)
    UNSET(CampvisApplicationHeaders)
    UNSET(CampvisApplicationToBeMocced)
189 190 191 192
    UNSET(ThisModExternalDllsDebug)
    UNSET(ThisModExternalDllsRelease)
    UNSET(ThisModShaderDirectories)
    UNSET(ThisModDependencies)
193 194 195
    UNSET(ThisModStatus)
    UNSET(ThisModExternalDependencies)
    UNSET(ModuleEnabled)
196
ENDMACRO(INCLUDE_MODULE)
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 243 244 245 246 247
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)
248

249
# copy and pasted from Voreen...
schultezub's avatar
schultezub committed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

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)

266 267 268 269 270 271 272 273 274 275
# 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
276 277
# copies the passed debug and release DLLs to bin/Debug and bin/Release, resp.
MACRO(COPY_EXTERNAL_DLLS DebugDLLs ReleaseDLLs failOnError)
278
    MESSAGE(STATUS "* Copying external DLLs")
schultezub's avatar
schultezub committed
279
    
schultezub's avatar
schultezub committed
280
    SET(debug_dir "${CMAKE_BINARY_DIR}/bin/Debug")
schultezub's avatar
schultezub committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    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
298
    SET(release_dir "${CMAKE_BINARY_DIR}/bin/Release")
schultezub's avatar
schultezub committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
    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()

317
MACRO(DEPLOY_DIRECTORY Target DirectoryList)
schultezub's avatar
schultezub committed
318
    MESSAGE(${Target})
319 320
    MESSAGE(${DirectoryList})
    FOREACH(Directory ${DirectoryList})
schultezub's avatar
schultezub committed
321 322
        ADD_CUSTOM_COMMAND(
            TARGET ${Target}
323
            COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_PATH}/${Directory}" "$<TARGET_FILE_DIR:${Target}>/${Directory}"
schultezub's avatar
schultezub committed
324 325
        )
    ENDFOREACH()
326
ENDMACRO(DEPLOY_DIRECTORY)
schultezub's avatar
schultezub committed
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 386 387 388 389 390

# 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)
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 431 432 433 434 435

# 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()
436
ENDMACRO(DEFINE_SOURCE_GROUPS_FROM_SUBDIR)