AssetsBrowser: Add ID Properties to Asset Indexer
[blender.git] / build_files / cmake / macros.cmake
1 # ***** BEGIN GPL LICENSE BLOCK *****
2 #
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # The Original Code is Copyright (C) 2006, Blender Foundation
18 # All rights reserved.
19 # ***** END GPL LICENSE BLOCK *****
20
21 macro(list_insert_after
22   list_id item_check item_add
23   )
24   set(_index)
25   list(FIND "${list_id}" "${item_check}" _index)
26   if("${_index}" MATCHES "-1")
27     message(FATAL_ERROR "'${list_id}' doesn't contain '${item_check}'")
28   endif()
29   math(EXPR _index "${_index} + 1")
30   list(INSERT ${list_id} "${_index}" ${item_add})
31   unset(_index)
32 endmacro()
33
34 macro(list_insert_before
35   list_id item_check item_add
36   )
37   set(_index)
38   list(FIND "${list_id}" "${item_check}" _index)
39   if("${_index}" MATCHES "-1")
40     message(FATAL_ERROR "'${list_id}' doesn't contain '${item_check}'")
41   endif()
42   list(INSERT ${list_id} "${_index}" ${item_add})
43   unset(_index)
44 endmacro()
45
46 function(list_assert_duplicates
47   list_id
48   )
49
50   # message(STATUS "list data: ${list_id}")
51
52   list(LENGTH list_id _len_before)
53   list(REMOVE_DUPLICATES list_id)
54   list(LENGTH list_id _len_after)
55   # message(STATUS "list size ${_len_before} -> ${_len_after}")
56   if(NOT _len_before EQUAL _len_after)
57     message(FATAL_ERROR "duplicate found in list which should not contain duplicates: ${list_id}")
58   endif()
59   unset(_len_before)
60   unset(_len_after)
61 endfunction()
62
63 # Adds a native path separator to the end of the path:
64 #
65 # - 'example' -> 'example/'
66 # - '/example///' -> '/example/'
67 #
68 macro(path_ensure_trailing_slash
69   path_new path_input
70   )
71   file(TO_NATIVE_PATH "/" _path_sep)
72   string(REGEX REPLACE "[${_path_sep}]+$" "" ${path_new} ${path_input})
73   set(${path_new} "${${path_new}}${_path_sep}")
74   unset(_path_sep)
75 endmacro()
76
77 # foo_bar.spam --> foo_barMySuffix.spam
78 macro(file_suffix
79   file_name_new file_name file_suffix
80   )
81
82   get_filename_component(_file_name_PATH ${file_name} PATH)
83   get_filename_component(_file_name_NAME_WE ${file_name} NAME_WE)
84   get_filename_component(_file_name_EXT ${file_name} EXT)
85   set(${file_name_new} "${_file_name_PATH}/${_file_name_NAME_WE}${file_suffix}${_file_name_EXT}")
86
87   unset(_file_name_PATH)
88   unset(_file_name_NAME_WE)
89   unset(_file_name_EXT)
90 endmacro()
91
92 # useful for adding debug suffix to library lists:
93 # /somepath/foo.lib --> /somepath/foo_d.lib
94 macro(file_list_suffix
95   fp_list_new fp_list fn_suffix
96   )
97
98   # incase of empty list
99   set(_fp)
100   set(_fp_suffixed)
101
102   set(fp_list_new)
103
104   foreach(_fp ${fp_list})
105     file_suffix(_fp_suffixed "${_fp}" "${fn_suffix}")
106     list(APPEND "${fp_list_new}" "${_fp_suffixed}")
107   endforeach()
108
109   unset(_fp)
110   unset(_fp_suffixed)
111
112 endmacro()
113
114 if(UNIX AND NOT APPLE)
115   macro(find_package_static)
116     set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
117     set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
118     find_package(${ARGV})
119     set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
120     unset(_cmake_find_library_suffixes_back)
121   endmacro()
122
123   macro(find_library_static)
124     set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
125     set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
126     find_library(${ARGV})
127     set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
128     unset(_cmake_find_library_suffixes_back)
129   endmacro()
130 endif()
131
132 function(target_link_libraries_optimized
133   TARGET
134   LIBS
135   )
136
137   foreach(_LIB ${LIBS})
138     target_link_libraries(${TARGET} INTERFACE optimized "${_LIB}")
139   endforeach()
140 endfunction()
141
142 function(target_link_libraries_debug
143   TARGET
144   LIBS
145   )
146
147   foreach(_LIB ${LIBS})
148     target_link_libraries(${TARGET} INTERFACE debug "${_LIB}")
149   endforeach()
150 endfunction()
151
152 # Nicer makefiles with -I/1/foo/ instead of -I/1/2/3/../../foo/
153 # use it instead of include_directories()
154 function(blender_include_dirs
155   includes
156   )
157
158   set(_ALL_INCS "")
159   foreach(_INC ${ARGV})
160     get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
161     list(APPEND _ALL_INCS ${_ABS_INC})
162     # for checking for invalid includes, disable for regular use
163     # if(NOT EXISTS "${_ABS_INC}/")
164     #   message(FATAL_ERROR "Include not found: ${_ABS_INC}/")
165     # endif()
166   endforeach()
167   include_directories(${_ALL_INCS})
168 endfunction()
169
170 function(blender_include_dirs_sys
171   includes
172   )
173
174   set(_ALL_INCS "")
175   foreach(_INC ${ARGV})
176     get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
177     list(APPEND _ALL_INCS ${_ABS_INC})
178     # if(NOT EXISTS "${_ABS_INC}/")
179     #   message(FATAL_ERROR "Include not found: ${_ABS_INC}/")
180     # endif()
181   endforeach()
182   include_directories(SYSTEM ${_ALL_INCS})
183 endfunction()
184
185 # Set include paths for header files included with "*.h" syntax.
186 # This enables auto-complete suggestions for user header files on Xcode.
187 # Build process is not affected since the include paths are the same
188 # as in HEADER_SEARCH_PATHS.
189 function(blender_user_header_search_paths
190   name
191   includes
192   )
193
194   if(XCODE)
195     set(_ALL_INCS "")
196     foreach(_INC ${includes})
197       get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
198       # _ALL_INCS is a space-separated string of file paths in quotes.
199       string(APPEND _ALL_INCS " \"${_ABS_INC}\"")
200     endforeach()
201     set_target_properties(${name} PROPERTIES XCODE_ATTRIBUTE_USER_HEADER_SEARCH_PATHS "${_ALL_INCS}")
202   endif()
203 endfunction()
204
205 function(blender_source_group
206   name
207   sources
208   )
209
210   # if enabled, use the sources directories as filters.
211   if(IDE_GROUP_SOURCES_IN_FOLDERS)
212     foreach(_SRC ${sources})
213       # remove ../'s
214       get_filename_component(_SRC_DIR ${_SRC} REALPATH)
215       get_filename_component(_SRC_DIR ${_SRC_DIR} DIRECTORY)
216       string(FIND ${_SRC_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/" _pos)
217       if(NOT _pos EQUAL -1)
218         string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" GROUP_ID ${_SRC_DIR})
219         string(REPLACE "/" "\\" GROUP_ID ${GROUP_ID})
220         source_group("${GROUP_ID}" FILES ${_SRC})
221       endif()
222       unset(_pos)
223     endforeach()
224   else()
225     # Group by location on disk
226     source_group("Source Files" FILES CMakeLists.txt)
227     foreach(_SRC ${sources})
228       get_filename_component(_SRC_EXT ${_SRC} EXT)
229       if((${_SRC_EXT} MATCHES ".h") OR
230          (${_SRC_EXT} MATCHES ".hpp") OR
231          (${_SRC_EXT} MATCHES ".hh"))
232
233         set(GROUP_ID "Header Files")
234       elseif(${_SRC_EXT} MATCHES ".glsl$")
235         set(GROUP_ID "Shaders")
236       else()
237         set(GROUP_ID "Source Files")
238       endif()
239       source_group("${GROUP_ID}" FILES ${_SRC})
240     endforeach()
241   endif()
242
243   # if enabled, set the FOLDER property for the projects
244   if(IDE_GROUP_PROJECTS_IN_FOLDERS)
245     get_filename_component(FolderDir ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
246     string(REPLACE ${CMAKE_SOURCE_DIR} "" FolderDir ${FolderDir})
247     set_target_properties(${name} PROPERTIES FOLDER ${FolderDir})
248   endif()
249 endfunction()
250
251
252 # Support per-target CMake flags
253 # Read from: CMAKE_C_FLAGS_**** (made upper case) when set.
254 #
255 # 'name' should always match the target name,
256 # use this macro before add_library or add_executable.
257 #
258 # Optionally takes an arg passed to set(), eg PARENT_SCOPE.
259 macro(add_cc_flags_custom_test
260   name
261   )
262
263   string(TOUPPER ${name} _name_upper)
264   if(DEFINED CMAKE_C_FLAGS_${_name_upper})
265     message(STATUS "Using custom CFLAGS: CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
266     string(APPEND CMAKE_C_FLAGS " ${CMAKE_C_FLAGS_${_name_upper}}" ${ARGV1})
267   endif()
268   if(DEFINED CMAKE_CXX_FLAGS_${_name_upper})
269     message(STATUS "Using custom CXXFLAGS: CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
270     string(APPEND CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS_${_name_upper}}" ${ARGV1})
271   endif()
272   unset(_name_upper)
273
274 endmacro()
275
276
277 # only MSVC uses SOURCE_GROUP
278 function(blender_add_lib__impl
279   name
280   sources
281   includes
282   includes_sys
283   library_deps
284   )
285
286   # message(STATUS "Configuring library ${name}")
287
288   # include_directories(${includes})
289   # include_directories(SYSTEM ${includes_sys})
290   blender_include_dirs("${includes}")
291   blender_include_dirs_sys("${includes_sys}")
292
293   add_library(${name} ${sources})
294
295   # On Windows certain libraries have two sets of binaries: one for debug builds and one for
296   # release builds. The root of this requirement goes into ABI, I believe, but that's outside
297   # of a scope of this comment.
298   #
299   # CMake have a native way of dealing with this, which is specifying what build type the
300   # libraries are provided for:
301   #
302   #   target_link_libraries(tagret optimized|debug|general <libraries>)
303   #
304   # The build type is to be provided as a separate argument to the function.
305   #
306   # CMake's variables for libraries will contain build type in such cases. For example:
307   #
308   #   set(FOO_LIBRARIES optimized libfoo.lib debug libfoo_d.lib)
309   #
310   # Complications starts with a single argument for library_deps: all the elements are being
311   # put to a list: "${FOO_LIBRARIES}" will become "optimized;libfoo.lib;debug;libfoo_d.lib".
312   # This makes it impossible to pass it as-is to target_link_libraries sine it will treat
313   # this argument as a list of libraries to be linked against, causing missing libraries
314   # for optimized.lib.
315   #
316   # What this code does it traverses library_deps and extracts information about whether
317   # library is to provided as general, debug or optimized. This is a little state machine which
318   # keeps track of which build type library is to provided for:
319   #
320   # - If "debug" or "optimized" word is found, the next element in the list is expected to be
321   #   a library which will be passed to target_link_libraries() under corresponding build type.
322   #
323   # - If there is no "debug" or "optimized" used library is specified for all build types.
324   #
325   # NOTE: If separated libraries for debug and release are needed every library is the list are
326   # to be prefixed explicitly.
327   #
328   #  Use: "optimized libfoo optimized libbar debug libfoo_d debug libbar_d"
329   #  NOT: "optimized libfoo libbar debug libfoo_d libbar_d"
330   if(NOT "${library_deps}" STREQUAL "")
331     set(next_library_mode "")
332     foreach(library ${library_deps})
333       string(TOLOWER "${library}" library_lower)
334       if(("${library_lower}" STREQUAL "optimized") OR
335          ("${library_lower}" STREQUAL "debug"))
336         set(next_library_mode "${library_lower}")
337       else()
338         if("${next_library_mode}" STREQUAL "optimized")
339           target_link_libraries(${name} INTERFACE optimized ${library})
340         elseif("${next_library_mode}" STREQUAL "debug")
341           target_link_libraries(${name} INTERFACE debug ${library})
342         else()
343           target_link_libraries(${name} INTERFACE ${library})
344         endif()
345         set(next_library_mode "")
346       endif()
347     endforeach()
348   endif()
349
350   # works fine without having the includes
351   # listed is helpful for IDE's (QtCreator/MSVC)
352   blender_source_group("${name}" "${sources}")
353   blender_user_header_search_paths("${name}" "${includes}")
354
355   list_assert_duplicates("${sources}")
356   list_assert_duplicates("${includes}")
357   # Not for system includes because they can resolve to the same path
358   # list_assert_duplicates("${includes_sys}")
359
360 endfunction()
361
362
363 function(blender_add_lib_nolist
364   name
365   sources
366   includes
367   includes_sys
368   library_deps
369   )
370
371   add_cc_flags_custom_test(${name} PARENT_SCOPE)
372
373   blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}" "${library_deps}")
374 endfunction()
375
376 function(blender_add_lib
377   name
378   sources
379   includes
380   includes_sys
381   library_deps
382   )
383
384   add_cc_flags_custom_test(${name} PARENT_SCOPE)
385
386   blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}" "${library_deps}")
387
388   set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name})
389 endfunction()
390
391 function(blender_add_test_suite)
392   if(ARGC LESS 1)
393     message(FATAL_ERROR "No arguments supplied to blender_add_test_suite()")
394   endif()
395
396   # Parse the arguments
397   set(oneValueArgs TARGET SUITE_NAME)
398   set(multiValueArgs SOURCES)
399   cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
400
401   # Figure out the release dir, as some tests need files from there.
402   GET_BLENDER_TEST_INSTALL_DIR(TEST_INSTALL_DIR)
403   if(APPLE)
404     set(_test_release_dir ${TEST_INSTALL_DIR}/Blender.app/Contents/Resources/${BLENDER_VERSION})
405   else()
406     if(WIN32 OR WITH_INSTALL_PORTABLE)
407       set(_test_release_dir ${TEST_INSTALL_DIR}/${BLENDER_VERSION})
408     else()
409       set(_test_release_dir ${TEST_INSTALL_DIR}/share/blender/${BLENDER_VERSION})
410     endif()
411   endif()
412
413   # Define a test case with our custom gtest_add_tests() command.
414   include(GTest)
415   gtest_add_tests(
416     TARGET ${ARGS_TARGET}
417     SOURCES "${ARGS_SOURCES}"
418     TEST_PREFIX ${ARGS_SUITE_NAME}
419     WORKING_DIRECTORY "${TEST_INSTALL_DIR}"
420     EXTRA_ARGS
421       --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests"
422       --test-release-dir "${_test_release_dir}"
423   )
424
425   unset(_test_release_dir)
426 endfunction()
427
428 # Add tests for a Blender library, to be called in tandem with blender_add_lib().
429 # The tests will be part of the blender_test executable (see tests/gtests/runner).
430 function(blender_add_test_lib
431   name
432   sources
433   includes
434   includes_sys
435   library_deps
436   )
437
438   add_cc_flags_custom_test(${name} PARENT_SCOPE)
439
440   # Otherwise external projects will produce warnings that we cannot fix.
441   remove_strict_flags()
442
443   # This duplicates logic that's also in GTestTesting.cmake, macro BLENDER_SRC_GTEST_EX.
444   # TODO(Sybren): deduplicate after the general approach in D7649 has been approved.
445   LIST(APPEND includes
446     ${CMAKE_SOURCE_DIR}/tests/gtests
447   )
448   LIST(APPEND includes_sys
449     ${GLOG_INCLUDE_DIRS}
450     ${GFLAGS_INCLUDE_DIRS}
451     ${CMAKE_SOURCE_DIR}/extern/gtest/include
452     ${CMAKE_SOURCE_DIR}/extern/gmock/include
453   )
454   add_definitions(-DBLENDER_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE})
455   add_definitions(${GFLAGS_DEFINES})
456   add_definitions(${GLOG_DEFINES})
457
458   blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}" "${library_deps}")
459
460   set_property(GLOBAL APPEND PROPERTY BLENDER_TEST_LIBS ${name})
461
462   blender_add_test_suite(
463     TARGET blender_test
464     SUITE_NAME ${name}
465     SOURCES "${sources}"
466   )
467 endfunction()
468
469
470 # Add tests for a Blender library, to be called in tandem with blender_add_lib().
471 # Test will be compiled into a ${name}_test executable.
472 #
473 # To be used for smaller isolated libraries, that do not have many dependencies.
474 # For libraries that do drag in many other Blender libraries and would create a
475 # very large executable, blender_add_test_lib() should be used instead.
476 function(blender_add_test_executable
477   name
478   sources
479   includes
480   includes_sys
481   library_deps
482   )
483
484   add_cc_flags_custom_test(${name} PARENT_SCOPE)
485
486   ## Otherwise external projects will produce warnings that we cannot fix.
487   remove_strict_flags()
488
489   include_directories(${includes})
490   include_directories(${includes_sys})
491
492   BLENDER_SRC_GTEST_EX(
493     NAME ${name}
494     SRC "${sources}"
495     EXTRA_LIBS "${library_deps}"
496     SKIP_ADD_TEST
497   )
498
499   blender_add_test_suite(
500     TARGET ${name}_test
501     SUITE_NAME ${name}
502     SOURCES "${sources}"
503   )
504 endfunction()
505
506 # Ninja only: assign 'heavy pool' to some targets that are especially RAM-consuming to build.
507 function(setup_heavy_lib_pool)
508   if(WITH_NINJA_POOL_JOBS AND NINJA_MAX_NUM_PARALLEL_COMPILE_HEAVY_JOBS)
509     if(WITH_CYCLES)
510       list(APPEND _HEAVY_LIBS "cycles_device" "cycles_kernel")
511     endif()
512     if(WITH_LIBMV)
513       list(APPEND _HEAVY_LIBS "extern_ceres" "bf_intern_libmv")
514     endif()
515     if(WITH_OPENVDB)
516       list(APPEND _HEAVY_LIBS "bf_intern_openvdb")
517     endif()
518
519     foreach(TARGET ${_HEAVY_LIBS})
520       if(TARGET ${TARGET})
521         set_property(TARGET ${TARGET} PROPERTY JOB_POOL_COMPILE compile_heavy_job_pool)
522       endif()
523     endforeach()
524   endif()
525 endfunction()
526
527 # Platform specific linker flags for targets.
528 function(setup_platform_linker_flags
529   target)
530   set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${PLATFORM_LINKFLAGS}")
531   set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_RELEASE " ${PLATFORM_LINKFLAGS_RELEASE}")
532   set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG " ${PLATFORM_LINKFLAGS_DEBUG}")
533 endfunction()
534
535 # Platform specific libraries for targets.
536 function(setup_platform_linker_libs
537   target
538   )
539   # jemalloc must be early in the list, to be before pthread (see T57998)
540   if(WITH_MEM_JEMALLOC)
541     target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
542   endif()
543
544   if(WIN32 AND NOT UNIX)
545     target_link_libraries(${target} ${PTHREADS_LIBRARIES})
546   endif()
547
548   # target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
549   target_link_libraries(${target} ${PLATFORM_LINKLIBS})
550 endfunction()
551
552 macro(TEST_SSE_SUPPORT
553   _sse_flags
554   _sse2_flags)
555
556   include(CheckCSourceRuns)
557
558   # message(STATUS "Detecting SSE support")
559   if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
560     set(${_sse_flags} "-msse")
561     set(${_sse2_flags} "-msse2")
562   elseif(MSVC)
563     # x86_64 has this auto enabled
564     if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
565       set(${_sse_flags} "")
566       set(${_sse2_flags} "")
567     else()
568       set(${_sse_flags} "/arch:SSE")
569       set(${_sse2_flags} "/arch:SSE2")
570     endif()
571   elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
572     set(${_sse_flags} "")  # icc defaults to -msse
573     set(${_sse2_flags} "")  # icc defaults to -msse2
574   else()
575     message(WARNING "SSE flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
576     set(${_sse_flags})
577     set(${_sse2_flags})
578   endif()
579
580   set(CMAKE_REQUIRED_FLAGS "${${_sse_flags}} ${${_sse2_flags}}")
581
582   if(NOT DEFINED SUPPORT_SSE_BUILD)
583     # result cached
584     check_c_source_runs("
585       #include <xmmintrin.h>
586       int main(void) { __m128 v = _mm_setzero_ps(); return 0; }"
587     SUPPORT_SSE_BUILD)
588   endif()
589
590   if(NOT DEFINED SUPPORT_SSE2_BUILD)
591     # result cached
592     check_c_source_runs("
593       #include <emmintrin.h>
594       int main(void) { __m128d v = _mm_setzero_pd(); return 0; }"
595     SUPPORT_SSE2_BUILD)
596   endif()
597
598   unset(CMAKE_REQUIRED_FLAGS)
599 endmacro()
600
601 macro(TEST_NEON_SUPPORT)
602   if(NOT DEFINED SUPPORT_NEON_BUILD)
603     include(CheckCXXSourceCompiles)
604     check_cxx_source_compiles(
605       "#include <arm_neon.h>
606        int main() {return vaddvq_s32(vdupq_n_s32(1));}"
607       SUPPORT_NEON_BUILD)
608   endif()
609 endmacro()
610
611 # Only print message if running CMake first time
612 macro(message_first_run)
613   if(FIRST_RUN)
614     message(${ARGV})
615   endif()
616 endmacro()
617
618 # when we have warnings as errors applied globally this
619 # needs to be removed for some external libs which we don't maintain.
620
621 # utility macro
622 macro(remove_cc_flag
623   _flag)
624
625   foreach(flag ${ARGV})
626     string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
627     string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
628     string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
629     string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
630     string(REGEX REPLACE ${flag} "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
631
632     string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
633     string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
634     string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
635     string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
636     string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
637   endforeach()
638   unset(flag)
639
640 endmacro()
641
642 macro(add_c_flag
643   flag)
644
645   string(APPEND CMAKE_C_FLAGS " ${flag}")
646   string(APPEND CMAKE_CXX_FLAGS " ${flag}")
647 endmacro()
648
649 macro(add_cxx_flag
650   flag)
651
652   string(APPEND CMAKE_CXX_FLAGS " ${flag}")
653 endmacro()
654
655 macro(remove_strict_flags)
656
657   if(CMAKE_COMPILER_IS_GNUCC)
658     remove_cc_flag(
659       "-Wstrict-prototypes"
660       "-Wmissing-prototypes"
661       "-Wmissing-declarations"
662       "-Wmissing-format-attribute"
663       "-Wunused-local-typedefs"
664       "-Wunused-macros"
665       "-Wunused-parameter"
666       "-Wwrite-strings"
667       "-Wredundant-decls"
668       "-Wundef"
669       "-Wshadow"
670       "-Wdouble-promotion"
671       "-Wold-style-definition"
672       "-Werror=[^ ]+"
673       "-Werror"
674     )
675
676     # negate flags implied by '-Wall'
677     add_c_flag("${C_REMOVE_STRICT_FLAGS}")
678     add_cxx_flag("${CXX_REMOVE_STRICT_FLAGS}")
679   endif()
680
681   if(CMAKE_C_COMPILER_ID MATCHES "Clang")
682     remove_cc_flag(
683       "-Wunused-parameter"
684       "-Wunused-variable"
685       "-Werror=[^ ]+"
686       "-Werror"
687     )
688
689     # negate flags implied by '-Wall'
690     add_c_flag("${C_REMOVE_STRICT_FLAGS}")
691     add_cxx_flag("${CXX_REMOVE_STRICT_FLAGS}")
692   endif()
693
694   if(MSVC)
695     remove_cc_flag(/w34189) # Restore warn C4189 (unused variable) back to w4
696   endif()
697
698 endmacro()
699
700 macro(remove_extra_strict_flags)
701   if(CMAKE_COMPILER_IS_GNUCC)
702     remove_cc_flag(
703       "-Wunused-parameter"
704     )
705   endif()
706
707   if(CMAKE_C_COMPILER_ID MATCHES "Clang")
708     remove_cc_flag(
709       "-Wunused-parameter"
710     )
711   endif()
712
713   if(MSVC)
714     # TODO
715   endif()
716 endmacro()
717
718 # note, we can only append flags on a single file so we need to negate the options.
719 # at the moment we can't shut up ffmpeg deprecations, so use this, but will
720 # probably add more removals here.
721 macro(remove_strict_c_flags_file
722   filenames)
723   foreach(_SOURCE ${ARGV})
724     if(CMAKE_COMPILER_IS_GNUCC OR
725        (CMAKE_C_COMPILER_ID MATCHES "Clang"))
726       set_source_files_properties(${_SOURCE}
727         PROPERTIES
728           COMPILE_FLAGS "${C_REMOVE_STRICT_FLAGS}"
729       )
730     endif()
731     if(MSVC)
732       # TODO
733     endif()
734   endforeach()
735   unset(_SOURCE)
736 endmacro()
737
738 macro(remove_strict_cxx_flags_file
739   filenames)
740   remove_strict_c_flags_file(${filenames} ${ARHV})
741   foreach(_SOURCE ${ARGV})
742     if(CMAKE_COMPILER_IS_GNUCC OR
743        (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
744       set_source_files_properties(${_SOURCE}
745         PROPERTIES
746           COMPILE_FLAGS "${CXX_REMOVE_STRICT_FLAGS}"
747       )
748     endif()
749     if(MSVC)
750       # TODO
751     endif()
752   endforeach()
753   unset(_SOURCE)
754 endmacro()
755
756 # External libs may need 'signed char' to be default.
757 macro(remove_cc_flag_unsigned_char)
758   if(CMAKE_COMPILER_IS_GNUCC OR
759      (CMAKE_C_COMPILER_ID MATCHES "Clang") OR
760      (CMAKE_C_COMPILER_ID MATCHES "Intel"))
761     remove_cc_flag("-funsigned-char")
762   elseif(MSVC)
763     remove_cc_flag("/J")
764   else()
765     message(WARNING
766       "Compiler '${CMAKE_C_COMPILER_ID}' failed to disable 'unsigned char' flag."
767       "Build files need updating."
768     )
769   endif()
770 endmacro()
771
772 function(ADD_CHECK_C_COMPILER_FLAG
773   _CFLAGS
774   _CACHE_VAR
775   _FLAG
776   )
777
778   include(CheckCCompilerFlag)
779
780   CHECK_C_COMPILER_FLAG("${_FLAG}" "${_CACHE_VAR}")
781   if(${_CACHE_VAR})
782     # message(STATUS "Using CFLAG: ${_FLAG}")
783     set(${_CFLAGS} "${${_CFLAGS}} ${_FLAG}" PARENT_SCOPE)
784   else()
785     message(STATUS "Unsupported CFLAG: ${_FLAG}")
786   endif()
787 endfunction()
788
789 function(ADD_CHECK_CXX_COMPILER_FLAG
790   _CXXFLAGS
791   _CACHE_VAR
792   _FLAG
793   )
794
795   include(CheckCXXCompilerFlag)
796
797   CHECK_CXX_COMPILER_FLAG("${_FLAG}" "${_CACHE_VAR}")
798   if(${_CACHE_VAR})
799     # message(STATUS "Using CXXFLAG: ${_FLAG}")
800     set(${_CXXFLAGS} "${${_CXXFLAGS}} ${_FLAG}" PARENT_SCOPE)
801   else()
802     message(STATUS "Unsupported CXXFLAG: ${_FLAG}")
803   endif()
804 endfunction()
805
806 function(get_blender_version)
807   # extracts header vars and defines them in the parent scope:
808   #
809   # - BLENDER_VERSION (major.minor)
810   # - BLENDER_VERSION_MAJOR
811   # - BLENDER_VERSION_MINOR
812   # - BLENDER_VERSION_PATCH
813   # - BLENDER_VERSION_CYCLE (alpha, beta, rc, release)
814
815   # So cmake depends on BKE_blender.h, beware of inf-loops!
816   CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/source/blender/blenkernel/BKE_blender_version.h
817                  ${CMAKE_BINARY_DIR}/source/blender/blenkernel/BKE_blender_version.h.done)
818
819   file(STRINGS ${CMAKE_SOURCE_DIR}/source/blender/blenkernel/BKE_blender_version.h _contents REGEX "^#define[ \t]+BLENDER_.*$")
820
821   string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION[ \t]+([0-9]+).*" "\\1" _out_version "${_contents}")
822   string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_PATCH[ \t]+([0-9]+).*" "\\1" _out_version_patch "${_contents}")
823   string(REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_CYCLE[ \t]+([a-z]+).*" "\\1" _out_version_cycle "${_contents}")
824
825   if(NOT ${_out_version} MATCHES "[0-9]+")
826     message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION")
827   endif()
828
829   if(NOT ${_out_version_patch} MATCHES "[0-9]+")
830     message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_PATCH")
831   endif()
832
833   if(NOT ${_out_version_cycle} MATCHES "[a-z]+")
834     message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_CYCLE")
835   endif()
836
837   math(EXPR _out_version_major "${_out_version} / 100")
838   math(EXPR _out_version_minor "${_out_version} % 100")
839
840   # output vars
841   set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE)
842   set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE)
843   set(BLENDER_VERSION_MINOR "${_out_version_minor}" PARENT_SCOPE)
844   set(BLENDER_VERSION_PATCH "${_out_version_patch}" PARENT_SCOPE)
845   set(BLENDER_VERSION_CYCLE "${_out_version_cycle}" PARENT_SCOPE)
846
847 endfunction()
848
849
850 # hacks to override initial project settings
851 # these macros must be called directly before/after project(Blender)
852 macro(blender_project_hack_pre)
853   # ------------------
854   # GCC -O3 HACK START
855   # needed because O3 can cause problems but
856   # allow the builder to set O3 manually after.
857   if(DEFINED CMAKE_C_FLAGS_RELEASE)
858     set(_reset_standard_cflags_rel OFF)
859   else()
860     set(_reset_standard_cflags_rel ON)
861   endif()
862   if(DEFINED CMAKE_CXX_FLAGS_RELEASE)
863     set(_reset_standard_cxxflags_rel OFF)
864   else()
865     set(_reset_standard_cxxflags_rel ON)
866   endif()
867 endmacro()
868
869
870 macro(blender_project_hack_post)
871   # ----------------
872   # GCC -O3 HACK END
873   if(_reset_standard_cflags_rel)
874     string(REGEX REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
875     set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE)
876     mark_as_advanced(CMAKE_C_FLAGS_RELEASE)
877   endif()
878
879   if(_reset_standard_cxxflags_rel)
880     string(REGEX REPLACE "-O3" "-O2" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
881     set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "" FORCE)
882     mark_as_advanced(CMAKE_CXX_FLAGS_RELEASE)
883   endif()
884
885   unset(_reset_standard_cflags_rel)
886   unset(_reset_standard_cxxflags_rel)
887
888 endmacro()
889
890 # pair of macros to allow libraries to be specify files to install, but to
891 # only install them at the end so the directories don't get cleared with
892 # the files in them. used by cycles to install addon.
893 function(delayed_install
894   base
895   files
896   destination)
897
898   foreach(f ${files})
899     if(IS_ABSOLUTE ${f})
900       set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${f})
901     else()
902       set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
903     endif()
904     set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
905   endforeach()
906   unset(f)
907 endfunction()
908
909 # note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
910 # does not get expanded in calling but is preserved
911 function(delayed_do_install
912   targetdir)
913
914   get_property(files GLOBAL PROPERTY DELAYED_INSTALL_FILES)
915   get_property(destinations GLOBAL PROPERTY DELAYED_INSTALL_DESTINATIONS)
916
917   if(files)
918     list(LENGTH files n)
919     math(EXPR n "${n}-1")
920
921     foreach(i RANGE ${n})
922       list(GET files ${i} f)
923       list(GET destinations ${i} d)
924       if(NOT IS_ABSOLUTE ${d})
925         install(FILES ${f} DESTINATION ${targetdir}/${d})
926       else()
927         install(FILES ${f} DESTINATION ${d})
928       endif()
929     endforeach()
930   endif()
931 endfunction()
932
933
934 function(data_to_c
935   file_from file_to
936   list_to_add
937   )
938
939   list(APPEND ${list_to_add} ${file_to})
940   set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
941
942   get_filename_component(_file_to_path ${file_to} PATH)
943
944   add_custom_command(
945     OUTPUT ${file_to}
946     COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
947     COMMAND "$<TARGET_FILE:datatoc>" ${file_from} ${file_to}
948     DEPENDS ${file_from} datatoc)
949
950   set_source_files_properties(${file_to} PROPERTIES GENERATED TRUE)
951 endfunction()
952
953
954 # same as above but generates the var name and output automatic.
955 function(data_to_c_simple
956   file_from
957   list_to_add
958   )
959
960   # remove ../'s
961   get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from}   REALPATH)
962   get_filename_component(_file_to   ${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c REALPATH)
963
964   list(APPEND ${list_to_add} ${_file_to})
965   source_group(Generated FILES ${_file_to})
966   list(APPEND ${list_to_add} ${file_from})
967   set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
968
969   get_filename_component(_file_to_path ${_file_to} PATH)
970
971   add_custom_command(
972     OUTPUT  ${_file_to}
973     COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
974     COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to}
975     DEPENDS ${_file_from} datatoc)
976
977   set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
978 endfunction()
979
980 # Function for converting pixmap directory to a '.png' and then a '.c' file.
981 function(data_to_c_simple_icons
982   path_from icon_prefix icon_names
983   list_to_add
984   )
985
986   # Conversion steps
987   #  path_from  ->  _file_from  ->  _file_to
988   #  foo/*.dat  ->  foo.png     ->  foo.png.c
989
990   get_filename_component(_path_from_abs ${path_from} ABSOLUTE)
991   # remove ../'s
992   get_filename_component(_file_from ${CMAKE_CURRENT_BINARY_DIR}/${path_from}.png   REALPATH)
993   get_filename_component(_file_to   ${CMAKE_CURRENT_BINARY_DIR}/${path_from}.png.c REALPATH)
994
995   list(APPEND ${list_to_add} ${_file_to})
996   set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
997
998   get_filename_component(_file_to_path ${_file_to} PATH)
999
1000   # Construct a list of absolute paths from input
1001   set(_icon_files)
1002   foreach(_var ${icon_names})
1003     list(APPEND _icon_files "${_path_from_abs}/${icon_prefix}${_var}.dat")
1004   endforeach()
1005
1006   add_custom_command(
1007     OUTPUT  ${_file_from} ${_file_to}
1008     COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
1009     # COMMAND python3 ${CMAKE_SOURCE_DIR}/source/blender/datatoc/datatoc_icon.py ${_path_from_abs} ${_file_from}
1010     COMMAND "$<TARGET_FILE:datatoc_icon>" ${_path_from_abs} ${_file_from}
1011     COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to}
1012     DEPENDS
1013       ${_icon_files}
1014       datatoc_icon
1015       datatoc
1016       # could be an arg but for now we only create icons depending on UI_icons.h
1017       ${CMAKE_SOURCE_DIR}/source/blender/editors/include/UI_icons.h
1018     )
1019
1020   set_source_files_properties(${_file_from} ${_file_to} PROPERTIES GENERATED TRUE)
1021 endfunction()
1022
1023 # XXX Not used for now...
1024 function(svg_to_png
1025   file_from
1026   file_to
1027   dpi
1028   list_to_add
1029   )
1030
1031   # remove ../'s
1032   get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH)
1033   get_filename_component(_file_to   ${CMAKE_CURRENT_SOURCE_DIR}/${file_to}   REALPATH)
1034
1035   list(APPEND ${list_to_add} ${_file_to})
1036   set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
1037
1038   find_program(INKSCAPE_EXE inkscape)
1039   mark_as_advanced(INKSCAPE_EXE)
1040
1041   if(INKSCAPE_EXE)
1042     if(APPLE)
1043       # in OS X app bundle, the binary is a shim that doesn't take any
1044       # command line arguments, replace it with the actual binary
1045       string(REPLACE "MacOS/Inkscape" "Resources/bin/inkscape" INKSCAPE_REAL_EXE ${INKSCAPE_EXE})
1046       if(EXISTS "${INKSCAPE_REAL_EXE}")
1047         set(INKSCAPE_EXE ${INKSCAPE_REAL_EXE})
1048       endif()
1049     endif()
1050
1051     add_custom_command(
1052       OUTPUT  ${_file_to}
1053       COMMAND ${INKSCAPE_EXE} ${_file_from} --export-dpi=${dpi}  --without-gui --export-png=${_file_to}
1054       DEPENDS ${_file_from} ${INKSCAPE_EXE}
1055     )
1056   else()
1057     message(WARNING "Inkscape not found, could not re-generate ${_file_to} from ${_file_from}!")
1058   endif()
1059 endfunction()
1060
1061 function(msgfmt_simple
1062   file_from
1063   list_to_add
1064   )
1065
1066   # remove ../'s
1067   get_filename_component(_file_from_we ${file_from} NAME_WE)
1068
1069   get_filename_component(_file_from ${file_from} REALPATH)
1070   get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${_file_from_we}.mo REALPATH)
1071
1072   list(APPEND ${list_to_add} ${_file_to})
1073   set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
1074
1075   get_filename_component(_file_to_path ${_file_to} PATH)
1076
1077   add_custom_command(
1078     OUTPUT  ${_file_to}
1079     COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
1080     COMMAND "$<TARGET_FILE:msgfmt>" ${_file_from} ${_file_to}
1081     DEPENDS msgfmt ${_file_from})
1082
1083   set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
1084 endfunction()
1085
1086 function(find_python_package
1087   package
1088   relative_include_dir
1089   )
1090
1091   string(TOUPPER ${package} _upper_package)
1092
1093   # set but invalid
1094   if((NOT ${PYTHON_${_upper_package}_PATH} STREQUAL "") AND
1095      (NOT ${PYTHON_${_upper_package}_PATH} MATCHES NOTFOUND))
1096 #       if(NOT EXISTS "${PYTHON_${_upper_package}_PATH}/${package}")
1097 #           message(WARNING "PYTHON_${_upper_package}_PATH is invalid, ${package} not found in '${PYTHON_${_upper_package}_PATH}' "
1098 #                           "WITH_PYTHON_INSTALL_${_upper_package} option will be ignored when installing python")
1099 #           set(WITH_PYTHON_INSTALL${_upper_package} OFF)
1100 #       endif()
1101   # not set, so initialize
1102   else()
1103     string(REPLACE "." ";" _PY_VER_SPLIT "${PYTHON_VERSION}")
1104     list(GET _PY_VER_SPLIT 0 _PY_VER_MAJOR)
1105
1106     # re-cache
1107     unset(PYTHON_${_upper_package}_PATH CACHE)
1108     find_path(PYTHON_${_upper_package}_PATH
1109       NAMES
1110         ${package}
1111       HINTS
1112         "${PYTHON_LIBPATH}/"
1113         "${PYTHON_LIBPATH}/python${PYTHON_VERSION}/"
1114         "${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/"
1115       PATH_SUFFIXES
1116         site-packages
1117         dist-packages
1118         vendor-packages
1119       NO_DEFAULT_PATH
1120       DOC
1121         "Path to python site-packages or dist-packages containing '${package}' module"
1122     )
1123     mark_as_advanced(PYTHON_${_upper_package}_PATH)
1124
1125     if(NOT EXISTS "${PYTHON_${_upper_package}_PATH}")
1126       message(WARNING
1127         "Python package '${package}' path could not be found in:\n"
1128         "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${package}', "
1129         "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${package}', "
1130         "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', "
1131         "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', "
1132         "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/vendor-packages/${package}', "
1133         "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/vendor-packages/${package}', "
1134         "\n"
1135         "The 'WITH_PYTHON_INSTALL_${_upper_package}' option will be ignored when installing Python.\n"
1136         "The build will be usable, only add-ons that depend on this package won't be functional."
1137       )
1138       set(WITH_PYTHON_INSTALL_${_upper_package} OFF PARENT_SCOPE)
1139     else()
1140       message(STATUS "${package} found at '${PYTHON_${_upper_package}_PATH}'")
1141
1142       if(NOT "${relative_include_dir}" STREQUAL "")
1143         set(_relative_include_dir "${package}/${relative_include_dir}")
1144         unset(PYTHON_${_upper_package}_INCLUDE_DIRS CACHE)
1145         find_path(PYTHON_${_upper_package}_INCLUDE_DIRS
1146           NAMES
1147             "${_relative_include_dir}"
1148           HINTS
1149             "${PYTHON_LIBPATH}/"
1150             "${PYTHON_LIBPATH}/python${PYTHON_VERSION}/"
1151             "${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/"
1152           PATH_SUFFIXES
1153             "site-packages/"
1154             "dist-packages/"
1155             "vendor-packages/"
1156           NO_DEFAULT_PATH
1157           DOC
1158             "Path to python site-packages or dist-packages containing '${package}' module header files"
1159         )
1160         mark_as_advanced(PYTHON_${_upper_package}_INCLUDE_DIRS)
1161
1162         if(NOT EXISTS "${PYTHON_${_upper_package}_INCLUDE_DIRS}")
1163           message(WARNING
1164             "Python package '${package}' include dir path could not be found in:\n"
1165             "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${_relative_include_dir}', "
1166             "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${_relative_include_dir}', "
1167             "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${_relative_include_dir}', "
1168             "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${_relative_include_dir}', "
1169             "'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/vendor-packages/${_relative_include_dir}', "
1170             "'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/vendor-packages/${_relative_include_dir}', "
1171             "\n"
1172             "The 'WITH_PYTHON_${_upper_package}' option will be disabled.\n"
1173             "The build will be usable, only add-ons that depend on this package won't be functional."
1174           )
1175           set(WITH_PYTHON_${_upper_package} OFF PARENT_SCOPE)
1176         else()
1177           set(_temp "${PYTHON_${_upper_package}_INCLUDE_DIRS}/${package}/${relative_include_dir}")
1178           unset(PYTHON_${_upper_package}_INCLUDE_DIRS CACHE)
1179           set(PYTHON_${_upper_package}_INCLUDE_DIRS "${_temp}"
1180               CACHE PATH "Path to the include directory of the ${package} module")
1181
1182           message(STATUS "${package} include files found at '${PYTHON_${_upper_package}_INCLUDE_DIRS}'")
1183         endif()
1184       endif()
1185     endif()
1186   endif()
1187 endfunction()
1188
1189 # like Python's 'print(dir())'
1190 function(print_all_vars)
1191   get_cmake_property(_vars VARIABLES)
1192   foreach(_var ${_vars})
1193     message("${_var}=${${_var}}")
1194   endforeach()
1195 endfunction()
1196
1197 macro(openmp_delayload
1198   projectname
1199   )
1200     if(MSVC)
1201       if(WITH_OPENMP)
1202         if(MSVC_CLANG)
1203           set(OPENMP_DLL_NAME "libomp")
1204         elseif(MSVC_VERSION EQUAL 1800)
1205           set(OPENMP_DLL_NAME "vcomp120")
1206         else()
1207           set(OPENMP_DLL_NAME "vcomp140")
1208         endif()
1209         set_property(TARGET ${projectname} APPEND_STRING  PROPERTY LINK_FLAGS_RELEASE " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
1210         set_property(TARGET ${projectname} APPEND_STRING  PROPERTY LINK_FLAGS_DEBUG " /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib")
1211         set_property(TARGET ${projectname} APPEND_STRING  PROPERTY LINK_FLAGS_RELWITHDEBINFO " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
1212         set_property(TARGET ${projectname} APPEND_STRING  PROPERTY LINK_FLAGS_MINSIZEREL " /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib")
1213       endif()
1214     endif()
1215 endmacro()
1216
1217 macro(set_and_warn_dependency
1218   _dependency _setting _val)
1219   # when $_dependency is disabled, forces $_setting = $_val
1220   if(NOT ${${_dependency}} AND ${${_setting}})
1221     message(STATUS "'${_dependency}' is disabled: forcing 'set(${_setting} ${_val})'")
1222     set(${_setting} ${_val})
1223   endif()
1224 endmacro()
1225
1226 macro(without_system_libs_begin)
1227   set(CMAKE_IGNORE_PATH "${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES};${CMAKE_SYSTEM_INCLUDE_PATH};${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES};${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}")
1228   if(APPLE)
1229     # Avoid searching for headers in frameworks (like Mono), and libraries in LIBDIR.
1230     set(CMAKE_FIND_FRAMEWORK NEVER)
1231   endif()
1232 endmacro()
1233
1234 macro(without_system_libs_end)
1235   unset(CMAKE_IGNORE_PATH)
1236   if(APPLE)
1237     # FIRST is the default.
1238     set(CMAKE_FIND_FRAMEWORK FIRST)
1239   endif()
1240 endmacro()