mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
The reason for this was that the "wrapper" file that was including the actual GLSL file was written on every invocation of the CMake: the file timestamp changed, and the file was rightfully recompiled. Solved by using file(GENERATE) which only writes the output file only if the content changes. The tricky part is that the same GLSL source file might be used by multiple targets with different compiler definitions. This leads to file(GENERATE) complain that the same file was requested to be generated twice. To solve this issue the generated file name is prefixed with the library name. Pull Request: https://projects.blender.org/blender/blender/pulls/164068
1705 lines
55 KiB
CMake
1705 lines
55 KiB
CMake
# SPDX-FileCopyrightText: 2006 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
# Insert `item_add` into the list after `item_check`.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `${list_id}`: the modified list.
|
|
function(list_insert_after
|
|
list_id item_check item_add
|
|
)
|
|
set(_index "")
|
|
list(FIND "${list_id}" "${item_check}" _index)
|
|
if(${_index} EQUAL -1)
|
|
message(FATAL_ERROR "'${list_id}' doesn't contain '${item_check}'")
|
|
endif()
|
|
math(EXPR _index "${_index} + 1")
|
|
list(INSERT ${list_id} "${_index}" ${item_add})
|
|
set(${list_id} "${${list_id}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Insert `item_add` into the list before `item_check`.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `${list_id}`: the modified list.
|
|
function(list_insert_before
|
|
list_id item_check item_add
|
|
)
|
|
set(_index "")
|
|
list(FIND "${list_id}" "${item_check}" _index)
|
|
if(${_index} EQUAL -1)
|
|
message(FATAL_ERROR "'${list_id}' doesn't contain '${item_check}'")
|
|
endif()
|
|
list(INSERT ${list_id} "${_index}" ${item_add})
|
|
set(${list_id} "${${list_id}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(list_assert_duplicates
|
|
list_id
|
|
)
|
|
|
|
# message(STATUS "list data: ${list_id}")
|
|
|
|
list(REMOVE_ITEM list_id "PUBLIC" "PRIVATE" "INTERFACE")
|
|
list(LENGTH list_id _len_before)
|
|
list(REMOVE_DUPLICATES list_id)
|
|
list(LENGTH list_id _len_after)
|
|
# message(STATUS "list size ${_len_before} -> ${_len_after}")
|
|
if(NOT _len_before EQUAL _len_after)
|
|
message(FATAL_ERROR "duplicate found in list which should not contain duplicates: ${list_id}")
|
|
endif()
|
|
unset(_len_before)
|
|
unset(_len_after)
|
|
endfunction()
|
|
|
|
# Adds a native path separator to the end of the path:
|
|
#
|
|
# - 'example' -> 'example/'
|
|
# - '/example///' -> '/example/'
|
|
#
|
|
# Return values:
|
|
# - `${path_new}`: the path with a trailing separator.
|
|
function(path_ensure_trailing_slash
|
|
path_new path_input
|
|
)
|
|
file(TO_NATIVE_PATH "/" _path_sep)
|
|
# Escape for use in regex (`string(REGEX QUOTE ...)` is only available in CMake 4.2+).
|
|
string(REPLACE "\\" "\\\\" _path_sep_escaped "${_path_sep}")
|
|
string(REGEX REPLACE "[${_path_sep_escaped}]+$" "" ${path_new} ${path_input})
|
|
set(${path_new} "${${path_new}}${_path_sep}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Strip trailing path separators.
|
|
#
|
|
# Return values:
|
|
# - `${path_new}`: the path without trailing separators.
|
|
function(path_strip_trailing_slash
|
|
path_new path_input
|
|
)
|
|
file(TO_NATIVE_PATH "/" _path_sep)
|
|
# Escape for use in regex (`string(REGEX QUOTE ...)` is only available in CMake 4.2+).
|
|
string(REPLACE "\\" "\\\\" _path_sep_escaped "${_path_sep}")
|
|
string(REGEX REPLACE "[${_path_sep_escaped}]+$" "" ${path_new} ${path_input})
|
|
set(${path_new} "${${path_new}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# foo_bar.spam --> foo_barMySuffix.spam
|
|
#
|
|
# Return values:
|
|
# - `${file_name_new}`: the file name with the suffix inserted.
|
|
function(file_suffix
|
|
file_name_new file_name file_suffix
|
|
)
|
|
|
|
get_filename_component(_file_name_PATH ${file_name} PATH)
|
|
get_filename_component(_file_name_NAME_WE ${file_name} NAME_WE)
|
|
get_filename_component(_file_name_EXT ${file_name} EXT)
|
|
set(${file_name_new}
|
|
"${_file_name_PATH}/${_file_name_NAME_WE}${file_suffix}${_file_name_EXT}"
|
|
PARENT_SCOPE
|
|
)
|
|
endfunction()
|
|
|
|
# useful for adding debug suffix to library lists:
|
|
# /somepath/foo.lib --> /somepath/foo_d.lib
|
|
#
|
|
# Return values:
|
|
# - `${fp_list_new}`: the list with suffixes applied to each entry.
|
|
function(file_list_suffix
|
|
fp_list_new fp_list fn_suffix
|
|
)
|
|
|
|
set(_fp_list_new "")
|
|
|
|
foreach(_fp ${fp_list})
|
|
file_suffix(_fp_suffixed "${_fp}" "${fn_suffix}")
|
|
list(APPEND _fp_list_new "${_fp_suffixed}")
|
|
endforeach()
|
|
|
|
set(${fp_list_new} "${_fp_list_new}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
if(UNIX AND NOT APPLE)
|
|
# NOTE: must be a macro, forwards `${ARGV}` to `find_package()`
|
|
# whose result variables must be visible in the caller's scope.
|
|
macro(find_package_static)
|
|
set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
|
find_package(${ARGV})
|
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
|
|
unset(_cmake_find_library_suffixes_back)
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, forwards `${ARGV}` to `find_library()`
|
|
# whose result variables must be visible in the caller's scope.
|
|
macro(find_library_static)
|
|
set(_cmake_find_library_suffixes_back ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
|
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
|
find_library(${ARGV})
|
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ${_cmake_find_library_suffixes_back})
|
|
unset(_cmake_find_library_suffixes_back)
|
|
endmacro()
|
|
endif()
|
|
|
|
function(target_link_libraries_optimized
|
|
TARGET
|
|
LIBS
|
|
)
|
|
|
|
foreach(_LIB ${LIBS})
|
|
target_link_libraries(${TARGET} INTERFACE optimized "${_LIB}")
|
|
endforeach()
|
|
endfunction()
|
|
|
|
function(target_link_libraries_debug
|
|
TARGET
|
|
LIBS
|
|
)
|
|
|
|
foreach(_LIB ${LIBS})
|
|
target_link_libraries(${TARGET} INTERFACE debug "${_LIB}")
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# Nicer makefiles with -I/1/foo/ instead of -I/1/2/3/../../foo/
|
|
# use it instead of include_directories()
|
|
function(absolute_include_dirs
|
|
includes_absolute)
|
|
|
|
set(_ALL_INCS "")
|
|
foreach(_INC ${ARGN})
|
|
# Pass any scoping keywords as is
|
|
if(("${_INC}" STREQUAL "PUBLIC") OR
|
|
("${_INC}" STREQUAL "PRIVATE") OR
|
|
("${_INC}" STREQUAL "INTERFACE"))
|
|
list(APPEND _ALL_INCS ${_INC})
|
|
else()
|
|
get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
|
|
list(APPEND _ALL_INCS ${_ABS_INC})
|
|
# for checking for invalid includes, disable for regular use
|
|
# if(NOT EXISTS "${_ABS_INC}/")
|
|
# message(FATAL_ERROR "Include not found: ${_ABS_INC}/")
|
|
# endif()
|
|
endif()
|
|
endforeach()
|
|
|
|
set(${includes_absolute} ${_ALL_INCS} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(blender_target_include_dirs_impl
|
|
target
|
|
system
|
|
includes
|
|
)
|
|
set(next_interface_mode "PRIVATE")
|
|
foreach(_INC ${includes})
|
|
if(("${_INC}" STREQUAL "PUBLIC") OR
|
|
("${_INC}" STREQUAL "PRIVATE") OR
|
|
("${_INC}" STREQUAL "INTERFACE"))
|
|
set(next_interface_mode "${_INC}")
|
|
else()
|
|
if(system)
|
|
target_include_directories(${target} SYSTEM ${next_interface_mode} ${_INC})
|
|
else()
|
|
target_include_directories(${target} ${next_interface_mode} ${_INC})
|
|
endif()
|
|
set(next_interface_mode "PRIVATE")
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# Nicer makefiles with -I/1/foo/ instead of -I/1/2/3/../../foo/
|
|
# use it instead of target_include_directories()
|
|
function(blender_target_include_dirs
|
|
target
|
|
)
|
|
absolute_include_dirs(_ALL_INCS ${ARGN})
|
|
blender_target_include_dirs_impl(${target} FALSE "${_ALL_INCS}")
|
|
endfunction()
|
|
|
|
function(blender_target_include_dirs_sys
|
|
target
|
|
)
|
|
absolute_include_dirs(_ALL_INCS ${ARGN})
|
|
blender_target_include_dirs_impl(${target} TRUE "${_ALL_INCS}")
|
|
endfunction()
|
|
|
|
# Enable unity build for the given target.
|
|
function(blender_set_target_unity_build target batch_size)
|
|
if(WITH_UNITY_BUILD)
|
|
set_target_properties(${target} PROPERTIES
|
|
UNITY_BUILD ON
|
|
UNITY_BUILD_BATCH_SIZE ${batch_size}
|
|
)
|
|
if(WITH_NINJA_POOL_JOBS AND NINJA_MAX_NUM_PARALLEL_COMPILE_HEAVY_JOBS)
|
|
# Unity builds are typically heavy.
|
|
set_target_properties(${target} PROPERTIES JOB_POOL_COMPILE compile_heavy_job_pool)
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
# Set include paths for header files included with "*.h" syntax.
|
|
# This enables auto-complete suggestions for user header files on Xcode.
|
|
# Build process is not affected since the include paths are the same
|
|
# as in HEADER_SEARCH_PATHS.
|
|
function(blender_user_header_search_paths
|
|
name
|
|
includes
|
|
)
|
|
|
|
if(XCODE)
|
|
set(_ALL_INCS "")
|
|
foreach(_INC ${includes})
|
|
get_filename_component(_ABS_INC ${_INC} ABSOLUTE)
|
|
# _ALL_INCS is a space-separated string of file paths in quotes.
|
|
string(APPEND _ALL_INCS " \"${_ABS_INC}\"")
|
|
endforeach()
|
|
set_target_properties(
|
|
${name} PROPERTIES
|
|
XCODE_ATTRIBUTE_USER_HEADER_SEARCH_PATHS "${_ALL_INCS}"
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(blender_source_group
|
|
name
|
|
sources
|
|
)
|
|
|
|
# if enabled, use the sources directories as filters.
|
|
if(IDE_GROUP_SOURCES_IN_FOLDERS)
|
|
foreach(_SRC ${sources})
|
|
# remove ../'s
|
|
cmake_path(ABSOLUTE_PATH _SRC NORMALIZE OUTPUT_VARIABLE _SRC_DIR)
|
|
cmake_path(GET _SRC_DIR PARENT_PATH _SRC_DIR)
|
|
string(FIND "${_SRC_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/" _pos)
|
|
if(NOT _pos EQUAL -1)
|
|
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" GROUP_ID ${_SRC_DIR})
|
|
string(REPLACE "/" "\\" GROUP_ID ${GROUP_ID})
|
|
source_group("${GROUP_ID}" FILES ${_SRC})
|
|
endif()
|
|
unset(_pos)
|
|
endforeach()
|
|
else()
|
|
# Group by location on disk
|
|
source_group("Source Files" FILES CMakeLists.txt)
|
|
foreach(_SRC ${sources})
|
|
get_filename_component(_SRC_EXT ${_SRC} EXT)
|
|
if(("${_SRC_EXT}" STREQUAL ".h") OR
|
|
("${_SRC_EXT}" STREQUAL ".hpp") OR
|
|
("${_SRC_EXT}" STREQUAL ".hh"))
|
|
|
|
set(GROUP_ID "Header Files")
|
|
elseif("${_SRC_EXT}" STREQUAL ".glsl")
|
|
set(GROUP_ID "Shaders")
|
|
else()
|
|
set(GROUP_ID "Source Files")
|
|
endif()
|
|
source_group("${GROUP_ID}" FILES ${_SRC})
|
|
endforeach()
|
|
endif()
|
|
|
|
# if enabled, set the FOLDER property for the projects
|
|
if(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
|
get_filename_component(FolderDir ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
|
|
string(REPLACE ${CMAKE_SOURCE_DIR} "" FolderDir ${FolderDir})
|
|
set_target_properties(${name} PROPERTIES FOLDER ${FolderDir})
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
# Support per-target CMake flags
|
|
# Read from: CMAKE_C_FLAGS_**** (made upper case) when set.
|
|
#
|
|
# 'name' should always match the target name,
|
|
# use this macro before add_library or add_executable.
|
|
#
|
|
# Optionally takes an ARGV1 passed to set(), eg `PARENT_SCOPE`.
|
|
#
|
|
# NOTE: must be a macro, modifies `CMAKE_C_FLAGS` and `CMAKE_CXX_FLAGS`
|
|
# in the caller's scope.
|
|
macro(add_c_and_cxx_flags_custom_test
|
|
name
|
|
)
|
|
|
|
# NOTE: When ARGV1 is PARENT_SCOPE, propagate to the caller's parent scope.
|
|
# `string(APPEND)` alone only modifies the local scope, and `set()` is
|
|
# needed because `string(APPEND)` does not support PARENT_SCOPE.
|
|
string(TOUPPER ${name} _name_upper)
|
|
if(DEFINED CMAKE_C_FLAGS_${_name_upper})
|
|
message(
|
|
STATUS
|
|
"Using custom CFLAGS: "
|
|
"CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"")
|
|
string(APPEND CMAKE_C_FLAGS " ${CMAKE_C_FLAGS_${_name_upper}}")
|
|
# Harmless if ARGV1 isn't set.
|
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" ${ARGV1})
|
|
endif()
|
|
if(DEFINED CMAKE_CXX_FLAGS_${_name_upper})
|
|
message(
|
|
STATUS
|
|
"Using custom CXXFLAGS: "
|
|
"CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\""
|
|
)
|
|
string(APPEND CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS_${_name_upper}}")
|
|
# Harmless if ARGV1 isn't set.
|
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" ${ARGV1})
|
|
endif()
|
|
unset(_name_upper)
|
|
|
|
endmacro()
|
|
|
|
function(blender_link_libraries
|
|
target
|
|
library_deps
|
|
)
|
|
|
|
# On Windows certain libraries have two sets of binaries: one for debug builds and one for
|
|
# release builds. The root of this requirement goes into ABI, I believe, but that's outside
|
|
# of a scope of this comment.
|
|
#
|
|
# CMake have a native way of dealing with this, which is specifying what build type the
|
|
# libraries are provided for:
|
|
#
|
|
# target_link_libraries(target optimized|debug|general <libraries>)
|
|
#
|
|
# The build type is to be provided as a separate argument to the function.
|
|
#
|
|
# CMake's variables for libraries will contain build type in such cases. For example:
|
|
#
|
|
# set(FOO_LIBRARIES optimized libfoo.lib debug libfoo_d.lib)
|
|
#
|
|
# Complications start with a single argument for library_deps: all the elements are being
|
|
# put to a list: "${FOO_LIBRARIES}" will become "optimized;libfoo.lib;debug;libfoo_d.lib".
|
|
# This makes it impossible to pass it as-is to target_link_libraries since it will treat
|
|
# this argument as a list of libraries to be linked against, causing missing libraries
|
|
# for optimized.lib.
|
|
#
|
|
# What this code does is traverse library_deps and extracts information about whether
|
|
# library is to be provided as general, debug or optimized. This is a little state machine which
|
|
# keeps track of which build type library is to be provided for:
|
|
#
|
|
# - If "debug" or "optimized" word is found, the next element in the list is expected to be
|
|
# a library which will be passed to target_link_libraries() under corresponding build type.
|
|
#
|
|
# - If there is no "debug" or "optimized" used library is specified for all build types.
|
|
#
|
|
# NOTE: If separated libraries for debug and release are needed every library in the list is
|
|
# to be prefixed explicitly.
|
|
#
|
|
# Use: "optimized libfoo optimized libbar debug libfoo_d debug libbar_d"
|
|
# NOT: "optimized libfoo libbar debug libfoo_d libbar_d"
|
|
set(dependency_libraries "")
|
|
if(NOT "${library_deps}" STREQUAL "")
|
|
set(next_library_mode "")
|
|
set(next_interface_mode "PRIVATE")
|
|
foreach(library ${library_deps})
|
|
string(TOLOWER "${library}" library_lower)
|
|
if(("${library_lower}" STREQUAL "optimized") OR
|
|
("${library_lower}" STREQUAL "debug"))
|
|
set(next_library_mode "${library_lower}")
|
|
elseif(("${library}" STREQUAL "PUBLIC") OR
|
|
("${library}" STREQUAL "PRIVATE") OR
|
|
("${library}" STREQUAL "INTERFACE"))
|
|
set(next_interface_mode "${library}")
|
|
else()
|
|
if("${next_library_mode}" STREQUAL "optimized")
|
|
set(link_library ${next_interface_mode} optimized ${library})
|
|
elseif("${next_library_mode}" STREQUAL "debug")
|
|
set(link_library ${next_interface_mode} debug ${library})
|
|
else()
|
|
set(link_library ${next_interface_mode} ${library})
|
|
endif()
|
|
set(next_library_mode "")
|
|
if(library MATCHES "^bf::dependencies")
|
|
list(APPEND dependency_libraries ${link_library})
|
|
else()
|
|
target_link_libraries(${target} ${link_library})
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
# Ensure external dependencies are last in the list of libraries, so that bf::extern include
|
|
# directories have priority over system library include directories that might conflict.
|
|
target_link_libraries(${target} ${dependency_libraries})
|
|
endfunction()
|
|
|
|
function(is_c_or_cxx_source file variable)
|
|
set(result FALSE)
|
|
cmake_path(GET file EXTENSION LAST_ONLY _ext)
|
|
# Files without an extension are not sources.
|
|
if(_ext)
|
|
# Strip the leading dot.
|
|
string(SUBSTRING "${_ext}" 1 -1 _ext)
|
|
if(("${_ext}" IN_LIST CMAKE_C_SOURCE_FILE_EXTENSIONS) OR
|
|
("${_ext}" IN_LIST CMAKE_CXX_SOURCE_FILE_EXTENSIONS))
|
|
set(result TRUE)
|
|
endif()
|
|
endif()
|
|
set(${variable} ${result} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(blender_add_lib__impl
|
|
name
|
|
sources
|
|
includes
|
|
includes_sys
|
|
library_deps
|
|
)
|
|
|
|
# message(STATUS "Configuring library ${name}")
|
|
|
|
# Check if all sources are header-only (not C/C++ sources).
|
|
set(_all_headers TRUE)
|
|
foreach(_src ${sources})
|
|
is_c_or_cxx_source("${_src}" _is_source)
|
|
if(_is_source)
|
|
set(_all_headers FALSE)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
unset(_src)
|
|
unset(_is_source)
|
|
|
|
if(_all_headers)
|
|
add_library(${name} INTERFACE)
|
|
target_sources(${name} PRIVATE ${sources})
|
|
else()
|
|
add_library(${name} ${sources})
|
|
endif()
|
|
unset(_all_headers)
|
|
|
|
# On windows vcpkg goes out of its way to make its libs the preferred
|
|
# libs, and needs to be explicitly be told not to do that.
|
|
if(WIN32)
|
|
set_target_properties(${name} PROPERTIES VS_GLOBAL_VcpkgEnabled "false")
|
|
endif()
|
|
blender_target_include_dirs(${name} ${includes})
|
|
blender_target_include_dirs_sys(${name} ${includes_sys})
|
|
|
|
if(library_deps)
|
|
blender_link_libraries(${name} "${library_deps}")
|
|
endif()
|
|
|
|
# works fine without having the includes
|
|
# listed is helpful for IDE's (QtCreator/MSVC)
|
|
blender_source_group("${name}" "${sources}")
|
|
blender_user_header_search_paths("${name}" "${includes}")
|
|
|
|
list_assert_duplicates("${sources}")
|
|
list_assert_duplicates("${includes}")
|
|
# Not for system includes because they can resolve to the same path
|
|
# list_assert_duplicates("${includes_sys}")
|
|
|
|
# Blender's dependency loops are longer than cmake expects and we need additional loops to
|
|
# properly link.
|
|
set_property(TARGET ${name} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 3)
|
|
endfunction()
|
|
|
|
|
|
function(blender_add_lib_nolist
|
|
name
|
|
sources
|
|
includes
|
|
includes_sys
|
|
library_deps
|
|
)
|
|
|
|
add_c_and_cxx_flags_custom_test(${name} PARENT_SCOPE)
|
|
|
|
blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}" "${library_deps}")
|
|
endfunction()
|
|
|
|
function(blender_add_lib
|
|
name
|
|
sources
|
|
includes
|
|
includes_sys
|
|
library_deps
|
|
)
|
|
|
|
add_c_and_cxx_flags_custom_test(${name} PARENT_SCOPE)
|
|
|
|
blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}" "${library_deps}")
|
|
|
|
set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name})
|
|
endfunction()
|
|
|
|
# Ninja only: assign 'heavy pool' to some targets that are especially RAM-consuming to build.
|
|
function(setup_heavy_lib_pool)
|
|
if(WITH_NINJA_POOL_JOBS AND NINJA_MAX_NUM_PARALLEL_COMPILE_HEAVY_JOBS)
|
|
set(_HEAVY_LIBS "")
|
|
set(_HEAVY_FILES "")
|
|
set(_TARGET "")
|
|
if(WITH_CYCLES)
|
|
list(APPEND _HEAVY_LIBS "cycles_device" "cycles_kernel" "cycles_hydra")
|
|
endif()
|
|
if(WITH_LIBMV)
|
|
list(APPEND _HEAVY_LIBS "extern_ceres" "bf_intern_libmv")
|
|
endif()
|
|
if(WITH_OPENVDB)
|
|
list(APPEND _HEAVY_LIBS "bf_intern_openvdb")
|
|
endif()
|
|
|
|
# A few specific files are very heavy to compile in Clang or GCC
|
|
# (several GB of RAM required in debug + ASAN builds e.g.).
|
|
list(APPEND _HEAVY_FILES "source/blender/blenkernel/intern/volume.cc")
|
|
list(APPEND _HEAVY_FILES "source/blender/blenkernel/intern/volume_to_mesh.cc")
|
|
list(APPEND _HEAVY_FILES "source/blender/blenkernel/intern/volume_grid.cc")
|
|
list(APPEND _HEAVY_FILES "source/blender/modifiers/intern/MOD_volume_displace.cc")
|
|
list(APPEND _HEAVY_FILES "source/blender/geometry/intern/mesh_to_volume.cc")
|
|
|
|
foreach(_TARGET ${_HEAVY_LIBS})
|
|
if(TARGET ${_TARGET})
|
|
set_property(TARGET ${_TARGET} PROPERTY JOB_POOL_COMPILE compile_heavy_job_pool)
|
|
endif()
|
|
endforeach()
|
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL "4.2.0")
|
|
foreach(_FILE ${_HEAVY_FILES})
|
|
set_property(SOURCE ${_FILE} PROPERTY JOB_POOL_COMPILE compile_heavy_job_pool)
|
|
endforeach()
|
|
endif()
|
|
unset(_TARGET)
|
|
unset(_HEAVY_LIBS)
|
|
unset(_HEAVY_FILES)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Platform specific linker flags for targets.
|
|
function(setup_platform_linker_flags
|
|
target)
|
|
set_property(
|
|
TARGET ${target} APPEND_STRING PROPERTY
|
|
LINK_FLAGS " ${PLATFORM_LINKFLAGS}"
|
|
)
|
|
set_property(
|
|
TARGET ${target} APPEND_STRING PROPERTY
|
|
LINK_FLAGS_RELEASE " ${PLATFORM_LINKFLAGS_RELEASE}"
|
|
)
|
|
set_property(
|
|
TARGET ${target} APPEND_STRING PROPERTY
|
|
LINK_FLAGS_DEBUG " ${PLATFORM_LINKFLAGS_DEBUG}"
|
|
)
|
|
|
|
get_target_property(target_type ${target} TYPE)
|
|
if(target_type STREQUAL "EXECUTABLE")
|
|
set_property(
|
|
TARGET ${target} APPEND_STRING PROPERTY
|
|
LINK_FLAGS " ${PLATFORM_LINKFLAGS_EXECUTABLE}"
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Hide internal symbols for targets that might otherwise conflict with plugins.
|
|
function(setup_platform_linker_symbol_hiding target)
|
|
if(DEFINED PLATFORM_LINKFLAGS_SYMBOL_HIDING)
|
|
set_property(
|
|
TARGET ${target} APPEND_STRING PROPERTY
|
|
LINK_FLAGS " ${PLATFORM_LINKFLAGS_SYMBOL_HIDING}"
|
|
)
|
|
endif()
|
|
|
|
if(DEFINED PLATFORM_SYMBOLS_MAP)
|
|
set_target_properties(${target} PROPERTIES LINK_DEPENDS ${PLATFORM_SYMBOLS_MAP})
|
|
endif()
|
|
endfunction()
|
|
|
|
# Platform specific libraries for targets.
|
|
function(setup_platform_linker_libs
|
|
target
|
|
)
|
|
# TBB malloc must be early in the list, to be before PTHREAD (see #57998).
|
|
if(WITH_TBB_MALLOC_PROXY)
|
|
target_link_libraries(${target}
|
|
PRIVATE ${TBB_MALLOC_LIBRARIES}
|
|
PRIVATE ${TBB_MALLOC_PROXY_LIBRARIES}
|
|
)
|
|
endif()
|
|
|
|
if(WIN32 AND NOT UNIX)
|
|
if(DEFINED PTHREADS_LIBRARIES)
|
|
target_link_libraries(${target} PRIVATE ${PTHREADS_LIBRARIES})
|
|
endif()
|
|
endif()
|
|
|
|
# target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
|
|
target_link_libraries(${target} PRIVATE ${PLATFORM_LINKLIBS})
|
|
endfunction()
|
|
|
|
# Return values:
|
|
# - `${_simd_flags}`: compiler flags to enable SIMD support.
|
|
function(get_compiler_simd_flags
|
|
_simd_flags)
|
|
|
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64)" OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64)
|
|
# message(STATUS "Detecting SIMD support")
|
|
if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
|
set(${_simd_flags} "-march=x86-64-v2" PARENT_SCOPE)
|
|
elseif(MSVC)
|
|
# MSVC has no specific compile flags for SSE42 (only for AVX).
|
|
set(${_simd_flags} PARENT_SCOPE)
|
|
# It also doesn't define __SSE__/__MMX__ flags and only does the AVX and higher flags.
|
|
# For consistency we define these flags for MSVC.
|
|
add_compile_definitions(__MMX__ __SSE__ __SSE2__ __SSE3__ __SSE4_1__ __SSE4_2__)
|
|
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
|
if(WIN32)
|
|
set(${_simd_flags} "/QxSSE4.2" PARENT_SCOPE)
|
|
else()
|
|
set(${_simd_flags} "-xsse4.2" PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
message(WARNING "SIMD flags for this compiler: '${CMAKE_C_COMPILER_ID}' not known")
|
|
set(${_simd_flags} PARENT_SCOPE)
|
|
endif()
|
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
|
if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
|
if(UNIX AND NOT APPLE)
|
|
# Target ARMv8.2-A with dot product and half float.
|
|
set(${_simd_flags} "-march=armv8.2-a+dotprod+fp16+lse" PARENT_SCOPE)
|
|
else()
|
|
set(${_simd_flags} PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
set(${_simd_flags} PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
# Not a supported system, don't set any SIMD compiler flags.
|
|
set(${_simd_flags} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(test_neon_support)
|
|
if(NOT DEFINED SUPPORTS_NEON_BUILD)
|
|
include(CheckCXXSourceCompiles)
|
|
check_cxx_source_compiles(
|
|
"#include <arm_neon.h>
|
|
int main() {return vaddvq_s32(vdupq_n_s32(1));}"
|
|
SUPPORTS_NEON_BUILD)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Only print message if running CMake first time
|
|
function(message_first_run)
|
|
if(FIRST_RUN)
|
|
message(${ARGV})
|
|
endif()
|
|
endfunction()
|
|
|
|
# when we have warnings as errors applied globally this
|
|
# needs to be removed for some external libs which we don't maintain.
|
|
|
|
|
|
# NOTE: must be a macro, modifies `CMAKE_C_FLAGS` and per-config
|
|
# variants in the caller's scope.
|
|
macro(remove_c_flag
|
|
_flag)
|
|
|
|
foreach(f ${ARGV})
|
|
string(REGEX REPLACE ${f} "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
|
endforeach()
|
|
unset(f)
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, modifies `CMAKE_CXX_FLAGS` and per-config
|
|
# variants in the caller's scope.
|
|
macro(remove_cxx_flag
|
|
_flag)
|
|
|
|
foreach(f ${ARGV})
|
|
string(REGEX REPLACE ${f} "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
|
|
string(REGEX REPLACE ${f} "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
|
endforeach()
|
|
unset(f)
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, calls `remove_c_flag`/`remove_cxx_flag`
|
|
# which modify `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(remove_c_and_cxx_flag
|
|
_flag)
|
|
|
|
remove_c_flag(${ARGV})
|
|
remove_cxx_flag(${ARGV})
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, modifies `CMAKE_C_FLAGS` in the caller's scope.
|
|
macro(add_c_flag
|
|
flag)
|
|
|
|
string(APPEND CMAKE_C_FLAGS " ${flag}")
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, modifies `CMAKE_CXX_FLAGS` in the caller's scope.
|
|
macro(add_cxx_flag
|
|
flag)
|
|
|
|
string(APPEND CMAKE_CXX_FLAGS " ${flag}")
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, calls `add_c_flag`/`add_cxx_flag`
|
|
# which modify `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(add_c_and_cxx_flag
|
|
flag)
|
|
|
|
add_c_flag("${flag}")
|
|
add_cxx_flag("${flag}")
|
|
endmacro()
|
|
|
|
# Needed to "negate" options: `-Wno-example`
|
|
# as this doesn't work when added to `CMAKE_CXX_FLAGS`.
|
|
#
|
|
# NOTE: must be a macro, modifies per-config `CMAKE_C_FLAGS_*`
|
|
# variants in the caller's scope.
|
|
macro(add_c_flag_per_config
|
|
flag)
|
|
|
|
string(APPEND CMAKE_C_FLAGS_DEBUG " ${flag}")
|
|
string(APPEND CMAKE_C_FLAGS_RELEASE " ${flag}")
|
|
string(APPEND CMAKE_C_FLAGS_MINSIZEREL " ${flag}")
|
|
string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO " ${flag}")
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, modifies per-config `CMAKE_CXX_FLAGS_*`
|
|
# variants in the caller's scope.
|
|
macro(add_cxx_flag_per_config
|
|
flag)
|
|
|
|
string(APPEND CMAKE_CXX_FLAGS_DEBUG " ${flag}")
|
|
string(APPEND CMAKE_CXX_FLAGS_RELEASE " ${flag}")
|
|
string(APPEND CMAKE_CXX_FLAGS_MINSIZEREL " ${flag}")
|
|
string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " ${flag}")
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, calls `remove_cc_flag`/`add_c_flag`/`add_cxx_flag`/`add_cc_flag`
|
|
# which modify `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(remove_strict_flags)
|
|
|
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
|
remove_c_and_cxx_flag(
|
|
"-Wstrict-prototypes"
|
|
"-Wsuggest-attribute=format"
|
|
"-Wmissing-prototypes"
|
|
"-Wmissing-declarations"
|
|
"-Wmissing-format-attribute"
|
|
"-Wunused-local-typedefs"
|
|
"-Wunused-macros"
|
|
"-Wunused-parameter"
|
|
"-Wwrite-strings"
|
|
"-Wredundant-decls"
|
|
"-Wundef"
|
|
"-Wshadow"
|
|
"-Wdouble-promotion"
|
|
"-Wold-style-definition"
|
|
"-Wextra"
|
|
"-Werror=[^ ]+"
|
|
"-Werror"
|
|
)
|
|
|
|
# negate flags implied by '-Wall'
|
|
add_c_flag("${C_REMOVE_STRICT_FLAGS}")
|
|
add_cxx_flag("${CXX_REMOVE_STRICT_FLAGS}")
|
|
add_c_and_cxx_flag("${C_AND_CXX_REMOVE_STRICT_FLAGS}")
|
|
endif()
|
|
|
|
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|
remove_c_and_cxx_flag(
|
|
"-Wunused-parameter"
|
|
"-Wunused-variable"
|
|
"-Werror=[^ ]+"
|
|
"-Werror"
|
|
)
|
|
|
|
# negate flags implied by '-Wall'
|
|
add_c_flag("${C_REMOVE_STRICT_FLAGS}")
|
|
add_cxx_flag("${CXX_REMOVE_STRICT_FLAGS}")
|
|
add_c_and_cxx_flag("${C_AND_CXX_REMOVE_STRICT_FLAGS}")
|
|
endif()
|
|
|
|
if(MSVC)
|
|
add_cxx_flag(
|
|
# Warning C5038: data member 'foo' will be initialized after data member 'bar'.
|
|
"/wd5038"
|
|
)
|
|
remove_c_and_cxx_flag(
|
|
# Restore warn C4100 (unreferenced formal parameter) back to w4.
|
|
"/w34100"
|
|
# Restore warn C4189 (unused variable) back to w4.
|
|
"/w34189"
|
|
)
|
|
endif()
|
|
|
|
endmacro()
|
|
|
|
# NOTE: must be a macro, calls `remove_cc_flag`
|
|
# which modifies `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(remove_extra_strict_flags)
|
|
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
|
remove_c_and_cxx_flag(
|
|
"-Wunused-parameter"
|
|
)
|
|
endif()
|
|
|
|
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|
remove_c_and_cxx_flag(
|
|
"-Wunused-parameter"
|
|
)
|
|
endif()
|
|
|
|
if(MSVC)
|
|
remove_c_and_cxx_flag(
|
|
# Restore warn C4100 (unreferenced formal parameter) back to w4.
|
|
"/w34100"
|
|
)
|
|
endif()
|
|
endmacro()
|
|
|
|
# note, we can only append flags on a single file so we need to negate the options.
|
|
# at the moment we can't shut up ffmpeg deprecations, so use this, but will
|
|
# probably add more removals here.
|
|
function(remove_strict_c_flags_file
|
|
filenames)
|
|
foreach(_SOURCE ${ARGV})
|
|
if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR
|
|
(CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
|
set_source_files_properties(
|
|
${_SOURCE} PROPERTIES
|
|
COMPILE_FLAGS "${C_REMOVE_STRICT_FLAGS} ${C_AND_CXX_REMOVE_STRICT_FLAGS}"
|
|
)
|
|
endif()
|
|
if(MSVC)
|
|
# TODO
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
function(remove_strict_cxx_flags_file
|
|
filenames)
|
|
foreach(_SOURCE ${ARGV})
|
|
if((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
|
|
(CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
|
set_source_files_properties(
|
|
${_SOURCE} PROPERTIES
|
|
COMPILE_FLAGS "${CXX_REMOVE_STRICT_FLAGS} ${C_AND_CXX_REMOVE_STRICT_FLAGS}"
|
|
)
|
|
endif()
|
|
if(MSVC)
|
|
# TODO
|
|
endif()
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# External libs may need 'signed char' to be default.
|
|
#
|
|
# NOTE: must be a macro, calls `remove_c_and_cxx_flag`
|
|
# which modifies `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(remove_c_and_cxx_flag_unsigned_char)
|
|
if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR
|
|
(CMAKE_C_COMPILER_ID MATCHES "Clang") OR
|
|
(CMAKE_C_COMPILER_ID STREQUAL "Intel"))
|
|
remove_c_and_cxx_flag("-funsigned-char")
|
|
elseif(MSVC)
|
|
remove_c_and_cxx_flag("/J")
|
|
else()
|
|
message(WARNING
|
|
"Compiler '${CMAKE_C_COMPILER_ID}' failed to disable 'unsigned char' flag."
|
|
"Build files need updating."
|
|
)
|
|
endif()
|
|
endmacro()
|
|
|
|
function(add_check_c_compiler_flag_impl
|
|
_CFLAGS
|
|
_CACHE_VAR
|
|
_FLAG
|
|
)
|
|
|
|
include(CheckCCompilerFlag)
|
|
|
|
set(_is_new TRUE)
|
|
if(DEFINED CACHE{${_CACHE_VAR}})
|
|
set(_is_new FALSE)
|
|
endif()
|
|
|
|
check_c_compiler_flag("${_FLAG}" "${_CACHE_VAR}")
|
|
if(${_CACHE_VAR})
|
|
# message(STATUS "Using CFLAG: ${_FLAG}")
|
|
set(${_CFLAGS} "${${_CFLAGS}} ${_FLAG}" PARENT_SCOPE)
|
|
else()
|
|
if(_is_new)
|
|
message(STATUS "Unsupported CFLAG: ${_FLAG}")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
function(add_check_cxx_compiler_flag_impl
|
|
_CXXFLAGS
|
|
_CACHE_VAR
|
|
_FLAG
|
|
)
|
|
|
|
include(CheckCXXCompilerFlag)
|
|
|
|
set(_is_new TRUE)
|
|
if(DEFINED CACHE{${_CACHE_VAR}})
|
|
set(_is_new FALSE)
|
|
endif()
|
|
|
|
check_cxx_compiler_flag("${_FLAG}" "${_CACHE_VAR}")
|
|
if(${_CACHE_VAR})
|
|
# message(STATUS "Using CXXFLAG: ${_FLAG}")
|
|
set(${_CXXFLAGS} "${${_CXXFLAGS}} ${_FLAG}" PARENT_SCOPE)
|
|
else()
|
|
if(_is_new)
|
|
message(STATUS "Unsupported CXXFLAG: ${_FLAG}")
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
function(ADD_CHECK_C_COMPILER_FLAGS _CFLAGS)
|
|
# Iterate over pairs & check each.
|
|
set(cache_var "")
|
|
foreach(arg ${ARGN})
|
|
if(cache_var)
|
|
add_check_c_compiler_flag_impl("${_CFLAGS}" "${cache_var}" "${arg}")
|
|
set(cache_var "")
|
|
else()
|
|
set(cache_var "${arg}")
|
|
endif()
|
|
endforeach()
|
|
set(${_CFLAGS} "${${_CFLAGS}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(ADD_CHECK_CXX_COMPILER_FLAGS _CXXFLAGS)
|
|
# Iterate over pairs & check each.
|
|
set(cache_var "")
|
|
foreach(arg ${ARGN})
|
|
if(cache_var)
|
|
add_check_cxx_compiler_flag_impl("${_CXXFLAGS}" "${cache_var}" "${arg}")
|
|
set(cache_var "")
|
|
else()
|
|
set(cache_var "${arg}")
|
|
endif()
|
|
endforeach()
|
|
set(${_CXXFLAGS} "${${_CXXFLAGS}}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(get_blender_version)
|
|
# extracts header vars and defines them in the parent scope:
|
|
#
|
|
# - BLENDER_VERSION (major.minor)
|
|
# - BLENDER_VERSION_MAJOR
|
|
# - BLENDER_VERSION_MINOR
|
|
# - BLENDER_VERSION_PATCH
|
|
# - BLENDER_VERSION_CYCLE (alpha, beta, rc, release)
|
|
|
|
# So CMAKE depends on `BKE_blender_version.h`, beware of infinite-loops!
|
|
configure_file(
|
|
${CMAKE_SOURCE_DIR}/source/blender/blenkernel/BKE_blender_version.h
|
|
${CMAKE_BINARY_DIR}/source/blender/blenkernel/BKE_blender_version.h.done
|
|
)
|
|
|
|
file(
|
|
STRINGS ${CMAKE_SOURCE_DIR}/source/blender/blenkernel/BKE_blender_version.h
|
|
_contents REGEX "^#define[ \t]+BLENDER_.*$"
|
|
)
|
|
|
|
string(
|
|
REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION[ \t]+([0-9]+).*" "\\1"
|
|
_out_version "${_contents}"
|
|
)
|
|
string(
|
|
REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_PATCH[ \t]+([0-9]+).*" "\\1"
|
|
_out_version_patch "${_contents}"
|
|
)
|
|
string(
|
|
REGEX REPLACE ".*#define[ \t]+BLENDER_VERSION_CYCLE[ \t]+([a-z]+).*" "\\1"
|
|
_out_version_cycle "${_contents}"
|
|
)
|
|
|
|
if(NOT ${_out_version} MATCHES "^[0-9]+$")
|
|
message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION")
|
|
endif()
|
|
|
|
if(NOT ${_out_version_patch} MATCHES "^[0-9]+$")
|
|
message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_PATCH")
|
|
endif()
|
|
|
|
if(NOT ${_out_version_cycle} MATCHES "^[a-z]+$")
|
|
message(FATAL_ERROR "Version parsing failed for BLENDER_VERSION_CYCLE")
|
|
endif()
|
|
|
|
math(EXPR _out_version_major "${_out_version} / 100")
|
|
math(EXPR _out_version_minor "${_out_version} % 100")
|
|
|
|
# output vars
|
|
set(BLENDER_VERSION "${_out_version_major}.${_out_version_minor}" PARENT_SCOPE)
|
|
set(BLENDER_VERSION_MAJOR "${_out_version_major}" PARENT_SCOPE)
|
|
set(BLENDER_VERSION_MINOR "${_out_version_minor}" PARENT_SCOPE)
|
|
set(BLENDER_VERSION_PATCH "${_out_version_patch}" PARENT_SCOPE)
|
|
set(BLENDER_VERSION_CYCLE "${_out_version_cycle}" PARENT_SCOPE)
|
|
|
|
endfunction()
|
|
|
|
|
|
# pair of macros to allow libraries to be specify files to install, but to
|
|
# only install them at the end so the directories don't get cleared with
|
|
# the files in them. used by cycles to install addon.
|
|
function(delayed_install
|
|
base
|
|
files
|
|
destination)
|
|
|
|
foreach(f ${files})
|
|
if(IS_ABSOLUTE ${f} OR "${base}" STREQUAL "")
|
|
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${f})
|
|
else()
|
|
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_FILES ${base}/${f})
|
|
endif()
|
|
set_property(GLOBAL APPEND PROPERTY DELAYED_INSTALL_DESTINATIONS ${destination})
|
|
endforeach()
|
|
unset(f)
|
|
endfunction()
|
|
|
|
# note this is a function instead of a macro so that ${BUILD_TYPE} in targetdir
|
|
# does not get expanded in calling but is preserved
|
|
function(delayed_do_install
|
|
targetdir)
|
|
|
|
get_property(files GLOBAL PROPERTY DELAYED_INSTALL_FILES)
|
|
get_property(destinations GLOBAL PROPERTY DELAYED_INSTALL_DESTINATIONS)
|
|
|
|
if(files)
|
|
list(LENGTH files n)
|
|
math(EXPR n "${n}-1")
|
|
|
|
foreach(i RANGE ${n})
|
|
list(GET files ${i} f)
|
|
list(GET destinations ${i} d)
|
|
if(NOT IS_ABSOLUTE ${d})
|
|
install(FILES ${f} DESTINATION ${targetdir}/${d})
|
|
else()
|
|
install(FILES ${f} DESTINATION ${d})
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
endfunction()
|
|
|
|
# Same as above but generates the var name and output automatic.
|
|
function(data_to_c
|
|
file_from file_to
|
|
list_to_add
|
|
# Optional 4th argument: override the symbol name used in the generated C file,
|
|
# useful when different files share the same basename and would produce conflicting symbols.
|
|
# When omitted the symbol name is derived from the filename.
|
|
symbol_name_override
|
|
)
|
|
|
|
list(APPEND ${list_to_add} ${file_to})
|
|
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${file_to}
|
|
COMMAND "$<TARGET_FILE:datatoc>" ${file_from} ${file_to} ${symbol_name_override}
|
|
DEPENDS ${file_from} datatoc)
|
|
|
|
set_source_files_properties(${file_to} PROPERTIES GENERATED TRUE)
|
|
endfunction()
|
|
|
|
|
|
# Same as above but generates the var name and output automatic.
|
|
function(data_to_c_simple
|
|
file_from
|
|
list_to_add
|
|
)
|
|
|
|
# remove ../'s
|
|
cmake_path(SET _file_from NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/${file_from}")
|
|
cmake_path(SET _file_to NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c")
|
|
|
|
list(APPEND ${list_to_add} ${_file_to})
|
|
source_group(Generated FILES ${_file_to})
|
|
list(APPEND ${list_to_add} ${file_from})
|
|
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${_file_to}
|
|
COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to}
|
|
DEPENDS ${_file_from} datatoc)
|
|
|
|
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
|
endfunction()
|
|
|
|
|
|
# Process glsl file and convert it to c
|
|
function(glsl_to_c
|
|
file_from
|
|
list_to_add
|
|
include_list
|
|
)
|
|
|
|
# remove ../'s
|
|
cmake_path(SET _file_from NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/${file_from}")
|
|
cmake_path(SET _file_tmp NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.tmp")
|
|
cmake_path(SET _file_meta NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.hh")
|
|
cmake_path(SET _file_info NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.info")
|
|
cmake_path(SET _file_to NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.c")
|
|
cmake_path(SET _file_dep NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${file_from}.d")
|
|
|
|
# Turn include directories into absolute paths
|
|
set(_inc_list "")
|
|
foreach(path IN LISTS ${include_list})
|
|
cmake_path(SET _inc_path NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/${path}")
|
|
list(APPEND _inc_list ${_inc_path})
|
|
endforeach()
|
|
|
|
list(APPEND ${list_to_add} ${_file_to})
|
|
source_group(Generated FILES ${_file_to})
|
|
list(APPEND ${list_to_add} ${file_from})
|
|
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${_file_tmp} ${_file_meta} ${_file_info} ${_file_dep}
|
|
DEPFILE ${_file_dep}
|
|
COMMAND
|
|
"$<TARGET_FILE:shader_tool>"
|
|
${_file_from} ${_file_tmp} ${_file_meta} ${_file_info} ${_file_dep} ${_inc_list}
|
|
DEPENDS ${_file_from} shader_tool)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${_file_to}
|
|
COMMAND "$<TARGET_FILE:datatoc>" ${_file_tmp} ${_file_to}
|
|
DEPENDS ${_file_tmp} datatoc)
|
|
|
|
set_source_files_properties(${_file_tmp} PROPERTIES GENERATED TRUE)
|
|
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
|
set_source_files_properties(${_file_meta} PROPERTIES GENERATED TRUE)
|
|
set_source_files_properties(${_file_info} PROPERTIES GENERATED TRUE)
|
|
endfunction()
|
|
|
|
|
|
function(msgfmt_simple
|
|
file_from
|
|
list_to_add
|
|
)
|
|
|
|
# remove ../'s
|
|
get_filename_component(_file_from_we ${file_from} NAME_WE)
|
|
|
|
cmake_path(ABSOLUTE_PATH file_from NORMALIZE OUTPUT_VARIABLE _file_from)
|
|
cmake_path(SET _file_to NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${_file_from_we}.mo")
|
|
|
|
list(APPEND ${list_to_add} ${_file_to})
|
|
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
|
|
get_filename_component(_file_to_path ${_file_to} PATH)
|
|
|
|
add_custom_command(
|
|
OUTPUT ${_file_to}
|
|
|
|
COMMAND ${CMAKE_COMMAND} -E
|
|
make_directory ${_file_to_path}
|
|
|
|
COMMAND ${CMAKE_COMMAND} -E
|
|
env ${PLATFORM_ENV_BUILD} "$<TARGET_FILE:msgfmt>" ${_file_from} ${_file_to}
|
|
|
|
DEPENDS msgfmt ${_file_from})
|
|
|
|
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
|
endfunction()
|
|
|
|
function(find_python_package
|
|
package
|
|
relative_inc_dir
|
|
)
|
|
|
|
string(TOUPPER ${package} _upper_package)
|
|
|
|
# Set but invalid.
|
|
if((NOT ${PYTHON_${_upper_package}_PATH} STREQUAL "") AND
|
|
(NOT ${PYTHON_${_upper_package}_PATH} MATCHES NOTFOUND))
|
|
# if(NOT EXISTS "${PYTHON_${_upper_package}_PATH}/${package}")
|
|
# message(
|
|
# WARNING
|
|
# "PYTHON_${_upper_package}_PATH is invalid, ${package} not found in "
|
|
# "'${PYTHON_${_upper_package}_PATH}' "
|
|
# "WITH_PYTHON_INSTALL_${_upper_package} option will be ignored when installing Python"
|
|
# )
|
|
# set(WITH_PYTHON_INSTALL${_upper_package} OFF)
|
|
# endif()
|
|
# Not set, so initialize.
|
|
else()
|
|
string(REPLACE "." ";" _PY_VER_SPLIT "${PYTHON_VERSION}")
|
|
list(GET _PY_VER_SPLIT 0 _PY_VER_MAJOR)
|
|
|
|
# re-cache
|
|
unset(PYTHON_${_upper_package}_PATH CACHE)
|
|
find_path(PYTHON_${_upper_package}_PATH
|
|
NAMES
|
|
${package}
|
|
HINTS
|
|
"${PYTHON_LIBPATH}/"
|
|
"${PYTHON_LIBPATH}/python${PYTHON_VERSION}/"
|
|
"${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/"
|
|
PATH_SUFFIXES
|
|
site-packages
|
|
dist-packages
|
|
vendor-packages
|
|
NO_DEFAULT_PATH
|
|
DOC
|
|
"Path to python site-packages or dist-packages containing '${package}' module"
|
|
)
|
|
mark_as_advanced(PYTHON_${_upper_package}_PATH)
|
|
|
|
if(NOT EXISTS "${PYTHON_${_upper_package}_PATH}")
|
|
message(WARNING
|
|
"Python package '${package}' path could not be found in:\n"
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${package}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${package}', "
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${package}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${package}', "
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/vendor-packages/${package}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/vendor-packages/${package}', "
|
|
"\n"
|
|
"The 'WITH_PYTHON_INSTALL_${_upper_package}' option will be ignored "
|
|
"when installing Python.\n"
|
|
"The build will be usable, only add-ons that depend on this package won't be functional."
|
|
)
|
|
set(WITH_PYTHON_INSTALL_${_upper_package} OFF PARENT_SCOPE)
|
|
else()
|
|
message(STATUS "${package} found at '${PYTHON_${_upper_package}_PATH}'")
|
|
|
|
if(NOT "${relative_inc_dir}" STREQUAL "")
|
|
set(_relative_inc_dir "${package}/${relative_inc_dir}")
|
|
unset(PYTHON_${_upper_package}_INCLUDE_DIRS CACHE)
|
|
find_path(PYTHON_${_upper_package}_INCLUDE_DIRS
|
|
NAMES
|
|
"${_relative_inc_dir}"
|
|
HINTS
|
|
"${PYTHON_LIBPATH}/"
|
|
"${PYTHON_LIBPATH}/python${PYTHON_VERSION}/"
|
|
"${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/"
|
|
PATH_SUFFIXES
|
|
"site-packages/"
|
|
"dist-packages/"
|
|
"vendor-packages/"
|
|
NO_DEFAULT_PATH
|
|
DOC
|
|
"\
|
|
Path to python site-packages or dist-packages containing '${package}' module header files"
|
|
)
|
|
mark_as_advanced(PYTHON_${_upper_package}_INCLUDE_DIRS)
|
|
|
|
if(NOT EXISTS "${PYTHON_${_upper_package}_INCLUDE_DIRS}")
|
|
message(WARNING
|
|
"Python package '${package}' include dir path could not be found in:\n"
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/${_relative_inc_dir}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/site-packages/${_relative_inc_dir}', "
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/dist-packages/${_relative_inc_dir}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/dist-packages/${_relative_inc_dir}', "
|
|
"'${PYTHON_LIBPATH}/python${PYTHON_VERSION}/vendor-packages/${_relative_inc_dir}', "
|
|
"'${PYTHON_LIBPATH}/python${_PY_VER_MAJOR}/vendor-packages/${_relative_inc_dir}', "
|
|
"\n"
|
|
"The 'WITH_PYTHON_${_upper_package}' option will be disabled.\n"
|
|
"The build will be usable, only add-ons that depend on this package "
|
|
"won't be functional."
|
|
)
|
|
set(WITH_PYTHON_${_upper_package} OFF PARENT_SCOPE)
|
|
else()
|
|
set(_temp "${PYTHON_${_upper_package}_INCLUDE_DIRS}/${package}/${relative_inc_dir}")
|
|
unset(PYTHON_${_upper_package}_INCLUDE_DIRS CACHE)
|
|
set(PYTHON_${_upper_package}_INCLUDE_DIRS "${_temp}"
|
|
CACHE PATH "Path to the include directory of the ${package} module")
|
|
|
|
message(STATUS
|
|
"${package} include files found at '${PYTHON_${_upper_package}_INCLUDE_DIRS}'"
|
|
)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
# Find a file in Python's module path and cache it.
|
|
# Re-generating cache upon changes to the Python installation.
|
|
#
|
|
# Return values:
|
|
# - `${out_var_abs}`: absolute path (cached).
|
|
# - `${out_var_rel}`: `PYTHON_ROOT` relative path (not cached).
|
|
function(find_python_module_file
|
|
module_file
|
|
out_var_abs
|
|
out_var_rel
|
|
)
|
|
|
|
# Reset if the file isn't found.
|
|
if(DEFINED ${out_var_abs})
|
|
if(NOT EXISTS ${${out_var_abs}})
|
|
unset(${out_var_abs} CACHE)
|
|
endif()
|
|
endif()
|
|
|
|
# Reset if the version number or Python path changes.
|
|
set(_python_mod_file_deps_test "${PYTHON_LIBPATH};${PYTHON_VERSION}")
|
|
if(DEFINED _${out_var_abs}_DEPS)
|
|
if(NOT (_${out_var_abs}_DEPS STREQUAL _python_mod_file_deps_test))
|
|
unset(${out_var_abs} CACHE)
|
|
endif()
|
|
else()
|
|
unset(${out_var_abs} CACHE)
|
|
endif()
|
|
|
|
path_strip_trailing_slash(_python_root "${PYTHON_LIBPATH}")
|
|
if(WIN32)
|
|
# MS-Windows has no `python${PYTHON_VERSION}` directory, `site-packages` is directly in `lib`.
|
|
set(_python_base "${_python_root}")
|
|
else()
|
|
set(_python_base "${_python_root}/python${PYTHON_VERSION}")
|
|
endif()
|
|
# This always moves up one level (even if there is a trailing slash).
|
|
get_filename_component(_python_root "${_python_root}" DIRECTORY)
|
|
path_ensure_trailing_slash(_python_root "${_python_root}")
|
|
|
|
if(NOT (DEFINED ${out_var_abs}))
|
|
message(STATUS "Finding Python Module File: ${module_file}")
|
|
find_file(${out_var_abs}
|
|
NAMES
|
|
"${module_file}"
|
|
PATHS
|
|
"${_python_base}"
|
|
PATH_SUFFIXES
|
|
"site-packages"
|
|
"dist-packages"
|
|
"vendor-packages"
|
|
""
|
|
NO_DEFAULT_PATH
|
|
)
|
|
if(${out_var_abs})
|
|
# Internal because this is only to track changes (users never need to manipulate it).
|
|
set(_${out_var_abs}_DEPS "${_python_mod_file_deps_test}" CACHE INTERNAL "")
|
|
endif()
|
|
endif()
|
|
|
|
if(${out_var_abs})
|
|
string(LENGTH "${_python_root}" _python_root_len)
|
|
string(SUBSTRING ${${out_var_abs}} ${_python_root_len} -1 ${out_var_rel})
|
|
set(${out_var_rel} "${${out_var_rel}}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
|
|
# like Python's 'print(dir())'
|
|
function(print_all_vars)
|
|
get_cmake_property(_vars VARIABLES)
|
|
foreach(_var ${_vars})
|
|
message(STATUS "${_var}=${${_var}}")
|
|
endforeach()
|
|
endfunction()
|
|
|
|
# When `_dependency` is disabled, force `_setting` to `_val`.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `${_setting}`: set to `_val` when the dependency is disabled.
|
|
function(set_and_warn_dependency
|
|
_dependency _setting _val)
|
|
if(NOT ${${_dependency}} AND ${${_setting}})
|
|
if(WITH_STRICT_BUILD_OPTIONS)
|
|
message(SEND_ERROR "${_dependency} disabled but required by ${_setting}")
|
|
else()
|
|
message(STATUS "${_dependency} is disabled, setting ${_setting}=${_val}")
|
|
endif()
|
|
set(${_setting} ${_val} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# When `_dependency` is enabled, force `_setting` to `_val`.
|
|
# Both should be defined, warn if they're not.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `${_setting}`: set to `_val` when the dependency is enabled.
|
|
function(set_and_warn_incompatible
|
|
_dependency _setting _val)
|
|
if(NOT DEFINED ${_dependency})
|
|
message(STATUS "${_dependency} not defined!")
|
|
elseif(NOT DEFINED ${_setting})
|
|
message(STATUS "${_setting} not defined!")
|
|
elseif(${${_dependency}} AND ${${_setting}})
|
|
if(WITH_STRICT_BUILD_OPTIONS)
|
|
message(SEND_ERROR "${_dependency} enabled but incompatible with ${_setting}")
|
|
else()
|
|
message(STATUS "${_dependency} is enabled but incompatible, setting ${_setting}=${_val}")
|
|
endif()
|
|
set(${_setting} ${_val} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Disable `_setting` when the library is not found.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `${_setting}`: set to `OFF` when the library is not found.
|
|
function(set_and_warn_library_found
|
|
_library_name _library_found _setting)
|
|
if(((NOT ${_library_found}) OR (NOT ${${_library_found}})) AND ${${_setting}})
|
|
if(WITH_STRICT_BUILD_OPTIONS)
|
|
message(SEND_ERROR "${_library_name} required but not found")
|
|
else()
|
|
message(STATUS "${_library_name} not found, disabling ${_setting}")
|
|
endif()
|
|
set(${_setting} OFF PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Modifies in parent scope:
|
|
# - `CMAKE_IGNORE_PATH`: set to system implicit paths.
|
|
function(without_system_libs_begin)
|
|
set(CMAKE_IGNORE_PATH
|
|
"${CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES}"
|
|
"${CMAKE_SYSTEM_INCLUDE_PATH}"
|
|
"${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}"
|
|
"${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}"
|
|
PARENT_SCOPE
|
|
)
|
|
endfunction()
|
|
|
|
# Modifies in parent scope:
|
|
# - `CMAKE_IGNORE_PATH`: unset.
|
|
function(without_system_libs_end)
|
|
unset(CMAKE_IGNORE_PATH PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Utility to gather and install precompiled shared libraries.
|
|
#
|
|
# Modifies in parent scope:
|
|
# - `PLATFORM_BUNDLED_LIBRARIES`: appended with found libraries.
|
|
# - `PLATFORM_BUNDLED_LIBRARY_DIRS`: appended with the library directory.
|
|
function(add_bundled_libraries library_dir)
|
|
if(DEFINED LIBDIR)
|
|
set(_library_dir ${LIBDIR}/${library_dir})
|
|
if(WIN32)
|
|
file(GLOB _all_library_versions ${_library_dir}/*\.dll)
|
|
elseif(APPLE)
|
|
file(GLOB _all_library_versions ${_library_dir}/*\.dylib*)
|
|
else()
|
|
file(GLOB _all_library_versions ${_library_dir}/*\.so*)
|
|
endif()
|
|
list(APPEND PLATFORM_BUNDLED_LIBRARIES ${_all_library_versions})
|
|
list(APPEND PLATFORM_BUNDLED_LIBRARY_DIRS ${_library_dir})
|
|
set(PLATFORM_BUNDLED_LIBRARIES "${PLATFORM_BUNDLED_LIBRARIES}" PARENT_SCOPE)
|
|
set(PLATFORM_BUNDLED_LIBRARY_DIRS "${PLATFORM_BUNDLED_LIBRARY_DIRS}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Modifies in parent scope:
|
|
# - `WINDOWS_SHARED_MANIFEST_DEBUG`: appended with files (when debug).
|
|
# - `WINDOWS_SHARED_MANIFEST_RELEASE`: appended with files (when release).
|
|
function(windows_install_shared_manifest)
|
|
set(options OPTIONAL DEBUG RELEASE ALL)
|
|
set(oneValueArgs "")
|
|
set(multiValueArgs FILES)
|
|
cmake_parse_arguments(
|
|
WINDOWS_INSTALL
|
|
"${options}"
|
|
"${oneValueArgs}"
|
|
"${multiValueArgs}"
|
|
${ARGN}
|
|
)
|
|
# If none of the options are set assume ALL.
|
|
unset(WINDOWS_CONFIGURATIONS)
|
|
if(NOT WINDOWS_INSTALL_ALL AND
|
|
NOT WINDOWS_INSTALL_DEBUG AND
|
|
NOT WINDOWS_INSTALL_RELEASE)
|
|
set(WINDOWS_INSTALL_ALL TRUE)
|
|
endif()
|
|
# If all is set, turn both DEBUG and RELEASE on.
|
|
if(WINDOWS_INSTALL_ALL)
|
|
set(WINDOWS_INSTALL_DEBUG TRUE)
|
|
set(WINDOWS_INSTALL_RELEASE TRUE)
|
|
endif()
|
|
if(WINDOWS_INSTALL_DEBUG)
|
|
set(WINDOWS_CONFIGURATIONS "${WINDOWS_CONFIGURATIONS};Debug")
|
|
endif()
|
|
if(WINDOWS_INSTALL_RELEASE)
|
|
set(WINDOWS_CONFIGURATIONS "${WINDOWS_CONFIGURATIONS};Release;RelWithDebInfo;MinSizeRel")
|
|
endif()
|
|
if(NOT WITH_PYTHON_MODULE)
|
|
# Blender executable with manifest.
|
|
if(WINDOWS_INSTALL_DEBUG)
|
|
list(APPEND WINDOWS_SHARED_MANIFEST_DEBUG ${WINDOWS_INSTALL_FILES})
|
|
endif()
|
|
if(WINDOWS_INSTALL_RELEASE)
|
|
list(APPEND WINDOWS_SHARED_MANIFEST_RELEASE ${WINDOWS_INSTALL_FILES})
|
|
endif()
|
|
set(WINDOWS_SHARED_MANIFEST_DEBUG "${WINDOWS_SHARED_MANIFEST_DEBUG}" PARENT_SCOPE)
|
|
set(WINDOWS_SHARED_MANIFEST_RELEASE "${WINDOWS_SHARED_MANIFEST_RELEASE}" PARENT_SCOPE)
|
|
install(
|
|
FILES ${WINDOWS_INSTALL_FILES}
|
|
DESTINATION "blender.shared"
|
|
CONFIGURATIONS ${WINDOWS_CONFIGURATIONS}
|
|
)
|
|
else()
|
|
# Python module without manifest.
|
|
install(
|
|
FILES ${WINDOWS_INSTALL_FILES}
|
|
DESTINATION "bpy"
|
|
CONFIGURATIONS ${WINDOWS_CONFIGURATIONS}
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(windows_generate_manifest)
|
|
set(options "")
|
|
set(oneValueArgs OUTPUT NAME)
|
|
set(multiValueArgs FILES)
|
|
cmake_parse_arguments(
|
|
WINDOWS_MANIFEST
|
|
"${options}"
|
|
"${oneValueArgs}"
|
|
"${multiValueArgs}"
|
|
${ARGN}
|
|
)
|
|
set(MANIFEST_LIBS "")
|
|
foreach(lib ${WINDOWS_MANIFEST_FILES})
|
|
get_filename_component(filename ${lib} NAME)
|
|
set(MANIFEST_LIBS "${MANIFEST_LIBS} <file name=\"${filename}\"/>\n")
|
|
endforeach()
|
|
configure_file(
|
|
${CMAKE_SOURCE_DIR}/release/windows/manifest/blender.manifest.in
|
|
${WINDOWS_MANIFEST_OUTPUT}
|
|
@ONLY
|
|
)
|
|
endfunction()
|
|
|
|
function(windows_generate_shared_manifest)
|
|
if(WINDOWS_SHARED_MANIFEST_DEBUG)
|
|
windows_generate_manifest(
|
|
FILES "${WINDOWS_SHARED_MANIFEST_DEBUG}"
|
|
OUTPUT "${CMAKE_BINARY_DIR}/Debug/blender.shared.manifest"
|
|
NAME "blender.shared"
|
|
)
|
|
install(
|
|
FILES ${CMAKE_BINARY_DIR}/Debug/blender.shared.manifest
|
|
DESTINATION "blender.shared"
|
|
CONFIGURATIONS Debug
|
|
)
|
|
endif()
|
|
if(WINDOWS_SHARED_MANIFEST_RELEASE)
|
|
windows_generate_manifest(
|
|
FILES "${WINDOWS_SHARED_MANIFEST_RELEASE}"
|
|
OUTPUT "${CMAKE_BINARY_DIR}/Release/blender.shared.manifest"
|
|
NAME "blender.shared"
|
|
)
|
|
install(
|
|
FILES ${CMAKE_BINARY_DIR}/Release/blender.shared.manifest
|
|
DESTINATION "blender.shared"
|
|
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
# Modifies in parent scope:
|
|
# - `WINDOWS_SHARED_MANIFEST_DEBUG`: accumulated via `windows_install_shared_manifest`.
|
|
# - `WINDOWS_SHARED_MANIFEST_RELEASE`: accumulated via `windows_install_shared_manifest`.
|
|
function(windows_process_platform_bundled_libraries library_deps)
|
|
if(NOT "${library_deps}" STREQUAL "")
|
|
set(next_library_mode "ALL")
|
|
foreach(library ${library_deps})
|
|
string(TOUPPER "${library}" library_upper)
|
|
if(("${library_upper}" STREQUAL "RELEASE") OR
|
|
("${library_upper}" STREQUAL "DEBUG") OR
|
|
("${library_upper}" STREQUAL "ALL"))
|
|
set(next_library_mode "${library_upper}")
|
|
else()
|
|
windows_install_shared_manifest(
|
|
FILES ${library}
|
|
${next_library_mode}
|
|
)
|
|
set(next_library_mode "ALL")
|
|
endif()
|
|
endforeach()
|
|
set(WINDOWS_SHARED_MANIFEST_DEBUG "${WINDOWS_SHARED_MANIFEST_DEBUG}" PARENT_SCOPE)
|
|
set(WINDOWS_SHARED_MANIFEST_RELEASE "${WINDOWS_SHARED_MANIFEST_RELEASE}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(compile_sources_as_cpp
|
|
library
|
|
sources
|
|
define
|
|
)
|
|
|
|
# On Windows, MSVC/Clang echo the filename being compiled to the console.
|
|
# Ninja suppresses this only for recognized C++ extensions (.cc/.cpp etc.),
|
|
# not .glsl. Generate a .cc wrapper per source so Ninja suppresses the echo.
|
|
# On other platforms, just set LANGUAGE CXX directly on each source file.
|
|
|
|
if(WIN32)
|
|
foreach(glsl_file ${sources})
|
|
get_filename_component(_glsl_file_dir "${glsl_file}" DIRECTORY)
|
|
get_filename_component(_glsl_file_name "${glsl_file}" NAME)
|
|
cmake_path(APPEND _glsl_file_dir "${library}_${_glsl_file_name}.cc" OUTPUT_VARIABLE _glsl_file_cc)
|
|
|
|
cmake_path(SET _file_from NORMALIZE "${CMAKE_CURRENT_SOURCE_DIR}/${glsl_file}")
|
|
cmake_path(SET _file_to NORMALIZE "${CMAKE_CURRENT_BINARY_DIR}/${_glsl_file_cc}")
|
|
file(GENERATE OUTPUT "${_file_to}" CONTENT "#include \"${_file_from}\"\n")
|
|
list(APPEND sources ${_file_to})
|
|
# Mark the original file as header only, so no attempt will be made at compiling it
|
|
# regardless of extention.
|
|
set_source_files_properties(${glsl_file} PROPERTIES HEADER_FILE_ONLY TRUE)
|
|
endforeach()
|
|
else()
|
|
foreach(glsl_file ${sources})
|
|
set_source_files_properties(${glsl_file} PROPERTIES LANGUAGE CXX)
|
|
endforeach()
|
|
endif()
|
|
|
|
add_library(${library} OBJECT ${sources})
|
|
set_target_properties(${library} PROPERTIES LINKER_LANGUAGE CXX)
|
|
target_include_directories(${library} PUBLIC ${INC_GLSL})
|
|
target_compile_definitions(${library} PRIVATE ${define} -DGPU_SHADER)
|
|
|
|
# avoid noisy warnings
|
|
if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
|
|
target_compile_options(${library} PRIVATE "-Wno-unused-result")
|
|
target_compile_options(${library} PRIVATE "-Wno-missing-declarations")
|
|
# Would be nice to enable the warning once we support references.
|
|
target_compile_options(${library} PRIVATE "-Wno-uninitialized")
|
|
# To compile libraries.
|
|
target_compile_options(${library} PRIVATE "-Wno-pragma-once-outside-header")
|
|
target_compile_options(${library} PRIVATE "-Wno-unknown-pragmas")
|
|
elseif(MSVC)
|
|
# Equivalent to "-Wno-uninitialized"
|
|
target_compile_options(${library} PRIVATE "/wd4700")
|
|
# Disable "potential divide by 0" warning
|
|
target_compile_options(${library} PRIVATE "/wd4723")
|
|
# Disable unkown pragma warning
|
|
target_compile_options(${library} PRIVATE "/wd4068")
|
|
# Disable unknown attribute warning
|
|
target_compile_options(${library} PRIVATE "/wd5030")
|
|
target_compile_options(${library} PRIVATE "/wd5222")
|
|
endif()
|
|
if(WIN32 AND NOT MSVC_CLANG)
|
|
set_target_properties(${library} PROPERTIES STATIC_LIBRARY_OPTIONS "-ignore:4006")
|
|
endif()
|
|
endfunction()
|
|
|
|
# NOTE: must be a macro, calls `remove_cc_flag` on Windows
|
|
# which modifies `CMAKE_*_FLAGS` in the caller's scope.
|
|
macro(optimize_debug_target executable)
|
|
if(WITH_OPTIMIZED_BUILD_TOOLS)
|
|
if(WIN32)
|
|
remove_c_and_cxx_flag("/Od" "/RTC1")
|
|
target_compile_options(${executable} PRIVATE "/Ox")
|
|
target_compile_definitions(${executable} PRIVATE "_ITERATOR_DEBUG_LEVEL=0")
|
|
else()
|
|
target_compile_options(${executable} PRIVATE "-O2")
|
|
endif()
|
|
endif()
|
|
endmacro()
|