1################################################################################
2# Python modules
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################################################################################
10
11# Function: declare_mlir_python_sources
12# Declares pure python sources as part of a named grouping that can be built
13# later.
14# Arguments:
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
21#     mixed.
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#   DEST_PREFIX: Destination prefix to prepend to files in the python
27#     package directory namespace.
28function(declare_mlir_python_sources name)
29  cmake_parse_arguments(ARG
30    ""
31    "ROOT_DIR;ADD_TO_PARENT;DEST_PREFIX"
32    "SOURCES;SOURCES_GLOB"
33    ${ARGN})
34
35  if(NOT ARG_ROOT_DIR)
36    set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
37  endif()
38  set(_install_destination "src/python/${name}")
39
40  # Process the glob.
41  set(_glob_sources)
42  if(ARG_SOURCES_GLOB)
43    set(_glob_spec ${ARG_SOURCES_GLOB})
44    list(TRANSFORM _glob_spec PREPEND "${ARG_ROOT_DIR}/")
45    file(GLOB_RECURSE _glob_sources
46      RELATIVE "${ARG_ROOT_DIR}"
47      ${_glob_spec}
48    )
49    list(APPEND ARG_SOURCES ${_glob_sources})
50  endif()
51
52  # We create a custom target to carry properties and dependencies for
53  # generated sources.
54  add_library(${name} INTERFACE)
55  set(_file_depends "${ARG_SOURCES}")
56  list(TRANSFORM _file_depends PREPEND "${ARG_ROOT_DIR}/")
57  set_target_properties(${name} PROPERTIES
58    # Yes: Leading-lowercase property names are load bearing and the recommended
59    # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
60    # Note that ROOT_DIR and FILE_DEPENDS are not exported because they are
61    # only relevant to in-tree uses.
62    EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_DEST_PREFIX;mlir_python_DEST_PREFIX;mlir_python_SOURCES;mlir_python_DEPENDS"
63    mlir_python_SOURCES_TYPE pure
64    mlir_python_ROOT_DIR "${ARG_ROOT_DIR}"
65    mlir_python_DEST_PREFIX "${ARG_DEST_PREFIX}"
66    mlir_python_SOURCES "${ARG_SOURCES}"
67    mlir_python_FILE_DEPENDS "${_file_depends}"
68    mlir_python_DEPENDS ""
69  )
70  # Note that an "include" directory has no meaning to such faux targets,
71  # but it is a CMake supported way to specify a directory search list in a
72  # way that works both in-tree and out. It has some super powers which are
73  # not possible to emulate with custom properties (because of the prohibition
74  # on using generator expressions in exported custom properties and the
75  # special dispensation for $<INSTALL_PREFIX>).
76  target_include_directories(${name} INTERFACE
77    "$<BUILD_INTERFACE:${ARG_ROOT_DIR}>"
78    "$<INSTALL_INTERFACE:${_install_destination}>"
79  )
80
81  # Add to parent.
82  if(ARG_ADD_TO_PARENT)
83    set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
84  endif()
85
86  # Install.
87  if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
88    _mlir_python_install_sources(
89      ${name} "${ARG_ROOT_DIR}" "${_install_destination}"
90      ${ARG_SOURCES}
91    )
92  endif()
93endfunction()
94
95# Function: declare_mlir_python_extension
96# Declares a buildable python extension from C++ source files. The built
97# module is considered a python source file and included as everything else.
98# Arguments:
99#   ROOT_DIR: Root directory where sources are interpreted relative to.
100#     Defaults to CMAKE_CURRENT_SOURCE_DIR.
101#   MODULE_NAME: Local import name of the module (i.e. "_mlir").
102#   ADD_TO_PARENT: Same as for declare_mlir_python_sources.
103#   SOURCES: C++ sources making up the module.
104#   PRIVATE_LINK_LIBS: List of libraries to link in privately to the module
105#     regardless of how it is included in the project (generally should be
106#     static libraries that can be included with hidden visibility).
107#   EMBED_CAPI_LINK_LIBS: Dependent CAPI libraries that this extension depends
108#     on. These will be collected for all extensions and put into an
109#     aggregate dylib that is linked against.
110function(declare_mlir_python_extension name)
111  cmake_parse_arguments(ARG
112    ""
113    "ROOT_DIR;MODULE_NAME;ADD_TO_PARENT"
114    "SOURCES;PRIVATE_LINK_LIBS;EMBED_CAPI_LINK_LIBS"
115    ${ARGN})
116
117  if(NOT ARG_ROOT_DIR)
118    set(ARG_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
119  endif()
120  set(_install_destination "src/python/${name}")
121
122  add_library(${name} INTERFACE)
123  set_target_properties(${name} PROPERTIES
124    # Yes: Leading-lowercase property names are load bearing and the recommended
125    # way to do this: https://gitlab.kitware.com/cmake/cmake/-/issues/19261
126    # Note that ROOT_DIR and FILE_DEPENDS are not exported because they are
127    # only relevant to in-tree uses.
128    EXPORT_PROPERTIES "mlir_python_SOURCES_TYPE;mlir_python_EXTENSION_MODULE_NAME;mlir_python_CPP_SOURCES;mlir_python_PRIVATE_LINK_LIBS;mlir_python_EMBED_CAPI_LINK_LIBS;mlir_python_DEPENDS"
129    mlir_python_SOURCES_TYPE extension
130    mlir_python_ROOT_DIR "${ARG_ROOT_DIR}"
131    mlir_python_EXTENSION_MODULE_NAME "${ARG_MODULE_NAME}"
132    mlir_python_CPP_SOURCES "${ARG_SOURCES}"
133    mlir_python_PRIVATE_LINK_LIBS "${ARG_PRIVATE_LINK_LIBS}"
134    mlir_python_EMBED_CAPI_LINK_LIBS "${ARG_EMBED_CAPI_LINK_LIBS}"
135    mlir_python_FILE_DEPENDS ""
136    mlir_python_DEPENDS ""
137  )
138  # Note that an "include" directory has no meaning to such faux targets,
139  # but it is a CMake supported way to specify an install-prefix relative
140  # directory. It has some super powers which are not possible to emulate
141  # with custom properties (because of the prohibition on using generator
142  # expressions in exported custom properties and the special dispensation
143  # for $<INSTALL_PREFIX> and $<INSTALL_INTERFACE>). On imported targets,
144  # this is used as a single value, not as a list, so it must only have one
145  # item in it.
146  target_include_directories(${name} INTERFACE
147    "$<INSTALL_INTERFACE:${_install_destination}>"
148  )
149
150  # Add to parent.
151  if(ARG_ADD_TO_PARENT)
152    set_property(TARGET ${ARG_ADD_TO_PARENT} APPEND PROPERTY mlir_python_DEPENDS ${name})
153  endif()
154
155  # Install.
156  if(NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
157    _mlir_python_install_sources(
158      ${name} "${ARG_ROOT_DIR}" "src/python/${name}"
159      ${ARG_SOURCES}
160    )
161  endif()
162endfunction()
163
164function(_mlir_python_install_sources name source_root_dir destination)
165  foreach(source_relative_path ${ARGN})
166    # Transform "a/b/c.py" -> "${install_prefix}/a/b" for installation.
167    get_filename_component(
168      dest_relative_path "${source_relative_path}" DIRECTORY
169      BASE_DIR "${source_root_dir}"
170    )
171    install(
172      FILES "${source_root_dir}/${source_relative_path}"
173      DESTINATION "${destination}/${dest_relative_path}"
174      COMPONENT "${name}"
175    )
176  endforeach()
177  get_target_export_arg(${name} MLIR export_to_mlirtargets UMBRELLA mlir-libraries)
178  install(TARGETS ${name}
179    COMPONENT ${name}
180    ${export_to_mlirtargets}
181  )
182endfunction()
183
184# Function: add_mlir_python_modules
185# Adds python modules to a project, building them from a list of declared
186# source groupings (see declare_mlir_python_sources and
187# declare_mlir_python_extension). One of these must be called for each
188# packaging root in use.
189# Arguments:
190#   ROOT_PREFIX: The directory in the build tree to emit sources. This will
191#     typically be something like ${MY_BINARY_DIR}/python_packages/foobar
192#     for non-relocatable modules or a deeper directory tree for relocatable.
193#   INSTALL_PREFIX: Prefix into the install tree for installing the package.
194#     Typically mirrors the path above but without an absolute path.
195#   DECLARED_SOURCES: List of declared source groups to include. The entire
196#     DAG of source modules is included.
197#   COMMON_CAPI_LINK_LIBS: List of dylibs (typically one) to make every
198#     extension depend on (see mlir_python_add_common_capi_library).
199function(add_mlir_python_modules name)
200  cmake_parse_arguments(ARG
201    ""
202    "ROOT_PREFIX;INSTALL_PREFIX;COMMON_CAPI_LINK_LIBS"
203    "DECLARED_SOURCES"
204    ${ARGN})
205  # Helper to process an individual target.
206  function(_process_target modules_target sources_target)
207    get_target_property(_source_type ${sources_target} mlir_python_SOURCES_TYPE)
208
209    # The root directory differs based on whether it is IMPORTED (installed
210    # dep).
211    get_target_property(_is_imported ${sources_target} IMPORTED)
212    if(NOT _is_imported)
213      # In-tree.
214      get_target_property(_python_root_dir ${sources_target} mlir_python_ROOT_DIR)
215    else()
216      # Imported.
217      # Note: We only populate a single directory in
218      # INTERFACE_INCLUDE_DIRECTORIES, so we can get away with just using it
219      # as a single value.
220      get_target_property(_python_root_dir ${sources_target} INTERFACE_INCLUDE_DIRECTORIES)
221    endif()
222
223    if(_source_type STREQUAL "pure")
224      # Pure python sources to link into the tree.
225      get_target_property(_python_sources ${sources_target} mlir_python_SOURCES)
226      get_target_property(_specified_dest_prefix ${sources_target} mlir_python_DEST_PREFIX)
227      foreach(_source_relative_path ${_python_sources})
228        set(_dest_relative_path "${_source_relative_path}")
229        if(_specified_dest_prefix)
230          set(_dest_relative_path "${_specified_dest_prefix}/${_dest_relative_path}")
231        endif()
232        set(_src_path "${_python_root_dir}/${_source_relative_path}")
233        set(_dest_path "${ARG_ROOT_PREFIX}/${_dest_relative_path}")
234
235        get_filename_component(_dest_dir "${_dest_path}" DIRECTORY)
236        get_filename_component(_install_path "${ARG_INSTALL_PREFIX}/${_dest_relative_path}" DIRECTORY)
237
238        file(MAKE_DIRECTORY "${_dest_dir}")
239        add_custom_command(
240          TARGET ${modules_target} PRE_BUILD
241          COMMENT "Copying python source ${_src_path} -> ${_dest_path}"
242          DEPENDS "${_src_path}"
243          BYPRODUCTS "${_dest_path}"
244          COMMAND "${CMAKE_COMMAND}" -E create_symlink
245              "${_src_path}" "${_dest_path}"
246        )
247        install(
248          FILES "${_src_path}"
249          DESTINATION "${_install_path}"
250          COMPONENT ${modules_target}
251        )
252      endforeach()
253    elseif(_source_type STREQUAL "extension")
254      # Native CPP extension.
255      get_target_property(_module_name ${sources_target} mlir_python_EXTENSION_MODULE_NAME)
256      get_target_property(_cpp_sources ${sources_target} mlir_python_CPP_SOURCES)
257      get_target_property(_private_link_libs ${sources_target} mlir_python_PRIVATE_LINK_LIBS)
258      # Transform relative source to based on root dir.
259      list(TRANSFORM _cpp_sources PREPEND "${_python_root_dir}/")
260      set(_extension_target "${name}.extension.${_module_name}.dso")
261      add_mlir_python_extension(${_extension_target} "${_module_name}"
262        INSTALL_COMPONENT ${modules_target}
263        INSTALL_DIR "${ARG_INSTALL_PREFIX}/_mlir_libs"
264        OUTPUT_DIRECTORY "${ARG_ROOT_PREFIX}/_mlir_libs"
265        SOURCES ${_cpp_sources}
266        LINK_LIBS PRIVATE
267          ${_private_link_libs}
268          ${ARG_COMMON_CAPI_LINK_LIBS}
269      )
270      add_dependencies(${name} ${_extension_target})
271      mlir_python_setup_extension_rpath(${_extension_target})
272    else()
273      message(SEND_ERROR "Unrecognized source type '${_source_type}' for python source target ${sources_target}")
274      return()
275    endif()
276  endfunction()
277
278  _flatten_mlir_python_targets(_flat_targets ${ARG_DECLARED_SOURCES})
279  # Collect dependencies.
280  set(_depends)
281  foreach(sources_target ${_flat_targets})
282    get_target_property(_local_depends ${sources_target} mlir_python_FILE_DEPENDS)
283    if(_local_depends)
284      list(APPEND _depends ${_local_depends})
285    endif()
286  endforeach()
287
288  # Build the modules target.
289  add_custom_target(${name} ALL DEPENDS ${_depends})
290  foreach(sources_target ${_flat_targets})
291    _process_target(${name} ${sources_target})
292  endforeach()
293
294  # Create an install target.
295  if (NOT LLVM_ENABLE_IDE)
296    add_llvm_install_targets(
297      install-${name}
298      DEPENDS ${name}
299      COMPONENT ${name})
300  endif()
301endfunction()
302
303# Function: declare_mlir_dialect_python_bindings
304# Helper to generate source groups for dialects, including both static source
305# files and a TD_FILE to generate wrappers.
306#
307# This will generate a source group named ${ADD_TO_PARENT}.${DIALECT_NAME}.
308#
309# Arguments:
310#   ROOT_DIR: Same as for declare_mlir_python_sources().
311#   ADD_TO_PARENT: Same as for declare_mlir_python_sources(). Unique names
312#     for the subordinate source groups are derived from this.
313#   TD_FILE: Tablegen file to generate source for (relative to ROOT_DIR).
314#   DIALECT_NAME: Python name of the dialect.
315#   SOURCES: Same as declare_mlir_python_sources().
316#   SOURCES_GLOB: Same as declare_mlir_python_sources().
317#   DEPENDS: Additional dependency targets.
318function(declare_mlir_dialect_python_bindings)
319  cmake_parse_arguments(ARG
320    ""
321    "ROOT_DIR;ADD_TO_PARENT;TD_FILE;DIALECT_NAME"
322    "SOURCES;SOURCES_GLOB;DEPENDS"
323    ${ARGN})
324  # Sources.
325  set(_dialect_target "${ARG_ADD_TO_PARENT}.${ARG_DIALECT_NAME}")
326  declare_mlir_python_sources(${_dialect_target}
327    ROOT_DIR "${ARG_ROOT_DIR}"
328    ADD_TO_PARENT "${ARG_ADD_TO_PARENT}"
329    SOURCES "${ARG_SOURCES}"
330    SOURCES_GLOB "${ARG_SOURCES_GLOB}"
331  )
332
333  # Tablegen
334  if(ARG_TD_FILE)
335    set(tblgen_target "${ARG_ADD_TO}.${ARG_DIALECT_NAME}.tablegen")
336    set(td_file "${ARG_ROOT_DIR}/${ARG_TD_FILE}")
337    get_filename_component(relative_td_directory "${ARG_TD_FILE}" DIRECTORY)
338    set(dialect_filename "${relative_td_directory}/_${ARG_DIALECT_NAME}_ops_gen.py")
339    set(LLVM_TARGET_DEFINITIONS ${td_file})
340    mlir_tablegen("${dialect_filename}" -gen-python-op-bindings
341                  -bind-dialect=${ARG_DIALECT_NAME})
342    add_public_tablegen_target(${tblgen_target})
343    if(ARG_DEPENDS)
344      add_dependencies(${tblgen_target} ${ARG_DEPENDS})
345    endif()
346
347    # Generated.
348    declare_mlir_python_sources("${ARG_ADD_TO_PARENT}.${ARG_DIALECT_NAME}.ops_gen"
349      ROOT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
350      ADD_TO_PARENT "${_dialect_target}"
351      SOURCES "${dialect_filename}"
352    )
353  endif()
354endfunction()
355
356# Function: mlir_python_setup_extension_rpath
357# Sets RPATH properties on a target, assuming that it is being output to
358# an _mlir_libs directory with all other libraries. For static linkage,
359# the RPATH will just be the origin. If linking dynamically, then the LLVM
360# library directory will be added.
361# Arguments:
362#   RELATIVE_INSTALL_ROOT: If building dynamically, an RPATH entry will be
363#     added to the install tree lib/ directory by first traversing this
364#     path relative to the installation location. Typically a number of ".."
365#     entries, one for each level of the install path.
366function(mlir_python_setup_extension_rpath target)
367  cmake_parse_arguments(ARG
368    ""
369    "RELATIVE_INSTALL_ROOT"
370    ""
371    ${ARGN})
372
373  # RPATH handling.
374  # For the build tree, include the LLVM lib directory and the current
375  # directory for RPATH searching. For install, just the current directory
376  # (assumes that needed dependencies have been installed).
377  if(NOT APPLE AND NOT UNIX)
378    return()
379  endif()
380
381  set(_origin_prefix "\$ORIGIN")
382  if(APPLE)
383    set(_origin_prefix "@loader_path")
384  endif()
385  set_target_properties(${target} PROPERTIES
386    BUILD_WITH_INSTALL_RPATH OFF
387    BUILD_RPATH "${_origin_prefix}"
388    INSTALL_RPATH "${_origin_prefix}"
389  )
390
391  # For static builds, that is all that is needed: all dependencies will be in
392  # the one directory. For shared builds, then we also need to add the global
393  # lib directory. This will be absolute for the build tree and relative for
394  # install.
395  # When we have access to CMake >= 3.20, there is a helper to calculate this.
396  if(BUILD_SHARED_LIBS AND ARG_RELATIVE_INSTALL_ROOT)
397    get_filename_component(_real_lib_dir "${LLVM_LIBRARY_OUTPUT_INTDIR}" REALPATH)
398    set_property(TARGET ${target} APPEND PROPERTY
399      BUILD_RPATH "${_real_lib_dir}")
400    set_property(TARGET ${target} APPEND PROPERTY
401      INSTALL_RPATH "${_origin_prefix}/${ARG_RELATIVE_INSTALL_ROOT}/lib${LLVM_LIBDIR_SUFFIX}")
402  endif()
403endfunction()
404
405# Function: add_mlir_python_common_capi_library
406# Adds a shared library which embeds dependent CAPI libraries needed to link
407# all extensions.
408# Arguments:
409#   INSTALL_COMPONENT: Name of the install component. Typically same as the
410#     target name passed to add_mlir_python_modules().
411#   INSTALL_DESTINATION: Prefix into the install tree in which to install the
412#     library.
413#   OUTPUT_DIRECTORY: Full path in the build tree in which to create the
414#     library. Typically, this will be the common _mlir_libs directory where
415#     all extensions are emitted.
416#   RELATIVE_INSTALL_ROOT: See mlir_python_setup_extension_rpath().
417#   DECLARED_SOURCES: Source groups from which to discover dependent
418#     EMBED_CAPI_LINK_LIBS.
419#   EMBED_LIBS: Additional libraries to embed (must be built with OBJECTS and
420#     have an "obj.${name}" object library associated).
421function(add_mlir_python_common_capi_library name)
422  cmake_parse_arguments(ARG
423    ""
424    "INSTALL_COMPONENT;INSTALL_DESTINATION;OUTPUT_DIRECTORY;RELATIVE_INSTALL_ROOT"
425    "DECLARED_SOURCES;EMBED_LIBS"
426    ${ARGN})
427  # Collect all explicit and transitive embed libs.
428  set(_embed_libs ${ARG_EMBED_LIBS})
429  _flatten_mlir_python_targets(_all_source_targets ${ARG_DECLARED_SOURCES})
430  foreach(t ${_all_source_targets})
431    get_target_property(_local_embed_libs ${t} mlir_python_EMBED_CAPI_LINK_LIBS)
432    if(_local_embed_libs)
433      list(APPEND _embed_libs ${_local_embed_libs})
434    endif()
435  endforeach()
436  list(REMOVE_DUPLICATES _embed_libs)
437
438  # Generate the aggregate .so that everything depends on.
439  add_mlir_aggregate(${name}
440    SHARED
441    DISABLE_INSTALL
442    EMBED_LIBS ${_embed_libs}
443  )
444
445  if(MSVC)
446    set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
447  endif()
448  set_target_properties(${name} PROPERTIES
449    LIBRARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
450    BINARY_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
451    # Needed for windows (and don't hurt others).
452    RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
453    ARCHIVE_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}"
454  )
455  mlir_python_setup_extension_rpath(${name}
456    RELATIVE_INSTALL_ROOT "${ARG_RELATIVE_INSTALL_ROOT}"
457  )
458  install(TARGETS ${name}
459    COMPONENT ${ARG_INSTALL_COMPONENT}
460    LIBRARY DESTINATION "${ARG_INSTALL_DESTINATION}"
461    RUNTIME DESTINATION "${ARG_INSTALL_DESTINATION}"
462  )
463
464endfunction()
465
466function(_flatten_mlir_python_targets output_var)
467  set(_flattened)
468  foreach(t ${ARGN})
469    get_target_property(_source_type ${t} mlir_python_SOURCES_TYPE)
470    get_target_property(_depends ${t} mlir_python_DEPENDS)
471    if(_source_type)
472      list(APPEND _flattened "${t}")
473      if(_depends)
474        _flatten_mlir_python_targets(_local_flattened ${_depends})
475        list(APPEND _flattened ${_local_flattened})
476      endif()
477    endif()
478  endforeach()
479  list(REMOVE_DUPLICATES _flattened)
480  set(${output_var} "${_flattened}" PARENT_SCOPE)
481endfunction()
482
483################################################################################
484# Build python extension
485################################################################################
486function(add_mlir_python_extension libname extname)
487  cmake_parse_arguments(ARG
488  ""
489  "INSTALL_COMPONENT;INSTALL_DIR;OUTPUT_DIRECTORY"
490  "SOURCES;LINK_LIBS"
491  ${ARGN})
492  if (ARG_UNPARSED_ARGUMENTS)
493    message(FATAL_ERROR " Unhandled arguments to add_mlir_python_extension(${libname}, ... : ${ARG_UNPARSED_ARGUMENTS}")
494  endif()
495  if ("${ARG_SOURCES}" STREQUAL "")
496    message(FATAL_ERROR " Missing SOURCES argument to add_mlir_python_extension(${libname}, ...")
497  endif()
498
499  # The actual extension library produces a shared-object or DLL and has
500  # sources that must be compiled in accordance with pybind11 needs (RTTI and
501  # exceptions).
502  pybind11_add_module(${libname}
503    ${ARG_SOURCES}
504  )
505
506  # The extension itself must be compiled with RTTI and exceptions enabled.
507  # Also, some warning classes triggered by pybind11 are disabled.
508  target_compile_options(${libname} PRIVATE
509    $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
510      # Enable RTTI and exceptions.
511      -frtti -fexceptions
512    >
513    $<$<CXX_COMPILER_ID:MSVC>:
514      # Enable RTTI and exceptions.
515      /EHsc /GR>
516  )
517
518  # Configure the output to match python expectations.
519  set_target_properties(
520    ${libname} PROPERTIES
521    LIBRARY_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
522    OUTPUT_NAME "${extname}"
523    NO_SONAME ON
524  )
525
526  if(WIN32)
527    # Need to also set the RUNTIME_OUTPUT_DIRECTORY on Windows in order to
528    # control where the .dll gets written.
529    set_target_properties(
530      ${libname} PROPERTIES
531      RUNTIME_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
532      ARCHIVE_OUTPUT_DIRECTORY ${ARG_OUTPUT_DIRECTORY}
533    )
534  endif()
535
536  # Python extensions depends *only* on the public API and LLVMSupport unless
537  # if further dependencies are added explicitly.
538  target_link_libraries(${libname}
539    PRIVATE
540    ${ARG_LINK_LIBS}
541    ${PYEXT_LIBADD}
542  )
543
544  target_link_options(${libname}
545    PRIVATE
546      # On Linux, disable re-export of any static linked libraries that
547      # came through.
548      $<$<PLATFORM_ID:Linux>:LINKER:--exclude-libs,ALL>
549  )
550
551  ################################################################################
552  # Install
553  ################################################################################
554  if (ARG_INSTALL_DIR)
555    install(TARGETS ${libname}
556      COMPONENT ${ARG_INSTALL_COMPONENT}
557      LIBRARY DESTINATION ${ARG_INSTALL_DIR}
558      ARCHIVE DESTINATION ${ARG_INSTALL_DIR}
559      # NOTE: Even on DLL-platforms, extensions go in the lib directory tree.
560      RUNTIME DESTINATION ${ARG_INSTALL_DIR}
561    )
562  endif()
563endfunction()
564