1####################################################################################
2#                                                                                  #
3#  Copyright (c) 2014 - 2018 Axel Menzel <info@rttr.org>                           #
4#                                                                                  #
5#  This file is part of RTTR (Run Time Type Reflection)                            #
6#  License: MIT License                                                            #
7#                                                                                  #
8#  Permission is hereby granted, free of charge, to any person obtaining           #
9#  a copy of this software and associated documentation files (the "Software"),    #
10#  to deal in the Software without restriction, including without limitation       #
11#  the rights to use, copy, modify, merge, publish, distribute, sublicense,        #
12#  and/or sell copies of the Software, and to permit persons to whom the           #
13#  Software is furnished to do so, subject to the following conditions:            #
14#                                                                                  #
15#  The above copyright notice and this permission notice shall be included in      #
16#  all copies or substantial portions of the Software.                             #
17#                                                                                  #
18#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR      #
19#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,        #
20#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE     #
21#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER          #
22#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,   #
23#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE   #
24#  SOFTWARE.                                                                       #
25#                                                                                  #
26####################################################################################
27
28####################################################################################
29# Welcome to the CMake build system for RTTR.
30# This file contains several helper function to make the life easier with cmake.
31####################################################################################
32
33####################################################################################
34# create hierarchical source groups, useful for big VS-Projects
35# FILE_LIST <= a list of files with absolute path
36####################################################################################
37function (createSrcGroups FILE_LIST )
38  # we want to get the relative path from the
39  # current source dir
40  string(LENGTH ${CMAKE_CURRENT_SOURCE_DIR} curDirLen)
41  set(TMP_FILE_LIST ${${FILE_LIST}})
42
43  foreach ( SOURCE ${TMP_FILE_LIST} )
44    string(LENGTH ${SOURCE} fullPathLen)
45    math(EXPR RelPathLen ${fullPathLen}-${curDirLen})
46    string(SUBSTRING ${SOURCE} ${curDirLen} ${RelPathLen} curStr)
47
48    string ( REGEX REPLACE "[\\/]" "\\\\" normPath ${curStr} )
49    string ( REGEX MATCH "\\\\(.*)\\\\" ouput ${normPath} )
50    if(NOT CMAKE_MATCH_1 STREQUAL "")
51      source_group ( ${CMAKE_MATCH_1} FILES ${SOURCE} )
52    endif()
53  endforeach()
54endfunction()
55
56####################################################################################
57# Create a UnityFile. This is a file which inlcudes all other source files.
58# This is usefull, when you want a fast rebuild.
59# _UNITY_FILE <= The name of the UnityFile
60# _SRC_FILES <= The list of source files
61####################################################################################
62function(generateUnityFile _UNITY_FILE _SRC_FILES)
63  set(files ${${_SRC_FILES}})
64  # Generate a unique filename for the unity build translation unit
65  set(unit_build_file ${CMAKE_CURRENT_BINARY_DIR}/ub_${_UNITY_FILE}.cpp)
66  set_source_files_properties(${files} PROPERTIES HEADER_FILE_ONLY true)
67  # Open the ub file
68  FILE(WRITE ${unit_build_file} "// Unity Build generated by CMake\n")
69  # Add include statement for each translation unit
70  foreach(sourceFile ${files} )
71    #FILE( APPEND ${unit_build_file} "#include <${CMAKE_CURRENT_SOURCE_DIR}/${sourceFile}>\n")
72    FILE( APPEND ${unit_build_file} "#include \"${sourceFile}\"\n")
73  endforeach()
74  # Complement list of translation units with the name of ub
75  set(${_UNITY_FILE} ${unit_build_file} PARENT_SCOPE)
76  source_group("Generated Files" FILES ${unit_build_file})
77endfunction()
78
79####################################################################################
80# Returns the name of the Directory, where the file in the FILE_PATH is located.
81####################################################################################
82function(getNameOfDir FILE_PATH DIR_NAME)
83  get_filename_component(HAS_FILE_IN_PATH ${${FILE_PATH}} EXT)
84  if (HAS_FILE_IN_PATH)
85    get_filename_component(PATH_WITHOUT_FILENAME ${${FILE_PATH}} PATH)
86    get_filename_component(NAME_OF_DIR  ${PATH_WITHOUT_FILENAME} NAME)
87    set(${DIR_NAME} ${NAME_OF_DIR} PARENT_SCOPE)
88  else()
89    get_filename_component(NAME_OF_DIR ${${FILE_PATH}} NAME)
90    set(${DIR_NAME} ${NAME_OF_DIR} PARENT_SCOPE)
91  endif()
92endfunction()
93
94####################################################################################
95# Returns relative path from the given file path; starting from CMAKE_CURRENT_SOURCE_DIR
96####################################################################################
97
98function(getRelativePath FILE_PATH RELATIVE_PATH)
99  string(LENGTH ${CMAKE_CURRENT_SOURCE_DIR} CUR_DIR_LEN)
100  get_filename_component(PATH_WITHOUT_FILE ${${FILE_PATH}} PATH)
101  string(LENGTH ${PATH_WITHOUT_FILE} FULL_PATH_LEN)
102  math(EXPR REL_PATH_LEN ${FULL_PATH_LEN}-${CUR_DIR_LEN})
103  math(EXPR REL_PATH_START "${CUR_DIR_LEN}")
104  string(SUBSTRING ${PATH_WITHOUT_FILE} ${REL_PATH_START} ${REL_PATH_LEN} REL_PATH)
105  string(REGEX REPLACE "^/" "" out_path "${REL_PATH}")
106  set(${RELATIVE_PATH} ${out_path} PARENT_SCOPE)
107endfunction()
108
109####################################################################################
110# Loads a FOLDER, which should contain a FOLDER.cmake.
111# In this file all source and header files should be declared.
112# In this cmake files all files have to be declared relative.
113# They will be read with absolut path.
114# FOLDER <= The name of the folder
115# _HEADER_FILES => The list of header files
116# _SOURCE_FILES => The list of source files
117# [OPTIONAL] 3rdArg => performs the installation of the header and source files
118####################################################################################
119function(loadFolder FOLDER _HEADER_FILES _SOURCE_FILES)
120  set(FULL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${FOLDER}.cmake)
121  include(${FULL_PATH})
122  get_filename_component(ABS_PATH_TO_FILES ${FULL_PATH} PATH)
123  set(shouldInstall ${ARGV3})
124  set(QT_MOC_HEADERS)
125  set(QT_UI_FILES)
126  set(QT_QRC_FILES)
127
128  foreach(headerFile ${HEADER_FILES} )
129    if (${headerFile} MATCHES ".*.h.in$")
130      string ( REGEX REPLACE ".h.in$" ".h" out_path ${headerFile} )
131      configure_file(${headerFile} ${CMAKE_CURRENT_BINARY_DIR}/${out_path} @ONLY)
132      set(FULL_HEADER_PATH ${ABS_PATH_TO_FILES}/${headerFile})
133      getRelativePath(FULL_HEADER_PATH REL_PATH)
134      set(FULL_HEADER_PATH ${CMAKE_CURRENT_BINARY_DIR}/${out_path})
135      if (REL_PATH)
136        string ( REGEX REPLACE "[\\/]" "\\\\" normalized_path ${REL_PATH} )
137        source_group ( ${normalized_path} FILES ${FULL_HEADER_PATH} )
138      endif()
139      list(APPEND ALL_HPP_FILES ${FULL_HEADER_PATH})
140    elseif (${headerFile} MATCHES ".*.rc.in$")
141      string ( REGEX REPLACE ".rc.in$" ".rc" out_path ${headerFile} )
142      configure_file(${headerFile} ${CMAKE_CURRENT_BINARY_DIR}/${out_path} @ONLY)
143      source_group("Generated Files" FILES ${CMAKE_CURRENT_BINARY_DIR}/${out_path})
144      list(APPEND ALL_HPP_FILES ${CMAKE_CURRENT_BINARY_DIR}/${out_path})
145    elseif (${headerFile} MATCHES ".*.ui$")
146        set(FULL_HEADER_PATH ${ABS_PATH_TO_FILES}/${headerFile})
147        list(APPEND QT_UI_FILES ${FULL_HEADER_PATH})
148        list(APPEND ALL_HPP_FILES ${FULL_HEADER_PATH})
149    elseif (${headerFile} MATCHES ".*.qrc$")
150        set(FULL_HEADER_PATH ${ABS_PATH_TO_FILES}/${headerFile})
151        list(APPEND QT_QRC_FILES ${FULL_HEADER_PATH})
152        list(APPEND ALL_HPP_FILES ${FULL_HEADER_PATH})
153    else()
154      set(FULL_HEADER_PATH ${ABS_PATH_TO_FILES}/${headerFile})
155      file(STRINGS ${FULL_HEADER_PATH} var REGEX "Q_OBJECT")
156      if(var)
157         list(APPEND QT_MOC_HEADERS ${FULL_HEADER_PATH})
158      endif()
159
160      # returns the relative path, from the current source dir
161      getRelativePath(FULL_HEADER_PATH REL_PATH)
162      list(APPEND HEADER_LIST_OF_CUR_DIR ${FULL_HEADER_PATH})
163    endif()
164    # get the name of the current directory
165    getNameOfDir(CMAKE_CURRENT_SOURCE_DIR DIRNAME)
166    if (${shouldInstall})
167      if (NOT ${FULL_HEADER_PATH} MATCHES ".*_p.h$") # we don't want to install header files which are marked as private
168        install(FILES ${FULL_HEADER_PATH} DESTINATION "include/${DIRNAME}/${REL_PATH}")
169      endif()
170    endif()
171  endforeach()
172
173  # and now the source files
174  list(APPEND QML_SOURCES)
175  foreach(srcFile ${SOURCE_FILES} )
176    # the source_group placement doesn't work at the moment
177     if (${srcFile} MATCHES ".*.qml$")
178       string(REGEX REPLACE "[\\/]" "_" qrc_resource_file ${srcFile} )
179       string(REGEX REPLACE ".qml$" ".qrc" qrc_resource_file ${qrc_resource_file} )
180       set(qrc_resource_file ${CMAKE_CURRENT_BINARY_DIR}/${qrc_resource_file})
181       file(WRITE ${qrc_resource_file} "<!DOCTYPE RCC><RCC version=\"1.0\"><qresource prefix=\"/\"><file alias=\"${srcFile}\">${ABS_PATH_TO_FILES}/${srcFile}</file></qresource></RCC>")
182       qt5_add_resources(compiled_resource_file ${qrc_resource_file})
183       source_group("Generated Files" FILES ${compiled_resource_file})
184       source_group("Generated Files" FILES ${qrc_resource_file})
185       list(APPEND QML_SOURCES ${compiled_resource_file})
186     elseif (${srcFile} MATCHES ".*.ui$")
187        set(FULL_SRC_PATH ${ABS_PATH_TO_FILES}/${srcFile})
188        list(APPEND QT_UI_FILES ${FULL_SRC_PATH})
189        list(APPEND SOURCE_LIST_OF_CUR_DIR ${FULL_SRC_PATH})
190    elseif (${srcFile} MATCHES ".*.qrc$")
191        set(FULL_SRC_PATH ${ABS_PATH_TO_FILES}/${srcFile})
192        list(APPEND QT_QRC_FILES ${FULL_SRC_PATH})
193        list(APPEND SOURCE_LIST_OF_CUR_DIR ${FULL_SRC_PATH})
194     else()
195       list(APPEND SOURCE_LIST_OF_CUR_DIR ${ABS_PATH_TO_FILES}/${srcFile})
196     endif()
197
198    list(APPEND SOURCE_LIST_OF_CUR_DIR ${ABS_PATH_TO_FILES}/${srcFile})
199  endforeach()
200
201  list(APPEND QT_MOC_SOURCES)
202
203  if (QT_MOC_HEADERS)
204    qt5_wrap_cpp(QT_MOC_SOURCES ${QT_MOC_HEADERS})
205    source_group("Generated Files" FILES ${QT_MOC_SOURCES})
206  endif()
207
208  list(APPEND QT_UI_SOURCES)
209  if (QT_UI_FILES)
210    qt5_wrap_ui(QT_UI_SOURCES ${QT_UI_FILES})
211    source_group("Generated Files" FILES ${QT_UI_SOURCES})
212  endif()
213
214  list(APPEND QT_QRC_SOURCES)
215  if (QT_QRC_FILES)
216    qt5_add_resources(QT_QRC_SOURCES ${QT_QRC_FILES})
217    source_group("Generated Files" FILES ${QT_QRC_SOURCES})
218  endif()
219
220  list(APPEND ALL_HPP_FILES ${${_HEADER_FILES}} ${HEADER_LIST_OF_CUR_DIR})
221  list(APPEND ALL_CPP_FILES ${${_SOURCE_FILES}} ${SOURCE_LIST_OF_CUR_DIR} ${QT_MOC_SOURCES} ${QT_UI_SOURCES} ${QT_QRC_SOURCES} ${QML_SOURCES})
222  set(${_HEADER_FILES} ${ALL_HPP_FILES} PARENT_SCOPE)
223  set(${_SOURCE_FILES} ${ALL_CPP_FILES} PARENT_SCOPE)
224
225  createSrcGroups(HEADER_LIST_OF_CUR_DIR)
226  createSrcGroups(SOURCE_LIST_OF_CUR_DIR)
227  message( STATUS "${FOLDER} directory included" )
228endfunction()
229
230####################################################################################
231# This function checks if the current generator is used for a Viusal Studio build
232# _INPUT This variable will be set to TRUE if its a Visual Studio build, otherwise to FALSE.
233####################################################################################
234function (is_vs_based_build _INPUT)
235  if(${CMAKE_GENERATOR} MATCHES "Visual Studio")
236    set(${_INPUT} TRUE PARENT_SCOPE)
237  else()
238    set(${_INPUT} FALSE PARENT_SCOPE)
239  endif()
240endfunction()
241
242####################################################################################
243# Copy a release dependency in the correct CMAKE_RUNTIME_OUTPUT_DIRECTORY
244# _INPUT The full path of the dependency incl. FileName
245# _OUTPUT The directory where the libraries should be installed.
246# OPTIONAL: RELATIVE Path - as third argument an optional relative path can be specified
247####################################################################################
248
249function(copy_dependency_release _INPUT _OUTPUT)
250  is_vs_based_build(VS_BUILD)
251
252  # when this is a DEBUG build we dont copy the files
253  if(NOT VS_BUILD)
254    if(${CMAKE_BUILD_TYPE} STREQUAL Debug)
255      return()
256    endif()
257  endif()
258  # as third argument an optional relative path can be specified
259  set(REL_PATH ${ARGV2})
260  set(_PATH ${_INPUT})
261  # make the path to normal path with / as dir separator
262  string ( REGEX REPLACE "[\\/]" "/" FILE_PATH ${_PATH} )
263  get_filename_component(FILE_NAME ${FILE_PATH} NAME)
264
265  if (VS_BUILD)
266    if (IS_DIRECTORY ${_INPUT})
267      file(COPY ${_INPUT} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release/${REL_PATH})
268    else()
269      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release/${REL_PATH}/${FILE_NAME} COPYONLY)
270      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/RelWithDebInfo/${REL_PATH}/${FILE_NAME} COPYONLY)
271      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MinSizeRel/${REL_PATH}/${FILE_NAME} COPYONLY)
272    endif()
273  else()
274    if (IS_DIRECTORY ${_INPUT})
275      file(COPY ${_INPUT} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${REL_PATH})
276    else()
277      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${REL_PATH}/${FILE_NAME} COPYONLY)
278    endif()
279  endif()
280
281  if (IS_DIRECTORY ${_INPUT})
282    install(DIRECTORY
283            ${FILE_PATH}
284            DESTINATION ${_OUTPUT}/${REL_PATH}
285            CONFIGURATIONS Release)
286  else()
287    install(FILES
288            ${FILE_PATH}
289            DESTINATION ${_OUTPUT}/${REL_PATH}
290            CONFIGURATIONS Release)
291  endif()
292endfunction()
293
294####################################################################################
295# Copy a debug dependency in the correct CMAKE_RUNTIME_OUTPUT_DIRECTORY
296# _INPUT The full path of the dependency incl. FileName
297# _OUTPUT The directory where the libraries should be installed.
298# OPTIONAL: RELATIVE Path - as third argument an optional relative path can be specified
299####################################################################################
300
301function(copy_dependency_debug _INPUT _OUTPUT)
302  is_vs_based_build(VS_BUILD)
303
304  # when this is NOT a DEBUG build we dont copy the files
305  if(NOT VS_BUILD)
306    if(NOT ${CMAKE_BUILD_TYPE} STREQUAL Debug)
307      return()
308    endif()
309  endif()
310  # as third argument an optional relative path can be specified
311  set(REL_PATH ${ARGV2})
312  set(_PATH ${_INPUT})
313  # make the path to normal path with / as dir separator
314  string ( REGEX REPLACE "[\\/]" "////" FILE_PATH ${_PATH} )
315  get_filename_component(FILE_NAME ${FILE_PATH} NAME)
316
317  if (VS_BUILD)
318    if (IS_DIRECTORY ${_INPUT})
319      file(COPY ${_INPUT} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug/${REL_PATH})
320     else()
321      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug/${REL_PATH}/${FILE_NAME} COPYONLY)
322    endif()
323  else()
324    if (IS_DIRECTORY ${_INPUT})
325      file(COPY ${_INPUT} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${REL_PATH})
326    else()
327      configure_file(${FILE_PATH} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${REL_PATH}/${FILE_NAME} COPYONLY)
328    endif()
329  endif()
330
331 if (IS_DIRECTORY ${_INPUT})
332   install(DIRECTORY
333           ${FILE_PATH}
334           DESTINATION ${_OUTPUT}/${REL_PATH}
335           CONFIGURATIONS Debug)
336 else()
337   install(FILES
338           ${FILE_PATH}
339           DESTINATION ${_OUTPUT}/${REL_PATH}
340           CONFIGURATIONS Debug)
341  endif()
342endfunction()
343
344####################################################################################
345# Creates a PreCompiled Header
346# _PRECOMPILED_HEADER The full path of the dependency incl. FileName
347# _SRC_FILES (Only works with CPP files)
348####################################################################################
349function(activate_precompiled_headers _PRECOMPILED_HEADER _SOURCE_FILES)
350  set(SRC_FILES ${${_SOURCE_FILES}})
351  get_filename_component(pch_basename ${_PRECOMPILED_HEADER} NAME_WE)
352  set(pch_abs ${CMAKE_CURRENT_SOURCE_DIR}/${_PRECOMPILED_HEADER})
353  set(pch_unity ${CMAKE_CURRENT_BINARY_DIR}/${pch_basename}.cpp)
354
355  if(MSVC)
356    # First specify the name of the PCH file
357    # it seems to be that nmake build cant handle the $(IntDir) variable
358    if(NOT MSVC_IDE)
359      set(pch_bin ${CMAKE_CURRENT_BINARY_DIR}/${pch_basename}.pch)
360    else()
361      set(pch_bin "$(IntDir)/${pch_basename}.pch")
362    endif()
363    # Generate precompiled header translation unit
364    if (NOT EXISTS ${pch_unity})
365      file(WRITE ${pch_unity} "// Precompiled header unity generated by CMake\n")
366      file(APPEND ${pch_unity} "#include <${pch_abs}>\n")
367    endif()
368    # this creates the precompild header
369    set_source_files_properties(${pch_unity}
370                                PROPERTIES COMPILE_FLAGS "/Yc\"${pch_abs}\" /Fp\"${pch_bin}\""
371                                           OBJECT_OUTPUTS "${pch_bin}")
372    # Update properties of source files to use the precompiled header.
373    # Additionally, force the inclusion of the precompiled header at beginning of each source file.
374    set_source_files_properties(${SRC_FILES}
375                                PROPERTIES COMPILE_FLAGS "/Yu\"${pch_abs}\" /FI\"${pch_abs}\" /Fp\"${pch_bin}\""
376                                           OBJECT_DEPENDS "${pch_bin}")
377    # Finally, update the source file collection to contain the precompiled header translation unit
378    set(${_SOURCE_FILES} ${pch_unity} ${pch_abs} ${${_SOURCE_FILES}} PARENT_SCOPE)
379
380    source_group("Generated Files" FILES ${pch_unity})
381    get_filename_component(PATH_TO_PCH ${_PRECOMPILED_HEADER} DIRECTORY)
382    if (PATH_TO_PCH)
383        string ( REGEX REPLACE "[\\/]" "\\\\" normalized_path ${PATH_TO_PCH} )
384        source_group(${normalized_path} FILES ${pch_abs})
385    endif()
386  endif()
387endfunction()
388
389####################################################################################
390# Adds warnings compiler options to the target depending on the category
391# target Target name
392####################################################################################
393function( set_compiler_warnings target)
394  if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
395    set(WARNINGS "-Werror"
396                 "-Wall")
397  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
398    set(WARNINGS "-Werror"
399                 "-Wall")
400  elseif(MSVC)
401    set(WARNINGS "/WX"
402                 "/W4")
403  endif()
404
405  target_compile_options(${target} PRIVATE ${WARNINGS})
406endfunction()
407
408####################################################################################
409# Adds or replace a compiler option
410# _OLD_OPTION The option which should be replaced
411# _NEW_OPTION The new option which should be added
412####################################################################################
413function( replace_compiler_option _OLD_OPTION _NEW_OPTION)
414  foreach(flag_var
415          CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
416          CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
417    if(${flag_var} MATCHES ${_OLD_OPTION})
418      # the whitespace after_OLD_OPTION is necessary to really match only the flag and not some sub flag (/MD should match by /MDd)
419      string(REGEX REPLACE "${_OLD_OPTION} " "${_NEW_OPTION} " ${flag_var} "${${flag_var}}")
420    else()
421      set(${flag_var} "${${flag_var}} ${_NEW_OPTION} ")
422    endif()
423   set(${flag_var} ${${flag_var}} PARENT_SCOPE)
424  endforeach()
425endfunction()
426
427####################################################################################
428# enables or disables the user of RTTI for all following source files.
429# _ENABLE If true, will enable RTTI, otherwise will disable RTTI.
430####################################################################################
431macro(enable_rtti _ENABLE)
432  set(enable_rtti_opt "")
433  set(disable_rtti_opt "")
434  if (MSVC)
435    set(enable_rtti_opt "/GR")
436    set(disable_rtti_opt "/GR-")
437  elseif(CMAKE_COMPILER_IS_GNUCXX )
438    set(enable_rtti_opt "-frtti")
439    set(disable_rtti_opt "-fno-rtti")
440  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
441    set(enable_rtti_opt "-frtti")
442    set(disable_rtti_opt "-fno-rtti")
443  else()
444    message(FATAL_ERROR "Don't know how to enable/disable RTTI for this compiler.")
445  endif()
446
447  if (${_ENABLE})
448    message(STATUS "Enabled: use of RTTI")
449    replace_compiler_option("${disable_rtti_opt}" "${enable_rtti_opt}")
450  else()
451    message(STATUS "Disabled: use of RTTI")
452    replace_compiler_option("${enable_rtti_opt}" "${disable_rtti_opt}")
453  endif()
454endmacro()
455
456
457####################################################################################
458# Returns the name of the used compiler.
459# _COMPILER_NAME
460####################################################################################
461function(getCompilerName _COMPILER_NAME)
462  if(MSVC_VERSION EQUAL 1400)
463    set(COMPILER_NAME "vs2005")
464  elseif(MSVC_VERSION EQUAL 1500)
465    set(COMPILER_NAME "vs2008")
466  elseif(MSVC_VERSION EQUAL 1600)
467    set(COMPILER_NAME "vs2010")
468  elseif(MSVC_VERSION EQUAL 1700)
469    set(COMPILER_NAME "vs2012")
470  elseif(MSVC_VERSION EQUAL 1800)
471    set(COMPILER_NAME "vs2013")
472  elseif(MSVC_VERSION EQUAL 1900)
473    set(COMPILER_NAME "vs2015")
474  elseif((MSVC_VERSION EQUAL 1910 OR MSVC_VERSION GREATER 1910) AND (MSVC_VERSION EQUAL 1919 OR MSVC_VERSION LESS 1919))
475    set(COMPILER_NAME "vs2017")
476  elseif(CMAKE_COMPILER_IS_GNUCXX)
477    set(COMPILER_NAME "gcc")
478    if(WIN32)
479      execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "-dumpversion" OUTPUT_VARIABLE GCC_VERSION_OUTPUT)
480      string(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" GCC_VERSION "${GCC_VERSION_OUTPUT}")
481      set(COMPILER_NAME ${COMPILER_NAME}${GCC_VERSION})
482    endif()
483  elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
484     set(COMPILER_NAME "clang")
485  else()
486    message(WARNING "Can not retrieve compiler name!")
487    return()
488  endif()
489
490  set(${_COMPILER_NAME} ${COMPILER_NAME} PARENT_SCOPE)
491endfunction()
492
493####################################################################################
494# This will install the PDB files also into the "bin" folder of the installation directory
495# _TARGET_NAME The name of the target
496####################################################################################
497
498function(install_pdb_files _TARGET_NAME)
499    if (MSVC)
500        install(FILES $<TARGET_PDB_FILE:${_TARGET_NAME}> DESTINATION "bin" CONFIGURATIONS Debug RelWithDebInfo)
501    endif()
502endfunction()
503
504
505####################################################################################
506# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes
507# _COMPILER_NAME
508####################################################################################
509macro(getenv_path VAR)
510   set(ENV_${VAR} $ENV{${VAR}})
511   # replace won't work if var is blank
512   if (ENV_${VAR})
513     string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} )
514   endif ()
515endmacro()
516
517macro(generateLibraryVersionVariables MAJOR MINOR PATCH PRODUCT_NAME PRODUCT_CPY_RIGHT PRODUCT_LICENSE)
518  set(LIBRARY_VERSION_MAJOR ${MAJOR})
519  set(LIBRARY_VERSION_MINOR ${MINOR})
520  set(LIBRARY_VERSION_PATCH ${PATCH})
521  set(LIBRARY_VERSION ${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH})
522  set(LIBRARY_VERSION_STR "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}")
523  math(EXPR LIBRARY_VERSION_CALC "${LIBRARY_VERSION_MAJOR}*1000 + ${LIBRARY_VERSION_MINOR}*100 + ${LIBRARY_VERSION_PATCH}")
524  set(LIBRARY_PRODUCT_NAME ${PRODUCT_NAME})
525  set(LIBRARY_COPYRIGHT ${PRODUCT_CPY_RIGHT})
526  set(LIBRARY_LICENSE ${PRODUCT_LICENSE})
527endmacro()
528
529function(get_latest_supported_cxx CXX_STANDARD)
530    if (POLICY CMP0067)
531        cmake_policy(SET CMP0067 NEW)
532    endif()
533
534    # we need to set CMAKE_CXX_STANDARD in order to use the flags for 'check_cxx_source_compiles'
535    if(${CMAKE_VERSION} VERSION_LESS "3.8.0")
536        set(CMAKE_CXX_STANDARD 14)
537    else()
538        set(CMAKE_CXX_STANDARD 17)
539    endif()
540
541    include(CheckCXXSourceCompiles)
542
543    check_cxx_source_compiles("
544                              #include <type_traits>
545                              typedef void F();
546                              typedef void G() noexcept;
547
548                              std::enable_if<
549                                  !std::is_same<F, G>::value,
550                                  int
551                              >::type i = 42;
552
553                              int main() { return 0; }
554                              "
555                              HAS_NO_EXCEPT_TYPE_SIGNATURE_SUPPORT)
556
557    check_cxx_source_compiles("
558                              #include <type_traits>
559                              struct foo { void func() const noexcept {} };
560                              template<typename T>
561                              void test_func(T)
562                              {
563                                  static_assert(std::is_member_function_pointer<T>::value, \"Failed\");
564                              }
565                              int main() { test_func(&foo::func); return 0; }
566                              "
567                              HAS_STL_NO_EXCEPT_TYPE_SIGNATURE_SUPPORT)
568
569    check_cxx_source_compiles("
570                              constexpr int abs(int x)
571                              {
572                                  if(x < 0) x = -x;
573                                  return x;
574                              }
575
576                              int main() { }
577                              "
578                              HAS_CXX_CONSTEXPR)
579
580    check_cxx_source_compiles( "
581                               #include <type_traits>
582                               template<typename T>
583                               struct template_type_trait : std::false_type {};
584
585                               template<template < bool > class T, bool N>
586                               struct template_type_trait<T<N>> : std::true_type {};
587
588                               template<template <std::size_t> class T, std::size_t N>
589                               struct template_type_trait<T<N>> : std::true_type {};
590
591                               template<std::size_t T>
592                               struct bar{};
593
594                               int main() { static bool foo = template_type_trait<bar<100>>::value;}
595                               "
596                               HAS_PARTIAL_SPECIALIZATION_FOR_ARRAYS)
597
598    if (HAS_NO_EXCEPT_TYPE_SIGNATURE_SUPPORT AND HAS_STL_NO_EXCEPT_TYPE_SIGNATURE_SUPPORT AND
599        HAS_PARTIAL_SPECIALIZATION_FOR_ARRAYS)
600        set(MAX_CXX_STD 17)
601    else()
602        if (HAS_CXX_CONSTEXPR)
603            set(MAX_CXX_STD 14)
604        else()
605            set(MAX_CXX_STD 11)
606        endif()
607    endif()
608
609    set(${CXX_STANDARD} ${MAX_CXX_STD} PARENT_SCOPE)
610endfunction()
611
612