1 ################################################################################
3 # MLIR's Python modules are both directly used by the core project and are
4 # available for use and embedding into external projects (in their own
5 # namespace and with their own deps). In order to facilitate this, python
6 # artifacts are split between declarations, which make a subset of
7 # things available to be built and "add", which in line with the normal LLVM
8 # nomenclature, adds libraries.
9 ################################################################################
11 # Function: declare_mlir_python_sources
12 # Declares pure python sources as part of a named grouping that can be built
15 # ROOT_DIR: Directory where the python namespace begins (defaults to
16 # CMAKE_CURRENT_SOURCE_DIR). For non-relocatable sources, this will
17 # typically just be the root of the python source tree (current directory).
18 # For relocatable sources, this will point deeper into the directory that
19 # can be relocated. For generated sources, can be relative to
20 # CMAKE_CURRENT_BINARY_DIR. Generated and non generated sources cannot be
22 # ADD_TO_PARENT: Adds this source grouping to a previously declared source
23 # grouping. Source groupings form a DAG.
24 # SOURCES: List of specific source files relative to ROOT_DIR to include.
25 # SOURCES_GLOB: List of glob patterns relative to ROOT_DIR to include.
26 function(declare_mlir_python_sources name)
27 cmake_parse_arguments(ARG
29 "ROOT_DIR;ADD_TO_PARENT"
30 "SOURCES;SOURCES_GLOB"
34 set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
36 set(_install_destination "src/python/${name}")
41 set(_glob_spec ${ARG_SOURCES_GLOB})
42 list(TRANSFORM _glob_spec PREPEND "${ARG_ROOT_DIR}/")
43 file(GLOB_RECURSE _glob_sources
44 RELATIVE "${ARG_ROOT_DIR}"
47 list(APPEND ARG_SOURCES ${_glob_sources})
50 # We create a custom target to carry properties and dependencies for
52 add_library(${name} INTERFACE)
53 set_target_properties(${name} PROPERTIES
54 # Yes: Leading-lowercase property names are load bearing and the recommended
55 # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
56 EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_DEPENDS"
57 mlir_python_SOURCES_TYPE pure
58 mlir_python_DEPENDS ""
61 # Use the interface include directories and sources on the target to carry the
62 # properties we would like to export. These support generator expressions and
63 # allow us to properly specify paths in both the local build and install scenarios.
64 # The one caveat here is that because we don't directly build against the interface
65 # library, we need to specify the INCLUDE_DIRECTORIES and SOURCES properties as well
66 # via private properties because the evaluation would happen at configuration time
67 # instead of build time.
68 # Eventually this could be done using a FILE_SET simplifying the logic below.
69 # FILE_SET is available in cmake 3.23+, so it is not an option at the moment.
70 target_include_directories(${name} INTERFACE
71 "$<BUILD_INTERFACE:${ARG_ROOT_DIR}>"
72 "$<INSTALL_INTERFACE:${_install_destination}>"
74 set_property(TARGET ${name} PROPERTY INCLUDE_DIRECTORIES ${ARG_ROOT_DIR})
77 list(TRANSFORM ARG_SOURCES PREPEND "${ARG_ROOT_DIR}/" OUTPUT_VARIABLE _build_sources)
78 list(TRANSFORM ARG_SOURCES PREPEND "${_install_destination}/" OUTPUT_VARIABLE _install_sources)
79 target_sources(${name}
81 "$<INSTALL_INTERFACE:${_install_sources}>"
82 "$<BUILD_INTERFACE:${_build_sources}>"
83 PRIVATE ${_build_sources}
89 set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
93 set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
94 if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
95 _mlir_python_install_sources(
96 ${name} "${ARG_ROOT_DIR}" "${_install_destination}"
102 # Function: declare_mlir_python_extension
103 # Declares a buildable python extension from C++ source files. The built
104 # module is considered a python source file and included as everything else.
106 # ROOT_DIR: Root directory where sources are interpreted relative to.
107 # Defaults to CMAKE_CURRENT_SOURCE_DIR.
108 # MODULE_NAME: Local import name of the module (i.e. "_mlir").
109 # ADD_TO_PARENT: Same as for declare_mlir_python_sources.
110 # SOURCES: C++ sources making up the module.
111 # PRIVATE_LINK_LIBS: List of libraries to link in privately to the module
112 # regardless of how it is included in the project (generally should be
113 # static libraries that can be included with hidden visibility).
114 # EMBED_CAPI_LINK_LIBS: Dependent CAPI libraries that this extension depends
115 # on. These will be collected for all extensions and put into an
116 # aggregate dylib that is linked against.
117 function(declare_mlir_python_extension name)
118 cmake_parse_arguments(ARG
120 "ROOT_DIR;MODULE_NAME;ADD_TO_PARENT"
121 "SOURCES;PRIVATE_LINK_LIBS;EMBED_CAPI_LINK_LIBS"
125 set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
127 set(_install_destination "src/python/${name}")
129 add_library(${name} INTERFACE)
130 set_target_properties(${name} PROPERTIES
131 # Yes: Leading-lowercase property names are load bearing and the recommended
132 # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
133 EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS"
134 mlir_python_SOURCES_TYPE extension
135 mlir_python_EXTENSION_MODULE_NAME "${ARG_MODULE_NAME}"
136 mlir_python_EMBED_CAPI_LINK_LIBS "${ARG_EMBED_CAPI_LINK_LIBS}"
137 mlir_python_DEPENDS ""
140 # Set the interface source and link_libs properties of the target
141 # These properties support generator expressions and are automatically exported
142 list(TRANSFORM ARG_SOURCES PREPEND "${ARG_ROOT_DIR}/" OUTPUT_VARIABLE _build_sources)
143 list(TRANSFORM ARG_SOURCES PREPEND "${_install_destination}/" OUTPUT_VARIABLE _install_sources)
144 target_sources(${name} INTERFACE
145 "$<BUILD_INTERFACE:${_build_sources}>"
146 "$<INSTALL_INTERFACE:${_install_sources}>"
148 target_link_libraries(${name} INTERFACE
149 ${ARG_PRIVATE_LINK_LIBS}
153 if(ARG_ADD_TO_PARENT)
154 set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
158 set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
159 if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
160 _mlir_python_install_sources(
161 ${name} "${ARG_ROOT_DIR}" "${_install_destination}"
167 function(_mlir_python_install_sources name source_root_dir destination)
168 foreach(source_relative_path ${ARGN})
169 # Transform "a/b/c.py" -> "${install_prefix}/a/b" for installation.
170 get_filename_component(
171 dest_relative_dir "${source_relative_path}" DIRECTORY
172 BASE_DIR "${source_root_dir}"
175 FILES "${source_root_dir}/${source_relative_path}"
176 DESTINATION "${destination}/${dest_relative_dir}"
180 get_target_export_arg(${name} MLIR export_to_mlirtargets UMBRELLA mlir-libraries)
181 install(TARGETS ${name}
183 ${export_to_mlirtargets}
187 # Function: add_mlir_python_modules
188 # Adds python modules to a project, building them from a list of declared
189 # source groupings (see declare_mlir_python_sources and
190 # declare_mlir_python_extension). One of these must be called for each
191 # packaging root in use.
193 # ROOT_PREFIX: The directory in the build tree to emit sources. This will
194 # typically be something like ${MY_BINARY_DIR}/python_packages/foobar
195 # for non-relocatable modules or a deeper directory tree for relocatable.
196 # INSTALL_PREFIX: Prefix into the install tree for installing the package.
197 # Typically mirrors the path above but without an absolute path.
198 # DECLARED_SOURCES: List of declared source groups to include. The entire
199 # DAG of source modules is included.
200 # COMMON_CAPI_LINK_LIBS: List of dylibs (typically one) to make every
201 # extension depend on (see mlir_python_add_common_capi_library).
202 function(add_mlir_python_modules name)
203 cmake_parse_arguments(ARG
205 "ROOT_PREFIX;INSTALL_PREFIX;COMMON_CAPI_LINK_LIBS"
208 # Helper to process an individual target.
209 function(_process_target modules_target sources_target)
210 get_target_property(_source_type ${sources_target} mlir_python_SOURCES_TYPE)
212 if(_source_type STREQUAL "pure")
213 # Pure python sources to link into the tree.
214 set(_pure_sources_target "${modules_target}.sources.${sources_target}")
215 add_mlir_python_sources_target(${_pure_sources_target}
216 INSTALL_COMPONENT ${modules_target}
217 INSTALL_DIR ${ARG_INSTALL_PREFIX}
218 OUTPUT_DIRECTORY ${ARG_ROOT_PREFIX}
219 SOURCES_TARGETS ${sources_target}
221 add_dependencies(${modules_target} ${_pure_sources_target})
222 elseif(_source_type STREQUAL "extension")
223 # Native CPP extension.
224 get_target_property(_module_name ${sources_target} mlir_python_EXTENSION_MODULE_NAME)
225 # Transform relative source to based on root dir.
226 set(_extension_target "${modules_target}.extension.${_module_name}.dso")
227 add_mlir_python_extension(${_extension_target} "${_module_name}"
228 INSTALL_COMPONENT ${modules_target}
229 INSTALL_DIR "${ARG_INSTALL_PREFIX}/_mlir_libs"
230 OUTPUT_DIRECTORY "${ARG_ROOT_PREFIX}/_mlir_libs"
233 ${ARG_COMMON_CAPI_LINK_LIBS}
235 add_dependencies(${modules_target} ${_extension_target})
236 mlir_python_setup_extension_rpath(${_extension_target})
238 message(SEND_ERROR "Unrecognized source type '${_source_type}' for python source target ${sources_target}")
243 # Build the modules target.
244 add_custom_target(${name} ALL)
245 _flatten_mlir_python_targets(_flat_targets ${ARG_DECLARED_SOURCES})
246 foreach(sources_target ${_flat_targets})
247 _process_target(${name} ${sources_target})
250 # Create an install target.
251 if(NOT LLVM_ENABLE_IDE)
252 add_llvm_install_targets(
259 # Function: declare_mlir_dialect_python_bindings
260 # Helper to generate source groups for dialects, including both static source
261 # files and a TD_FILE to generate wrappers.
263 # This will generate a source group named ${ADD_TO_PARENT}.${DIALECT_NAME}.
266 # ROOT_DIR: Same as for declare_mlir_python_sources().
267 # ADD_TO_PARENT: Same as for declare_mlir_python_sources(). Unique names
268 # for the subordinate source groups are derived from this.
269 # TD_FILE: Tablegen file to generate source for (relative to ROOT_DIR).
270 # DIALECT_NAME: Python name of the dialect.
271 # SOURCES: Same as declare_mlir_python_sources().
272 # SOURCES_GLOB: Same as declare_mlir_python_sources().
273 # DEPENDS: Additional dependency targets.
274 function(declare_mlir_dialect_python_bindings)
275 cmake_parse_arguments(ARG
277 "ROOT_DIR;ADD_TO_PARENT;TD_FILE;DIALECT_NAME"
278 "SOURCES;SOURCES_GLOB;DEPENDS"
281 set(_dialect_target "${ARG_ADD_TO_PARENT}.${ARG_DIALECT_NAME}")
282 declare_mlir_python_sources(${_dialect_target}
283 ROOT_DIR "${ARG_ROOT_DIR}"
284 ADD_TO_PARENT "${ARG_ADD_TO_PARENT}"
285 SOURCES "${ARG_SOURCES}"
286 SOURCES_GLOB "${ARG_SOURCES_GLOB}"
291 set(tblgen_target "${_dialect_target}.tablegen")
292 set(td_file "${ARG_ROOT_DIR}/${ARG_TD_FILE}")
293 get_filename_component(relative_td_directory "${ARG_TD_FILE}" DIRECTORY)
294 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${relative_td_directory}")
295 set(dialect_filename "${relative_td_directory}/_${ARG_DIALECT_NAME}_ops_gen.py")
296 set(LLVM_TARGET_DEFINITIONS ${td_file})
297 mlir_tablegen("${dialect_filename}"
298 -gen-python-op-bindings -bind-dialect=${ARG_DIALECT_NAME}
299 DEPENDS ${ARG_DEPENDS}
301 add_public_tablegen_target(${tblgen_target})
304 declare_mlir_python_sources("${_dialect_target}.ops_gen"
305 ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
306 ADD_TO_PARENT "${_dialect_target}"
307 SOURCES "${dialect_filename}"
312 # Function: declare_mlir_dialect_extension_python_bindings
313 # Helper to generate source groups for dialect extensions, including both
314 # static source files and a TD_FILE to generate wrappers.
316 # This will generate a source group named ${ADD_TO_PARENT}.${EXTENSION_NAME}.
319 # ROOT_DIR: Same as for declare_mlir_python_sources().
320 # ADD_TO_PARENT: Same as for declare_mlir_python_sources(). Unique names
321 # for the subordinate source groups are derived from this.
322 # TD_FILE: Tablegen file to generate source for (relative to ROOT_DIR).
323 # DIALECT_NAME: Python name of the dialect.
324 # EXTENSION_NAME: Python name of the dialect extension.
325 # SOURCES: Same as declare_mlir_python_sources().
326 # SOURCES_GLOB: Same as declare_mlir_python_sources().
327 # DEPENDS: Additional dependency targets.
328 function(declare_mlir_dialect_extension_python_bindings)
329 cmake_parse_arguments(ARG
331 "ROOT_DIR;ADD_TO_PARENT;TD_FILE;DIALECT_NAME;EXTENSION_NAME"
332 "SOURCES;SOURCES_GLOB;DEPENDS"
335 set(_extension_target "${ARG_ADD_TO_PARENT}.${ARG_EXTENSION_NAME}")
336 declare_mlir_python_sources(${_extension_target}
337 ROOT_DIR "${ARG_ROOT_DIR}"
338 ADD_TO_PARENT "${ARG_ADD_TO_PARENT}"
339 SOURCES "${ARG_SOURCES}"
340 SOURCES_GLOB "${ARG_SOURCES_GLOB}"
345 set(tblgen_target "${ARG_ADD_TO_PARENT}.${ARG_EXTENSION_NAME}.tablegen")
346 set(td_file "${ARG_ROOT_DIR}/${ARG_TD_FILE}")
347 get_filename_component(relative_td_directory "${ARG_TD_FILE}" DIRECTORY)
348 file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${relative_td_directory}")
349 set(output_filename "${relative_td_directory}/_${ARG_EXTENSION_NAME}_ops_gen.py")
350 set(LLVM_TARGET_DEFINITIONS ${td_file})
351 mlir_tablegen("${output_filename}" -gen-python-op-bindings
352 -bind-dialect=${ARG_DIALECT_NAME}
353 -dialect-extension=${ARG_EXTENSION_NAME})
354 add_public_tablegen_target(${tblgen_target})
356 add_dependencies(${tblgen_target} ${ARG_DEPENDS})
359 declare_mlir_python_sources("${_extension_target}.ops_gen"
360 ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
361 ADD_TO_PARENT "${_extension_target}"
362 SOURCES "${output_filename}"
367 # Function: mlir_python_setup_extension_rpath
368 # Sets RPATH properties on a target, assuming that it is being output to
369 # an _mlir_libs directory with all other libraries. For static linkage,
370 # the RPATH will just be the origin. If linking dynamically, then the LLVM
371 # library directory will be added.
373 # RELATIVE_INSTALL_ROOT: If building dynamically, an RPATH entry will be
374 # added to the install tree lib/ directory by first traversing this
375 # path relative to the installation location. Typically a number of ".."
376 # entries, one for each level of the install path.
377 function(mlir_python_setup_extension_rpath target)
378 cmake_parse_arguments(ARG
380 "RELATIVE_INSTALL_ROOT"
385 # For the build tree, include the LLVM lib directory and the current
386 # directory for RPATH searching. For install, just the current directory
387 # (assumes that needed dependencies have been installed).
388 if(NOT APPLE AND NOT UNIX)
392 set(_origin_prefix "\$ORIGIN")
394 set(_origin_prefix "@loader_path")
396 set_target_properties(${target} PROPERTIES
397 BUILD_WITH_INSTALL_RPATH OFF
398 BUILD_RPATH "${_origin_prefix}"
399 INSTALL_RPATH "${_origin_prefix}"
402 # For static builds, that is all that is needed: all dependencies will be in
403 # the one directory. For shared builds, then we also need to add the global
404 # lib directory. This will be absolute for the build tree and relative for
406 # When we have access to CMake >= 3.20, there is a helper to calculate this.
407 if(BUILD_SHARED_LIBS AND ARG_RELATIVE_INSTALL_ROOT)
408 get_filename_component(_real_lib_dir "${LLVM_LIBRARY_OUTPUT_INTDIR}" REALPATH)
409 set_property(TARGET ${target} APPEND PROPERTY
410 BUILD_RPATH "${_real_lib_dir}")
411 set_property(TARGET ${target} APPEND PROPERTY
412 INSTALL_RPATH "${_origin_prefix}/${ARG_RELATIVE_INSTALL_ROOT}/lib${LLVM_LIBDIR_SUFFIX}")
416 # Function: add_mlir_python_common_capi_library
417 # Adds a shared library which embeds dependent CAPI libraries needed to link
420 # INSTALL_COMPONENT: Name of the install component. Typically same as the
421 # target name passed to add_mlir_python_modules().
422 # INSTALL_DESTINATION: Prefix into the install tree in which to install the
424 # OUTPUT_DIRECTORY: Full path in the build tree in which to create the
425 # library. Typically, this will be the common _mlir_libs directory where
426 # all extensions are emitted.
427 # RELATIVE_INSTALL_ROOT: See mlir_python_setup_extension_rpath().
428 # DECLARED_HEADERS: Source groups from which to discover headers that belong
429 # to the library and should be installed with it.
430 # DECLARED_SOURCES: Source groups from which to discover dependent
431 # EMBED_CAPI_LINK_LIBS.
432 # EMBED_LIBS: Additional libraries to embed (must be built with OBJECTS and
433 # have an "obj.${name}" object library associated).
434 function(add_mlir_python_common_capi_library name)
435 cmake_parse_arguments(ARG
437 "INSTALL_COMPONENT;INSTALL_DESTINATION;OUTPUT_DIRECTORY;RELATIVE_INSTALL_ROOT"
438 "DECLARED_HEADERS;DECLARED_SOURCES;EMBED_LIBS"
440 # Collect all explicit and transitive embed libs.
441 set(_embed_libs ${ARG_EMBED_LIBS})
442 _flatten_mlir_python_targets(_all_source_targets ${ARG_DECLARED_SOURCES})
443 foreach(t ${_all_source_targets})
444 get_target_property(_local_embed_libs ${t} mlir_python_EMBED_CAPI_LINK_LIBS)
445 if(_local_embed_libs)
446 list(APPEND _embed_libs ${_local_embed_libs})
449 list(REMOVE_DUPLICATES _embed_libs)
451 # Generate the aggregate .so that everything depends on.
452 add_mlir_aggregate(${name}
455 EMBED_LIBS ${_embed_libs}
458 # Process any headers associated with the library
459 _flatten_mlir_python_targets(_flat_header_targets ${ARG_DECLARED_HEADERS})
460 set(_header_sources_target "${name}.sources")
461 add_mlir_python_sources_target(${_header_sources_target}
462 INSTALL_COMPONENT ${ARG_INSTALL_COMPONENT}
463 INSTALL_DIR "${ARG_INSTALL_DESTINATION}/include"
464 OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}/include"
465 SOURCES_TARGETS ${_flat_header_targets}
467 add_dependencies(${name} ${_header_sources_target})
470 set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
472 set_target_properties(${name} PROPERTIES
473 LIBRARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
474 BINARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
475 # Needed for windows (and don't hurt others).
476 RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
477 ARCHIVE_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
479 mlir_python_setup_extension_rpath(${name}
480 RELATIVE_INSTALL_ROOT "${ARG_RELATIVE_INSTALL_ROOT}"
482 install(TARGETS ${name}
483 COMPONENT ${ARG_INSTALL_COMPONENT}
484 LIBRARY DESTINATION "${ARG_INSTALL_DESTINATION}"
485 RUNTIME DESTINATION "${ARG_INSTALL_DESTINATION}"
489 function(_flatten_mlir_python_targets output_var)
492 get_target_property(_source_type ${t} mlir_python_SOURCES_TYPE)
493 get_target_property(_depends ${t} mlir_python_DEPENDS)
495 list(APPEND _flattened "${t}")
497 _flatten_mlir_python_targets(_local_flattened ${_depends})
498 list(APPEND _flattened ${_local_flattened})
502 list(REMOVE_DUPLICATES _flattened)
503 set(${output_var} "${_flattened}" PARENT_SCOPE)
506 # Function: add_mlir_python_sources_target
507 # Adds a target corresponding to an interface target that carries source
508 # information. This target is responsible for "building" the sources by
509 # placing them in the correct locations in the build and install trees.
511 # INSTALL_COMPONENT: Name of the install component. Typically same as the
512 # target name passed to add_mlir_python_modules().
513 # INSTALL_DESTINATION: Prefix into the install tree in which to install the
515 # OUTPUT_DIRECTORY: Full path in the build tree in which to create the
516 # library. Typically, this will be the common _mlir_libs directory where
517 # all extensions are emitted.
518 # SOURCES_TARGETS: List of interface libraries that carry source information.
519 function(add_mlir_python_sources_target name)
520 cmake_parse_arguments(ARG
522 "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY"
526 if(ARG_UNPARSED_ARGUMENTS)
527 message(FATAL_ERROR "Unhandled arguments to add_mlir_python_sources_target(${name}, ... : ${ARG_UNPARSED_ARGUMENTS}")
530 add_custom_target(${name})
532 # On Windows create_symlink requires special permissions. Use copy_if_different instead.
534 set(_link_or_copy copy_if_different)
536 set(_link_or_copy create_symlink)
539 foreach(_sources_target ${ARG_SOURCES_TARGETS})
540 add_dependencies(${name} ${_sources_target})
542 get_target_property(_src_paths ${_sources_target} SOURCES)
544 get_target_property(_src_paths ${_sources_target} INTERFACE_SOURCES)
550 get_target_property(_root_dir ${_sources_target} INCLUDE_DIRECTORIES)
552 get_target_property(_root_dir ${_sources_target} INTERFACE_INCLUDE_DIRECTORIES)
555 foreach(_src_path ${_src_paths})
556 file(RELATIVE_PATH _source_relative_path "${_root_dir}" "${_src_path}")
557 set(_dest_path "${ARG_OUTPUT_DIRECTORY}/${_source_relative_path}")
559 get_filename_component(_dest_dir "${_dest_path}" DIRECTORY)
560 file(MAKE_DIRECTORY "${_dest_dir}")
563 TARGET ${name} PRE_BUILD
564 COMMENT "Copying python source ${_src_path} -> ${_dest_path}"
565 DEPENDS "${_src_path}"
566 BYPRODUCTS "${_dest_path}"
567 COMMAND "${CMAKE_COMMAND}" -E ${_link_or_copy}
568 "${_src_path}" "${_dest_path}"
571 # We have to install each file individually because we need to preserve
572 # the relative directory structure in the install destination.
573 # As an example, ${_source_relative_path} may be dialects/math.py
574 # which would be transformed to ${ARG_INSTALL_DIR}/dialects
575 # here. This could be moved outside of the loop and cleaned up
576 # if we used FILE_SETS (introduced in CMake 3.23).
577 get_filename_component(_install_destination "${ARG_INSTALL_DIR}/${_source_relative_path}" DIRECTORY)
580 DESTINATION "${_install_destination}"
581 COMPONENT ${ARG_INSTALL_COMPONENT}
588 ################################################################################
589 # Build python extension
590 ################################################################################
591 function(add_mlir_python_extension libname extname)
592 cmake_parse_arguments(ARG
594 "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY"
597 if(ARG_UNPARSED_ARGUMENTS)
598 message(FATAL_ERROR "Unhandled arguments to add_mlir_python_extension(${libname}, ... : ${ARG_UNPARSED_ARGUMENTS}")
601 # The actual extension library produces a shared-object or DLL and has
602 # sources that must be compiled in accordance with pybind11 needs (RTTI and
604 pybind11_add_module(${libname}
608 # The extension itself must be compiled with RTTI and exceptions enabled.
609 # Also, some warning classes triggered by pybind11 are disabled.
610 target_compile_options(${libname} PRIVATE
611 $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
612 # Enable RTTI and exceptions.
615 $<$<CXX_COMPILER_ID:MSVC>:
616 # Enable RTTI and exceptions.
620 # Configure the output to match python expectations.
621 set_target_properties(
622 ${libname} PROPERTIES
623 LIBRARY_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
624 OUTPUT_NAME "${extname}"
629 # Need to also set the RUNTIME_OUTPUT_DIRECTORY on Windows in order to
630 # control where the .dll gets written.
631 set_target_properties(
632 ${libname} PROPERTIES
633 RUNTIME_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
634 ARCHIVE_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
638 target_link_libraries(${libname}
643 target_link_options(${libname}
645 # On Linux, disable re-export of any static linked libraries that
647 $<$<PLATFORM_ID:Linux>:LINKER:--exclude-libs,ALL>
651 # On Windows, pyconfig.h (and by extension python.h) hardcode the version of the
652 # python library which will be used for linkage depending on the flavor of the build.
653 # pybind11 has a workaround which depends on the definition of Py_DEBUG (if Py_DEBUG
654 # is not passed in as a compile definition, pybind11 undefs _DEBUG when including
655 # python.h, so that the release python library would be used).
656 # Since mlir uses pybind11, we can leverage their workaround by never directly
657 # pyconfig.h or python.h and instead relying on the pybind11 headers to include the
658 # necessary python headers. This results in mlir always linking against the
659 # release python library via the (undocumented) cmake property Python3_LIBRARY_RELEASE.
660 target_link_libraries(${libname} PRIVATE ${Python3_LIBRARY_RELEASE})
663 ################################################################################
665 ################################################################################
667 install(TARGETS ${libname}
668 COMPONENT ${ARG_INSTALL_COMPONENT}
669 LIBRARY DESTINATION ${ARG_INSTALL_DIR}
670 ARCHIVE DESTINATION ${ARG_INSTALL_DIR}
671 # NOTE: Even on DLL-platforms, extensions go in the lib directory tree.
672 RUNTIME DESTINATION ${ARG_INSTALL_DIR}