1################################################################################ 2# Build python extension 3################################################################################ 4function(add_mlir_python_extension libname extname) 5 cmake_parse_arguments(ARG 6 "" 7 "INSTALL_DIR" 8 "SOURCES;LINK_LIBS" 9 ${ARGN}) 10 if (ARG_UNPARSED_ARGUMENTS) 11 message(FATAL_ERROR " Unhandled arguments to add_mlir_python_extension(${libname}, ... : ${ARG_UNPARSED_ARGUMENTS}") 12 endif() 13 if ("${ARG_SOURCES}" STREQUAL "") 14 message(FATAL_ERROR " Missing SOURCES argument to add_mlir_python_extension(${libname}, ...") 15 endif() 16 17 # Normally on unix-like platforms, extensions are built as "MODULE" libraries 18 # and do not explicitly link to the python shared object. This allows for 19 # some greater deployment flexibility since the extension will bind to 20 # symbols in the python interpreter on load. However, it also keeps the 21 # linker from erroring on undefined symbols, leaving this to (usually obtuse) 22 # runtime errors. Building in "SHARED" mode with an explicit link to the 23 # python libraries allows us to build with the expectation of no undefined 24 # symbols, which is better for development. Note that not all python 25 # configurations provide build-time libraries to link against, in which 26 # case, we fall back to MODULE linking. 27 if(Python3_LIBRARIES STREQUAL "" OR NOT MLIR_BINDINGS_PYTHON_LOCK_VERSION) 28 set(PYEXT_LINK_MODE MODULE) 29 set(PYEXT_LIBADD) 30 else() 31 set(PYEXT_LINK_MODE SHARED) 32 set(PYEXT_LIBADD ${Python3_LIBRARIES}) 33 endif() 34 35 # The actual extension library produces a shared-object or DLL and has 36 # sources that must be compiled in accordance with pybind11 needs (RTTI and 37 # exceptions). 38 add_library(${libname} ${PYEXT_LINK_MODE} 39 ${ARG_SOURCES} 40 ) 41 42 target_include_directories(${libname} PRIVATE 43 "${Python3_INCLUDE_DIRS}" 44 "${pybind11_INCLUDE_DIR}" 45 ) 46 47 target_link_directories(${libname} PRIVATE 48 "${Python3_LIBRARY_DIRS}" 49 ) 50 51 # The extension itself must be compiled with RTTI and exceptions enabled. 52 # Also, some warning classes triggered by pybind11 are disabled. 53 target_compile_options(${libname} PRIVATE 54 $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: 55 # Enable RTTI and exceptions. 56 -frtti -fexceptions 57 # Noisy pybind warnings 58 -Wno-unused-value 59 -Wno-covered-switch-default 60 > 61 $<$<CXX_COMPILER_ID:MSVC>: 62 # Enable RTTI and exceptions. 63 /EHsc /GR> 64 ) 65 66 # Configure the output to match python expectations. 67 set_target_properties( 68 ${libname} PROPERTIES 69 # Build-time RPath layouts require to be a directory one up from the 70 # binary root. 71 # TODO: Don't reference the LLVM_BINARY_DIR here: the invariant is that 72 # the output directory must be at the same level of the lib directory 73 # where libMLIR.so is installed. This is presently not optimal from a 74 # project separation perspective and a discussion on how to better 75 # segment MLIR libraries needs to happen. 76 LIBRARY_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/python 77 OUTPUT_NAME "${extname}" 78 PREFIX "${PYTHON_MODULE_PREFIX}" 79 SUFFIX "${PYTHON_MODULE_SUFFIX}${PYTHON_MODULE_EXTENSION}" 80 ) 81 82 if(WIN32) 83 # Need to also set the RUNTIME_OUTPUT_DIRECTORY on Windows in order to 84 # control where the .dll gets written. 85 set_target_properties( 86 ${libname} PROPERTIES 87 RUNTIME_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/python 88 ) 89 endif() 90 91 # pybind11 requires binding code to be compiled with -fvisibility=hidden 92 # For static linkage, better code can be generated if the entire project 93 # compiles that way, but that is not enforced here. Instead, include a linker 94 # script that explicitly hides anything but the PyInit_* symbols, allowing gc 95 # to take place. 96 set_target_properties(${libname} PROPERTIES CXX_VISIBILITY_PRESET "hidden") 97 98 # Python extensions depends *only* on the public API and LLVMSupport unless 99 # if further dependencies are added explicitly. 100 target_link_libraries(${libname} 101 PRIVATE 102 MLIRPublicAPI 103 LLVMSupport 104 ${ARG_LINK_LIBS} 105 ${PYEXT_LIBADD} 106 ) 107 108 target_link_options(${libname} 109 PRIVATE 110 # On Linux, disable re-export of any static linked libraries that 111 # came through. 112 $<$<PLATFORM_ID:Linux>:LINKER:--exclude-libs,ALL> 113 ) 114 115 llvm_setup_rpath(${libname}) 116 117 ################################################################################ 118 # Install 119 ################################################################################ 120 if (ARG_INSTALL_DIR) 121 install(TARGETS ${libname} 122 COMPONENT ${libname} 123 LIBRARY DESTINATION ${ARG_INSTALL_DIR} 124 ARCHIVE DESTINATION ${ARG_INSTALL_DIR} 125 # NOTE: Even on DLL-platforms, extensions go in the lib directory tree. 126 RUNTIME DESTINATION ${ARG_INSTALL_DIR} 127 ) 128 endif() 129 130 if (NOT LLVM_ENABLE_IDE) 131 add_llvm_install_targets( 132 install-${libname} 133 DEPENDS ${libname} 134 COMPONENT ${libname}) 135 endif() 136 137endfunction() 138 139function(add_mlir_dialect_python_bindings tblgen_target) 140 cmake_parse_arguments(ARG 141 "" 142 "TD_FILE;DIALECT_NAME" 143 "DEPENDS" 144 ${ARGN}) 145 146 set(dialect_filename "_${ARG_DIALECT_NAME}_ops_gen.py") 147 set(LLVM_TARGET_DEFINITIONS ${ARG_TD_FILE}) 148 mlir_tablegen("${dialect_filename}" -gen-python-op-bindings 149 -bind-dialect=${ARG_DIALECT_NAME}) 150 add_public_tablegen_target( 151 ${tblgen_target}) 152 if(ARG_DEPENDS) 153 add_dependencies(${tblgen_target} ${ARG_DEPENDS}) 154 endif() 155 156 add_custom_command( 157 TARGET ${tblgen_target} POST_BUILD 158 COMMENT "Copying generated python source \"dialects/${dialect_filename}\"" 159 BYPRODUCTS "${PROJECT_BINARY_DIR}/python/mlir/dialects/${dialect_filename}" 160 COMMAND "${CMAKE_COMMAND}" -E copy_if_different 161 "${CMAKE_CURRENT_BINARY_DIR}/${dialect_filename}" 162 "${PROJECT_BINARY_DIR}/python/mlir/dialects/${dialect_filename}") 163endfunction() 164 165