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} 39 ${PYEXT_LINK_MODE} 40 ${ARG_SOURCES} 41 ) 42 43 target_include_directories(${libname} PRIVATE 44 "${Python3_INCLUDE_DIRS}" 45 "${pybind11_INCLUDE_DIR}" 46 ) 47 48 target_link_directories(${libname} PRIVATE 49 "${Python3_LIBRARY_DIRS}" 50 ) 51 52 # The extension itself must be compiled with RTTI and exceptions enabled. 53 # Also, some warning classes triggered by pybind11 are disabled. 54 target_compile_options(${libname} PRIVATE 55 $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: 56 # Enable RTTI and exceptions. 57 -frtti -fexceptions 58 # Noisy pybind warnings 59 -Wno-unused-value 60 -Wno-covered-switch-default 61 > 62 $<$<CXX_COMPILER_ID:MSVC>: 63 # Enable RTTI and exceptions. 64 /EHsc /GR> 65 ) 66 67 # Configure the output to match python expectations. 68 set_target_properties( 69 ${libname} PROPERTIES 70 # Build-time RPath layouts require to be a directory one up from the 71 # binary root. 72 # TODO: Don't reference the LLVM_BINARY_DIR here: the invariant is that 73 # the output directory must be at the same level of the lib directory 74 # where libMLIR.so is installed. This is presently not optimal from a 75 # project separation perspective and a discussion on how to better 76 # segment MLIR libraries needs to happen. 77 LIBRARY_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/python 78 OUTPUT_NAME "${extname}" 79 PREFIX "${PYTHON_MODULE_PREFIX}" 80 SUFFIX "${PYTHON_MODULE_SUFFIX}${PYTHON_MODULE_EXTENSION}" 81 ) 82 83 if(WIN32) 84 # Need to also set the RUNTIME_OUTPUT_DIRECTORY on Windows in order to 85 # control where the .dll gets written. 86 set_target_properties( 87 ${libname} PROPERTIES 88 RUNTIME_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/python 89 ) 90 endif() 91 92 # pybind11 requires binding code to be compiled with -fvisibility=hidden 93 # For static linkage, better code can be generated if the entire project 94 # compiles that way, but that is not enforced here. Instead, include a linker 95 # script that explicitly hides anything but the PyInit_* symbols, allowing gc 96 # to take place. 97 set_target_properties(${libname} PROPERTIES CXX_VISIBILITY_PRESET "hidden") 98 99 # Python extensions depends *only* on the public API and LLVMSupport unless 100 # if further dependencies are added explicitly. 101 target_link_libraries(${libname} 102 PRIVATE 103 ${ARG_LINK_LIBS} 104 ${PYEXT_LIBADD} 105 ) 106 107 target_link_options(${libname} 108 PRIVATE 109 # On Linux, disable re-export of any static linked libraries that 110 # came through. 111 $<$<PLATFORM_ID:Linux>:LINKER:--exclude-libs,ALL> 112 ) 113 114 llvm_setup_rpath(${libname}) 115 116 ################################################################################ 117 # Install 118 ################################################################################ 119 if (ARG_INSTALL_DIR) 120 install(TARGETS ${libname} 121 COMPONENT ${libname} 122 LIBRARY DESTINATION ${ARG_INSTALL_DIR} 123 ARCHIVE DESTINATION ${ARG_INSTALL_DIR} 124 # NOTE: Even on DLL-platforms, extensions go in the lib directory tree. 125 RUNTIME DESTINATION ${ARG_INSTALL_DIR} 126 ) 127 endif() 128 129 if (NOT LLVM_ENABLE_IDE) 130 add_llvm_install_targets( 131 install-${libname} 132 DEPENDS ${libname} 133 COMPONENT ${libname}) 134 endif() 135 136endfunction() 137 138function(add_mlir_dialect_python_bindings tblgen_target) 139 cmake_parse_arguments(ARG 140 "" 141 "TD_FILE;DIALECT_NAME" 142 "DEPENDS" 143 ${ARGN}) 144 145 set(dialect_filename "_${ARG_DIALECT_NAME}_ops_gen.py") 146 set(LLVM_TARGET_DEFINITIONS ${ARG_TD_FILE}) 147 mlir_tablegen("${dialect_filename}" -gen-python-op-bindings 148 -bind-dialect=${ARG_DIALECT_NAME}) 149 add_public_tablegen_target( 150 ${tblgen_target}) 151 if(ARG_DEPENDS) 152 add_dependencies(${tblgen_target} ${ARG_DEPENDS}) 153 endif() 154 155 add_custom_command( 156 TARGET ${tblgen_target} POST_BUILD 157 COMMENT "Copying generated python source \"dialects/${dialect_filename}\"" 158 BYPRODUCTS "${PROJECT_BINARY_DIR}/python/mlir/dialects/${dialect_filename}" 159 COMMAND "${CMAKE_COMMAND}" -E copy_if_different 160 "${CMAKE_CURRENT_BINARY_DIR}/${dialect_filename}" 161 "${PROJECT_BINARY_DIR}/python/mlir/dialects/${dialect_filename}") 162endfunction() 163 164