| # Copyright 2019 The IREE Authors |
| # |
| # Licensed under the Apache License v2.0 with LLVM Exceptions. |
| # See https://llvm.org/LICENSE.txt for license information. |
| # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| include(CMakeParseArguments) |
| |
| #------------------------------------------------------------------------------- |
| # Missing CMake Variables |
| #------------------------------------------------------------------------------- |
| |
| if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") |
| set(IREE_HOST_SCRIPT_EXT "bat") |
| # https://gitlab.kitware.com/cmake/cmake/-/issues/17553 |
| set(IREE_HOST_EXECUTABLE_SUFFIX ".exe") |
| else() |
| set(IREE_HOST_SCRIPT_EXT "sh") |
| set(IREE_HOST_EXECUTABLE_SUFFIX "") |
| endif() |
| |
| |
| #------------------------------------------------------------------------------- |
| # IREE_ARCH: identifies the target CPU architecture. May be empty when this is |
| # ill-defined, such as multi-architecture builds. |
| # This should be kept consistent with the C preprocessor token IREE_ARCH defined |
| # in target_platform.h. |
| #------------------------------------------------------------------------------- |
| |
| # First, get the raw CMake architecture name, not yet normalized. Even that is |
| # non-trivial: it usually is CMAKE_SYSTEM_PROCESSOR, but on some platforms, we |
| # have to read other variables instead. |
| if(CMAKE_OSX_ARCHITECTURES) |
| # Borrowing from: |
| # https://boringssl.googlesource.com/boringssl/+/c5f0e58e653d2d9afa8facc090ce09f8aaa3fa0d/CMakeLists.txt#43 |
| # https://github.com/google/XNNPACK/blob/2eb43787bfad4a99bdb613111cea8bc5a82f390d/CMakeLists.txt#L40 |
| list(LENGTH CMAKE_OSX_ARCHITECTURES NUM_ARCHES) |
| if(${NUM_ARCHES} EQUAL 1) |
| # Only one arch in CMAKE_OSX_ARCHITECTURES, use that. |
| set(_IREE_UNNORMALIZED_ARCH "${CMAKE_OSX_ARCHITECTURES}") |
| endif() |
| # Leaving _IREE_UNNORMALIZED_ARCH empty disables arch code paths. We will |
| # issue a performance warning about that below. |
| elseif(CMAKE_GENERATOR MATCHES "^Visual Studio " AND CMAKE_GENERATOR_PLATFORM) |
| # Borrowing from: |
| # https://github.com/google/XNNPACK/blob/2eb43787bfad4a99bdb613111cea8bc5a82f390d/CMakeLists.txt#L50 |
| set(_IREE_UNNORMALIZED_ARCH "${CMAKE_GENERATOR_PLATFORM}") |
| else() |
| set(_IREE_UNNORMALIZED_ARCH "${CMAKE_SYSTEM_PROCESSOR}") |
| endif() |
| |
| string(TOLOWER "${_IREE_UNNORMALIZED_ARCH}" _IREE_UNNORMALIZED_ARCH_LOWERCASE) |
| |
| # Normalize _IREE_UNNORMALIZED_ARCH into IREE_ARCH. |
| if(EMSCRIPTEN) |
| # TODO: figure what to do about the wasm target, which masquerades as x86. |
| # This is the one case where the IREE_ARCH CMake variable is currently |
| # inconsistent with the IREE_ARCH C preprocessor token. |
| set(IREE_ARCH "") |
| elseif((_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "aarch64") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "arm64") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "arm64e") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "arm64ec")) |
| set(IREE_ARCH "arm_64") |
| elseif((_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "arm") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE MATCHES "^armv[5-8]")) |
| set(IREE_ARCH "arm_32") |
| elseif((_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "x86_64") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "amd64") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "x64")) |
| set(IREE_ARCH "x86_64") |
| elseif((_IREE_UNNORMALIZED_ARCH_LOWERCASE MATCHES "^i[3-7]86$") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "x86") OR |
| (_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "win32")) |
| set(IREE_ARCH "x86_32") |
| elseif(_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "riscv64") |
| set(IREE_ARCH "riscv_64") |
| elseif(_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "riscv32") |
| set(IREE_ARCH "riscv_32") |
| elseif(_IREE_UNNORMALIZED_ARCH_LOWERCASE STREQUAL "") |
| set(IREE_ARCH "") |
| message(WARNING "Performance advisory: architecture-specific code paths " |
| "disabled because no target architecture was specified or we didn't know " |
| "which CMake variable to read. Some relevant CMake variables:\n" |
| "CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}\n" |
| "CMAKE_GENERATOR=${CMAKE_GENERATOR}\n" |
| "CMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}\n" |
| "CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}\n" |
| ) |
| else() |
| set(IREE_ARCH "") |
| message(SEND_ERROR "Unrecognized target architecture ${_IREE_UNNORMALIZED_ARCH_LOWERCASE}") |
| endif() |
| |
| # iree_arch_to_llvm_arch() |
| # |
| # Helper mapping an architecture in IREE's naming scheme (as in IREE_ARCH) |
| # to an architecture in LLVM's naming scheme (as in LLVM target triples). |
| function(iree_arch_to_llvm_arch DST_LLVM_ARCH_VARIABLE SRC_ARCH) |
| if("${SRC_ARCH}" STREQUAL "arm_64") |
| set(${DST_LLVM_ARCH_VARIABLE} "aarch64" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "arm_32") |
| set(${DST_LLVM_ARCH_VARIABLE} "arm" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "x86_64") |
| set(${DST_LLVM_ARCH_VARIABLE} "x86_64" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "x86_32") |
| set(${DST_LLVM_ARCH_VARIABLE} "i386" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "riscv_64") |
| set(${DST_LLVM_ARCH_VARIABLE} "riscv64" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "riscv_32") |
| set(${DST_LLVM_ARCH_VARIABLE} "riscv32" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "wasm_64") |
| set(${DST_LLVM_ARCH_VARIABLE} "wasm64" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "wasm_32") |
| set(${DST_LLVM_ARCH_VARIABLE} "wasm32" PARENT_SCOPE) |
| else() |
| message(SEND_ERROR "What is the LLVM name of the architecture that we call ${SRC_ARCH} ?") |
| set(${DST_LLVM_ARCH_VARIABLE} "unknown" PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| # iree_arch_to_llvm_target() |
| # |
| # Helper mapping an architecture in IREE's naming scheme (as in IREE_ARCH) |
| # to a LLVM CPU target (as in LLVM_TARGETS_TO_BUILD, the CMake variable). |
| function(iree_arch_to_llvm_target DST_LLVM_TARGET_VARIABLE SRC_ARCH) |
| if("${SRC_ARCH}" STREQUAL "arm_64") |
| set(${DST_LLVM_TARGET_VARIABLE} "AArch64" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" STREQUAL "arm_32") |
| set(${DST_LLVM_TARGET_VARIABLE} "ARM" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" MATCHES "^x86_") |
| set(${DST_LLVM_TARGET_VARIABLE} "X86" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" MATCHES "^riscv_") |
| set(${DST_LLVM_TARGET_VARIABLE} "RISCV" PARENT_SCOPE) |
| elseif("${SRC_ARCH}" MATCHES "^wasm_") |
| set(${DST_LLVM_TARGET_VARIABLE} "WebAssembly" PARENT_SCOPE) |
| else() |
| message(SEND_ERROR "What is the LLVM target handling of the architecture that we call ${SRC_ARCH} ?") |
| set(${DST_LLVM_TARGET_VARIABLE} "" PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| # iree_compiler_targeting_iree_arch |
| # |
| # Helper returning true if we are building the IREE compiler with the llvm-cpu |
| # backend enabled and with the LLVM target supporting the CPU architecture |
| # give in IREE's naming scheme (as in IREE_ARCH). |
| function(iree_compiler_targeting_iree_arch DST_VAR SRC_ARCH) |
| if (NOT IREE_BUILD_COMPILER OR NOT IREE_TARGET_BACKEND_LLVM_CPU) |
| set(${DST_VAR} OFF PARENT_SCOPE) |
| return() |
| endif() |
| |
| iree_arch_to_llvm_target(_LLVM_TARGET "${SRC_ARCH}") |
| # WebAssembly is unconditionally enabled, and not enumerated in LLVM_TARGETS_TO_BUILD. |
| if (_LLVM_TARGET IN_LIST LLVM_TARGETS_TO_BUILD OR _LLVM_TARGET STREQUAL "WebAssembly") |
| set(${DST_VAR} ON PARENT_SCOPE) |
| else() |
| set(${DST_VAR} OFF PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # General utilities |
| #------------------------------------------------------------------------------- |
| |
| # iree_to_bool |
| # |
| # Sets `variable` to `ON` if `value` is true and `OFF` otherwise. |
| function(iree_to_bool VARIABLE VALUE) |
| if(VALUE) |
| set(${VARIABLE} "ON" PARENT_SCOPE) |
| else() |
| set(${VARIABLE} "OFF" PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| # iree_append_list_to_string |
| # |
| # Joins ${ARGN} together as a string separated by " " and appends it to |
| # ${VARIABLE}. |
| function(iree_append_list_to_string VARIABLE) |
| if(NOT "${ARGN}" STREQUAL "") |
| string(JOIN " " _ARGN_STR ${ARGN}) |
| set(${VARIABLE} "${${VARIABLE}} ${_ARGN_STR}" PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| |
| #------------------------------------------------------------------------------- |
| # Packages and Paths |
| #------------------------------------------------------------------------------- |
| |
| # Performs a variety of setup tasks for a directory that forms the root |
| # of a C source tree. Many of our build macros use directory-scoped CMake |
| # variables to drive default behavior, and this sets those up in a consolidated |
| # way. |
| # Arguments: |
| # DEFAULT_EXPORT_SET: |
| # The export set to use by default. If linking any static libraries |
| # that are to be installed as dev libraries, then this is mandatory |
| # (or each target must specify it). Typically this must be set in |
| # runtime directories. |
| # DEFAULT_INSTALL_COMPONENT: |
| # The default install component for libraries. |
| # IMPLICIT_DEFS_TARGET: |
| # A new target to create and export/install which includes the current |
| # source and binary directory as an include dir. It will be added to |
| # every cc library created after this in this directory tree. |
| # IMPLICIT_DEFS_INSTALL_COMPONENT: |
| # Install component for *just* the implicit defs target. |
| # IMPLICIT_DEFS_EXPORT_SET: |
| # Export set for *just* the implicit defs target. |
| # PACKAGE_ROOT_PREFIX: |
| # Explicitly set the package root prefix (as something like "iree::foobar"). |
| # Default is empty. |
| # See runtime/src/CMakeLists.txt for typical usage in a directory tree |
| # that installs static dev libraries. |
| # |
| # See compiler/src/CMakeLists.txt for typical usage that does not install |
| # static dev libraries. |
| function(iree_setup_c_src_root) |
| cmake_parse_arguments( |
| _RULE |
| "" |
| "PACKAGE_ROOT_PREFIX;DEFAULT_EXPORT_SET;DEFAULT_INSTALL_COMPONENT;IMPLICIT_DEFS_TARGET;IMPLICIT_DEFS_INSTALL_COMPONENT;IMPLICIT_DEFS_EXPORT_SET" |
| "" |
| ${ARGN} |
| ) |
| |
| # Make C++ library package names start here unless if told not to. |
| set(IREE_PACKAGE_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) |
| set(IREE_PACKAGE_ROOT_PREFIX "${_RULE_PACKAGE_ROOT_PREFIX}" PARENT_SCOPE) |
| |
| # Instruct install support that headers are installable from this root |
| # directory. |
| set(IREE_HDRS_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) |
| |
| # Export and install by default. |
| if(_RULE_DEFAULT_EXPORT_SET) |
| set(IREE_INSTALL_LIBRARY_TARGETS_DEFAULT_EXPORT_SET |
| "${_RULE_DEFAULT_EXPORT_SET}" |
| PARENT_SCOPE) |
| endif() |
| if(_RULE_DEFAULT_INSTALL_COMPONENT) |
| set(IREE_INSTALL_LIBRARY_TARGETS_DEFAULT_COMPONENT |
| "${_RULE_DEFAULT_INSTALL_COMPONENT}" |
| PARENT_SCOPE) |
| endif() |
| |
| # Tell tablegen to include from here. |
| set(IREE_COMPILER_TABLEGEN_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE) |
| |
| # Create an implicit defs target that adds this include directory. |
| if(_RULE_IMPLICIT_DEFS_TARGET) |
| add_library(${_RULE_IMPLICIT_DEFS_TARGET} INTERFACE) |
| target_include_directories(${_RULE_IMPLICIT_DEFS_TARGET} |
| INTERFACE |
| $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> |
| $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> |
| ) |
| if(NOT _RULE_IMPLICIT_DEFS_INSTALL_COMPONENT) |
| set(_RULE_IMPLICIT_DEFS_INSTALL_COMPONENT ${_RULE_DEFAULT_INSTALL_COMPONENT}) |
| endif() |
| if(NOT _RULE_IMPLICIT_DEFS_EXPORT_SET) |
| set(_RULE_IMPLICIT_DEFS_EXPORT_SET ${_RULE_DEFAULT_EXPORT_SET}) |
| endif() |
| iree_install_targets( |
| TARGETS ${_RULE_IMPLICIT_DEFS_TARGET} |
| COMPONENT "${_RULE_IMPLICIT_DEFS_INSTALL_COMPONENT}" |
| EXPORT_SET "${_RULE_IMPLICIT_DEFS_EXPORT_SET}" |
| ) |
| |
| # Include this target in all cc_libraries. |
| set(IREE_IMPLICIT_DEFS_CC_DEPS ${_RULE_IMPLICIT_DEFS_TARGET} PARENT_SCOPE) |
| endif() |
| endfunction() |
| |
| # Sets ${PACKAGE_NS} to the IREE-root relative package name in C++ namespace |
| # format (::). |
| # |
| # Examples: |
| # compiler/src/iree/compiler/Utils/CMakeLists.txt -> iree::compiler::Utils |
| # runtime/src/iree/base/CMakeLists.txt -> iree::base |
| # tests/e2e/CMakeLists.txt -> iree::tests::e2e |
| function(iree_package_ns PACKAGE_NS) |
| if(DEFINED IREE_PACKAGE_ROOT_DIR) |
| # If an enclosing package root dir is set, then the package is just the |
| # relative part after that. |
| cmake_path(RELATIVE_PATH CMAKE_CURRENT_LIST_DIR |
| BASE_DIRECTORY "${IREE_PACKAGE_ROOT_DIR}" |
| OUTPUT_VARIABLE _PACKAGE) |
| if(_PACKAGE STREQUAL ".") |
| set(_PACKAGE "") |
| endif() |
| if(IREE_PACKAGE_ROOT_PREFIX) |
| if("${_PACKAGE}" STREQUAL "") |
| set(_PACKAGE "${IREE_PACKAGE_ROOT_PREFIX}") |
| else() |
| set(_PACKAGE "${IREE_PACKAGE_ROOT_PREFIX}/${_PACKAGE}") |
| endif() |
| endif() |
| else() |
| # Get the relative path of the current dir (i.e. runtime/src/iree/vm). |
| string(REPLACE ${IREE_ROOT_DIR} "" _IREE_RELATIVE_PATH ${CMAKE_CURRENT_LIST_DIR}) |
| string(SUBSTRING ${_IREE_RELATIVE_PATH} 1 -1 _IREE_RELATIVE_PATH) |
| |
| if(NOT ${CMAKE_CURRENT_LIST_DIR} MATCHES "^${IREE_ROOT_DIR}/.*") |
| # Function is being called from outside IREE. Use the source-relative path. |
| # Please check the README.md to see the potential risk. |
| string(REPLACE ${PROJECT_SOURCE_DIR} "" _SOURCE_RELATIVE_PATH ${CMAKE_CURRENT_LIST_DIR}) |
| string(SUBSTRING ${_SOURCE_RELATIVE_PATH} 1 -1 _SOURCE_RELATIVE_PATH) |
| set(_PACKAGE "${_SOURCE_RELATIVE_PATH}") |
| |
| # If changing the directory/package mapping rules, please also implement |
| # the corresponding rule in: |
| # build_tools/bazel_to_cmake/bazel_to_cmake_targets.py |
| # Some sub-trees form their own roots for package purposes. Rewrite them. |
| else() |
| message(SEND_ERROR "iree_package_ns(): Could not determine package for ${CMAKE_CURRENT_LIST_DIR}") |
| set(_PACKAGE "iree/unknown") |
| endif() |
| endif() |
| |
| string(REPLACE "/" "::" _PACKAGE_NS "${_PACKAGE}") |
| |
| if(_DEBUG_IREE_PACKAGE_NAME) |
| message(STATUS "iree_package_ns(): map ${CMAKE_CURRENT_LIST_DIR} -> ${_PACKAGE_NS}") |
| endif() |
| |
| set(${PACKAGE_NS} ${_PACKAGE_NS} PARENT_SCOPE) |
| endfunction() |
| |
| # Sets ${PACKAGE_NAME} to the IREE-root relative package name. |
| # |
| # Example when called from iree/base/CMakeLists.txt: |
| # iree_base |
| function(iree_package_name PACKAGE_NAME) |
| iree_package_ns(_PACKAGE_NS) |
| string(REPLACE "::" "_" _PACKAGE_NAME "${_PACKAGE_NS}") |
| set(${PACKAGE_NAME} ${_PACKAGE_NAME} PARENT_SCOPE) |
| endfunction() |
| |
| # Sets ${PACKAGE_PATH} to the IREE-root relative package path. |
| # |
| # Example when called from iree/base/CMakeLists.txt: |
| # iree/base |
| function(iree_package_path PACKAGE_PATH) |
| iree_package_ns(_PACKAGE_NS) |
| string(REPLACE "::" "/" _PACKAGE_PATH ${_PACKAGE_NS}) |
| set(${PACKAGE_PATH} ${_PACKAGE_PATH} PARENT_SCOPE) |
| endfunction() |
| |
| # Sets ${PACKAGE_DIR} to the directory name of the current package. |
| # |
| # Example when called from iree/base/CMakeLists.txt: |
| # base |
| function(iree_package_dir PACKAGE_DIR) |
| iree_package_ns(_PACKAGE_NS) |
| string(FIND "${_PACKAGE_NS}" "::" _END_OFFSET REVERSE) |
| math(EXPR _END_OFFSET "${_END_OFFSET} + 2") |
| string(SUBSTRING ${_PACKAGE_NS} ${_END_OFFSET} -1 _PACKAGE_DIR) |
| set(${PACKAGE_DIR} ${_PACKAGE_DIR} PARENT_SCOPE) |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # select()-like Evaluation |
| #------------------------------------------------------------------------------- |
| |
| # Appends ${OPTS} with a list of values based on the current compiler. |
| # |
| # Example: |
| # iree_select_compiler_opts(COPTS |
| # CLANG |
| # "-Wno-foo" |
| # "-Wno-bar" |
| # CLANG_CL |
| # "/W3" |
| # GCC |
| # "-Wsome-old-flag" |
| # MSVC |
| # "/W3" |
| # ) |
| # |
| # Note that variables are allowed, making it possible to share options between |
| # different compiler targets. |
| function(iree_select_compiler_opts OPTS) |
| cmake_parse_arguments( |
| PARSE_ARGV 1 |
| _IREE_SELECTS |
| "" |
| "" |
| "ALL;CLANG;CLANG_GTE_10;CLANG_GTE_12;CLANG_CL;MSVC;GCC;CLANG_OR_GCC;MSVC_OR_CLANG_CL" |
| ) |
| # OPTS is a variable containing the *name* of the variable being populated, so |
| # we need to dereference it twice. |
| set(_OPTS "${${OPTS}}") |
| list(APPEND _OPTS "${_IREE_SELECTS_ALL}") |
| if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") |
| list(APPEND _OPTS "${_IREE_SELECTS_GCC}") |
| list(APPEND _OPTS "${_IREE_SELECTS_CLANG_OR_GCC}") |
| elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") |
| if(MSVC) |
| list(APPEND _OPTS ${_IREE_SELECTS_CLANG_CL}) |
| list(APPEND _OPTS ${_IREE_SELECTS_MSVC_OR_CLANG_CL}) |
| else() |
| list(APPEND _OPTS ${_IREE_SELECTS_CLANG}) |
| if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10) |
| list(APPEND _OPTS ${_IREE_SELECTS_CLANG_GTE_10}) |
| endif() |
| if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12) |
| list(APPEND _OPTS ${_IREE_SELECTS_CLANG_GTE_12}) |
| endif() |
| list(APPEND _OPTS ${_IREE_SELECTS_CLANG_OR_GCC}) |
| endif() |
| elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") |
| list(APPEND _OPTS ${_IREE_SELECTS_MSVC}) |
| list(APPEND _OPTS ${_IREE_SELECTS_MSVC_OR_CLANG_CL}) |
| else() |
| message(ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER}") |
| list(APPEND _OPTS "") |
| endif() |
| set(${OPTS} ${_OPTS} PARENT_SCOPE) |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # Data dependencies |
| #------------------------------------------------------------------------------- |
| |
| # Adds 'data' dependencies to a target. |
| # |
| # Parameters: |
| # NAME: name of the target to add data dependencies to |
| # DATA: List of targets and/or files in the source tree (relative to the |
| # project root). |
| function(iree_add_data_dependencies) |
| cmake_parse_arguments( |
| _RULE |
| "" |
| "NAME" |
| "DATA" |
| ${ARGN} |
| ) |
| |
| if(NOT _RULE_DATA) |
| return() |
| endif() |
| |
| foreach(_DATA_LABEL ${_RULE_DATA}) |
| if(TARGET ${_DATA_LABEL}) |
| add_dependencies(${_RULE_NAME} ${_DATA_LABEL}) |
| else() |
| # Not a target, assume to be a file instead. |
| set(_FILE_PATH ${_DATA_LABEL}) |
| |
| # Create a target which copies the data file into the build directory. |
| # If this file is included in multiple rules, only create the target once. |
| string(REPLACE "::" "_" _DATA_TARGET ${_DATA_LABEL}) |
| string(REPLACE "/" "_" _DATA_TARGET ${_DATA_TARGET}) |
| if(NOT TARGET ${_DATA_TARGET}) |
| set(_INPUT_PATH "${PROJECT_SOURCE_DIR}/${_FILE_PATH}") |
| set(_OUTPUT_PATH "${PROJECT_BINARY_DIR}/${_FILE_PATH}") |
| add_custom_target(${_DATA_TARGET} |
| COMMAND ${CMAKE_COMMAND} -E copy ${_INPUT_PATH} ${_OUTPUT_PATH} |
| ) |
| endif() |
| |
| add_dependencies(${_RULE_NAME} ${_DATA_TARGET}) |
| endif() |
| endforeach() |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # iree_make_empty_file |
| #------------------------------------------------------------------------------- |
| |
| # Creates an empty file by copying an in-tree empty file. Unlike `file(WRITE)` |
| # or `file(TOUCH)`, this does not update the timestamp every time CMake is run, |
| # avoiding unnecessary rebuilds when the empty file is used as a rule input. |
| function(iree_make_empty_file _FILENAME) |
| configure_file("${PROJECT_SOURCE_DIR}/build_tools/cmake/empty_file" "${_FILENAME}" COPYONLY) |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # Emscripten |
| #------------------------------------------------------------------------------- |
| |
| # A global counter to guarantee unique names for js library files. |
| set(_LINK_JS_COUNTER 1) |
| |
| # Links a JavaScript library to a target using --js-library=file.js. |
| # |
| # This function is only supported when running under Emscripten (emcmake). |
| # This implementation is forked from `em_add_tracked_link_flag()` in |
| # https://github.com/emscripten-core/emscripten/blob/main/cmake/Modules/Platform/Emscripten.cmake |
| # with changes to be compatible with IREE project style and CMake conventions. |
| # |
| # Parameters: |
| # TARGET: Name of the target to link against |
| # SRCS: List of JavaScript source files to link |
| function(iree_link_js_library) |
| cmake_parse_arguments( |
| _RULE |
| "" |
| "TARGET" |
| "SRCS" |
| ${ARGN} |
| ) |
| |
| # Convert from aliased, possibly package-relative, names to target names. |
| iree_package_ns(_PACKAGE_NS) |
| string(REGEX REPLACE "^::" "${_PACKAGE_NS}::" _RULE_TARGET ${_RULE_TARGET}) |
| string(REPLACE "::" "_" _RULE_TARGET ${_RULE_TARGET}) |
| |
| foreach(_SRC_FILE ${_RULE_SRCS}) |
| # If the JS file is changed, we want to relink dependent binaries, but |
| # unfortunately it is not possible to make a link step depend directly on a |
| # source file. Instead, we must make a dummy no-op build target on that |
| # source file, and make the original target depend on that dummy target. |
| |
| # Sanitate the source .js filename to a good dummy filename. |
| get_filename_component(_JS_NAME "${_SRC_FILE}" NAME) |
| string(REGEX REPLACE "[/:\\\\.\ ]" "_" _DUMMY_JS_TARGET ${_JS_NAME}) |
| set(_DUMMY_LIB_NAME ${_RULE_TARGET}_${_LINK_JS_COUNTER}_${_DUMMY_JS_TARGET}) |
| set(_DUMMY_C_NAME "${CMAKE_BINARY_DIR}/${_DUMMY_JS_TARGET}_tracker.c") |
| |
| # Create a new static library target that with a single dummy .c file. |
| add_library(${_DUMMY_LIB_NAME} STATIC ${_DUMMY_C_NAME}) |
| # Make the dummy .c file depend on the .js file we are linking, so that if |
| # the .js file is edited, the dummy .c file, and hence the static library |
| # will be rebuild (no-op). This causes the main application to be |
| # relinked, which is what we want. This approach was recommended by |
| # http://www.cmake.org/pipermail/cmake/2010-May/037206.html |
| add_custom_command( |
| OUTPUT ${_DUMMY_C_NAME} |
| COMMAND ${CMAKE_COMMAND} -E touch ${_DUMMY_C_NAME} |
| DEPENDS ${_SRC_FILE} |
| ) |
| target_link_libraries(${_RULE_TARGET} |
| PUBLIC |
| ${_DUMMY_LIB_NAME} |
| ) |
| |
| iree_install_targets( |
| TARGETS ${_DUMMY_LIB_NAME} |
| ) |
| |
| # Link the js-library to the target. |
| # When a linked library starts with a "-" cmake will just add it to the |
| # linker command line as it is. The advantage of doing it this way is |
| # that the js-library will also be automatically linked to targets that |
| # depend on this target. |
| get_filename_component(_SRC_ABSOLUTE_PATH "${_SRC_FILE}" ABSOLUTE) |
| target_link_libraries(${_RULE_TARGET} |
| PUBLIC |
| "--js-library \"${_SRC_ABSOLUTE_PATH}\"" |
| ) |
| |
| math(EXPR _LINK_JS_COUNTER "${_LINK_JS_COUNTER} + 1") |
| endforeach() |
| endfunction() |
| |
| #------------------------------------------------------------------------------- |
| # Tool symlinks |
| #------------------------------------------------------------------------------- |
| |
| # iree_symlink_tool |
| # |
| # Adds a command to TARGET which symlinks a tool from elsewhere |
| # (FROM_TOOL_TARGET_NAME) to a local file name (TO_EXE_NAME) in the current |
| # binary directory. |
| # |
| # Parameters: |
| # TARGET: Local target to which to add the symlink command (i.e. an |
| # iree_py_library, etc). |
| # FROM_TOOL_TARGET: Target of the tool executable that is the source of the |
| # link. |
| # TO_EXE_NAME: The executable name to output in the current binary dir. |
| function(iree_symlink_tool) |
| cmake_parse_arguments( |
| _RULE |
| "" |
| "TARGET;FROM_TOOL_TARGET;TO_EXE_NAME" |
| "" |
| ${ARGN} |
| ) |
| |
| # Transform TARGET |
| iree_package_ns(_PACKAGE_NS) |
| iree_package_name(_PACKAGE_NAME) |
| set(_TARGET "${_PACKAGE_NAME}_${_RULE_TARGET}") |
| set(_FROM_TOOL_TARGET ${_RULE_FROM_TOOL_TARGET}) |
| set(_TO_TOOL_PATH "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_TO_EXE_NAME}${CMAKE_EXECUTABLE_SUFFIX}") |
| get_filename_component(_TO_TOOL_DIR "${_TO_TOOL_PATH}" DIRECTORY) |
| |
| |
| add_custom_command( |
| TARGET "${_TARGET}" |
| BYPRODUCTS |
| "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_TO_EXE_NAME}${CMAKE_EXECUTABLE_SUFFIX}" |
| COMMAND |
| ${CMAKE_COMMAND} -E make_directory "${_TO_TOOL_DIR}" |
| COMMAND |
| ${CMAKE_COMMAND} -E create_symlink |
| "$<TARGET_FILE:${_FROM_TOOL_TARGET}>" |
| "${_TO_TOOL_PATH}" |
| ) |
| endfunction() |
| |
| |
| #------------------------------------------------------------------------------- |
| # Tests |
| #------------------------------------------------------------------------------- |
| |
| # iree_check_defined |
| # |
| # A lightweight way to check that all the given variables are defined. Useful |
| # in cases like checking that a function has been passed all required arguments. |
| # Doesn't give usage-specific error messages, but still significantly better |
| # than no error checking. |
| # Variable names should be passed directly without quoting or dereferencing. |
| # Example: |
| # iree_check_defined(_SOME_VAR _AND_ANOTHER_VAR) |
| macro(iree_check_defined) |
| foreach(_VAR ${ARGN}) |
| if(NOT DEFINED "${_VAR}") |
| message(SEND_ERROR "${_VAR} is not defined") |
| endif() |
| endforeach() |
| endmacro() |
| |
| # iree_validate_required_arguments |
| # |
| # Validates that no arguments went unparsed or were given no values and that all |
| # required arguments have values. Expects to be called after |
| # cmake_parse_arguments and verifies that the variables it creates have been |
| # populated as appropriate. |
| function(iree_validate_required_arguments |
| PREFIX |
| REQUIRED_ONE_VALUE_KEYWORDS |
| REQUIRED_MULTI_VALUE_KEYWORDS) |
| if(DEFINED ${PREFIX}_UNPARSED_ARGUMENTS) |
| message(SEND_ERROR "Unparsed argument(s): '${${PREFIX}_UNPARSED_ARGUMENTS}'") |
| endif() |
| if(DEFINED ${PREFIX}_KEYWORDS_MISSING_VALUES) |
| message(SEND_ERROR |
| "No values for field(s) '${${PREFIX}_KEYWORDS_MISSING_VALUES}'") |
| endif() |
| |
| foreach(_KEYWORD IN LISTS REQUIRED_ONE_VALUE_KEYWORDS REQUIRED_MULTI_VALUE_KEYWORDS) |
| if(NOT DEFINED ${PREFIX}_${_KEYWORD}) |
| message(SEND_ERROR "Missing required argument ${_KEYWORD}") |
| endif() |
| endforeach() |
| endfunction() |
| |
| # iree_compile_flags_for_patform |
| # |
| # Helper function to add necessary compile flags based on platform-specific |
| # configurations. Note the flags are added for cpu backends only. |
| function(iree_compile_flags_for_platform OUT_FLAGS IN_FLAGS) |
| if(NOT (IN_FLAGS MATCHES "iree-hal-target-backends=llvm-cpu" OR |
| IN_FLAGS MATCHES "iree-hal-target-backends=vmvx")) |
| set(${OUT_FLAGS} "" PARENT_SCOPE) |
| return() |
| endif() |
| |
| if(ANDROID AND NOT IN_FLAGS MATCHES "iree-llvmcpu-target-triple") |
| # Android's CMake toolchain defines some variables that we can use to infer |
| # the appropriate target triple from the configured settings: |
| # https://developer.android.com/ndk/guides/cmake#android_platform |
| # |
| # In typical CMake fashion, the various strings are pretty fuzzy and can |
| # have multiple values like "latest", "android-25"/"25"/"android-N-MR1". |
| # |
| # From looking at the toolchain file, ANDROID_PLATFORM_LEVEL seems like it |
| # should pretty consistently be just a number we can use for target triple. |
| set(_TARGET_TRIPLE "aarch64-none-linux-android${ANDROID_PLATFORM_LEVEL}") |
| list(APPEND _FLAGS "--iree-llvmcpu-target-triple=${_TARGET_TRIPLE}") |
| endif() |
| |
| if(IREE_ARCH STREQUAL "riscv_64" AND |
| CMAKE_SYSTEM_NAME STREQUAL "Linux" AND |
| NOT IN_FLAGS MATCHES "iree-llvmcpu-target-triple") |
| # RV64 Linux crosscompile toolchain can support iree-compile with |
| # specific CPU flags. Add the llvm flags to support RV64 RVV codegen if |
| # llvm-target-triple is not specified. |
| list(APPEND _FLAGS ${RISCV64_TEST_DEFAULT_LLVM_FLAGS}) |
| elseif(IREE_ARCH STREQUAL "riscv_32" AND |
| CMAKE_SYSTEM_NAME STREQUAL "Linux" AND |
| NOT IN_FLAGS MATCHES "iree-llvmcpu-target-triple") |
| # RV32 Linux crosscompile toolchain can support iree-compile with |
| # specific CPU flags. Add the llvm flags to support RV32 RVV codegen if |
| # llvm-target-triple is not specified. |
| list(APPEND _FLAGS ${RISCV32_TEST_DEFAULT_LLVM_FLAGS}) |
| endif() |
| |
| if(EMSCRIPTEN AND NOT IN_FLAGS MATCHES "iree-llvmcpu-target-triple") |
| set(_EMSCRIPTEN_TEST_DEFAULT_FLAGS |
| "--iree-llvmcpu-target-triple=wasm32-unknown-emscripten" |
| ) |
| list(APPEND _FLAGS ${_EMSCRIPTEN_TEST_DEFAULT_FLAGS}) |
| endif() |
| |
| set(${OUT_FLAGS} "${_FLAGS}" PARENT_SCOPE) |
| endfunction() |