blob: 0fcb89e6ff59bbe1164aaea5592103bd4a42ee5e [file] [log] [blame] [edit]
# 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()