# Copyright (C) 2022-2023 Intel Corporation # Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. # See LICENSE.TXT # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required(VERSION 3.20.0 FATAL_ERROR) project(unified-runtime VERSION 0.12.0) # Check if unified runtime is built as a standalone project. if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR UR_STANDALONE_BUILD) set(UR_STANDALONE_BUILD TRUE) endif() include(GNUInstallDirs) include(CheckCXXSourceCompiles) include(CMakePackageConfigHelpers) include(CTest) # Build Options option(UR_BUILD_EXAMPLES "Build example applications." ON) option(UR_BUILD_TESTS "Build unit tests." ON) option(UR_BUILD_TOOLS "build ur tools" ON) option(UR_FORMAT_CPP_STYLE "format code style of C++ sources" OFF) option(UR_DEVELOPER_MODE "treats warnings as errors" OFF) option(UR_ENABLE_FAST_SPEC_MODE "enable fast specification generation mode" OFF) option(UR_USE_ASAN "enable AddressSanitizer" OFF) option(UR_USE_UBSAN "enable UndefinedBehaviorSanitizer" OFF) option(UR_USE_MSAN "enable MemorySanitizer" OFF) option(UR_USE_TSAN "enable ThreadSanitizer" OFF) option(UR_USE_CFI "enable Control Flow Integrity checks (requires clang and implies -flto)" OFF) option(UR_ENABLE_TRACING "enable api tracing through xpti" OFF) option(UR_ENABLE_SANITIZER "enable device sanitizer" ON) option(UR_ENABLE_SYMBOLIZER "enable symoblizer for sanitizer" OFF) option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" ON) option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON) option(UR_BUILD_ADAPTER_L0 "Build the Level-Zero adapter" OFF) option(UR_BUILD_ADAPTER_OPENCL "Build the OpenCL adapter" OFF) option(UR_BUILD_ADAPTER_CUDA "Build the CUDA adapter" OFF) option(UR_BUILD_ADAPTER_HIP "Build the HIP adapter" OFF) option(UR_BUILD_ADAPTER_NATIVE_CPU "Build the Native-CPU adapter" OFF) option(UR_BUILD_ADAPTER_ALL "Build all currently supported adapters" OFF) option(UR_BUILD_ADAPTER_L0_V2 "Build the (experimental) Level-Zero v2 adapter" OFF) option(UR_STATIC_ADAPTER_L0 "Build the Level-Zero adapter as static and embed in the loader" OFF) option(UR_BUILD_EXAMPLE_CODEGEN "Build the codegen example." OFF) option(VAL_USE_LIBBACKTRACE_BACKTRACE "enable libbacktrace validation backtrace for linux" OFF) option(UR_ENABLE_ASSERTIONS "Enable assertions for all build types" OFF) option(UR_BUILD_XPTI_LIBS "Build the XPTI libraries when tracing is enabled" ON) option(UR_STATIC_LOADER "Build loader as a static library" OFF) option(UR_FORCE_LIBSTDCXX "Force use of libstdc++ in a build using libc++ on Linux" OFF) option(UR_ENABLE_LATENCY_HISTOGRAM "Enable latncy histogram" OFF) set(UR_DPCXX "" CACHE FILEPATH "Path of the DPC++ compiler executable") set(UR_DPCXX_BUILD_FLAGS "" CACHE STRING "Build flags to pass to DPC++ when compiling device programs") set(UR_SYCL_LIBRARY_DIR "" CACHE PATH "Path of the SYCL runtime library directory") set(UR_CONFORMANCE_TARGET_TRIPLES "" CACHE STRING "List of sycl targets to build CTS device binaries for") set(UR_CONFORMANCE_AMD_ARCH "" CACHE STRING "AMD device target ID to build CTS binaries for") option(UR_CONFORMANCE_ENABLE_MATCH_FILES "Enable CTS match files" ON) option(UR_CONFORMANCE_TEST_LOADER "Also test the loader in the conformance tests" OFF) set(UR_ADAPTER_LEVEL_ZERO_SOURCE_DIR "" CACHE PATH "Path to external 'level_zero' adapter source dir") set(UR_ADAPTER_OPENCL_SOURCE_DIR "" CACHE PATH "Path to external 'opencl' adapter source dir") set(UR_ADAPTER_CUDA_SOURCE_DIR "" CACHE PATH "Path to external 'cuda' adapter source dir") set(UR_ADAPTER_HIP_SOURCE_DIR "" CACHE PATH "Path to external 'hip' adapter source dir") set(UR_ADAPTER_NATIVE_CPU_SOURCE_DIR "" CACHE PATH "Path to external 'native_cpu' adapter source dir") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(helpers) if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(Python3_FIND_FRAMEWORK NEVER) set(Python3_FIND_STRATEGY LOCATION) endif() find_package(Python3 COMPONENTS Interpreter REQUIRED) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED YES) # There's little reason not to generate the compile_commands.json set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(Assertions) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Define rpath for libraries so that adapters can be found automatically set(CMAKE_BUILD_RPATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") # Define a path for custom commands to work around MSVC set(CUSTOM_COMMAND_BINARY_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) if(CMAKE_SYSTEM_NAME STREQUAL Windows AND NOT CMAKE_GENERATOR STREQUAL Ninja) # MSVC implicitly adds $ to the output path set(CUSTOM_COMMAND_BINARY_DIR ${CUSTOM_COMMAND_BINARY_DIR}/$) endif() if(UR_FORCE_LIBSTDCXX AND CMAKE_SYSTEM_NAME STREQUAL Linux) # Remove flags to specify using libc++ or static libstdc++ in order to # support sitatuions where the libstdc++ ABI is required. foreach(flags CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS) string(REPLACE "-stdlib=libc++" "" ${flags} "${${flags}}") string(REPLACE "-static-libstdc++" "" ${flags} "${${flags}}") endforeach() # Globally link against pthread, this is necessary when forcing use of # libstdc++ in a libc++ build as the FindThreads module may have already # been invoked and detected that pthread symbols are provided by libc++ # which is not the case for libstdc++. add_compile_options(-pthread) link_libraries(pthread) endif() if(NOT MSVC) # Determine if libstdc++ is being used. check_cxx_source_compiles(" #include #ifndef __GLIBCXX__ #error not using libstdc++ #endif int main() {}" USING_LIBSTDCXX) if(UR_FORCE_LIBSTDCXX OR USING_LIBSTDCXX) # Support older versions of GCC where the header is not # available and must be used instead. This # requires linking against libstdc++fs.a, on systems where # is available we still need to link this library. link_libraries(stdc++fs) endif() endif() if(UR_ENABLE_TRACING) add_compile_definitions(UR_ENABLE_TRACING) if (UR_BUILD_XPTI_LIBS) # fetch xpti proxy library for the tracing layer FetchContentSparse_Declare(xpti https://github.com/intel/llvm.git "nightly-2024-10-22" "xpti") FetchContent_MakeAvailable(xpti) # set -fPIC for xpti since we are linking it with a shared library set_target_properties(xpti PROPERTIES POSITION_INDEPENDENT_CODE ON) # fetch the xptifw dispatcher, mostly used for testing # these variables need to be set for xptifw to compile set(XPTI_SOURCE_DIR ${xpti_SOURCE_DIR}) set(XPTI_DIR ${xpti_SOURCE_DIR}) set(XPTI_ENABLE_TESTS OFF CACHE INTERNAL "Turn off xptifw tests") FetchContentSparse_Declare(xptifw https://github.com/intel/llvm.git "nightly-2024-10-22" "xptifw") FetchContent_MakeAvailable(xptifw) check_cxx_compiler_flag("-Wno-error=maybe-uninitialized" HAS_MAYBE_UNINIT) if (HAS_MAYBE_UNINIT) target_compile_options(xptifw PRIVATE -Wno-error=maybe-uninitialized) endif() set_target_properties(xptifw PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ) if (NOT MSVC) # Hardening flags cause issues on Windows add_ur_target_compile_options(xptifw) add_ur_target_link_options(xptifw) endif() if (UR_STATIC_LOADER) install(TARGETS xpti xptifw EXPORT ${PROJECT_NAME}-targets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() endif() if (MSVC) set(TARGET_XPTI $,xpti,xptid>) else() set(TARGET_XPTI xpti) endif() endif() if(UR_ENABLE_SANITIZER) if(APPLE) message(WARNING "Sanitizer layer isn't supported on macOS") set(UR_ENABLE_SANITIZER OFF) elseif(WIN32) message(WARNING "Sanitizer layer isn't supported on Windows") set(UR_ENABLE_SANITIZER OFF) else() add_compile_definitions(UR_ENABLE_SANITIZER) endif() if(UR_ENABLE_SYMBOLIZER AND UR_STANDALONE_BUILD) find_package(LLVM REQUIRED) endif() else() if(UR_ENABLE_SYMBOLIZER) message(FATAL_ERROR "Symbolizer must be enabled with Sanitizer layer") endif() endif() if(UR_USE_ASAN) add_sanitizer_flag(address) endif() if(UR_USE_UBSAN) add_sanitizer_flag(undefined) endif() if(UR_USE_TSAN) add_sanitizer_flag(thread) endif() if(UR_USE_MSAN) message(WARNING "MemorySanitizer requires that all code is built with its instrumentation, otherwise false positives are possible. See https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo#instrumented-libc for details") add_sanitizer_flag(memory) endif() if(NOT (UR_BUILD_ADAPTER_CUDA OR UR_BUILD_ADAPTER_HIP OR UR_BUILD_ADAPTER_L0 OR UR_BUILD_ADAPTER_OPENCL OR UR_BUILD_ADAPTER_NATIVE_CPU OR UR_BUILD_ADAPTER_L0_V2 OR UR_BUILD_ADAPTER_ALL)) message(WARNING "No adapters have been enabled; conformance tests will not be ran") message(STATUS "Consider setting UR_BUILD_ADAPTER_*") endif() # Check if clang-format (in correct version) is available for Cpp code formatting. if(UR_FORMAT_CPP_STYLE) find_program(CLANG_FORMAT NAMES clang-format-18 clang-format-18.1 clang-format) if(CLANG_FORMAT) get_program_version_major_minor(${CLANG_FORMAT} CLANG_FORMAT_VERSION) message(STATUS "Found clang-format: ${CLANG_FORMAT} (version: ${CLANG_FORMAT_VERSION})") set(CLANG_FORMAT_REQUIRED "18.1") if(NOT (CLANG_FORMAT_VERSION VERSION_EQUAL CLANG_FORMAT_REQUIRED)) message(FATAL_ERROR "required clang-format version is ${CLANG_FORMAT_REQUIRED}") endif() else() message(FATAL_ERROR "UR_FORMAT_CPP_STYLE=ON, but clang-format not found (required version: ${CLANG_FORMAT_REQUIRED})") endif() endif() # Obtain files for clang-format and license check set(format_glob) set(license_glob) foreach(dir examples include source test tools) list(APPEND format_glob "${dir}/*.h" "${dir}/*.hpp" "${dir}/*.c" "${dir}/*.cpp" "${dir}/**/*.h" "${dir}/**/*.hpp" "${dir}/**/*.c" "${dir}/**/*.cpp") list(APPEND license_glob "${dir}/*.yml" "${dir}/**/*.yml" "${dir}/*.py" "${dir}/**/*.py" "${dir}/**/CMakeLists.txt" "${dir}/CMakeLists.txt" ) endforeach() file(GLOB_RECURSE format_src ${format_glob}) file(GLOB_RECURSE license_src ${license_glob}) # Add license check target list(FILTER license_src EXCLUDE REGEX "registry.yml") add_custom_target(verify-licenses COMMAND ${Python3_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/verify_license.py" "--files" ${format_src} ${license_src} COMMENT "Verify all files contain a license." ) # Add hardening check add_custom_target(verify-hardening COMMAND "${PROJECT_SOURCE_DIR}/scripts/check-hardening.sh" ${CMAKE_BINARY_DIR} COMMENT "Check hardening settings on built binaries and libraries" ) # Add code formatter target add_custom_target(cppformat) # ... and all source files to the formatter add_cppformat(all-sources ${format_src}) # Allow custom third_party folder if(NOT DEFINED THIRD_PARTY_DIR) set(THIRD_PARTY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party) endif() add_subdirectory(${THIRD_PARTY_DIR}) # A header only library to specify include directories in transitive # dependencies. add_library(ur_headers INTERFACE) # Alias target to support FetchContent. add_library(${PROJECT_NAME}::headers ALIAS ur_headers) target_include_directories(ur_headers INTERFACE $ $) # Add the include directory and the headers target to the install. install( DIRECTORY "${PROJECT_SOURCE_DIR}/include/" DESTINATION include COMPONENT ur_headers) install( TARGETS ur_headers EXPORT ${PROJECT_NAME}-targets) add_subdirectory(source) if(UR_BUILD_EXAMPLES) add_subdirectory(examples) endif() if(UR_BUILD_TESTS) add_subdirectory(test) endif() if(UR_BUILD_TOOLS) add_subdirectory(tools) endif() # Add the list of installed targets to the install. This includes the namespace # which all installed targets will be prefixed with, e.g. for the headers # target users will depend on ${PROJECT_NAME}::headers. install( EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}-targets.cmake NAMESPACE ${PROJECT_NAME}:: DESTINATION lib/cmake/${PROJECT_NAME}) # Configure the package versions file for use in find_package when installed. write_basic_package_version_file( ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config-version.cmake COMPATIBILITY SameMajorVersion) # Configure the package file that is searched for by find_package when # installed. configure_package_config_file( ${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config.cmake INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}) # Add the package files to the install. install( FILES ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config.cmake ${PROJECT_BINARY_DIR}/cmake/${PROJECT_NAME}-config-version.cmake DESTINATION lib/cmake/${PROJECT_NAME}) set(API_JSON_FILE ${PROJECT_BINARY_DIR}/unified_runtime.json) if(UR_FORMAT_CPP_STYLE) # Generate source from the specification add_custom_target(generate-code USES_TERMINAL WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/scripts COMMAND ${Python3_EXECUTABLE} run.py --api-json ${API_JSON_FILE} --clang-format=${CLANG_FORMAT} $<$:--fast-mode> COMMAND ${Python3_EXECUTABLE} json2src.py --api-json ${API_JSON_FILE} ${PROJECT_SOURCE_DIR} ) # Generate and format source from the specification add_custom_target(generate USES_TERMINAL COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target generate-code COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target cppformat ) # Generate source and check for uncommitted diffs add_custom_target(check-generated WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND git diff --exit-code DEPENDS generate ) else() message(STATUS " UR_FORMAT_CPP_STYLE not set. Targets: 'generate' and 'check-generated' are not available") endif()