include(GNUInstallDirs)
include(LLVMDistributionSupport)
function(mlir_tablegen ofn)
tablegen(MLIR ${ARGV})
set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
PARENT_SCOPE)
# Get the current set of include paths for this td file.
cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
# Filter out any empty include items.
list(REMOVE_ITEM tblgen_includes "")
# Build the absolute path for the current input file.
if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
else()
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TARGET_DEFINITIONS})
endif()
# Append the includes used for this file to the tablegen_compile_commands
# file.
file(APPEND ${CMAKE_BINARY_DIR}/tablegen_compile_commands.yml
"--- !FileInfo:\n"
" filepath: \"${LLVM_TARGET_DEFINITIONS_ABSOLUTE}\"\n"
" includes: \"${CMAKE_CURRENT_SOURCE_DIR};${tblgen_includes}\"\n"
)
endfunction()
# Clear out any pre-existing compile_commands file before processing. This
# allows for generating a clean compile_commands on each configure.
file(REMOVE ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml)
# Declare a helper function/copy of tablegen rule for using tablegen without
# additional tblgen specific flags when invoking PDLL generator.
function(_pdll_tablegen project ofn)
cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
# Validate calling context.
if(NOT ${project}_TABLEGEN_EXE)
message(FATAL_ERROR "${project}_TABLEGEN_EXE not set")
endif()
# Use depfile instead of globbing arbitrary *.td(s) for Ninja.
if(CMAKE_GENERATOR MATCHES "Ninja")
# Make output path relative to build.ninja, assuming located on
# ${CMAKE_BINARY_DIR}.
# CMake emits build targets as relative paths but Ninja doesn't identify
# absolute path (in *.d) as relative path (in build.ninja)
# Note that tblgen is executed on ${CMAKE_BINARY_DIR} as working directory.
file(RELATIVE_PATH ofn_rel
${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${ofn})
set(additional_cmdline
-o ${ofn_rel}
-d ${ofn_rel}.d
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.d
)
set(local_tds)
set(global_tds)
else()
file(GLOB local_tds "*.td")
file(GLOB_RECURSE global_tds "${LLVM_MAIN_INCLUDE_DIR}/llvm/*.td")
set(additional_cmdline
-o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
)
endif()
if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
else()
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE
${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TARGET_DEFINITIONS})
endif()
if (CMAKE_GENERATOR MATCHES "Visual Studio")
# Visual Studio has problems with llvm-tblgen's native --write-if-changed
# behavior. Since it doesn't do restat optimizations anyway, just don't
# pass --write-if-changed there.
set(tblgen_change_flag)
else()
set(tblgen_change_flag "--write-if-changed")
endif()
# We need both _TABLEGEN_TARGET and _TABLEGEN_EXE in the DEPENDS list
# (both the target and the file) to have .inc files rebuilt on
# a tablegen change, as cmake does not propagate file-level dependencies
# of custom targets. See the following ticket for more information:
# https://cmake.org/Bug/view.php?id=15858
# The dependency on both, the target and the file, produces the same
# dependency twice in the result file when
# ("${${project}_TABLEGEN_TARGET}" STREQUAL "${${project}_TABLEGEN_EXE}")
# but lets us having smaller and cleaner code here.
get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
# Filter out empty items before prepending each entry with -I
list(REMOVE_ITEM tblgen_includes "")
list(TRANSFORM tblgen_includes PREPEND -I)
set(tablegen_exe ${${project}_TABLEGEN_EXE})
set(tablegen_depends ${${project}_TABLEGEN_TARGET} ${tablegen_exe})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
COMMAND ${tablegen_exe} ${ARG_UNPARSED_ARGUMENTS} -I ${CMAKE_CURRENT_SOURCE_DIR}
${tblgen_includes}
${LLVM_TARGET_DEFINITIONS_ABSOLUTE}
${tblgen_change_flag}
${additional_cmdline}
# The file in LLVM_TARGET_DEFINITIONS may be not in the current
# directory and local_tds may not contain it, so we must
# explicitly list it here:
DEPENDS ${ARG_DEPENDS} ${tablegen_depends}
${local_tds} ${global_tds}
${LLVM_TARGET_DEFINITIONS_ABSOLUTE}
${LLVM_TARGET_DEPENDS}
COMMENT "Building ${ofn}..."
)
# `make clean' must remove all those generated files:
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${ofn})
set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn} PARENT_SCOPE)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${ofn} PROPERTIES
GENERATED 1)
endfunction()
# Declare a PDLL library in the current directory.
function(add_mlir_pdll_library target inputFile ofn)
set(LLVM_TARGET_DEFINITIONS ${inputFile})
_pdll_tablegen(MLIR_PDLL ${ofn} -x=cpp ${ARGN})
set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
PARENT_SCOPE)
# Get the current set of include paths for this pdll file.
cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
# Filter out any empty include items.
list(REMOVE_ITEM tblgen_includes "")
# Build the absolute path for the current input file.
if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${inputFile})
else()
set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${inputFile})
endif()
# Append the includes used for this file to the pdll_compilation_commands
# file.
file(APPEND ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml
"--- !FileInfo:\n"
" filepath: \"${LLVM_TARGET_DEFINITIONS_ABSOLUTE}\"\n"
" includes: \"${CMAKE_CURRENT_SOURCE_DIR};${tblgen_includes}\"\n"
)
add_public_tablegen_target(${target})
endfunction()
# Declare a dialect in the include directory
function(add_mlir_dialect dialect dialect_namespace)
set(LLVM_TARGET_DEFINITIONS ${dialect}.td)
mlir_tablegen(${dialect}.h.inc -gen-op-decls)
mlir_tablegen(${dialect}.cpp.inc -gen-op-defs)
mlir_tablegen(${dialect}Types.h.inc -gen-typedef-decls -typedefs-dialect=${dialect_namespace})
mlir_tablegen(${dialect}Types.cpp.inc -gen-typedef-defs -typedefs-dialect=${dialect_namespace})
mlir_tablegen(${dialect}Dialect.h.inc -gen-dialect-decls -dialect=${dialect_namespace})
mlir_tablegen(${dialect}Dialect.cpp.inc -gen-dialect-defs -dialect=${dialect_namespace})
add_public_tablegen_target(MLIR${dialect}IncGen)
add_dependencies(mlir-headers MLIR${dialect}IncGen)
endfunction()
# Declare sharded dialect operation declarations and definitions
function(add_sharded_ops ops_target shard_count)
set(LLVM_TARGET_DEFINITIONS ${ops_target}.td)
mlir_tablegen(${ops_target}.h.inc -gen-op-decls -op-shard-count=${shard_count})
mlir_tablegen(${ops_target}.cpp.inc -gen-op-defs -op-shard-count=${shard_count})
set(LLVM_TARGET_DEFINITIONS ${ops_target}.cpp)
foreach(index RANGE ${shard_count})
set(SHARDED_SRC ${ops_target}.${index}.cpp)
list(APPEND SHARDED_SRCS ${SHARDED_SRC})
tablegen(MLIR_SRC_SHARDER ${SHARDED_SRC} -op-shard-index=${index})
set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${SHARDED_SRC})
endforeach()
add_public_tablegen_target(MLIR${ops_target}ShardGen)
set(SHARDED_SRCS ${SHARDED_SRCS} PARENT_SCOPE)
endfunction()
# Declare a dialect in the include directory
function(add_mlir_interface interface)
set(LLVM_TARGET_DEFINITIONS ${interface}.td)
mlir_tablegen(${interface}.h.inc -gen-op-interface-decls)
mlir_tablegen(${interface}.cpp.inc -gen-op-interface-defs)
add_public_tablegen_target(MLIR${interface}IncGen)
add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
endfunction()
# Generate Documentation
function(add_mlir_doc doc_filename output_file output_directory command)
set(LLVM_TARGET_DEFINITIONS ${doc_filename}.td)
# The MLIR docs use Hugo, so we allow Hugo specific features here.
tablegen(MLIR ${output_file}.md ${command} -allow-hugo-specific-features ${ARGN})
set(GEN_DOC_FILE ${MLIR_BINARY_DIR}/docs/${output_directory}${output_file}.md)
add_custom_command(
OUTPUT ${GEN_DOC_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md
${GEN_DOC_FILE}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md)
add_custom_target(${output_file}DocGen DEPENDS ${GEN_DOC_FILE})
set_target_properties(${output_file}DocGen PROPERTIES FOLDER "MLIR/Tablegenning/Docs")
add_dependencies(mlir-doc ${output_file}DocGen)
endfunction()
# Sets ${srcs} to contain the list of additional headers for the target. Extra
# arguments are included into the list of additional headers.
function(_set_mlir_additional_headers_as_srcs)
set(srcs)
if(MSVC_IDE OR XCODE)
# Add public headers
file(RELATIVE_PATH lib_path
${MLIR_SOURCE_DIR}/lib/
${CMAKE_CURRENT_SOURCE_DIR}
)
if(NOT lib_path MATCHES "^[.][.]")
file( GLOB_RECURSE headers
${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.h
${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.def
)
set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
file( GLOB_RECURSE tds
${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.td
)
source_group("TableGen descriptions" FILES ${tds})
set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
if(headers OR tds)
set(srcs ${headers} ${tds})
endif()
endif()
endif(MSVC_IDE OR XCODE)
if(srcs OR ARGN)
set(srcs
ADDITIONAL_HEADERS
${srcs}
${ARGN} # It may contain unparsed unknown args.
PARENT_SCOPE
)
endif()
endfunction()
# Checks that the LLVM components are not listed in the extra arguments,
# assumed to be coming from the LINK_LIBS variable.
function(_check_llvm_components_usage name)
# LINK_COMPONENTS is necessary to allow libLLVM.so to be properly
# substituted for individual library dependencies if LLVM_LINK_LLVM_DYLIB
# Perhaps this should be in llvm_add_library instead? However, it fails
# on libclang-cpp.so
get_property(llvm_component_libs GLOBAL PROPERTY LLVM_COMPONENT_LIBS)
foreach(lib ${ARGN})
if(${lib} IN_LIST llvm_component_libs)
message(SEND_ERROR "${name} specifies LINK_LIBS ${lib}, but LINK_LIBS cannot be used for LLVM libraries. Please use LINK_COMPONENTS instead.")
endif()
endforeach()
endfunction()
function(add_mlir_example_library name)
cmake_parse_arguments(ARG
"SHARED;DISABLE_INSTALL"
""
"ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS"
${ARGN})
_set_mlir_additional_headers_as_srcs(${ARG_ADDITIONAL_HEADERS})
if (ARG_SHARED)
set(LIBTYPE SHARED)
else()
if(BUILD_SHARED_LIBS)
set(LIBTYPE SHARED)
else()
set(LIBTYPE STATIC)
endif()
endif()
# MLIR libraries uniformly depend on LLVMSupport. Just specify it once here.
list(APPEND ARG_LINK_COMPONENTS Support)
_check_llvm_components_usage(${name} ${ARG_LINK_LIBS})
list(APPEND ARG_DEPENDS mlir-generic-headers)
llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs} DEPENDS ${ARG_DEPENDS} LINK_COMPONENTS ${ARG_LINK_COMPONENTS} LINK_LIBS ${ARG_LINK_LIBS})
set_target_properties(${name} PROPERTIES FOLDER "MLIR/Examples")
if (LLVM_BUILD_EXAMPLES AND NOT ${ARG_DISABLE_INSTALL})
add_mlir_library_install(${name})
else()
set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL ON)
endif()
endfunction()
# Declare an mlir library which can be compiled in libMLIR.so
# In addition to everything that llvm_add_library accepts, this
# also has the following option:
# EXCLUDE_FROM_LIBMLIR
# Don't include this library in libMLIR.so. This option should be used
# for test libraries, executable-specific libraries, or rarely used libraries
# with large dependencies.
# OBJECT
# The library's object library is referenced using "obj.${name}". For this to
# work reliably, this flag ensures that the OBJECT library exists.
# ENABLE_AGGREGATION
# Exports additional metadata,
# and installs additional object files needed to include this as part of an
# aggregate shared library.
# TODO: Make this the default for all MLIR libraries once all libraries
# are compatible with building an object library.
function(add_mlir_library name)
cmake_parse_arguments(ARG
"SHARED;INSTALL_WITH_TOOLCHAIN;EXCLUDE_FROM_LIBMLIR;DISABLE_INSTALL;ENABLE_AGGREGATION;OBJECT"
""
"ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS"
${ARGN})
_set_mlir_additional_headers_as_srcs(${ARG_ADDITIONAL_HEADERS})
# Determine type of library.
if(ARG_SHARED)
set(LIBTYPE SHARED)
else()
# llvm_add_library ignores BUILD_SHARED_LIBS if STATIC is explicitly set,
# so we need to handle it here.
if(BUILD_SHARED_LIBS)
set(LIBTYPE SHARED)
else()
set(LIBTYPE STATIC)
endif()
endif()
# Is an object library needed...?
# Note that the XCode generator doesn't handle object libraries correctly and
# usability is degraded in the Visual Studio solution generators.
# llvm_add_library may also itself decide to create an object library.
set(NEEDS_OBJECT_LIB OFF)
if(ARG_OBJECT)
# Yes, because the target "obj.${name}" is referenced.
set(NEEDS_OBJECT_LIB ON)
endif ()
if(LLVM_BUILD_LLVM_DYLIB AND NOT ARG_EXCLUDE_FROM_LIBMLIR AND NOT XCODE)
# Yes, because in addition to the shared library, the object files are
# needed for linking into libMLIR.so (see mlir/tools/mlir-shlib/CMakeLists.txt).
# For XCode, -force_load is used instead.
# Windows is not supported (LLVM_BUILD_LLVM_DYLIB=ON will cause an error).
set(NEEDS_OBJECT_LIB ON)
set_property(GLOBAL APPEND PROPERTY MLIR_STATIC_LIBS ${name})
set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${ARG_LINK_COMPONENTS})
set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS})
endif ()
if(ARG_ENABLE_AGGREGATION AND NOT XCODE)
# Yes, because this library is added to an aggergate library such as
# libMLIR-C.so which is links together all the object files.
# For XCode, -force_load is used instead.
set(NEEDS_OBJECT_LIB ON)
endif()
if (NOT ARG_SHARED AND NOT ARG_EXCLUDE_FROM_LIBMLIR AND NOT XCODE AND NOT MSVC_IDE)
# Yes, but only for legacy reasons. Also avoid object libraries for
# Visual Studio solutions.
set(NEEDS_OBJECT_LIB ON)
endif()
if(NEEDS_OBJECT_LIB)
list(APPEND LIBTYPE OBJECT)
endif()
# MLIR libraries uniformly depend on LLVMSupport. Just specify it once here.
list(APPEND ARG_LINK_COMPONENTS Support)
_check_llvm_components_usage(${name} ${ARG_LINK_LIBS})
list(APPEND ARG_DEPENDS mlir-generic-headers)
llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs} DEPENDS ${ARG_DEPENDS} LINK_COMPONENTS ${ARG_LINK_COMPONENTS} LINK_LIBS ${ARG_LINK_LIBS})
if(TARGET ${name})
target_link_libraries(${name} INTERFACE ${LLVM_COMMON_LIBS})
if(NOT ARG_DISABLE_INSTALL)
add_mlir_library_install(${name})
endif()
else()
# Add empty "phony" target
add_custom_target(${name})
endif()
set_target_properties(${name} PROPERTIES FOLDER "MLIR/Libraries")
# Setup aggregate.
if(ARG_ENABLE_AGGREGATION)
# Compute and store the properties needed to build aggregates.
set(AGGREGATE_OBJECTS)
set(AGGREGATE_OBJECT_LIB)
set(AGGREGATE_DEPS)
if(XCODE)
# XCode has limited support for object libraries. Instead, add dep flags
# that force the entire library to be embedded.
list(APPEND AGGREGATE_DEPS "-force_load" "${name}")
elseif(TARGET obj.${name})
# FIXME: *.obj can also be added via target_link_libraries since CMake 3.12.
list(APPEND AGGREGATE_OBJECTS "$<TARGET_OBJECTS:obj.${name}>")
list(APPEND AGGREGATE_OBJECT_LIB "obj.${name}")
else()
message(SEND_ERROR "Aggregate library not supported on this platform")
endif()
# For each declared dependency, transform it into a generator expression
# which excludes it if the ultimate link target is excluding the library.
set(NEW_LINK_LIBRARIES)
get_target_property(CURRENT_LINK_LIBRARIES ${name} LINK_LIBRARIES)
get_mlir_filtered_link_libraries(NEW_LINK_LIBRARIES ${CURRENT_LINK_LIBRARIES})
set_target_properties(${name} PROPERTIES LINK_LIBRARIES "${NEW_LINK_LIBRARIES}")
list(APPEND AGGREGATE_DEPS ${NEW_LINK_LIBRARIES})
set_target_properties(${name} PROPERTIES
EXPORT_PROPERTIES "MLIR_AGGREGATE_OBJECT_LIB_IMPORTED;MLIR_AGGREGATE_DEP_LIBS_IMPORTED"
MLIR_AGGREGATE_OBJECTS "${AGGREGATE_OBJECTS}"
MLIR_AGGREGATE_DEPS "${AGGREGATE_DEPS}"
MLIR_AGGREGATE_OBJECT_LIB_IMPORTED "${AGGREGATE_OBJECT_LIB}"
MLIR_AGGREGATE_DEP_LIBS_IMPORTED "${CURRENT_LINK_LIBRARIES}"
)
# In order for out-of-tree projects to build aggregates of this library,
# we need to install the OBJECT library.
if(TARGET "obj.${name}" AND MLIR_INSTALL_AGGREGATE_OBJECTS AND NOT ARG_DISABLE_INSTALL)
add_mlir_library_install(obj.${name})
endif()
endif()
endfunction(add_mlir_library)
macro(add_mlir_tool name)
llvm_add_tool(MLIR ${ARGV})
endmacro()
# Sets a variable with a transformed list of link libraries such individual
# libraries will be dynamically excluded when evaluated on a final library
# which defines an MLIR_AGGREGATE_EXCLUDE_LIBS which contains any of the
# libraries. Each link library can be a generator expression but must not
# resolve to an arity > 1 (i.e. it can be optional).
function(get_mlir_filtered_link_libraries output)
set(_results)
foreach(linklib ${ARGN})
# In English, what this expression does:
# For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
# on the context target (i.e. the executable or shared library being linked)
# and, if it is not in that list, emit the library name. Otherwise, empty.
list(APPEND _results
"$<$<NOT:$<IN_LIST:${linklib},$<GENEX_EVAL:$<TARGET_PROPERTY:MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${linklib}>"
)
endforeach()
set(${output} "${_results}" PARENT_SCOPE)
endfunction(get_mlir_filtered_link_libraries)
# Declares an aggregate library. Such a library is a combination of arbitrary
# regular add_mlir_library() libraries with the special feature that they can
# be configured to statically embed some subset of their dependencies, as is
# typical when creating a .so/.dylib/.dll or a mondo static library.
#
# It is always safe to depend on the aggregate directly in order to compile/link
# against the superset of embedded entities and transitive deps.
#
# Arguments:
# PUBLIC_LIBS: list of dependent libraries to add to the
# INTERFACE_LINK_LIBRARIES property, exporting them to users. This list
# will be transitively filtered to exclude any EMBED_LIBS.
# EMBED_LIBS: list of dependent libraries that should be embedded directly
# into this library. Each of these must be an add_mlir_library() library
# without DISABLE_AGGREGATE.
#
# Note: This is a work in progress and is presently only sufficient for certain
# non nested cases involving the C-API.
function(add_mlir_aggregate name)
cmake_parse_arguments(ARG
"SHARED;STATIC"
""
"PUBLIC_LIBS;EMBED_LIBS"
${ARGN})
set(_libtype)
if(ARG_STATIC)
list(APPEND _libtype STATIC)
endif()
if(ARG_SHARED)
list(APPEND _libtype SHARED)
endif()
set(_debugmsg)
set(_embed_libs)
set(_objects)
set(_deps)
foreach(lib ${ARG_EMBED_LIBS})
# We have to handle imported vs in-tree differently:
# in-tree: To support arbitrary ordering, the generator expressions get
# set on the dependent target when it is constructed and then just
# eval'd here. This means we can build an aggregate from targets that
# may not yet be defined, which is typical for in-tree.
# imported: Exported properties do not support generator expressions, so
# we imperatively query and manage the expansion here. This is fine
# because imported targets will always be found/configured first and
# do not need to support arbitrary ordering. If CMake every supports
# exporting generator expressions, then this can be simplified.
set(_is_imported OFF)
if(TARGET ${lib})
get_target_property(_is_imported ${lib} IMPORTED)
endif()
if(NOT _is_imported)
# Evaluate the in-tree generator expressions directly (this allows target
# order independence, since these aren't evaluated until the generate
# phase).
# What these expressions do:
# In the context of this aggregate, resolve the list of OBJECTS and DEPS
# that each library advertises and patch it into the whole.
set(_local_objects $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_OBJECTS>>)
set(_local_deps $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_DEPS>>)
else()
# It is an imported target, which can only have flat strings populated
# (no generator expressions).
# Rebuild the generator expressions from the imported flat string lists.
if(NOT MLIR_INSTALL_AGGREGATE_OBJECTS)
message(SEND_ERROR "Cannot build aggregate from imported targets which were not installed via MLIR_INSTALL_AGGREGATE_OBJECTS (for ${lib}).")
endif()
get_property(_has_object_lib_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_OBJECT_LIB_IMPORTED SET)
get_property(_has_dep_libs_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_DEP_LIBS_IMPORTED SET)
if(NOT _has_object_lib_prop OR NOT _has_dep_libs_prop)
message(SEND_ERROR "Cannot create an aggregate out of imported ${lib}: It is missing properties indicating that it was built for aggregation")
endif()
get_target_property(_imp_local_object_lib ${lib} MLIR_AGGREGATE_OBJECT_LIB_IMPORTED)
get_target_property(_imp_dep_libs ${lib} MLIR_AGGREGATE_DEP_LIBS_IMPORTED)
set(_local_objects)
if(_imp_local_object_lib)
set(_local_objects "$<TARGET_OBJECTS:${_imp_local_object_lib}>")
endif()
# We should just be able to do this:
# get_mlir_filtered_link_libraries(_local_deps ${_imp_dep_libs})
# However, CMake complains about the unqualified use of the one-arg
# $<TARGET_PROPERTY> expression. So we do the same thing but use the
# two-arg form which takes an explicit target.
foreach(_imp_dep_lib ${_imp_dep_libs})
# In English, what this expression does:
# For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
# on the context target (i.e. the executable or shared library being linked)
# and, if it is not in that list, emit the library name. Otherwise, empty.
list(APPEND _local_deps
"$<$<NOT:$<IN_LIST:${_imp_dep_lib},$<GENEX_EVAL:$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${_imp_dep_lib}>"
)
endforeach()
endif()
list(APPEND _embed_libs ${lib})
list(APPEND _objects ${_local_objects})
list(APPEND _deps ${_local_deps})
string(APPEND _debugmsg
": EMBED_LIB ${lib}:\n"
" OBJECTS = ${_local_objects}\n"
" DEPS = ${_local_deps}\n\n")
endforeach()
add_mlir_library(${name}
${_libtype}
${ARG_UNPARSED_ARGUMENTS}
PARTIAL_SOURCES_INTENDED
EXCLUDE_FROM_LIBMLIR
LINK_LIBS PRIVATE
${_deps}
${ARG_PUBLIC_LIBS}
)
target_sources(${name} PRIVATE ${_objects})
# Linux defaults to allowing undefined symbols in shared libraries whereas
# many other platforms are more strict. We want these libraries to be
# self contained, and we want any undefined symbols to be reported at
# library construction time, not at library use, so make Linux strict too.
# We make an exception for sanitizer builds, since the AddressSanitizer
# run-time doesn't get linked into shared libraries.
if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND (NOT LLVM_USE_SANITIZER))
target_link_options(${name} PRIVATE
"LINKER:-z,defs"
)
endif()
# TODO: Should be transitive.
set_target_properties(${name} PROPERTIES
MLIR_AGGREGATE_EXCLUDE_LIBS "${_embed_libs}")
if(MSVC)
set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# Debugging generator expressions can be hard. Uncomment the below to emit
# files next to the library with a lot of debug information:
# string(APPEND _debugmsg
# ": MAIN LIBRARY:\n"
# " OBJECTS = ${_objects}\n"
# " SOURCES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},SOURCES>>\n"
# " DEPS = ${_deps}\n"
# " LINK_LIBRARIES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},LINK_LIBRARIES>>\n"
# " MLIR_AGGREGATE_EXCLUDE_LIBS = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>\n"
# )
# file(GENERATE OUTPUT
# "${CMAKE_CURRENT_BINARY_DIR}/${name}.aggregate_debug.txt"
# CONTENT "${_debugmsg}"
# )
endfunction(add_mlir_aggregate)
# Adds an MLIR library target for installation.
# This is usually done as part of add_mlir_library but is broken out for cases
# where non-standard library builds can be installed.
function(add_mlir_library_install name)
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
get_target_export_arg(${name} MLIR export_to_mlirtargets UMBRELLA mlir-libraries)
install(TARGETS ${name}
COMPONENT ${name}
${export_to_mlirtargets}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
# Note that CMake will create a directory like:
# objects-${CMAKE_BUILD_TYPE}/obj.LibName
# and put object files there.
OBJECTS DESTINATION lib${LLVM_LIBDIR_SUFFIX}
)
if (NOT LLVM_ENABLE_IDE)
add_llvm_install_targets(install-${name}
DEPENDS ${name}
COMPONENT ${name})
endif()
set_property(GLOBAL APPEND PROPERTY MLIR_ALL_LIBS ${name})
endif()
set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
endfunction()
# Declare an mlir library which is part of the public C-API.
function(add_mlir_public_c_api_library name)
add_mlir_library(${name}
${ARGN}
OBJECT
EXCLUDE_FROM_LIBMLIR
ENABLE_AGGREGATION
ADDITIONAL_HEADER_DIRS
${MLIR_MAIN_INCLUDE_DIR}/mlir-c
)
# API libraries compile with hidden visibility and macros that enable
# exporting from the DLL. Only apply to the obj lib, which only affects
# the exports via a shared library.
set_target_properties(obj.${name}
PROPERTIES
CXX_VISIBILITY_PRESET hidden
)
target_compile_definitions(obj.${name}
PRIVATE
-DMLIR_CAPI_BUILDING_LIBRARY=1
)
endfunction()
# Declare the library associated with a dialect.
function(add_mlir_dialect_library name)
set_property(GLOBAL APPEND PROPERTY MLIR_DIALECT_LIBS ${name})
add_mlir_library(${ARGV} DEPENDS mlir-headers)
endfunction(add_mlir_dialect_library)
# Declare the library associated with a conversion.
function(add_mlir_conversion_library name)
set_property(GLOBAL APPEND PROPERTY MLIR_CONVERSION_LIBS ${name})
add_mlir_library(${ARGV} DEPENDS mlir-headers)
endfunction(add_mlir_conversion_library)
# Declare the library associated with an extension.
function(add_mlir_extension_library name)
set_property(GLOBAL APPEND PROPERTY MLIR_EXTENSION_LIBS ${name})
add_mlir_library(${ARGV} DEPENDS mlir-headers)
endfunction(add_mlir_extension_library)
# Declare the library associated with a translation.
function(add_mlir_translation_library name)
set_property(GLOBAL APPEND PROPERTY MLIR_TRANSLATION_LIBS ${name})
add_mlir_library(${ARGV} DEPENDS mlir-headers)
endfunction(add_mlir_translation_library)
# Verification tools to aid debugging.
function(mlir_check_link_libraries name)
if(TARGET ${name})
get_target_property(type ${name} TYPE)
if (${type} STREQUAL "INTERFACE_LIBRARY")
get_target_property(libs ${name} INTERFACE_LINK_LIBRARIES)
else()
get_target_property(libs ${name} LINK_LIBRARIES)
endif()
# message("${name} libs are: ${libs}")
set(linking_llvm 0)
foreach(lib ${libs})
if(lib)
if(${lib} MATCHES "^LLVM$")
set(linking_llvm 1)
endif()
if((${lib} MATCHES "^LLVM.+") AND ${linking_llvm})
# This will almost always cause execution problems, since the
# same symbol might be loaded from 2 separate libraries. This
# often comes from referring to an LLVM library target
# explicitly in target_link_libraries()
message("WARNING: ${name} links LLVM and ${lib}!")
endif()
endif()
endforeach()
endif()
endfunction(mlir_check_link_libraries)
function(mlir_check_all_link_libraries name)
mlir_check_link_libraries(${name})
if(TARGET ${name})
get_target_property(libs ${name} LINK_LIBRARIES)
# message("${name} libs are: ${libs}")
foreach(lib ${libs})
mlir_check_link_libraries(${lib})
endforeach()
endif()
endfunction(mlir_check_all_link_libraries)