macros.cmake 19.1 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")
294
295
    SET(minsizerel_dir "${CMAKE_BINARY_DIR}/bin/MinSizeRel")
    SET(relwithdebinfo_dir "${CMAKE_BINARY_DIR}/bin/RelWithDebInfo")
schultezub's avatar
schultezub committed
296
297
298
299
300
301
    IF(NOT EXISTS ${release_dir})
        FILE(MAKE_DIRECTORY ${release_dir})    
    ENDIF()
    FOREACH(dllPath ${${ReleaseDLLs}})
        IF(EXISTS ${dllPath})            
            GET_FILENAME_COMPONENT(dllName ${dllPath} NAME)
302

schultezub's avatar
schultezub committed
303
            FILE(COPY ${dllPath} DESTINATION ${release_dir})
304
305
            FILE(COPY ${dllPath} DESTINATION ${minsizerel_dir})
            FILE(COPY ${dllPath} DESTINATION ${relwithdebinfo_dir})
schultezub's avatar
schultezub committed
306
307
308
309
310
311
312
313
        ELSEIF(${failOnError})
            MESSAGE(FATAL_ERROR "Release DLL not found: ${dllPath}")
        ELSE()
            MESSAGE(WARNING "Release DLL not found: ${dllPath}")
        ENDIF()
    ENDFOREACH()
ENDMACRO()

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

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

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