From ec7390f3bb668ccd9812378d22cb27238e8868d6 Mon Sep 17 00:00:00 2001 From: Darryl Pogue Date: Tue, 6 Aug 2024 00:34:53 -0700 Subject: [PATCH] Allow building macOS client with Makefiles This removes the strict requirement to use the Xcode project generator, but still requires the Xcode build tools (and specifically the Metal compiler) to be installed. I expect that our official stance will always be that the Xcode project generator is the recommended and supported way to do macOS builds, but any day I don't have to launch Xcode is a good day. --- CMakeLists.txt | 2 + Sources/Plasma/Apps/plClient/CMakeLists.txt | 16 +- .../FeatureLib/pfMetalPipeline/CMakeLists.txt | 72 ++++---- cmake/CMakeDetermineMetalCompiler.cmake | 83 +++++++++ cmake/CMakeMetalCompiler.cmake.in | 27 +++ cmake/CMakeMetalInformation.cmake | 78 ++++++++ cmake/CMakeTestMetalCompiler.cmake | 75 ++++++++ cmake/CheckLanguage.cmake | 169 ++++++++++++++++++ cmake/MetalShaderSupport.cmake | 52 ++++++ 9 files changed, 524 insertions(+), 50 deletions(-) create mode 100644 cmake/CMakeDetermineMetalCompiler.cmake create mode 100644 cmake/CMakeMetalCompiler.cmake.in create mode 100644 cmake/CMakeMetalInformation.cmake create mode 100644 cmake/CMakeTestMetalCompiler.cmake create mode 100644 cmake/CheckLanguage.cmake create mode 100644 cmake/MetalShaderSupport.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 24f3192654..e7869c4d27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ include(CMakeDependentOption) include(FeatureSummary) include(Dependencies) include(VcpkgToolchain) +include(MetalShaderSupport) project(Plasma) @@ -161,6 +162,7 @@ endif(PLASMA_PIPELINE_GL) if(PLASMA_PIPELINE_METAL) add_definitions(-DPLASMA_PIPELINE_METAL) + enable_language(Metal) endif(PLASMA_PIPELINE_METAL) # Allow us to disable certain parts of the build diff --git a/Sources/Plasma/Apps/plClient/CMakeLists.txt b/Sources/Plasma/Apps/plClient/CMakeLists.txt index d8a882c400..0faa4b33e0 100644 --- a/Sources/Plasma/Apps/plClient/CMakeLists.txt +++ b/Sources/Plasma/Apps/plClient/CMakeLists.txt @@ -116,10 +116,6 @@ elseif(APPLE) Mac-Cocoa/PLSLoginWindowController.xib Mac-Cocoa/PLSPatcherWindowController.xib ) - list(APPEND plClient_SHADERTARGETS - pfMetalPipelineShadersMSL21 - pfMetalPipelineShadersMSL23 - ) else() list(APPEND plClient_SOURCES main.cpp @@ -158,17 +154,12 @@ if(APPLE) XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES" XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER org.Huru.UruExplorer - XCODE_EMBED_RESOURCES "${plClient_SHADERTARGETS}" ) target_compile_options(plClient PRIVATE -fobjc-arc) target_sources(plClient PRIVATE Mac-Cocoa/Assets.xcassets) set_source_files_properties(Mac-Cocoa/Assets.xcassets ${RESOURCES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) - - if(${CMAKE_VERSION} VERSION_LESS 3.28) - message(FATAL_ERROR "Cannot build Mac client without CMake 3.28") - endif() if(PLASMA_APPLE_DEVELOPMENT_TEAM_ID) set_target_properties(plClient PROPERTIES @@ -178,6 +169,13 @@ if(APPLE) endif() endif() +if(PLASMA_PIPELINE_METAL) + target_embed_metal_shader_libraries(plClient + pfMetalPipelineShadersMSL21 + pfMetalPipelineShadersMSL23 + ) +endif() + if(PLASMA_BUILD_RESOURCE_DAT) target_sources(plClient PRIVATE ${external_SCRIPTS} ${external_SOURCES} ${external_DAT}) endif() diff --git a/Sources/Plasma/FeatureLib/pfMetalPipeline/CMakeLists.txt b/Sources/Plasma/FeatureLib/pfMetalPipeline/CMakeLists.txt index 7a583ee2ef..2a0cbf4b91 100644 --- a/Sources/Plasma/FeatureLib/pfMetalPipeline/CMakeLists.txt +++ b/Sources/Plasma/FeatureLib/pfMetalPipeline/CMakeLists.txt @@ -44,6 +44,22 @@ set(pfMetalPipeline_HEADERS pfMetalPipelineCreatable.h ) +set(pfMetalPipeline_SHADERS + ShaderSrc/FixedPipelineShaders.metal + ShaderSrc/PlateShaders.metal + ShaderSrc/BiasNormals.metal + ShaderSrc/CompCosines.metal + ShaderSrc/WaveSet7.metal + ShaderSrc/Grass.metal + ShaderSrc/WaveDecEnv.metal + ShaderSrc/Avatar.metal + ShaderSrc/WaveDec1Lay_7.metal + ShaderSrc/WaveRip.metal + ShaderSrc/Clear.metal + ShaderSrc/GammaCorrection.metal + ShaderSrc/TextFontShader.metal +) + plasma_library(pfMetalPipeline SOURCES ${pfMetalPipeline_SOURCES} ${pfMetalPipeline_HEADERS}) target_link_libraries(pfMetalPipeline PUBLIC @@ -70,47 +86,21 @@ source_group("Source Files" FILES ${pfMetalPipeline_SOURCES}) source_group("Header Files" FILES ${pfMetalPipeline_HEADERS}) # All supported Macs for Plasma/Metal support MSL 2.1 -add_library(pfMetalPipelineShadersMSL21 MODULE) -# Build a 2.3 varient for macOS 11 and/or Apple Silicon specific features -add_library(pfMetalPipelineShadersMSL23 MODULE) - -set(pfMetalPipeline_SHADERS - ShaderSrc/FixedPipelineShaders.metal - ShaderSrc/PlateShaders.metal - ShaderSrc/BiasNormals.metal - ShaderSrc/CompCosines.metal - ShaderSrc/WaveSet7.metal - ShaderSrc/Grass.metal - ShaderSrc/WaveDecEnv.metal - ShaderSrc/Avatar.metal - ShaderSrc/WaveDec1Lay_7.metal - ShaderSrc/WaveRip.metal - ShaderSrc/Clear.metal - ShaderSrc/GammaCorrection.metal - ShaderSrc/TextFontShader.metal +add_metal_shader_library(pfMetalPipelineShadersMSL21 + STANDARD macos-metal2.1 + ${pfMetalPipeline_SHADERS} ) -set_target_properties(pfMetalPipelineShadersMSL21 PROPERTIES - XCODE_PRODUCT_TYPE com.apple.product-type.metal-library - XCODE_ATTRIBUTE_MTL_LANGUAGE_REVISION Metal21 - XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "${Plasma_SOURCE_DIR}/Sources/Plasma/NucleusLib/inc/" - SUFFIX ".metallib" - PREFIX "" - XCODE_ATTRIBUTE_MTL_FAST_MATH "YES" - XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=Debug] "INCLUDE_SOURCE" - XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=RelWithDebInfo] "INCLUDE_SOURCE" -) -set_target_properties(pfMetalPipelineShadersMSL23 PROPERTIES - XCODE_PRODUCT_TYPE com.apple.product-type.metal-library - XCODE_ATTRIBUTE_MTL_LANGUAGE_REVISION Metal23 - XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "${Plasma_SOURCE_DIR}/Sources/Plasma/NucleusLib/inc/" - SUFFIX ".metallib" - PREFIX "" - XCODE_ATTRIBUTE_MTL_FAST_MATH "YES" - XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=Debug] "INCLUDE_SOURCE" - XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=RelWithDebInfo] "INCLUDE_SOURCE" +target_include_directories(pfMetalPipelineShadersMSL21 + PRIVATE + $ ) -set_source_files_properties(${pfMetalPipeline_SHADERS} TARGET_DIRECTORY pfMetalPipelineShadersMSL21 PROPERTIES LANGUAGE METAL) -set_source_files_properties(${pfMetalPipeline_SHADERS} TARGET_DIRECTORY pfMetalPipelineShadersMSL23 PROPERTIES LANGUAGE METAL) -target_sources(pfMetalPipelineShadersMSL21 PRIVATE ${pfMetalPipeline_SHADERS}) -target_sources(pfMetalPipelineShadersMSL23 PRIVATE ${pfMetalPipeline_SHADERS}) +# Build a 2.3 varient for macOS 11 and/or Apple Silicon specific features +add_metal_shader_library(pfMetalPipelineShadersMSL23 + STANDARD macos-metal2.3 + ${pfMetalPipeline_SHADERS} +) +target_include_directories(pfMetalPipelineShadersMSL23 + PRIVATE + $ +) diff --git a/cmake/CMakeDetermineMetalCompiler.cmake b/cmake/CMakeDetermineMetalCompiler.cmake new file mode 100644 index 0000000000..bcf07e0f1c --- /dev/null +++ b/cmake/CMakeDetermineMetalCompiler.cmake @@ -0,0 +1,83 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +# CMakeDetermine(LANG)Compiler.cmake -> this should find the compiler for LANG and configure CMake(LANG)Compiler.cmake.in + +include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) + +if(NOT CMAKE_Metal_COMPILER_NAMES) + set(CMAKE_Metal_COMPILER_NAMES metal) +endif() + +if("${CMAKE_GENERATOR}" STREQUAL "Xcode") + set(CMAKE_Metal_COMPILER_XCODE_TYPE sourcecode.metal) + + execute_process(COMMAND xcrun --find metal + OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_VARIABLE _xcrun_err RESULT_VARIABLE _xcrun_result) + if(_xcrun_result EQUAL 0 AND EXISTS "${_xcrun_out}") + set(CMAKE_Metal_COMPILER "${_xcrun_out}") + else() + _cmake_find_compiler_path(Metal) + endif() +else() + if(CMAKE_Metal_COMPILER) + _cmake_find_compiler_path(Metal) + else() + set(CMAKE_Metal_COMPILER_INIT NOTFOUND) + + if(NOT $ENV{METALC} STREQUAL "") + get_filename_component(CMAKE_Metal_COMPILER_INIT $ENV{METALC} PROGRAM PROGRAM_ARGS CMAKE_Metal_FLAGS_ENV_INIT) + if(CMAKE_Metal_FLAGS_ENV_INIT) + set(CMAKE_Metal_COMPILER_ARG1 "${CMAKE_Metal_FLAGS_ENV_INIT}" CACHE STRING "Arguments to the Metal compiler") + endif() + if(NOT EXISTS ${CMAKE_Metal_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable METALC\n$ENV{METALC}.\n${CMAKE_Metal_COMPILER_INIT}") + endif() + endif() + + if(NOT CMAKE_Metal_COMPILER_INIT) + set(CMAKE_Metal_COMPILER_LIST metal ${_CMAKE_TOOLCHAIN_PREFIX}metal) + endif() + + _cmake_find_compiler(Metal) + endif() + + mark_as_advanced(CMAKE_Metal_COMPILER) +endif() + +# For Metal we need to explicitly query the version. +if(CMAKE_Metal_COMPILER AND NOT CMAKE_Metal_COMPILER_VERSION) + execute_process( + COMMAND "${CMAKE_Metal_COMPILER}" --version + OUTPUT_VARIABLE output ERROR_VARIABLE output + RESULT_VARIABLE result + TIMEOUT 10 + ) + message(CONFIGURE_LOG + "Running the Metal compiler: \"${CMAKE_Metal_COMPILER}\" --version\n" + "${output}\n" + ) + + if(output MATCHES [[metal version ([0-9]+\.[0-9]+(\.[0-9]+)?)]]) + set(CMAKE_Metal_COMPILER_VERSION "${CMAKE_MATCH_1}") + if(NOT CMAKE_Metal_COMPILER_ID) + set(CMAKE_Metal_COMPILER_ID "Apple") + endif() + endif() +endif() + +if (NOT _CMAKE_TOOLCHAIN_LOCATION) + get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Metal_COMPILER}" PATH) +endif () + +set(_CMAKE_PROCESSING_LANGUAGE "Metal") +include(CMakeFindBinUtils) +unset(_CMAKE_PROCESSING_LANGUAGE) + +configure_file( + ${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake +) + +set(CMAKE_Metal_COMPILER_ENV_VAR "METALC") diff --git a/cmake/CMakeMetalCompiler.cmake.in b/cmake/CMakeMetalCompiler.cmake.in new file mode 100644 index 0000000000..d636af4b7d --- /dev/null +++ b/cmake/CMakeMetalCompiler.cmake.in @@ -0,0 +1,27 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +# CMake(LANG)Compiler.cmake.in -> used by CMakeDetermine(LANG)Compiler.cmake +# This file is used to store compiler information and is copied down into try +# compile directories so that try compiles do not need to re-determine and test +# the LANG + +set(CMAKE_Metal_COMPILER "@CMAKE_Metal_COMPILER@") +set(CMAKE_Metal_COMPILER_ID "@CMAKE_Metal_COMPILER_ID@") +set(CMAKE_Metal_COMPILER_VERSION "@CMAKE_Metal_COMPILER_VERSION@") + +set(CMAKE_Metal_COMPILER_LOADED 1) +set(CMAKE_Metal_COMPILER_WORKS "@CMAKE_Metal_COMPILER_WORKS@") + +set(CMAKE_Metal_COMPILER_ENV_VAR "METALC") + +set(CMAKE_Metal_COMPILER_ID_RUN "@CMAKE_Metal_COMPILER_ID_RUN@") +set(CMAKE_Metal_SOURCE_FILE_EXTENSIONS metal) +set(CMAKE_Metal_OUTPUT_EXTENSION ".air") +set(CMAKE_STATIC_LIBRARY_PREFIX_Metal "") +set(CMAKE_STATIC_LIBRARY_SUFFIX_Metal ".metal-ar") +set(CMAKE_SHARED_LIBRARY_PREFIX_Metal "") +set(CMAKE_SHARED_LIBRARY_SUFFIX_Metal ".metallib") +set(CMAKE_SHARED_MODULE_PREFIX_Metal "") +set(CMAKE_SHARED_MODULE_SUFFIX_Metal ".metallib") +set(CMAKE_EXECUTABLE_SUFFIX_Metal ".metallib") diff --git a/cmake/CMakeMetalInformation.cmake b/cmake/CMakeMetalInformation.cmake new file mode 100644 index 0000000000..7b0c0011be --- /dev/null +++ b/cmake/CMakeMetalInformation.cmake @@ -0,0 +1,78 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +# CMake(LANG)Information.cmake -> set up rule variables for LANG : +# CMAKE_(LANG)_CREATE_SHARED_LIBRARY +# CMAKE_(LANG)_CREATE_SHARED_MODULE +# CMAKE_(LANG)_CREATE_STATIC_LIBRARY +# CMAKE_(LANG)_COMPILE_OBJECT +# CMAKE_(LANG)_LINK_EXECUTABLE + +include (CMakeCommonLanguageInclude) + +set(CMAKE_Metal_FLAGS_INIT "-ffast-math") +set(CMAKE_Metal_FLAGS_DEBUG_INIT "-gline-tables-only -frecord-sources") +set(CMAKE_Metal_FLAGS_RELWITHDEBINFO_INIT "-gline-tables-only -frecord-sources") + +cmake_initialize_per_config_variable(CMAKE_Metal_FLAGS "Flags used by the Metal compiler") + +set(CMAKE_INCLUDE_FLAG_Metal "-I ") +set(CMAKE_Metal_COMPILER_ARG1 "") +set(CMAKE_Metal_DEFINE_FLAG -D) +set(CMAKE_Metal_FRAMEWORK_SEARCH_FLAG "-F ") +set(CMAKE_Metal_LIBRARY_PATH_FLAG "-L ") +set(CMAKE_Metal_SYSROOT_FLAG "-isysroot") +set(CMAKE_Metal_COMPILE_OPTIONS_TARGET "-target ") +set(CMAKE_DEPFILE_FLAGS_Metal "-MMD -MT dependencies -MF ") + +if(CMAKE_GENERATOR MATCHES "Makefiles") + set(CMAKE_Metal_DEPFILE_FORMAT gcc) + set(CMAKE_Metal_DEPENDS_USE_COMPILER TRUE) +endif() + +set(CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "${CMAKE_Metal_COMPILER}") +if(CMAKE_Metal_COMPILER_TARGET) + list(APPEND CMAKE_Metal_COMPILER_PREDEFINES_COMMAND "-target" "${CMAKE_Metal_COMPILER_TARGET}") +endif() + +# now define the following rule variables + +# CMAKE_Metal_CREATE_SHARED_LIBRARY +# CMAKE_Metal_CREATE_SHARED_MODULE +# CMAKE_Metal_COMPILE_OBJECT +# CMAKE_Metal_LINK_EXECUTABLE + +# variables supplied by the generator at use time +# +# the target without the suffix +# +# +# +# +# + +# Metal compiler information +# +# +# +# + +if(NOT CMAKE_Metal_COMPILE_OBJECT) + set(CMAKE_Metal_COMPILE_OBJECT + " -c -o ") +endif() + +if(NOT CMAKE_Metal_CREATE_SHARED_LIBRARY) + set(CMAKE_Metal_CREATE_SHARED_LIBRARY " -o ") +endif() + +if(NOT CMAKE_Metal_CREATE_SHARED_MODULE) + set(CMAKE_Metal_CREATE_SHARED_MODULE "${CMAKE_Metal_CREATE_SHARED_LIBRARY}") +endif() + +if(NOT CMAKE_Metal_LINK_EXECUTABLE) + # Metal shaders don't really have "executables", but we need this for the try_compile to work properly, so we'll just have it output a metallib file + set(CMAKE_Metal_LINK_EXECUTABLE " -o ") +endif() + +set(CMAKE_Metal_INFORMATION_LOADED 1) diff --git a/cmake/CMakeTestMetalCompiler.cmake b/cmake/CMakeTestMetalCompiler.cmake new file mode 100644 index 0000000000..29a8db8b11 --- /dev/null +++ b/cmake/CMakeTestMetalCompiler.cmake @@ -0,0 +1,75 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +# CMakeTest(LANG)Compiler.cmake -> test the compiler and set: +# SET(CMAKE_(LANG)_COMPILER_WORKS 1 CACHE INTERNAL "") + +if(CMAKE_Metal_COMPILER_FORCED) + # The compiler configuration was forced by the user. + # Assume the user has configured all compiler information. + set(CMAKE_Metal_COMPILER_WORKS TRUE) + return() +endif() + +include (CMakeTestCompilerCommon) + +if("${CMAKE_GENERATOR}" STREQUAL "Xcode") + if(XCODE_VERSION VERSION_GREATER 7.0) + set(CMAKE_Metal_COMPILER_WORKS 1) + endif() +endif() + +# This file is used by EnableLanguage in cmGlobalGenerator to +# determine that that selected Metal compiler can actually compile +# and link the most basic of programs. If not, a fatal error +# is set and cmake stops processing commands and will not generate +# any makefiles or projects. +if(NOT CMAKE_Metal_COMPILER_WORKS) + PrintTestCompilerStatus("Metal") + __TestCompiler_setTryCompileTargetType() + + string(CONCAT __TestCompiler_testMetalCompilerSource + "#ifndef __METAL_VERSION__\n" + "# error \"The CMAKE_Metal_COMPILER is not a Metal compiler\"\n" + "#endif\n" + "#import \n" + "using namespace metal;\n") + + # Clear result from normal variable. + unset(CMAKE_Metal_COMPILER_WORKS) + + # Puts test result in cache variable. + try_compile(CMAKE_Metal_COMPILER_WORKS + SOURCE_FROM_VAR testMetalCompiler.metal __TestCompiler_testMetalCompilerSource + OUTPUT_VARIABLE __CMAKE_Metal_COMPILER_OUTPUT) + unset(__TestCompiler_testMetalCompilerSource) + + # Move result from cache to normal variable. + set(CMAKE_Metal_COMPILER_WORKS ${CMAKE_Metal_COMPILER_WORKS}) + unset(CMAKE_Metal_COMPILER_WORKS CACHE) + __TestCompiler_restoreTryCompileTargetType() + set(METAL_TEST_WAS_RUN 1) +endif() + +if(NOT CMAKE_Metal_COMPILER_WORKS) + PrintTestCompilerResult(CHECK_FAIL "broken") + string(REPLACE "\n" "\n " _output "${__CMAKE_Metal_COMPILER_OUTPUT}") + message(FATAL_ERROR "The Metal compiler\n \"${CMAKE_Metal_COMPILER}\"\n" + "is not able to compile a simple test program.\nIt fails " + "with the following output:\n ${_output}\n\n" + "CMake will not be able to correctly generate this project.") +else() + if(METAL_TEST_WAS_RUN) + PrintTestCompilerResult(CHECK_PASS "works") + endif() + + # Re-configure to save learned information. + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/CMakeMetalCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake + @ONLY + ) + include(${CMAKE_PLATFORM_INFO_DIR}/CMakeMetalCompiler.cmake) +endif() + +unset(__CMAKE_Metal_COMPILER_OUTPUT) diff --git a/cmake/CheckLanguage.cmake b/cmake/CheckLanguage.cmake new file mode 100644 index 0000000000..e212e3aab2 --- /dev/null +++ b/cmake/CheckLanguage.cmake @@ -0,0 +1,169 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckLanguage +------------- + +Check whether a language can be enabled by the :command:`enable_language` +or :command:`project` commands: + +.. command:: check_language + + .. code-block:: cmake + + check_language() + + Try enabling language ```` in a test project and record results + in the cache: + + :variable:`CMAKE__COMPILER` + If the language can be enabled, this variable is set to the compiler + that was found. If the language cannot be enabled, this variable is + set to ``NOTFOUND``. + + If this variable is already set, either explicitly or cached by + a previous call, the check is skipped. + + :variable:`CMAKE__HOST_COMPILER` + This variable is set when ```` is ``CUDA`` or ``HIP``. + + If the check detects an explicit host compiler that is required for + compilation, this variable will be set to that compiler. + If the check detects that no explicit host compiler is needed, + this variable will be cleared. + + If this variable is already set, its value is preserved only if + :variable:`CMAKE__COMPILER` is also set. + Otherwise, the check runs and overwrites + :variable:`CMAKE__HOST_COMPILER` with a new result. + Note that :variable:`CMAKE__HOST_COMPILER` documents it should + not be set without also setting + :variable:`CMAKE__COMPILER` to a NVCC compiler. + + :variable:`CMAKE__PLATFORM ` + This variable is set to the detected GPU platform when ```` is ``HIP``. + + If the variable is already set its value is always preserved. Only compatible values + will be considered for :variable:`CMAKE__COMPILER`. + +For example: + +.. code-block:: cmake + + check_language(Fortran) + if(CMAKE_Fortran_COMPILER) + enable_language(Fortran) + else() + message(STATUS "No Fortran support") + endif() +#]=======================================================================] + +# This file has been modified to take into account the CMAKE_MODULES path when trying to build the test project +# Ref https://gitlab.kitware.com/cmake/cmake/-/issues/26020 +# This was merged in to CMake 3.30.0, so we only need this for older versions + +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.30) + include(${CMAKE_ROOT}/Modules/CheckLanguage.cmake) +else() + include_guard(GLOBAL) + + block(SCOPE_FOR POLICIES) + cmake_policy(SET CMP0126 NEW) + + macro(check_language lang) + if(NOT DEFINED CMAKE_${lang}_COMPILER) + set(_desc "Looking for a ${lang} compiler") + message(CHECK_START "${_desc}") + file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}) + + set(extra_compiler_variables) + if("${lang}" MATCHES "^(CUDA|HIP)$" AND NOT CMAKE_GENERATOR MATCHES "Visual Studio") + set(extra_compiler_variables "set(CMAKE_${lang}_HOST_COMPILER \\\"\${CMAKE_${lang}_HOST_COMPILER}\\\")") + endif() + + if("${lang}" STREQUAL "HIP") + list(APPEND extra_compiler_variables "set(CMAKE_${lang}_PLATFORM \\\"\${CMAKE_${lang}_PLATFORM}\\\")") + endif() + + list(TRANSFORM extra_compiler_variables PREPEND "\"") + list(TRANSFORM extra_compiler_variables APPEND "\\n\"") + list(JOIN extra_compiler_variables "\n " extra_compiler_variables) + + set(_cl_content + "cmake_minimum_required(VERSION ${CMAKE_VERSION}) + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + project(Check${lang} ${lang}) + file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" + \"set(CMAKE_${lang}_COMPILER \\\"\${CMAKE_${lang}_COMPILER}\\\")\\n\" + ${extra_compiler_variables} + )" + ) + + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/CMakeLists.txt" + "${_cl_content}") + if(CMAKE_GENERATOR_INSTANCE) + set(_D_CMAKE_GENERATOR_INSTANCE "-DCMAKE_GENERATOR_INSTANCE:INTERNAL=${CMAKE_GENERATOR_INSTANCE}") + else() + set(_D_CMAKE_GENERATOR_INSTANCE "") + endif() + if(CMAKE_GENERATOR MATCHES "^(Xcode$|Green Hills MULTI$|Visual Studio)") + set(_D_CMAKE_MAKE_PROGRAM "") + else() + set(_D_CMAKE_MAKE_PROGRAM "-DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM}") + endif() + if(CMAKE_TOOLCHAIN_FILE) + set(_D_CMAKE_TOOLCHAIN_FILE "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}") + else() + set(_D_CMAKE_TOOLCHAIN_FILE "") + endif() + if(CMAKE_${lang}_PLATFORM) + set(_D_CMAKE_LANG_PLATFORM "-DCMAKE_${lang}_PLATFORM:STRING=${CMAKE_${lang}_PLATFORM}") + else() + set(_D_CMAKE_LANG_PLATFORM "") + endif() + execute_process( + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang} + COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} + -A "${CMAKE_GENERATOR_PLATFORM}" + -T "${CMAKE_GENERATOR_TOOLSET}" + ${_D_CMAKE_GENERATOR_INSTANCE} + ${_D_CMAKE_MAKE_PROGRAM} + ${_D_CMAKE_TOOLCHAIN_FILE} + ${_D_CMAKE_LANG_PLATFORM} + OUTPUT_VARIABLE _cl_output + ERROR_VARIABLE _cl_output + RESULT_VARIABLE _cl_result + ) + include(${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang}/result.cmake OPTIONAL) + if(CMAKE_${lang}_COMPILER AND "${_cl_result}" STREQUAL "0") + message(CONFIGURE_LOG + "${_desc} passed with the following output:\n" + "${_cl_output}\n") + set(_CHECK_COMPILER_STATUS CHECK_PASS) + else() + set(CMAKE_${lang}_COMPILER NOTFOUND) + set(_CHECK_COMPILER_STATUS CHECK_FAIL) + message(CONFIGURE_LOG + "${_desc} failed with the following output:\n" + "${_cl_output}\n") + endif() + message(${_CHECK_COMPILER_STATUS} "${CMAKE_${lang}_COMPILER}") + set(CMAKE_${lang}_COMPILER "${CMAKE_${lang}_COMPILER}" CACHE FILEPATH "${lang} compiler") + mark_as_advanced(CMAKE_${lang}_COMPILER) + + if(CMAKE_${lang}_HOST_COMPILER) + message(STATUS "Looking for a ${lang} host compiler - ${CMAKE_${lang}_HOST_COMPILER}") + set(CMAKE_${lang}_HOST_COMPILER "${CMAKE_${lang}_HOST_COMPILER}" CACHE FILEPATH "${lang} host compiler") + mark_as_advanced(CMAKE_${lang}_HOST_COMPILER) + endif() + + if(CMAKE_${lang}_PLATFORM) + set(CMAKE_${lang}_PLATFORM "${CMAKE_${lang}_PLATFORM}" CACHE STRING "${lang} platform") + mark_as_advanced(CMAKE_${lang}_PLATFORM) + endif() + endif() + endmacro() + + endblock() +endif() diff --git a/cmake/MetalShaderSupport.cmake b/cmake/MetalShaderSupport.cmake new file mode 100644 index 0000000000..bb214c1c0d --- /dev/null +++ b/cmake/MetalShaderSupport.cmake @@ -0,0 +1,52 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file LICENCE.txt or https://cmake.org/licensing for details. + +function(add_metal_shader_library TARGET) + cmake_parse_arguments(PARSE_ARGV 1 _amsl + "" + "STANDARD" + "" + ) + + add_library(${TARGET} MODULE ${_amsl_UNPARSED_ARGUMENTS}) + + set_target_properties(${TARGET} PROPERTIES + XCODE_PRODUCT_TYPE com.apple.product-type.metal-library + XCODE_ATTRIBUTE_MTL_FAST_MATH "YES" + XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=Debug] "INCLUDE_SOURCE" + XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO[variant=RelWithDebInfo] "INCLUDE_SOURCE" + XCODE_ATTRIBUTE_MTL_HEADER_SEARCH_PATHS "$(HEADER_SEARCH_PATHS)" + ) + + if(_amsl_STANDARD AND _amsl_STANDARD MATCHES "metal([0-9]+)\.([0-9]+)") + target_compile_options(${TARGET} + PRIVATE "-std=${_amsl_STANDARD}" + ) + + set_target_properties(${TARGET} PROPERTIES + XCODE_ATTRIBUTE_MTL_LANGUAGE_REVISION "Metal${CMAKE_MATCH_1}${CMAKE_MATCH_2}" + ) + endif() +endfunction() + +function(target_embed_metal_shader_libraries TARGET) + cmake_parse_arguments(PARSE_ARGV 1 _temsl + "" + "" + "" + ) + + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.28 AND ${CMAKE_GENERATOR} STREQUAL "Xcode") + set_target_properties(${TARGET} PROPERTIES + XCODE_EMBED_RESOURCES "${_temsl_UNPARSED_ARGUMENTS}" + ) + else() + foreach(SHADERLIB IN LISTS _temsl_UNPARSED_ARGUMENTS) + add_custom_command(TARGET ${TARGET} POST_BUILD + DEPENDS ${SHADERLIB} + COMMAND ${CMAKE_COMMAND} -E copy "$" "$/Resources/$" + VERBATIM + ) + endforeach() + endif() +endfunction()