xref: /llvm-project/mlir/cmake/modules/AddMLIRPython.cmake (revision 1a8f49fdda5b14ccc894aacee653f19130df3a30)
19f3f6d7bSStella Laurenzo################################################################################
2310c9496SStella Laurenzo# Python modules
3310c9496SStella Laurenzo# MLIR's Python modules are both directly used by the core project and are
4310c9496SStella Laurenzo# available for use and embedding into external projects (in their own
5310c9496SStella Laurenzo# namespace and with their own deps). In order to facilitate this, python
6310c9496SStella Laurenzo# artifacts are split between declarations, which make a subset of
7310c9496SStella Laurenzo# things available to be built and "add", which in line with the normal LLVM
8310c9496SStella Laurenzo# nomenclature, adds libraries.
9310c9496SStella Laurenzo################################################################################
10310c9496SStella Laurenzo
11310c9496SStella Laurenzo# Function: declare_mlir_python_sources
12310c9496SStella Laurenzo# Declares pure python sources as part of a named grouping that can be built
13310c9496SStella Laurenzo# later.
14310c9496SStella Laurenzo# Arguments:
15310c9496SStella Laurenzo#   ROOT_DIR: Directory where the python namespace begins (defaults to
16310c9496SStella Laurenzo#     CMAKE_CURRENT_SOURCE_DIR). For non-relocatable sources, this will
17310c9496SStella Laurenzo#     typically just be the root of the python source tree (current directory).
18310c9496SStella Laurenzo#     For relocatable sources, this will point deeper into the directory that
19310c9496SStella Laurenzo#     can be relocated. For generated sources, can be relative to
20310c9496SStella Laurenzo#     CMAKE_CURRENT_BINARY_DIR. Generated and non generated sources cannot be
21310c9496SStella Laurenzo#     mixed.
22310c9496SStella Laurenzo#   ADD_TO_PARENT: Adds this source grouping to a previously declared source
23310c9496SStella Laurenzo#     grouping. Source groupings form a DAG.
24310c9496SStella Laurenzo#   SOURCES: List of specific source files relative to ROOT_DIR to include.
25310c9496SStella Laurenzo#   SOURCES_GLOB: List of glob patterns relative to ROOT_DIR to include.
26310c9496SStella Laurenzofunction(declare_mlir_python_sources name)
27310c9496SStella Laurenzo  cmake_parse_arguments(ARG
28310c9496SStella Laurenzo    ""
29ac521d9eSStella Stamenova    "ROOT_DIR;ADD_TO_PARENT"
30310c9496SStella Laurenzo    "SOURCES;SOURCES_GLOB"
31310c9496SStella Laurenzo    ${ARGN})
32310c9496SStella Laurenzo
33310c9496SStella Laurenzo  if(NOT ARG_ROOT_DIR)
34310c9496SStella Laurenzo    set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
35310c9496SStella Laurenzo  endif()
36132bc6e2SStella Laurenzo  set(_install_destination "src/python/${name}")
37310c9496SStella Laurenzo
38310c9496SStella Laurenzo  # Process the glob.
39310c9496SStella Laurenzo  set(_glob_sources)
40310c9496SStella Laurenzo  if(ARG_SOURCES_GLOB)
41310c9496SStella Laurenzo    set(_glob_spec ${ARG_SOURCES_GLOB})
42310c9496SStella Laurenzo    list(TRANSFORM _glob_spec PREPEND "${ARG_ROOT_DIR}/")
43310c9496SStella Laurenzo    file(GLOB_RECURSE _glob_sources
44310c9496SStella Laurenzo      RELATIVE "${ARG_ROOT_DIR}"
45310c9496SStella Laurenzo      ${_glob_spec}
46310c9496SStella Laurenzo    )
47310c9496SStella Laurenzo    list(APPEND ARG_SOURCES ${_glob_sources})
48310c9496SStella Laurenzo  endif()
49310c9496SStella Laurenzo
50310c9496SStella Laurenzo  # We create a custom target to carry properties and dependencies for
51310c9496SStella Laurenzo  # generated sources.
52132bc6e2SStella Laurenzo  add_library(${name} INTERFACE)
53310c9496SStella Laurenzo  set_target_properties(${name} PROPERTIES
54132bc6e2SStella Laurenzo    # Yes: Leading-lowercase property names are load bearing and the recommended
55132bc6e2SStella Laurenzo    # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
56ac521d9eSStella Stamenova    EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_DEPENDS"
57132bc6e2SStella Laurenzo    mlir_python_SOURCES_TYPE pure
58132bc6e2SStella Laurenzo    mlir_python_DEPENDS ""
59132bc6e2SStella Laurenzo  )
60ac521d9eSStella Stamenova
61ac521d9eSStella Stamenova  # Use the interface include directories and sources on the target to carry the
62ac521d9eSStella Stamenova  # properties we would like to export. These support generator expressions and
63ac521d9eSStella Stamenova  # allow us to properly specify paths in both the local build and install scenarios.
64ac521d9eSStella Stamenova  # The one caveat here is that because we don't directly build against the interface
65ac521d9eSStella Stamenova  # library, we need to specify the INCLUDE_DIRECTORIES and SOURCES properties as well
66ac521d9eSStella Stamenova  # via private properties because the evaluation would happen at configuration time
67ac521d9eSStella Stamenova  # instead of build time.
68ac521d9eSStella Stamenova  # Eventually this could be done using a FILE_SET simplifying the logic below.
69ac521d9eSStella Stamenova  # FILE_SET is available in cmake 3.23+, so it is not an option at the moment.
70132bc6e2SStella Laurenzo  target_include_directories(${name} INTERFACE
71132bc6e2SStella Laurenzo    "$<BUILD_INTERFACE:${ARG_ROOT_DIR}>"
72132bc6e2SStella Laurenzo    "$<INSTALL_INTERFACE:${_install_destination}>"
73310c9496SStella Laurenzo  )
74ac521d9eSStella Stamenova  set_property(TARGET ${name} PROPERTY INCLUDE_DIRECTORIES ${ARG_ROOT_DIR})
75ac521d9eSStella Stamenova
76ac521d9eSStella Stamenova  if(ARG_SOURCES)
77ac521d9eSStella Stamenova    list(TRANSFORM ARG_SOURCES PREPEND "${ARG_ROOT_DIR}/" OUTPUT_VARIABLE _build_sources)
78ac521d9eSStella Stamenova    list(TRANSFORM ARG_SOURCES PREPEND "${_install_destination}/" OUTPUT_VARIABLE _install_sources)
79ac521d9eSStella Stamenova    target_sources(${name}
80ac521d9eSStella Stamenova      INTERFACE
81ac521d9eSStella Stamenova        "$<INSTALL_INTERFACE:${_install_sources}>"
82ac521d9eSStella Stamenova        "$<BUILD_INTERFACE:${_build_sources}>"
83ac521d9eSStella Stamenova      PRIVATE ${_build_sources}
84ac521d9eSStella Stamenova    )
85ac521d9eSStella Stamenova  endif()
86310c9496SStella Laurenzo
87310c9496SStella Laurenzo  # Add to parent.
88310c9496SStella Laurenzo  if(ARG_ADD_TO_PARENT)
89132bc6e2SStella Laurenzo    set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
90132bc6e2SStella Laurenzo  endif()
91132bc6e2SStella Laurenzo
92132bc6e2SStella Laurenzo  # Install.
93132bc6e2SStella Laurenzo  set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
94132bc6e2SStella Laurenzo  if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
95132bc6e2SStella Laurenzo    _mlir_python_install_sources(
96132bc6e2SStella Laurenzo      ${name} "${ARG_ROOT_DIR}" "${_install_destination}"
97132bc6e2SStella Laurenzo      ${ARG_SOURCES}
98132bc6e2SStella Laurenzo    )
99310c9496SStella Laurenzo  endif()
100310c9496SStella Laurenzoendfunction()
101310c9496SStella Laurenzo
102310c9496SStella Laurenzo# Function: declare_mlir_python_extension
103310c9496SStella Laurenzo# Declares a buildable python extension from C++ source files. The built
104310c9496SStella Laurenzo# module is considered a python source file and included as everything else.
105310c9496SStella Laurenzo# Arguments:
106132bc6e2SStella Laurenzo#   ROOT_DIR: Root directory where sources are interpreted relative to.
107132bc6e2SStella Laurenzo#     Defaults to CMAKE_CURRENT_SOURCE_DIR.
108310c9496SStella Laurenzo#   MODULE_NAME: Local import name of the module (i.e. "_mlir").
109310c9496SStella Laurenzo#   ADD_TO_PARENT: Same as for declare_mlir_python_sources.
110310c9496SStella Laurenzo#   SOURCES: C++ sources making up the module.
111310c9496SStella Laurenzo#   PRIVATE_LINK_LIBS: List of libraries to link in privately to the module
112310c9496SStella Laurenzo#     regardless of how it is included in the project (generally should be
113310c9496SStella Laurenzo#     static libraries that can be included with hidden visibility).
114310c9496SStella Laurenzo#   EMBED_CAPI_LINK_LIBS: Dependent CAPI libraries that this extension depends
115310c9496SStella Laurenzo#     on. These will be collected for all extensions and put into an
116310c9496SStella Laurenzo#     aggregate dylib that is linked against.
117392622d0SMaksim Levental#   PYTHON_BINDINGS_LIBRARY: Either pybind11 or nanobind.
118310c9496SStella Laurenzofunction(declare_mlir_python_extension name)
119310c9496SStella Laurenzo  cmake_parse_arguments(ARG
120310c9496SStella Laurenzo    ""
121392622d0SMaksim Levental    "ROOT_DIR;MODULE_NAME;ADD_TO_PARENT;PYTHON_BINDINGS_LIBRARY"
122310c9496SStella Laurenzo    "SOURCES;PRIVATE_LINK_LIBS;EMBED_CAPI_LINK_LIBS"
123310c9496SStella Laurenzo    ${ARGN})
124310c9496SStella Laurenzo
125132bc6e2SStella Laurenzo  if(NOT ARG_ROOT_DIR)
126132bc6e2SStella Laurenzo    set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
127132bc6e2SStella Laurenzo  endif()
128132bc6e2SStella Laurenzo  set(_install_destination "src/python/${name}")
129132bc6e2SStella Laurenzo
130392622d0SMaksim Levental  if(NOT ARG_PYTHON_BINDINGS_LIBRARY)
131392622d0SMaksim Levental    set(ARG_PYTHON_BINDINGS_LIBRARY "pybind11")
132392622d0SMaksim Levental  endif()
133392622d0SMaksim Levental
134132bc6e2SStella Laurenzo  add_library(${name} INTERFACE)
135310c9496SStella Laurenzo  set_target_properties(${name} PROPERTIES
136132bc6e2SStella Laurenzo    # Yes: Leading-lowercase property names are load bearing and the recommended
137132bc6e2SStella Laurenzo    # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
138392622d0SMaksim Levental    EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS;mlir_python_BINDINGS_LIBRARY"
139132bc6e2SStella Laurenzo    mlir_python_SOURCES_TYPE extension
140132bc6e2SStella Laurenzo    mlir_python_EXTENSION_MODULE_NAME "${ARG_MODULE_NAME}"
141132bc6e2SStella Laurenzo    mlir_python_EMBED_CAPI_LINK_LIBS "${ARG_EMBED_CAPI_LINK_LIBS}"
142132bc6e2SStella Laurenzo    mlir_python_DEPENDS ""
143392622d0SMaksim Levental    mlir_python_BINDINGS_LIBRARY "${ARG_PYTHON_BINDINGS_LIBRARY}"
144132bc6e2SStella Laurenzo  )
145ac521d9eSStella Stamenova
146ac521d9eSStella Stamenova  # Set the interface source and link_libs properties of the target
147ac521d9eSStella Stamenova  # These properties support generator expressions and are automatically exported
148ac521d9eSStella Stamenova  list(TRANSFORM ARG_SOURCES PREPEND "${ARG_ROOT_DIR}/" OUTPUT_VARIABLE _build_sources)
149ac521d9eSStella Stamenova  list(TRANSFORM ARG_SOURCES PREPEND "${_install_destination}/" OUTPUT_VARIABLE _install_sources)
150ac521d9eSStella Stamenova  target_sources(${name} INTERFACE
151ac521d9eSStella Stamenova    "$<BUILD_INTERFACE:${_build_sources}>"
152ac521d9eSStella Stamenova    "$<INSTALL_INTERFACE:${_install_sources}>"
153ac521d9eSStella Stamenova  )
154ac521d9eSStella Stamenova  target_link_libraries(${name} INTERFACE
155ac521d9eSStella Stamenova    ${ARG_PRIVATE_LINK_LIBS}
156310c9496SStella Laurenzo  )
157310c9496SStella Laurenzo
158310c9496SStella Laurenzo  # Add to parent.
159310c9496SStella Laurenzo  if(ARG_ADD_TO_PARENT)
160132bc6e2SStella Laurenzo    set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
161310c9496SStella Laurenzo  endif()
162132bc6e2SStella Laurenzo
163132bc6e2SStella Laurenzo  # Install.
164132bc6e2SStella Laurenzo  set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
165132bc6e2SStella Laurenzo  if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
166132bc6e2SStella Laurenzo    _mlir_python_install_sources(
167ac521d9eSStella Stamenova      ${name} "${ARG_ROOT_DIR}" "${_install_destination}"
168132bc6e2SStella Laurenzo      ${ARG_SOURCES}
169132bc6e2SStella Laurenzo    )
170132bc6e2SStella Laurenzo  endif()
171132bc6e2SStella Laurenzoendfunction()
172132bc6e2SStella Laurenzo
173132bc6e2SStella Laurenzofunction(_mlir_python_install_sources name source_root_dir destination)
174132bc6e2SStella Laurenzo  foreach(source_relative_path ${ARGN})
175132bc6e2SStella Laurenzo    # Transform "a/b/c.py" -> "${install_prefix}/a/b" for installation.
176132bc6e2SStella Laurenzo    get_filename_component(
177ac521d9eSStella Stamenova      dest_relative_dir "${source_relative_path}" DIRECTORY
178132bc6e2SStella Laurenzo      BASE_DIR "${source_root_dir}"
179132bc6e2SStella Laurenzo    )
180132bc6e2SStella Laurenzo    install(
181132bc6e2SStella Laurenzo      FILES "${source_root_dir}/${source_relative_path}"
182ac521d9eSStella Stamenova      DESTINATION "${destination}/${dest_relative_dir}"
1839494bd84SJack Wolfard      COMPONENT mlir-python-sources
184132bc6e2SStella Laurenzo    )
185132bc6e2SStella Laurenzo  endforeach()
1869494bd84SJack Wolfard  get_target_export_arg(${name} MLIR export_to_mlirtargets
1879494bd84SJack Wolfard    UMBRELLA mlir-python-sources)
188132bc6e2SStella Laurenzo  install(TARGETS ${name}
1899494bd84SJack Wolfard    COMPONENT mlir-python-sources
190132bc6e2SStella Laurenzo    ${export_to_mlirtargets}
191132bc6e2SStella Laurenzo  )
192310c9496SStella Laurenzoendfunction()
193310c9496SStella Laurenzo
194310c9496SStella Laurenzo# Function: add_mlir_python_modules
195310c9496SStella Laurenzo# Adds python modules to a project, building them from a list of declared
196310c9496SStella Laurenzo# source groupings (see declare_mlir_python_sources and
197310c9496SStella Laurenzo# declare_mlir_python_extension). One of these must be called for each
198310c9496SStella Laurenzo# packaging root in use.
199310c9496SStella Laurenzo# Arguments:
200310c9496SStella Laurenzo#   ROOT_PREFIX: The directory in the build tree to emit sources. This will
201310c9496SStella Laurenzo#     typically be something like ${MY_BINARY_DIR}/python_packages/foobar
202310c9496SStella Laurenzo#     for non-relocatable modules or a deeper directory tree for relocatable.
203310c9496SStella Laurenzo#   INSTALL_PREFIX: Prefix into the install tree for installing the package.
204310c9496SStella Laurenzo#     Typically mirrors the path above but without an absolute path.
205310c9496SStella Laurenzo#   DECLARED_SOURCES: List of declared source groups to include. The entire
206310c9496SStella Laurenzo#     DAG of source modules is included.
207310c9496SStella Laurenzo#   COMMON_CAPI_LINK_LIBS: List of dylibs (typically one) to make every
208310c9496SStella Laurenzo#     extension depend on (see mlir_python_add_common_capi_library).
209310c9496SStella Laurenzofunction(add_mlir_python_modules name)
210310c9496SStella Laurenzo  cmake_parse_arguments(ARG
211310c9496SStella Laurenzo    ""
21299c43e3cSBimo    "ROOT_PREFIX;INSTALL_PREFIX"
21399c43e3cSBimo    "COMMON_CAPI_LINK_LIBS;DECLARED_SOURCES"
214310c9496SStella Laurenzo    ${ARGN})
215310c9496SStella Laurenzo  # Helper to process an individual target.
216310c9496SStella Laurenzo  function(_process_target modules_target sources_target)
217132bc6e2SStella Laurenzo    get_target_property(_source_type ${sources_target} mlir_python_SOURCES_TYPE)
218132bc6e2SStella Laurenzo
219310c9496SStella Laurenzo    if(_source_type STREQUAL "pure")
220310c9496SStella Laurenzo      # Pure python sources to link into the tree.
221aa78c529SStella Laurenzo      set(_pure_sources_target "${modules_target}.sources.${sources_target}")
222ac521d9eSStella Stamenova      add_mlir_python_sources_target(${_pure_sources_target}
223ac521d9eSStella Stamenova        INSTALL_COMPONENT ${modules_target}
224ac521d9eSStella Stamenova        INSTALL_DIR ${ARG_INSTALL_PREFIX}
225ac521d9eSStella Stamenova        OUTPUT_DIRECTORY ${ARG_ROOT_PREFIX}
226ac521d9eSStella Stamenova        SOURCES_TARGETS ${sources_target}
227310c9496SStella Laurenzo      )
228ac521d9eSStella Stamenova      add_dependencies(${modules_target} ${_pure_sources_target})
229310c9496SStella Laurenzo    elseif(_source_type STREQUAL "extension")
230310c9496SStella Laurenzo      # Native CPP extension.
231132bc6e2SStella Laurenzo      get_target_property(_module_name ${sources_target} mlir_python_EXTENSION_MODULE_NAME)
232392622d0SMaksim Levental      get_target_property(_bindings_library ${sources_target} mlir_python_BINDINGS_LIBRARY)
233132bc6e2SStella Laurenzo      # Transform relative source to based on root dir.
234ac521d9eSStella Stamenova      set(_extension_target "${modules_target}.extension.${_module_name}.dso")
235310c9496SStella Laurenzo      add_mlir_python_extension(${_extension_target} "${_module_name}"
236310c9496SStella Laurenzo        INSTALL_COMPONENT ${modules_target}
237310c9496SStella Laurenzo        INSTALL_DIR "${ARG_INSTALL_PREFIX}/_mlir_libs"
238310c9496SStella Laurenzo        OUTPUT_DIRECTORY "${ARG_ROOT_PREFIX}/_mlir_libs"
239392622d0SMaksim Levental        PYTHON_BINDINGS_LIBRARY ${_bindings_library}
240310c9496SStella Laurenzo        LINK_LIBS PRIVATE
241ac521d9eSStella Stamenova          ${sources_target}
242310c9496SStella Laurenzo          ${ARG_COMMON_CAPI_LINK_LIBS}
243310c9496SStella Laurenzo      )
244ac521d9eSStella Stamenova      add_dependencies(${modules_target} ${_extension_target})
245310c9496SStella Laurenzo      mlir_python_setup_extension_rpath(${_extension_target})
246310c9496SStella Laurenzo    else()
247310c9496SStella Laurenzo      message(SEND_ERROR "Unrecognized source type '${_source_type}' for python source target ${sources_target}")
248310c9496SStella Laurenzo      return()
249310c9496SStella Laurenzo    endif()
250310c9496SStella Laurenzo  endfunction()
251310c9496SStella Laurenzo
252310c9496SStella Laurenzo  # Build the modules target.
253ac521d9eSStella Stamenova  add_custom_target(${name} ALL)
254ac521d9eSStella Stamenova  _flatten_mlir_python_targets(_flat_targets ${ARG_DECLARED_SOURCES})
255310c9496SStella Laurenzo  foreach(sources_target ${_flat_targets})
256310c9496SStella Laurenzo    _process_target(${name} ${sources_target})
257310c9496SStella Laurenzo  endforeach()
258310c9496SStella Laurenzo
259310c9496SStella Laurenzo  # Create an install target.
260310c9496SStella Laurenzo  if(NOT LLVM_ENABLE_IDE)
261310c9496SStella Laurenzo    add_llvm_install_targets(
262310c9496SStella Laurenzo      install-${name}
263310c9496SStella Laurenzo      DEPENDS ${name}
264310c9496SStella Laurenzo      COMPONENT ${name})
265310c9496SStella Laurenzo  endif()
266310c9496SStella Laurenzoendfunction()
267310c9496SStella Laurenzo
268310c9496SStella Laurenzo# Function: declare_mlir_dialect_python_bindings
269310c9496SStella Laurenzo# Helper to generate source groups for dialects, including both static source
270310c9496SStella Laurenzo# files and a TD_FILE to generate wrappers.
271310c9496SStella Laurenzo#
272310c9496SStella Laurenzo# This will generate a source group named ${ADD_TO_PARENT}.${DIALECT_NAME}.
273310c9496SStella Laurenzo#
274310c9496SStella Laurenzo# Arguments:
275310c9496SStella Laurenzo#   ROOT_DIR: Same as for declare_mlir_python_sources().
276310c9496SStella Laurenzo#   ADD_TO_PARENT: Same as for declare_mlir_python_sources(). Unique names
277310c9496SStella Laurenzo#     for the subordinate source groups are derived from this.
278310c9496SStella Laurenzo#   TD_FILE: Tablegen file to generate source for (relative to ROOT_DIR).
279310c9496SStella Laurenzo#   DIALECT_NAME: Python name of the dialect.
280310c9496SStella Laurenzo#   SOURCES: Same as declare_mlir_python_sources().
281310c9496SStella Laurenzo#   SOURCES_GLOB: Same as declare_mlir_python_sources().
282310c9496SStella Laurenzo#   DEPENDS: Additional dependency targets.
28392233062Smax#   GEN_ENUM_BINDINGS: Generate enum bindings.
28492233062Smax#   GEN_ENUM_BINDINGS_TD_FILE: Optional Tablegen file to generate enums for (relative to ROOT_DIR).
28592233062Smax#     This file is where the *EnumAttrs are defined, not where the *Enums are defined.
28692233062Smax#     **WARNING**: This arg will shortly be removed when the just-below TODO is satisfied. Use at your
28792233062Smax#     risk.
28867a910bbSRahul Kayaith#
28967a910bbSRahul Kayaith# TODO: Right now `TD_FILE` can't be the actual dialect tablegen file, since we
29067a910bbSRahul Kayaith#       use its path to determine where to place the generated python file. If
29167a910bbSRahul Kayaith#       we made the output path an additional argument here we could remove the
29267a910bbSRahul Kayaith#       need for the separate "wrapper" .td files
293310c9496SStella Laurenzofunction(declare_mlir_dialect_python_bindings)
294310c9496SStella Laurenzo  cmake_parse_arguments(ARG
29592233062Smax    "GEN_ENUM_BINDINGS"
296310c9496SStella Laurenzo    "ROOT_DIR;ADD_TO_PARENT;TD_FILE;DIALECT_NAME"
29792233062Smax    "SOURCES;SOURCES_GLOB;DEPENDS;GEN_ENUM_BINDINGS_TD_FILE"
298310c9496SStella Laurenzo    ${ARGN})
299310c9496SStella Laurenzo  # Sources.
300310c9496SStella Laurenzo  set(_dialect_target "${ARG_ADD_TO_PARENT}.${ARG_DIALECT_NAME}")
301310c9496SStella Laurenzo  declare_mlir_python_sources(${_dialect_target}
302310c9496SStella Laurenzo    ROOT_DIR "${ARG_ROOT_DIR}"
303310c9496SStella Laurenzo    ADD_TO_PARENT "${ARG_ADD_TO_PARENT}"
304310c9496SStella Laurenzo    SOURCES "${ARG_SOURCES}"
305310c9496SStella Laurenzo    SOURCES_GLOB "${ARG_SOURCES_GLOB}"
306310c9496SStella Laurenzo  )
307310c9496SStella Laurenzo
308310c9496SStella Laurenzo  # Tablegen
309310c9496SStella Laurenzo  if(ARG_TD_FILE)
310ac521d9eSStella Stamenova    set(tblgen_target "${_dialect_target}.tablegen")
311310c9496SStella Laurenzo    set(td_file "${ARG_ROOT_DIR}/${ARG_TD_FILE}")
312310c9496SStella Laurenzo    get_filename_component(relative_td_directory "${ARG_TD_FILE}" DIRECTORY)
313132bc6e2SStella Laurenzo    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${relative_td_directory}")
314310c9496SStella Laurenzo    set(dialect_filename "${relative_td_directory}/_${ARG_DIALECT_NAME}_ops_gen.py")
315310c9496SStella Laurenzo    set(LLVM_TARGET_DEFINITIONS ${td_file})
316ac521d9eSStella Stamenova    mlir_tablegen("${dialect_filename}"
317ac521d9eSStella Stamenova      -gen-python-op-bindings -bind-dialect=${ARG_DIALECT_NAME}
318ac521d9eSStella Stamenova      DEPENDS ${ARG_DEPENDS}
319ac521d9eSStella Stamenova    )
320310c9496SStella Laurenzo    add_public_tablegen_target(${tblgen_target})
321310c9496SStella Laurenzo
32292233062Smax    set(_sources ${dialect_filename})
32392233062Smax    if(ARG_GEN_ENUM_BINDINGS OR ARG_GEN_ENUM_BINDINGS_TD_FILE)
32492233062Smax      if(ARG_GEN_ENUM_BINDINGS_TD_FILE)
32592233062Smax        set(td_file "${ARG_ROOT_DIR}/${ARG_GEN_ENUM_BINDINGS_TD_FILE}")
32692233062Smax        set(LLVM_TARGET_DEFINITIONS ${td_file})
32792233062Smax      endif()
32892233062Smax      set(enum_filename "${relative_td_directory}/_${ARG_DIALECT_NAME}_enum_gen.py")
32992233062Smax      mlir_tablegen(${enum_filename} -gen-python-enum-bindings)
33092233062Smax      list(APPEND _sources ${enum_filename})
33192233062Smax    endif()
33292233062Smax
333310c9496SStella Laurenzo    # Generated.
334ac521d9eSStella Stamenova    declare_mlir_python_sources("${_dialect_target}.ops_gen"
335310c9496SStella Laurenzo      ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
336310c9496SStella Laurenzo      ADD_TO_PARENT "${_dialect_target}"
33792233062Smax      SOURCES ${_sources}
338310c9496SStella Laurenzo    )
339310c9496SStella Laurenzo  endif()
340310c9496SStella Laurenzoendfunction()
341310c9496SStella Laurenzo
3423f71765aSAlex Zinenko# Function: declare_mlir_dialect_extension_python_bindings
3433f71765aSAlex Zinenko# Helper to generate source groups for dialect extensions, including both
3443f71765aSAlex Zinenko# static source files and a TD_FILE to generate wrappers.
3453f71765aSAlex Zinenko#
3463f71765aSAlex Zinenko# This will generate a source group named ${ADD_TO_PARENT}.${EXTENSION_NAME}.
3473f71765aSAlex Zinenko#
3483f71765aSAlex Zinenko# Arguments:
3493f71765aSAlex Zinenko#   ROOT_DIR: Same as for declare_mlir_python_sources().
3503f71765aSAlex Zinenko#   ADD_TO_PARENT: Same as for declare_mlir_python_sources(). Unique names
3513f71765aSAlex Zinenko#     for the subordinate source groups are derived from this.
3523f71765aSAlex Zinenko#   TD_FILE: Tablegen file to generate source for (relative to ROOT_DIR).
3533f71765aSAlex Zinenko#   DIALECT_NAME: Python name of the dialect.
3543f71765aSAlex Zinenko#   EXTENSION_NAME: Python name of the dialect extension.
3553f71765aSAlex Zinenko#   SOURCES: Same as declare_mlir_python_sources().
3563f71765aSAlex Zinenko#   SOURCES_GLOB: Same as declare_mlir_python_sources().
3573f71765aSAlex Zinenko#   DEPENDS: Additional dependency targets.
35892233062Smax#   GEN_ENUM_BINDINGS: Generate enum bindings.
35992233062Smax#   GEN_ENUM_BINDINGS_TD_FILE: Optional Tablegen file to generate enums for (relative to ROOT_DIR).
36092233062Smax#     This file is where the *Attrs are defined, not where the *Enums are defined.
36192233062Smax#     **WARNING**: This arg will shortly be removed when the TODO for
36292233062Smax#     declare_mlir_dialect_python_bindings is satisfied. Use at your risk.
3633f71765aSAlex Zinenkofunction(declare_mlir_dialect_extension_python_bindings)
3643f71765aSAlex Zinenko  cmake_parse_arguments(ARG
36592233062Smax    "GEN_ENUM_BINDINGS"
3663f71765aSAlex Zinenko    "ROOT_DIR;ADD_TO_PARENT;TD_FILE;DIALECT_NAME;EXTENSION_NAME"
36792233062Smax    "SOURCES;SOURCES_GLOB;DEPENDS;GEN_ENUM_BINDINGS_TD_FILE"
3683f71765aSAlex Zinenko    ${ARGN})
3693f71765aSAlex Zinenko  # Source files.
3703f71765aSAlex Zinenko  set(_extension_target "${ARG_ADD_TO_PARENT}.${ARG_EXTENSION_NAME}")
3713f71765aSAlex Zinenko  declare_mlir_python_sources(${_extension_target}
3723f71765aSAlex Zinenko    ROOT_DIR "${ARG_ROOT_DIR}"
3733f71765aSAlex Zinenko    ADD_TO_PARENT "${ARG_ADD_TO_PARENT}"
3743f71765aSAlex Zinenko    SOURCES "${ARG_SOURCES}"
3753f71765aSAlex Zinenko    SOURCES_GLOB "${ARG_SOURCES_GLOB}"
3763f71765aSAlex Zinenko  )
3773f71765aSAlex Zinenko
3783f71765aSAlex Zinenko  # Tablegen
3793f71765aSAlex Zinenko  if(ARG_TD_FILE)
3803f71765aSAlex Zinenko    set(tblgen_target "${ARG_ADD_TO_PARENT}.${ARG_EXTENSION_NAME}.tablegen")
3813f71765aSAlex Zinenko    set(td_file "${ARG_ROOT_DIR}/${ARG_TD_FILE}")
3823f71765aSAlex Zinenko    get_filename_component(relative_td_directory "${ARG_TD_FILE}" DIRECTORY)
3833f71765aSAlex Zinenko    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${relative_td_directory}")
3843f71765aSAlex Zinenko    set(output_filename "${relative_td_directory}/_${ARG_EXTENSION_NAME}_ops_gen.py")
3853f71765aSAlex Zinenko    set(LLVM_TARGET_DEFINITIONS ${td_file})
3863f71765aSAlex Zinenko    mlir_tablegen("${output_filename}" -gen-python-op-bindings
3873f71765aSAlex Zinenko                  -bind-dialect=${ARG_DIALECT_NAME}
3883f71765aSAlex Zinenko                  -dialect-extension=${ARG_EXTENSION_NAME})
3893f71765aSAlex Zinenko    add_public_tablegen_target(${tblgen_target})
3903f71765aSAlex Zinenko    if(ARG_DEPENDS)
3913f71765aSAlex Zinenko      add_dependencies(${tblgen_target} ${ARG_DEPENDS})
3923f71765aSAlex Zinenko    endif()
3933f71765aSAlex Zinenko
39492233062Smax    set(_sources ${output_filename})
39592233062Smax    if(ARG_GEN_ENUM_BINDINGS OR ARG_GEN_ENUM_BINDINGS_TD_FILE)
39692233062Smax      if(ARG_GEN_ENUM_BINDINGS_TD_FILE)
39792233062Smax        set(td_file "${ARG_ROOT_DIR}/${ARG_GEN_ENUM_BINDINGS_TD_FILE}")
39892233062Smax        set(LLVM_TARGET_DEFINITIONS ${td_file})
39992233062Smax      endif()
40092233062Smax      set(enum_filename "${relative_td_directory}/_${ARG_EXTENSION_NAME}_enum_gen.py")
40192233062Smax      mlir_tablegen(${enum_filename} -gen-python-enum-bindings)
40292233062Smax      list(APPEND _sources ${enum_filename})
40392233062Smax    endif()
40492233062Smax
4053f71765aSAlex Zinenko    declare_mlir_python_sources("${_extension_target}.ops_gen"
4063f71765aSAlex Zinenko      ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
4073f71765aSAlex Zinenko      ADD_TO_PARENT "${_extension_target}"
40892233062Smax      SOURCES ${_sources}
4093f71765aSAlex Zinenko    )
4103f71765aSAlex Zinenko  endif()
4113f71765aSAlex Zinenkoendfunction()
4123f71765aSAlex Zinenko
413310c9496SStella Laurenzo# Function: mlir_python_setup_extension_rpath
414310c9496SStella Laurenzo# Sets RPATH properties on a target, assuming that it is being output to
415310c9496SStella Laurenzo# an _mlir_libs directory with all other libraries. For static linkage,
416310c9496SStella Laurenzo# the RPATH will just be the origin. If linking dynamically, then the LLVM
417310c9496SStella Laurenzo# library directory will be added.
418310c9496SStella Laurenzo# Arguments:
419310c9496SStella Laurenzo#   RELATIVE_INSTALL_ROOT: If building dynamically, an RPATH entry will be
420310c9496SStella Laurenzo#     added to the install tree lib/ directory by first traversing this
421310c9496SStella Laurenzo#     path relative to the installation location. Typically a number of ".."
422310c9496SStella Laurenzo#     entries, one for each level of the install path.
423310c9496SStella Laurenzofunction(mlir_python_setup_extension_rpath target)
424310c9496SStella Laurenzo  cmake_parse_arguments(ARG
425310c9496SStella Laurenzo    ""
426310c9496SStella Laurenzo    "RELATIVE_INSTALL_ROOT"
427310c9496SStella Laurenzo    ""
428310c9496SStella Laurenzo    ${ARGN})
429310c9496SStella Laurenzo
430310c9496SStella Laurenzo  # RPATH handling.
431310c9496SStella Laurenzo  # For the build tree, include the LLVM lib directory and the current
432310c9496SStella Laurenzo  # directory for RPATH searching. For install, just the current directory
433310c9496SStella Laurenzo  # (assumes that needed dependencies have been installed).
434310c9496SStella Laurenzo  if(NOT APPLE AND NOT UNIX)
435310c9496SStella Laurenzo    return()
436310c9496SStella Laurenzo  endif()
437310c9496SStella Laurenzo
438310c9496SStella Laurenzo  set(_origin_prefix "\$ORIGIN")
439310c9496SStella Laurenzo  if(APPLE)
440310c9496SStella Laurenzo    set(_origin_prefix "@loader_path")
441310c9496SStella Laurenzo  endif()
442310c9496SStella Laurenzo  set_target_properties(${target} PROPERTIES
443310c9496SStella Laurenzo    BUILD_WITH_INSTALL_RPATH OFF
444310c9496SStella Laurenzo    BUILD_RPATH "${_origin_prefix}"
445310c9496SStella Laurenzo    INSTALL_RPATH "${_origin_prefix}"
446310c9496SStella Laurenzo  )
447310c9496SStella Laurenzo
448310c9496SStella Laurenzo  # For static builds, that is all that is needed: all dependencies will be in
449310c9496SStella Laurenzo  # the one directory. For shared builds, then we also need to add the global
450310c9496SStella Laurenzo  # lib directory. This will be absolute for the build tree and relative for
451310c9496SStella Laurenzo  # install.
452310c9496SStella Laurenzo  # When we have access to CMake >= 3.20, there is a helper to calculate this.
453310c9496SStella Laurenzo  if(BUILD_SHARED_LIBS AND ARG_RELATIVE_INSTALL_ROOT)
454310c9496SStella Laurenzo    get_filename_component(_real_lib_dir "${LLVM_LIBRARY_OUTPUT_INTDIR}" REALPATH)
455310c9496SStella Laurenzo    set_property(TARGET ${target} APPEND PROPERTY
456310c9496SStella Laurenzo      BUILD_RPATH "${_real_lib_dir}")
457e941b031SJohn Ericson    set_property(TARGET ${target} APPEND PROPERTY
458e941b031SJohn Ericson      INSTALL_RPATH "${_origin_prefix}/${ARG_RELATIVE_INSTALL_ROOT}/lib${LLVM_LIBDIR_SUFFIX}")
459310c9496SStella Laurenzo  endif()
460310c9496SStella Laurenzoendfunction()
461310c9496SStella Laurenzo
462310c9496SStella Laurenzo# Function: add_mlir_python_common_capi_library
463310c9496SStella Laurenzo# Adds a shared library which embeds dependent CAPI libraries needed to link
464310c9496SStella Laurenzo# all extensions.
465310c9496SStella Laurenzo# Arguments:
466310c9496SStella Laurenzo#   INSTALL_COMPONENT: Name of the install component. Typically same as the
467310c9496SStella Laurenzo#     target name passed to add_mlir_python_modules().
468310c9496SStella Laurenzo#   INSTALL_DESTINATION: Prefix into the install tree in which to install the
469310c9496SStella Laurenzo#     library.
470310c9496SStella Laurenzo#   OUTPUT_DIRECTORY: Full path in the build tree in which to create the
471310c9496SStella Laurenzo#     library. Typically, this will be the common _mlir_libs directory where
472310c9496SStella Laurenzo#     all extensions are emitted.
473310c9496SStella Laurenzo#   RELATIVE_INSTALL_ROOT: See mlir_python_setup_extension_rpath().
474ac521d9eSStella Stamenova#   DECLARED_HEADERS: Source groups from which to discover headers that belong
475ac521d9eSStella Stamenova#     to the library and should be installed with it.
476310c9496SStella Laurenzo#   DECLARED_SOURCES: Source groups from which to discover dependent
477310c9496SStella Laurenzo#     EMBED_CAPI_LINK_LIBS.
478310c9496SStella Laurenzo#   EMBED_LIBS: Additional libraries to embed (must be built with OBJECTS and
479310c9496SStella Laurenzo#     have an "obj.${name}" object library associated).
480310c9496SStella Laurenzofunction(add_mlir_python_common_capi_library name)
481310c9496SStella Laurenzo  cmake_parse_arguments(ARG
482310c9496SStella Laurenzo    ""
483310c9496SStella Laurenzo    "INSTALL_COMPONENT;INSTALL_DESTINATION;OUTPUT_DIRECTORY;RELATIVE_INSTALL_ROOT"
484ac521d9eSStella Stamenova    "DECLARED_HEADERS;DECLARED_SOURCES;EMBED_LIBS"
485310c9496SStella Laurenzo    ${ARGN})
486310c9496SStella Laurenzo  # Collect all explicit and transitive embed libs.
487310c9496SStella Laurenzo  set(_embed_libs ${ARG_EMBED_LIBS})
488310c9496SStella Laurenzo  _flatten_mlir_python_targets(_all_source_targets ${ARG_DECLARED_SOURCES})
489310c9496SStella Laurenzo  foreach(t ${_all_source_targets})
490132bc6e2SStella Laurenzo    get_target_property(_local_embed_libs ${t} mlir_python_EMBED_CAPI_LINK_LIBS)
491310c9496SStella Laurenzo    if(_local_embed_libs)
492310c9496SStella Laurenzo      list(APPEND _embed_libs ${_local_embed_libs})
493310c9496SStella Laurenzo    endif()
494310c9496SStella Laurenzo  endforeach()
495310c9496SStella Laurenzo  list(REMOVE_DUPLICATES _embed_libs)
496310c9496SStella Laurenzo
497fe6d9937SStella Laurenzo  # Generate the aggregate .so that everything depends on.
498fe6d9937SStella Laurenzo  add_mlir_aggregate(${name}
499310c9496SStella Laurenzo    SHARED
500310c9496SStella Laurenzo    DISABLE_INSTALL
501fe6d9937SStella Laurenzo    EMBED_LIBS ${_embed_libs}
502310c9496SStella Laurenzo  )
503fe6d9937SStella Laurenzo
504ac521d9eSStella Stamenova  # Process any headers associated with the library
505ac521d9eSStella Stamenova  _flatten_mlir_python_targets(_flat_header_targets ${ARG_DECLARED_HEADERS})
506ac521d9eSStella Stamenova  set(_header_sources_target "${name}.sources")
507ac521d9eSStella Stamenova  add_mlir_python_sources_target(${_header_sources_target}
508ac521d9eSStella Stamenova    INSTALL_COMPONENT ${ARG_INSTALL_COMPONENT}
509ac521d9eSStella Stamenova    INSTALL_DIR "${ARG_INSTALL_DESTINATION}/include"
510ac521d9eSStella Stamenova    OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}/include"
511ac521d9eSStella Stamenova    SOURCES_TARGETS ${_flat_header_targets}
512ac521d9eSStella Stamenova  )
513ac521d9eSStella Stamenova  add_dependencies(${name} ${_header_sources_target})
514ac521d9eSStella Stamenova
5156a7687c4SMaksim Levental  if(WIN32)
516310c9496SStella Laurenzo    set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
517310c9496SStella Laurenzo  endif()
518310c9496SStella Laurenzo  set_target_properties(${name} PROPERTIES
519310c9496SStella Laurenzo    LIBRARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
520310c9496SStella Laurenzo    BINARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
521cb7b0381SStella Laurenzo    # Needed for windows (and don't hurt others).
522cb7b0381SStella Laurenzo    RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
523cb7b0381SStella Laurenzo    ARCHIVE_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
524310c9496SStella Laurenzo  )
525310c9496SStella Laurenzo  mlir_python_setup_extension_rpath(${name}
526310c9496SStella Laurenzo    RELATIVE_INSTALL_ROOT "${ARG_RELATIVE_INSTALL_ROOT}"
527310c9496SStella Laurenzo  )
528310c9496SStella Laurenzo  install(TARGETS ${name}
529310c9496SStella Laurenzo    COMPONENT ${ARG_INSTALL_COMPONENT}
530310c9496SStella Laurenzo    LIBRARY DESTINATION "${ARG_INSTALL_DESTINATION}"
531310c9496SStella Laurenzo    RUNTIME DESTINATION "${ARG_INSTALL_DESTINATION}"
532310c9496SStella Laurenzo  )
533310c9496SStella Laurenzoendfunction()
534310c9496SStella Laurenzo
535310c9496SStella Laurenzofunction(_flatten_mlir_python_targets output_var)
536310c9496SStella Laurenzo  set(_flattened)
537310c9496SStella Laurenzo  foreach(t ${ARGN})
538132bc6e2SStella Laurenzo    get_target_property(_source_type ${t} mlir_python_SOURCES_TYPE)
539132bc6e2SStella Laurenzo    get_target_property(_depends ${t} mlir_python_DEPENDS)
540310c9496SStella Laurenzo    if(_source_type)
541310c9496SStella Laurenzo      list(APPEND _flattened "${t}")
542310c9496SStella Laurenzo      if(_depends)
543310c9496SStella Laurenzo        _flatten_mlir_python_targets(_local_flattened ${_depends})
544310c9496SStella Laurenzo        list(APPEND _flattened ${_local_flattened})
545310c9496SStella Laurenzo      endif()
546310c9496SStella Laurenzo    endif()
547310c9496SStella Laurenzo  endforeach()
548310c9496SStella Laurenzo  list(REMOVE_DUPLICATES _flattened)
549310c9496SStella Laurenzo  set(${output_var} "${_flattened}" PARENT_SCOPE)
550310c9496SStella Laurenzoendfunction()
551310c9496SStella Laurenzo
552ac521d9eSStella Stamenova# Function: add_mlir_python_sources_target
553ac521d9eSStella Stamenova# Adds a target corresponding to an interface target that carries source
554ac521d9eSStella Stamenova# information. This target is responsible for "building" the sources by
555ac521d9eSStella Stamenova# placing them in the correct locations in the build and install trees.
556ac521d9eSStella Stamenova# Arguments:
557ac521d9eSStella Stamenova#   INSTALL_COMPONENT: Name of the install component. Typically same as the
558ac521d9eSStella Stamenova#     target name passed to add_mlir_python_modules().
559ac521d9eSStella Stamenova#   INSTALL_DESTINATION: Prefix into the install tree in which to install the
560ac521d9eSStella Stamenova#     library.
561ac521d9eSStella Stamenova#   OUTPUT_DIRECTORY: Full path in the build tree in which to create the
562ac521d9eSStella Stamenova#     library. Typically, this will be the common _mlir_libs directory where
563ac521d9eSStella Stamenova#     all extensions are emitted.
564ac521d9eSStella Stamenova#   SOURCES_TARGETS: List of interface libraries that carry source information.
565ac521d9eSStella Stamenovafunction(add_mlir_python_sources_target name)
566ac521d9eSStella Stamenova  cmake_parse_arguments(ARG
567ac521d9eSStella Stamenova  ""
568ac521d9eSStella Stamenova  "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY"
569ac521d9eSStella Stamenova  "SOURCES_TARGETS"
570ac521d9eSStella Stamenova  ${ARGN})
571ac521d9eSStella Stamenova
572ac521d9eSStella Stamenova  if(ARG_UNPARSED_ARGUMENTS)
573ac521d9eSStella Stamenova    message(FATAL_ERROR "Unhandled arguments to add_mlir_python_sources_target(${name}, ... : ${ARG_UNPARSED_ARGUMENTS}")
574ac521d9eSStella Stamenova  endif()
575ac521d9eSStella Stamenova
576ac521d9eSStella Stamenova  # On Windows create_symlink requires special permissions. Use copy_if_different instead.
577ac521d9eSStella Stamenova  if(CMAKE_HOST_WIN32)
578ac521d9eSStella Stamenova    set(_link_or_copy copy_if_different)
579ac521d9eSStella Stamenova  else()
580ac521d9eSStella Stamenova    set(_link_or_copy create_symlink)
581ac521d9eSStella Stamenova  endif()
582ac521d9eSStella Stamenova
583ac521d9eSStella Stamenova  foreach(_sources_target ${ARG_SOURCES_TARGETS})
584ac521d9eSStella Stamenova    get_target_property(_src_paths ${_sources_target} SOURCES)
585ac521d9eSStella Stamenova    if(NOT _src_paths)
586ac521d9eSStella Stamenova      get_target_property(_src_paths ${_sources_target} INTERFACE_SOURCES)
587ac521d9eSStella Stamenova      if(NOT _src_paths)
588ac521d9eSStella Stamenova        break()
589ac521d9eSStella Stamenova      endif()
590ac521d9eSStella Stamenova    endif()
591ac521d9eSStella Stamenova
592ac521d9eSStella Stamenova    get_target_property(_root_dir ${_sources_target} INCLUDE_DIRECTORIES)
593ac521d9eSStella Stamenova    if(NOT _root_dir)
594ac521d9eSStella Stamenova      get_target_property(_root_dir ${_sources_target} INTERFACE_INCLUDE_DIRECTORIES)
595ac521d9eSStella Stamenova    endif()
596ac521d9eSStella Stamenova
5971846523bSBrendan Duke    # Initialize an empty list of all Python source destination paths.
5981846523bSBrendan Duke    set(all_dest_paths "")
599ac521d9eSStella Stamenova    foreach(_src_path ${_src_paths})
600ac521d9eSStella Stamenova      file(RELATIVE_PATH _source_relative_path "${_root_dir}" "${_src_path}")
601ac521d9eSStella Stamenova      set(_dest_path "${ARG_OUTPUT_DIRECTORY}/${_source_relative_path}")
602ac521d9eSStella Stamenova
603ac521d9eSStella Stamenova      get_filename_component(_dest_dir "${_dest_path}" DIRECTORY)
604ac521d9eSStella Stamenova      file(MAKE_DIRECTORY "${_dest_dir}")
605ac521d9eSStella Stamenova
606ac521d9eSStella Stamenova      add_custom_command(
6071846523bSBrendan Duke        OUTPUT "${_dest_path}"
608ac521d9eSStella Stamenova        COMMENT "Copying python source ${_src_path} -> ${_dest_path}"
609ac521d9eSStella Stamenova        DEPENDS "${_src_path}"
610ac521d9eSStella Stamenova        COMMAND "${CMAKE_COMMAND}" -E ${_link_or_copy}
611ac521d9eSStella Stamenova            "${_src_path}" "${_dest_path}"
612ac521d9eSStella Stamenova      )
6131846523bSBrendan Duke
6141846523bSBrendan Duke      # Track the symlink or copy command output.
6151846523bSBrendan Duke      list(APPEND all_dest_paths "${_dest_path}")
6161846523bSBrendan Duke
617ac521d9eSStella Stamenova      if(ARG_INSTALL_DIR)
6182aa6d56dSStella Laurenzo        # We have to install each file individually because we need to preserve
6192aa6d56dSStella Laurenzo        # the relative directory structure in the install destination.
6202aa6d56dSStella Laurenzo        # As an example, ${_source_relative_path} may be dialects/math.py
6212aa6d56dSStella Laurenzo        # which would be transformed to ${ARG_INSTALL_DIR}/dialects
6222aa6d56dSStella Laurenzo        # here. This could be moved outside of the loop and cleaned up
6232aa6d56dSStella Laurenzo        # if we used FILE_SETS (introduced in CMake 3.23).
6242aa6d56dSStella Laurenzo        get_filename_component(_install_destination "${ARG_INSTALL_DIR}/${_source_relative_path}" DIRECTORY)
625ac521d9eSStella Stamenova        install(
6262aa6d56dSStella Laurenzo          FILES ${_src_path}
6272aa6d56dSStella Laurenzo          DESTINATION "${_install_destination}"
628ac521d9eSStella Stamenova          COMPONENT ${ARG_INSTALL_COMPONENT}
629ac521d9eSStella Stamenova        )
630ac521d9eSStella Stamenova      endif()
631ac521d9eSStella Stamenova    endforeach()
6322aa6d56dSStella Laurenzo  endforeach()
6331846523bSBrendan Duke
6341846523bSBrendan Duke  # Create a new custom target that depends on all symlinked or copied sources.
6351846523bSBrendan Duke  add_custom_target("${name}" DEPENDS ${all_dest_paths})
636ac521d9eSStella Stamenovaendfunction()
637ac521d9eSStella Stamenova
638310c9496SStella Laurenzo################################################################################
6399f3f6d7bSStella Laurenzo# Build python extension
6409f3f6d7bSStella Laurenzo################################################################################
6419f3f6d7bSStella Laurenzofunction(add_mlir_python_extension libname extname)
6429f3f6d7bSStella Laurenzo  cmake_parse_arguments(ARG
6439f3f6d7bSStella Laurenzo  ""
644392622d0SMaksim Levental  "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY;PYTHON_BINDINGS_LIBRARY"
6459f3f6d7bSStella Laurenzo  "SOURCES;LINK_LIBS"
6469f3f6d7bSStella Laurenzo  ${ARGN})
6479f3f6d7bSStella Laurenzo  if(ARG_UNPARSED_ARGUMENTS)
6489f3f6d7bSStella Laurenzo    message(FATAL_ERROR "Unhandled arguments to add_mlir_python_extension(${libname}, ... : ${ARG_UNPARSED_ARGUMENTS}")
6499f3f6d7bSStella Laurenzo  endif()
6509f3f6d7bSStella Laurenzo
6516a7687c4SMaksim Levental  # The extension itself must be compiled with RTTI and exceptions enabled.
6526a7687c4SMaksim Levental  # Also, some warning classes triggered by pybind11 are disabled.
6536a7687c4SMaksim Levental  set(eh_rtti_enable)
6546a7687c4SMaksim Levental  if (MSVC)
6556a7687c4SMaksim Levental    set(eh_rtti_enable /EHsc /GR)
6566a7687c4SMaksim Levental  elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE OR CLANG_CL)
6576a7687c4SMaksim Levental    set(eh_rtti_enable -frtti -fexceptions)
6586a7687c4SMaksim Levental  endif ()
6596a7687c4SMaksim Levental
6609f3f6d7bSStella Laurenzo  # The actual extension library produces a shared-object or DLL and has
6619f3f6d7bSStella Laurenzo  # sources that must be compiled in accordance with pybind11 needs (RTTI and
6629f3f6d7bSStella Laurenzo  # exceptions).
663392622d0SMaksim Levental  if(NOT DEFINED ARG_PYTHON_BINDINGS_LIBRARY OR ARG_PYTHON_BINDINGS_LIBRARY STREQUAL "pybind11")
66455e76c70SMike Urbach    pybind11_add_module(${libname}
6659f3f6d7bSStella Laurenzo      ${ARG_SOURCES}
6669f3f6d7bSStella Laurenzo    )
667392622d0SMaksim Levental  elseif(ARG_PYTHON_BINDINGS_LIBRARY STREQUAL "nanobind")
668392622d0SMaksim Levental    nanobind_add_module(${libname}
6699e863cd4Serwei-xilinx      NB_DOMAIN ${MLIR_BINDINGS_PYTHON_NB_DOMAIN}
670f136c800Svfdev      FREE_THREADED
671392622d0SMaksim Levental      ${ARG_SOURCES}
672392622d0SMaksim Levental    )
6735cd42747SPeter Hawkins
674*1a8f49fdSScott Todd    if (NOT MLIR_DISABLE_CONFIGURE_PYTHON_DEV_PACKAGES
675*1a8f49fdSScott Todd        AND (LLVM_COMPILER_IS_GCC_COMPATIBLE OR CLANG_CL))
676*1a8f49fdSScott Todd      # Avoid some warnings from upstream nanobind.
677*1a8f49fdSScott Todd      # If a superproject set MLIR_DISABLE_CONFIGURE_PYTHON_DEV_PACKAGES, let
678*1a8f49fdSScott Todd      # the super project handle compile options as it wishes.
679f136c800Svfdev      set(nanobind_target "nanobind-static")
680f136c800Svfdev      if (NOT TARGET ${nanobind_target})
681f136c800Svfdev        # Get correct nanobind target name: nanobind-static-ft or something else
682f136c800Svfdev        # It is set by nanobind_add_module function according to the passed options
683f136c800Svfdev        get_property(all_targets DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
684f136c800Svfdev
685f136c800Svfdev        # Iterate over the list of targets
686f136c800Svfdev        foreach(target ${all_targets})
687f136c800Svfdev          # Check if the target name matches the given string
688f136c800Svfdev          if("${target}" MATCHES "nanobind-")
689f136c800Svfdev            set(nanobind_target "${target}")
690f136c800Svfdev          endif()
691f136c800Svfdev        endforeach()
692f136c800Svfdev
693f136c800Svfdev        if (NOT TARGET ${nanobind_target})
694f136c800Svfdev          message(FATAL_ERROR "Could not find nanobind target to set compile options to")
695f136c800Svfdev        endif()
696f136c800Svfdev      endif()
697f136c800Svfdev      target_compile_options(${nanobind_target}
6985cd42747SPeter Hawkins        PRIVATE
6995cd42747SPeter Hawkins          -Wno-cast-qual
7005cd42747SPeter Hawkins          -Wno-zero-length-array
7015cd42747SPeter Hawkins          -Wno-nested-anon-types
7025cd42747SPeter Hawkins          -Wno-c++98-compat-extra-semi
7035cd42747SPeter Hawkins          -Wno-covered-switch-default
7046a7687c4SMaksim Levental          ${eh_rtti_enable}
7055cd42747SPeter Hawkins      )
7065cd42747SPeter Hawkins    endif()
70778f04477SMaksim Levental
70878f04477SMaksim Levental    if(APPLE)
70978f04477SMaksim Levental      # NanobindAdaptors.h uses PyClassMethod_New to build `pure_subclass`es but nanobind
71078f04477SMaksim Levental      # doesn't declare this API as undefined in its linker flags. So we need to declare it as such
71178f04477SMaksim Levental      # for downstream users that do not do something like `-undefined dynamic_lookup`.
71278f04477SMaksim Levental      set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-U -Wl,_PyClassMethod_New")
71378f04477SMaksim Levental    endif()
714392622d0SMaksim Levental  endif()
7159f3f6d7bSStella Laurenzo
7163adb0ac1SMarkus Böck  target_compile_options(${libname} PRIVATE ${eh_rtti_enable})
7179f3f6d7bSStella Laurenzo
7189f3f6d7bSStella Laurenzo  # Configure the output to match python expectations.
7199f3f6d7bSStella Laurenzo  set_target_properties(
7209f3f6d7bSStella Laurenzo    ${libname} PROPERTIES
721310c9496SStella Laurenzo    LIBRARY_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
7229f3f6d7bSStella Laurenzo    OUTPUT_NAME "${extname}"
7231de7a17fSStella Laurenzo    NO_SONAME ON
7249f3f6d7bSStella Laurenzo  )
7259f3f6d7bSStella Laurenzo
7269f3f6d7bSStella Laurenzo  if(WIN32)
7279f3f6d7bSStella Laurenzo    # Need to also set the RUNTIME_OUTPUT_DIRECTORY on Windows in order to
7289f3f6d7bSStella Laurenzo    # control where the .dll gets written.
7299f3f6d7bSStella Laurenzo    set_target_properties(
7309f3f6d7bSStella Laurenzo      ${libname} PROPERTIES
731310c9496SStella Laurenzo      RUNTIME_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
7325821047aSJohn Demme      ARCHIVE_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
7339f3f6d7bSStella Laurenzo    )
7349f3f6d7bSStella Laurenzo  endif()
7359f3f6d7bSStella Laurenzo
7369f3f6d7bSStella Laurenzo  target_link_libraries(${libname}
7379f3f6d7bSStella Laurenzo    PRIVATE
7389f3f6d7bSStella Laurenzo    ${ARG_LINK_LIBS}
7399f3f6d7bSStella Laurenzo  )
7409f3f6d7bSStella Laurenzo
7419f3f6d7bSStella Laurenzo  target_link_options(${libname}
7429f3f6d7bSStella Laurenzo    PRIVATE
7439f3f6d7bSStella Laurenzo      # On Linux, disable re-export of any static linked libraries that
7449f3f6d7bSStella Laurenzo      # came through.
7459f3f6d7bSStella Laurenzo      $<$<PLATFORM_ID:Linux>:LINKER:--exclude-libs,ALL>
7469f3f6d7bSStella Laurenzo  )
7479f3f6d7bSStella Laurenzo
748784a5bccSStella Stamenova  if(WIN32)
749784a5bccSStella Stamenova    # On Windows, pyconfig.h (and by extension python.h) hardcode the version of the
750784a5bccSStella Stamenova    # python library which will be used for linkage depending on the flavor of the build.
751784a5bccSStella Stamenova    # pybind11 has a workaround which depends on the definition of Py_DEBUG (if Py_DEBUG
752784a5bccSStella Stamenova    # is not passed in as a compile definition, pybind11 undefs _DEBUG when including
753784a5bccSStella Stamenova    # python.h, so that the release python library would be used).
754784a5bccSStella Stamenova    # Since mlir uses pybind11, we can leverage their workaround by never directly
755784a5bccSStella Stamenova    # pyconfig.h or python.h and instead relying on the pybind11 headers to include the
756784a5bccSStella Stamenova    # necessary python headers. This results in mlir always linking against the
757784a5bccSStella Stamenova    # release python library via the (undocumented) cmake property Python3_LIBRARY_RELEASE.
758784a5bccSStella Stamenova    target_link_libraries(${libname} PRIVATE ${Python3_LIBRARY_RELEASE})
759784a5bccSStella Stamenova  endif()
760784a5bccSStella Stamenova
7619f3f6d7bSStella Laurenzo  ################################################################################
7629f3f6d7bSStella Laurenzo  # Install
7639f3f6d7bSStella Laurenzo  ################################################################################
7649f3f6d7bSStella Laurenzo  if(ARG_INSTALL_DIR)
7659f3f6d7bSStella Laurenzo    install(TARGETS ${libname}
766310c9496SStella Laurenzo      COMPONENT ${ARG_INSTALL_COMPONENT}
7679f3f6d7bSStella Laurenzo      LIBRARY DESTINATION ${ARG_INSTALL_DIR}
7689f3f6d7bSStella Laurenzo      ARCHIVE DESTINATION ${ARG_INSTALL_DIR}
7699f3f6d7bSStella Laurenzo      # NOTE: Even on DLL-platforms, extensions go in the lib directory tree.
7709f3f6d7bSStella Laurenzo      RUNTIME DESTINATION ${ARG_INSTALL_DIR}
7719f3f6d7bSStella Laurenzo    )
7729f3f6d7bSStella Laurenzo  endif()
7739f3f6d7bSStella Laurenzoendfunction()
774