| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| ####################################################### |
| # Enhanced version of find llvm. |
| # |
| # Usage: |
| # find_llvm(${USE_LLVM} [${LLVM_VERSION}]) |
| # |
| # - When USE_LLVM=ON, use auto search |
| # - When USE_LLVM=/path/to/llvm-config, use corresponding config |
| # - The optional LLVM_VERSION=<required version> which will find a matching version |
| # If LLVM_VERSION=10 then it will find 10.X.X, any version of 10 |
| # If LLVM_VERSION=10.2 then it will find 10.2.X |
| # |
| # Provide variables: |
| # - LLVM_INCLUDE_DIRS |
| # - LLVM_LIBS |
| # - LLVM_DEFINITIONS |
| # - TVM_LLVM_VERSION |
| # - TVM_INFO_LLVM_VERSION |
| # |
| macro(find_llvm use_llvm) |
| if(${use_llvm} MATCHES ${IS_FALSE_PATTERN}) |
| return() |
| endif() |
| set(LLVM_CONFIG ${use_llvm}) |
| if(${ARGC} EQUAL 2) |
| set(llvm_version_required ${ARGV1}) |
| endif() |
| |
| if(${LLVM_CONFIG} MATCHES ${IS_TRUE_PATTERN}) |
| # This is a workaround for an upstream LLVM issue [0], in which |
| # the `CMAKE_INSTALL_LIBDIR` variable is used before definition. |
| # While there is an LLVM PR to resolve this fix [1], as of |
| # 2024-08-19 it has not yet been merged to LLVM. |
| # |
| # [0] https://github.com/llvm/llvm-project/issues/83802 |
| # [1] https://github.com/llvm/llvm-project/pull/83807 |
| include(GNUInstallDirs) |
| |
| find_package(LLVM ${llvm_version_required} REQUIRED CONFIG) |
| llvm_map_components_to_libnames(LLVM_LIBS "all") |
| if (NOT LLVM_LIBS) |
| message(STATUS "Not found - LLVM_LIBS") |
| message(STATUS "Fall back to using llvm-config") |
| set(LLVM_CONFIG "${LLVM_TOOLS_BINARY_DIR}/llvm-config") |
| endif() |
| endif() |
| |
| if(LLVM_LIBS) # check if defined, not if it is true |
| list (FIND LLVM_LIBS "LLVM" _llvm_dynlib_index) |
| if (${_llvm_dynlib_index} GREATER -1) |
| set(LLVM_LIBS LLVM) |
| message(STATUS "Link with dynamic LLVM library") |
| else() |
| list(REMOVE_ITEM LLVM_LIBS LTO) |
| message(STATUS "Link with static LLVM libraries") |
| endif() |
| set(TVM_LLVM_VERSION ${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}) |
| set(TVM_INFO_LLVM_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") |
| set(TVM_LLVM_HAS_AARCH64_TARGET 0) |
| if(DEFINED LLVM_TARGETS_TO_BUILD AND "AArch64" IN_LIST LLVM_TARGETS_TO_BUILD) |
| set(TVM_LLVM_HAS_AARCH64_TARGET 1) |
| endif() |
| else() |
| # use llvm config |
| message(STATUS "Use llvm-config=" ${LLVM_CONFIG}) |
| separate_arguments(LLVM_CONFIG) |
| execute_process(COMMAND ${LLVM_CONFIG} --libfiles |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_libfiles_space |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --libfiles") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --system-libs |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_system_libs |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --system-libs") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --cxxflags |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_cxxflags_space |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --cxxflags") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --version |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_version |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --version") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --prefix |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_prefix |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --prefix") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --libdir |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_libdir |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --libdir") |
| endif() |
| message(STATUS "LLVM libdir: ${__llvm_libdir}") |
| execute_process(COMMAND ${LLVM_CONFIG} --cmakedir |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_cmakedir |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --cmakedir") |
| endif() |
| execute_process(COMMAND ${LLVM_CONFIG} --targets-built |
| RESULT_VARIABLE __llvm_exit_code |
| OUTPUT_VARIABLE __llvm_targets_built |
| OUTPUT_STRIP_TRAILING_WHITESPACE) |
| if(NOT "${__llvm_exit_code}" STREQUAL "0") |
| message(FATAL_ERROR "Fatal error executing: ${LLVM_CONFIG} --targets-built") |
| endif() |
| cmake_path(SET "__llvm_cmakedir" "${__llvm_cmakedir}") |
| message(STATUS "LLVM cmakedir: ${__llvm_cmakedir}") |
| # map prefix => $ |
| # to handle the case when the prefix contains space. |
| string(REPLACE ${__llvm_prefix} "$" __llvm_cxxflags ${__llvm_cxxflags_space}) |
| string(REPLACE ${__llvm_prefix} "$" __llvm_libfiles ${__llvm_libfiles_space}) |
| # llvm version |
| set(TVM_INFO_LLVM_VERSION ${__llvm_version}) |
| string(REGEX REPLACE "^([^.]+)\.([^.])+\.[^.]+.*$" "\\1\\2" TVM_LLVM_VERSION ${__llvm_version}) |
| string(STRIP ${TVM_LLVM_VERSION} TVM_LLVM_VERSION) |
| # definitions |
| string(REGEX MATCHALL "(^| )-D[A-Za-z0-9_]*" __llvm_defs ${__llvm_cxxflags}) |
| set(LLVM_DEFINITIONS "") |
| foreach(__flag IN ITEMS ${__llvm_defs}) |
| string(STRIP "${__flag}" __llvm_def) |
| list(APPEND LLVM_DEFINITIONS "${__llvm_def}") |
| endforeach() |
| # include dir |
| string(REGEX MATCHALL "(^| )-I[^ ]*" __llvm_include_flags ${__llvm_cxxflags}) |
| set(LLVM_INCLUDE_DIRS "") |
| foreach(__flag IN ITEMS ${__llvm_include_flags}) |
| string(REGEX REPLACE "(^| )-I" "" __dir "${__flag}") |
| # map $ => prefix |
| string(REPLACE "$" ${__llvm_prefix} __dir_with_prefix "${__dir}") |
| list(APPEND LLVM_INCLUDE_DIRS "${__dir_with_prefix}") |
| endforeach() |
| # libfiles |
| set(LLVM_LIBS "") |
| separate_arguments(__llvm_libfiles) |
| foreach(__flag IN ITEMS ${__llvm_libfiles}) |
| # map $ => prefix |
| string(REPLACE "$" ${__llvm_prefix} __lib_with_prefix "${__flag}") |
| list(APPEND LLVM_LIBS "${__lib_with_prefix}") |
| endforeach() |
| # targets built |
| set(TVM_LLVM_HAS_AARCH64_TARGET 0) |
| separate_arguments(BUILT_TARGET_LIST NATIVE_COMMAND ${__llvm_targets_built}) |
| if("AArch64" IN_LIST BUILT_TARGET_LIST) |
| set(TVM_LLVM_HAS_AARCH64_TARGET 1) |
| endif() |
| if (${USE_MLIR}) |
| if (EXISTS "${__llvm_libdir}/libMLIRPresburger.a") |
| if (EXISTS "${__llvm_libdir}/libMLIRSupport.a") |
| message(STATUS "Found MLIR") |
| list(APPEND LLVM_LIBS "${__llvm_libdir}/libMLIRPresburger.a") |
| list(APPEND LLVM_LIBS "${__llvm_libdir}/libMLIRSupport.a") |
| set(TVM_MLIR_VERSION ${TVM_LLVM_VERSION}) |
| message(STATUS "Build with MLIR") |
| message(STATUS "Set TVM_MLIR_VERSION=" ${TVM_MLIR_VERSION}) |
| endif() |
| endif() |
| endif() |
| separate_arguments(__llvm_system_libs) |
| foreach(__flag IN ITEMS ${__llvm_system_libs}) |
| if("${__flag}" STREQUAL "-lm") |
| message(STATUS "LLVM links against math") |
| list(APPEND LLVM_LIBS "m") |
| elseif(("${__flag}" STREQUAL "-lz") OR ("${__flag}" STREQUAL "z.lib")) |
| message(STATUS "LLVM links against zlib") |
| find_package(ZLIB REQUIRED) |
| list(APPEND LLVM_LIBS "ZLIB::ZLIB") |
| elseif("${__flag}" STREQUAL "-lzstd") |
| list(APPEND CMAKE_MODULE_PATH "${__llvm_cmakedir}") |
| find_package(zstd REQUIRED) |
| if (TARGET "zstd::libzstd_static") |
| message(STATUS "LLVM links against static zstd") |
| list(APPEND LLVM_LIBS "zstd::libzstd_static") |
| else() |
| message(STATUS "LLVM links against shared zstd") |
| list(APPEND LLVM_LIBS "zstd::libzstd_shared") |
| endif() |
| elseif("${__flag}" STREQUAL "-lxml2") |
| message(STATUS "LLVM links against xml2") |
| list(APPEND LLVM_LIBS "-lxml2") |
| elseif("${__flag}" STREQUAL "zstd.dll.lib") |
| message(STATUS "LLVM linker flag under LLVM libdir: ${__llvm_libdir}/zstd.lib") |
| list(APPEND LLVM_LIBS "${__llvm_libdir}/zstd.lib") |
| elseif((__flag MATCHES ".lib$") AND (EXISTS "${__llvm_libdir}/${__flag}")) |
| # If the library file ends in .lib try to also search the llvm_libdir |
| message(STATUS "LLVM linker flag under LLVM libdir: ${__llvm_libdir}/${__flag}") |
| list(APPEND LLVM_LIBS "${__llvm_libdir}/${__flag}") |
| elseif((__flag MATCHES ".lib$") AND (EXISTS "${__llvm_libdir}/lib${__flag}")) |
| # If the library file ends in .lib try to also search the llvm_libdir with lib prefix |
| message(STATUS "LLVM linker flag under LLVM libdir: ${__llvm_libdir}/lib${__flag}") |
| list(APPEND LLVM_LIBS "${__llvm_libdir}/lib${__flag}") |
| else() |
| message(STATUS "LLVM linker flag: ${__flag}") |
| list(APPEND LLVM_LIBS "${__flag}") |
| endif() |
| endforeach() |
| endif() |
| message(STATUS "Found LLVM_INCLUDE_DIRS=" "${LLVM_INCLUDE_DIRS}") |
| message(STATUS "Found LLVM_DEFINITIONS=" "${LLVM_DEFINITIONS}") |
| message(STATUS "Found LLVM_LIBS=" "${LLVM_LIBS}") |
| message(STATUS "Found TVM_LLVM_VERSION=" ${TVM_LLVM_VERSION}) |
| if (${TVM_LLVM_VERSION} LESS 40) |
| message(FATAL_ERROR "TVM requires LLVM 4.0 or higher.") |
| endif() |
| message(STATUS "Found TVM_LLVM_HAS_AARCH64_TARGET=" ${TVM_LLVM_HAS_AARCH64_TARGET}) |
| endmacro(find_llvm) |