# SPDX-License-Identifier: GPL-2.0-or-later # Copyright 2016 Blender Foundation. All rights reserved. # Xcode and system configuration for Apple. # Detect processor architecture. if(NOT CMAKE_OSX_ARCHITECTURES) execute_process(COMMAND uname -m OUTPUT_VARIABLE ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "Detected native architecture ${ARCHITECTURE}.") set(CMAKE_OSX_ARCHITECTURES ${ARCHITECTURE} CACHE STRING "Choose the architecture you want to build Blender for: arm64 or x86_64" FORCE) endif() # Detect developer directory. Depending on configuration this may be either # an Xcode or Command Line Tools installation. execute_process( COMMAND xcode-select --print-path OUTPUT_VARIABLE XCODE_DEVELOPER_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) # Detect Xcode version. It is provided by the Xcode generator but not # Unix Makefiles or Ninja. if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode") # Note that `xcodebuild -version` gives output in two lines: first line will include # Xcode version, second one will include build number. We are only interested in the # first line. Here is an example of the output: # Xcode 11.4 # Build version 11E146 # The expected XCODE_VERSION in this case is 11.4. execute_process( COMMAND xcodebuild -version OUTPUT_VARIABLE _xcode_vers_build_nr RESULT_VARIABLE _xcode_vers_result ERROR_QUIET) if(_xcode_vers_result EQUAL 0) # Convert output to a single line by replacing newlines with spaces. # This is needed because regex replace can not operate through the newline character # and applies substitutions for each individual lines. string(REPLACE "\n" " " _xcode_vers_build_nr_single_line "${_xcode_vers_build_nr}") string(REGEX REPLACE "(.*)Xcode ([0-9\\.]+).*" "\\2" XCODE_VERSION "${_xcode_vers_build_nr_single_line}") unset(_xcode_vers_build_nr_single_line) endif() unset(_xcode_vers_build_nr) unset(_xcode_vers_result) endif() if(XCODE_VERSION) # Construct SDKs path ourselves, because xcode-select path could be ambiguous. # Both /Applications/Xcode.app/Contents/Developer or /Applications/Xcode.app would be allowed. set(XCODE_SDK_DIR ${XCODE_DEVELOPER_DIR}/Platforms/MacOSX.platform/Developer/SDKs) # Detect SDK version to use if(NOT DEFINED OSX_SYSTEM) execute_process( COMMAND xcodebuild -version -sdk macosx SDKVersion OUTPUT_VARIABLE OSX_SYSTEM OUTPUT_STRIP_TRAILING_WHITESPACE) endif() message(STATUS "Detected OS X ${OSX_SYSTEM} and Xcode ${XCODE_VERSION} at ${XCODE_DEVELOPER_DIR}") message(STATUS "SDKs Directory: " ${XCODE_SDK_DIR}) else() # If no Xcode version found, try detecting command line tools. execute_process( COMMAND pkgutil --pkg-info=com.apple.pkg.CLTools_Executables OUTPUT_VARIABLE _cltools_pkg_info OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE _cltools_pkg_info_result ERROR_QUIET) if(_cltools_pkg_info_result EQUAL 0) # Extract version. string(REGEX REPLACE ".*version: ([0-9]+)\\.([0-9]+).*" "\\1.\\2" XCODE_VERSION "${_cltools_pkg_info}") # SDK directory. set(XCODE_SDK_DIR "${XCODE_DEVELOPER_DIR}/SDKs") # Detect SDK version to use. if(NOT DEFINED OSX_SYSTEM) execute_process( COMMAND xcrun --sdk macosx --show-sdk-version OUTPUT_VARIABLE OSX_SYSTEM OUTPUT_STRIP_TRAILING_WHITESPACE) endif() message(STATUS "Detected OS X ${OSX_SYSTEM} and Command Line Tools ${XCODE_VERSION} at ${XCODE_DEVELOPER_DIR}") message(STATUS "SDKs Directory: " ${XCODE_SDK_DIR}) else() message(FATAL_ERROR "No Xcode or Command Line Tools detected") endif() unset( _cltools_pkg_info) unset(__cltools_pkg_info_result) endif() # Require a relatively recent Xcode version. if(${XCODE_VERSION} VERSION_LESS 10.0) message(FATAL_ERROR "Only Xcode version 10.0 and newer is supported") endif() # Collect list of OSX system versions which will be used to detect path to corresponding SDK. # Start with macOS SDK version reported by xcodebuild and include possible extra ones. # # The reason for need of extra ones is because it's possible that xcodebuild will report # SDK version in the full manner (aka major.minor.patch), but the actual path will only # include major.minor. # # This happens, for example, on macOS Catalina 10.15.4 and Xcode 11.4: xcodebuild on this # system outputs "10.15.4", but the actual SDK path is MacOSX10.15.sdk. # # This should be safe from picking wrong SDK version because (a) xcodebuild reports full semantic # SDK version, so such SDK does exist on the system. And if it doesn't exist with full version # in the path, what SDK is in the major.minor folder then. set(OSX_SDK_TEST_VERSIONS ${OSX_SYSTEM}) if(OSX_SYSTEM MATCHES "([0-9]+)\\.([0-9]+)\\.([0-9]+)") string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1.\\2" OSX_SYSTEM_NO_PATCH "${OSX_SYSTEM}") list(APPEND OSX_SDK_TEST_VERSIONS ${OSX_SYSTEM_NO_PATCH}) unset(OSX_SYSTEM_NO_PATCH) endif() # Loop through all possible versions and pick the first one which resolves to a valid SDK path. set(OSX_SDK_PATH) set(OSX_SDK_FOUND FALSE) set(OSX_SDKROOT) foreach(OSX_SDK_VERSION ${OSX_SDK_TEST_VERSIONS}) set(CURRENT_OSX_SDK_PATH "${XCODE_SDK_DIR}/MacOSX${OSX_SDK_VERSION}.sdk") if(EXISTS ${CURRENT_OSX_SDK_PATH}) set(OSX_SDK_PATH "${CURRENT_OSX_SDK_PATH}") set(OSX_SDKROOT macosx${OSX_SDK_VERSION}) set(OSX_SDK_FOUND TRUE) break() endif() endforeach() unset(OSX_SDK_TEST_VERSIONS) if(NOT OSX_SDK_FOUND) message(FATAL_ERROR "Unable to find SDK for macOS version ${OSX_SYSTEM}") endif() message(STATUS "Detected OSX_SYSROOT: ${OSX_SDK_PATH}") set(CMAKE_OSX_SYSROOT ${OSX_SDK_PATH} CACHE PATH "" FORCE) unset(OSX_SDK_PATH) unset(OSX_SDK_FOUND) if(${CMAKE_GENERATOR} MATCHES "Xcode") # to silence sdk not found warning, just overrides CMAKE_OSX_SYSROOT set(CMAKE_XCODE_ATTRIBUTE_SDKROOT ${OSX_SDKROOT}) endif() unset(OSX_SDKROOT) if("${CMAKE_OSX_ARCHITECTURES}" STREQUAL "arm64") # M1 chips run Big Sur onwards. set(OSX_MIN_DEPLOYMENT_TARGET 11.00) else() # 10.13 is our min. target, if you use higher sdk, weak linking happens set(OSX_MIN_DEPLOYMENT_TARGET 10.13) endif() set(CMAKE_OSX_DEPLOYMENT_TARGET "${OSX_MIN_DEPLOYMENT_TARGET}" CACHE STRING "" FORCE) if(NOT ${CMAKE_GENERATOR} MATCHES "Xcode") # Force CMAKE_OSX_DEPLOYMENT_TARGET for makefiles, will not work else (CMake bug?) string(APPEND CMAKE_C_FLAGS " -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") string(APPEND CMAKE_CXX_FLAGS " -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") add_definitions("-DMACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}") endif() if(WITH_COMPILER_CCACHE) if(CMAKE_GENERATOR STREQUAL "Xcode") find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) get_filename_component(ccompiler "${CMAKE_C_COMPILER}" NAME) get_filename_component(cxxcompiler "${CMAKE_CXX_COMPILER}" NAME) # Ccache can figure out which compiler to use if it's invoked from # a symlink with the name of the compiler. # https://ccache.dev/manual/4.1.html#_run_modes set(_fake_compiler_dir "${CMAKE_BINARY_DIR}/ccache") execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${_fake_compiler_dir}) set(_fake_C_COMPILER "${_fake_compiler_dir}/${ccompiler}") set(_fake_CXX_COMPILER "${_fake_compiler_dir}/${cxxcompiler}") execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CCACHE_PROGRAM}" ${_fake_C_COMPILER}) execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink "${CCACHE_PROGRAM}" ${_fake_CXX_COMPILER}) set(CMAKE_XCODE_ATTRIBUTE_CC ${_fake_C_COMPILER} CACHE STRING "" FORCE) set(CMAKE_XCODE_ATTRIBUTE_CXX ${_fake_CXX_COMPILER} CACHE STRING "" FORCE) set(CMAKE_XCODE_ATTRIBUTE_LD ${_fake_C_COMPILER} CACHE STRING "" FORCE) set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${_fake_CXX_COMPILER} CACHE STRING "" FORCE) unset(_fake_compiler_dir) unset(_fake_C_COMPILER) unset(_fake_CXX_COMPILER) else() message(WARNING "Ccache NOT found, disabling WITH_COMPILER_CCACHE") set(WITH_COMPILER_CCACHE OFF) endif() endif() endif()