1include(GNUInstallDirs)
2include(LLVMDistributionSupport)
3
4function(mlir_tablegen ofn)
5  tablegen(MLIR ${ARGV})
6  set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
7      PARENT_SCOPE)
8  include_directories(${CMAKE_CURRENT_BINARY_DIR})
9endfunction()
10
11# Declare a dialect in the include directory
12function(add_mlir_dialect dialect dialect_namespace)
13  set(LLVM_TARGET_DEFINITIONS ${dialect}.td)
14  mlir_tablegen(${dialect}.h.inc -gen-op-decls)
15  mlir_tablegen(${dialect}.cpp.inc -gen-op-defs)
16  mlir_tablegen(${dialect}Types.h.inc -gen-typedef-decls -typedefs-dialect=${dialect_namespace})
17  mlir_tablegen(${dialect}Types.cpp.inc -gen-typedef-defs -typedefs-dialect=${dialect_namespace})
18  mlir_tablegen(${dialect}Dialect.h.inc -gen-dialect-decls -dialect=${dialect_namespace})
19  mlir_tablegen(${dialect}Dialect.cpp.inc -gen-dialect-defs -dialect=${dialect_namespace})
20  add_public_tablegen_target(MLIR${dialect}IncGen)
21  add_dependencies(mlir-headers MLIR${dialect}IncGen)
22endfunction()
23
24# Declare a dialect in the include directory
25function(add_mlir_interface interface)
26  set(LLVM_TARGET_DEFINITIONS ${interface}.td)
27  mlir_tablegen(${interface}.h.inc -gen-op-interface-decls)
28  mlir_tablegen(${interface}.cpp.inc -gen-op-interface-defs)
29  add_public_tablegen_target(MLIR${interface}IncGen)
30  add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
31endfunction()
32
33
34# Generate Documentation
35function(add_mlir_doc doc_filename output_file output_directory command)
36  set(LLVM_TARGET_DEFINITIONS ${doc_filename}.td)
37  tablegen(MLIR ${output_file}.md ${command} ${ARGN})
38  set(GEN_DOC_FILE ${MLIR_BINARY_DIR}/docs/${output_directory}${output_file}.md)
39  add_custom_command(
40          OUTPUT ${GEN_DOC_FILE}
41          COMMAND ${CMAKE_COMMAND} -E copy
42                  ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md
43                  ${GEN_DOC_FILE}
44          DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md)
45  add_custom_target(${output_file}DocGen DEPENDS ${GEN_DOC_FILE})
46  add_dependencies(mlir-doc ${output_file}DocGen)
47endfunction()
48
49# Declare an mlir library which can be compiled in libMLIR.so
50# In addition to everything that llvm_add_librar accepts, this
51# also has the following option:
52# EXCLUDE_FROM_LIBMLIR
53#   Don't include this library in libMLIR.so.  This option should be used
54#   for test libraries, executable-specific libraries, or rarely used libraries
55#   with large dependencies.
56# ENABLE_AGGREGATION
57#   Forces generation of an OBJECT library, exports additional metadata,
58#   and installs additional object files needed to include this as part of an
59#   aggregate shared library.
60#   TODO: Make this the default for all MLIR libraries once all libraries
61#   are compatible with building an object library.
62function(add_mlir_library name)
63  cmake_parse_arguments(ARG
64    "SHARED;INSTALL_WITH_TOOLCHAIN;EXCLUDE_FROM_LIBMLIR;DISABLE_INSTALL;ENABLE_AGGREGATION"
65    ""
66    "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS"
67    ${ARGN})
68  set(srcs)
69  if(MSVC_IDE OR XCODE)
70    # Add public headers
71    file(RELATIVE_PATH lib_path
72      ${MLIR_SOURCE_DIR}/lib/
73      ${CMAKE_CURRENT_SOURCE_DIR}
74    )
75    if(NOT lib_path MATCHES "^[.][.]")
76      file( GLOB_RECURSE headers
77        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.h
78        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.def
79      )
80      set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
81
82      file( GLOB_RECURSE tds
83        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.td
84      )
85      source_group("TableGen descriptions" FILES ${tds})
86      set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
87
88      if(headers OR tds)
89        set(srcs ${headers} ${tds})
90      endif()
91    endif()
92  endif(MSVC_IDE OR XCODE)
93  if(srcs OR ARG_ADDITIONAL_HEADERS)
94    set(srcs
95      ADDITIONAL_HEADERS
96      ${srcs}
97      ${ARG_ADDITIONAL_HEADERS} # It may contain unparsed unknown args.
98      )
99  endif()
100
101  # Is an object library needed.
102  set(NEEDS_OBJECT_LIB OFF)
103  if(ARG_ENABLE_AGGREGATION)
104    set(NEEDS_OBJECT_LIB ON)
105  endif()
106
107  # Determine type of library.
108  if(ARG_SHARED)
109    set(LIBTYPE SHARED)
110  else()
111    # llvm_add_library ignores BUILD_SHARED_LIBS if STATIC is explicitly set,
112    # so we need to handle it here.
113    if(BUILD_SHARED_LIBS)
114      set(LIBTYPE SHARED)
115    else()
116      set(LIBTYPE STATIC)
117    endif()
118    # Test libraries and such shouldn't be include in libMLIR.so
119    if(NOT ARG_EXCLUDE_FROM_LIBMLIR)
120      set(NEEDS_OBJECT_LIB ON)
121      set_property(GLOBAL APPEND PROPERTY MLIR_STATIC_LIBS ${name})
122      set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${ARG_LINK_COMPONENTS})
123      set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS})
124    endif()
125  endif()
126
127  if(NEEDS_OBJECT_LIB AND NOT XCODE)
128    # The Xcode generator doesn't handle object libraries correctly.
129    # We special case xcode when building aggregates.
130    list(APPEND LIBTYPE OBJECT)
131  endif()
132
133  # MLIR libraries uniformly depend on LLVMSupport.  Just specify it once here.
134  list(APPEND ARG_LINK_COMPONENTS Support)
135
136  # LINK_COMPONENTS is necessary to allow libLLVM.so to be properly
137  # substituted for individual library dependencies if LLVM_LINK_LLVM_DYLIB
138  # Perhaps this should be in llvm_add_library instead?  However, it fails
139  # on libclang-cpp.so
140  get_property(llvm_component_libs GLOBAL PROPERTY LLVM_COMPONENT_LIBS)
141  foreach(lib ${ARG_LINK_LIBS})
142    if(${lib} IN_LIST llvm_component_libs)
143      message(SEND_ERROR "${name} specifies LINK_LIBS ${lib}, but LINK_LIBS cannot be used for LLVM libraries.  Please use LINK_COMPONENTS instead.")
144    endif()
145  endforeach()
146
147  list(APPEND ARG_DEPENDS mlir-generic-headers)
148  llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs} DEPENDS ${ARG_DEPENDS} LINK_COMPONENTS ${ARG_LINK_COMPONENTS} LINK_LIBS ${ARG_LINK_LIBS})
149
150  if(TARGET ${name})
151    target_link_libraries(${name} INTERFACE ${LLVM_COMMON_LIBS})
152    if(NOT ARG_DISABLE_INSTALL)
153      add_mlir_library_install(${name})
154    endif()
155  else()
156    # Add empty "phony" target
157    add_custom_target(${name})
158  endif()
159  set_target_properties(${name} PROPERTIES FOLDER "MLIR libraries")
160
161  # Setup aggregate.
162  if(ARG_ENABLE_AGGREGATION)
163    # Compute and store the properties needed to build aggregates.
164    set(AGGREGATE_OBJECTS)
165    set(AGGREGATE_OBJECT_LIB)
166    set(AGGREGATE_DEPS)
167    if(XCODE)
168      # XCode has limited support for object libraries. Instead, add dep flags
169      # that force the entire library to be embedded.
170      list(APPEND AGGREGATE_DEPS "-force_load" "${name}")
171    else()
172      list(APPEND AGGREGATE_OBJECTS "$<TARGET_OBJECTS:obj.${name}>")
173      list(APPEND AGGREGATE_OBJECT_LIB "obj.${name}")
174    endif()
175
176    # For each declared dependency, transform it into a generator expression
177    # which excludes it if the ultimate link target is excluding the library.
178    set(NEW_LINK_LIBRARIES)
179    get_target_property(CURRENT_LINK_LIBRARIES  ${name} LINK_LIBRARIES)
180    get_mlir_filtered_link_libraries(NEW_LINK_LIBRARIES ${CURRENT_LINK_LIBRARIES})
181    set_target_properties(${name} PROPERTIES LINK_LIBRARIES "${NEW_LINK_LIBRARIES}")
182    list(APPEND AGGREGATE_DEPS ${NEW_LINK_LIBRARIES})
183    set_target_properties(${name} PROPERTIES
184      EXPORT_PROPERTIES "MLIR_AGGREGATE_OBJECT_LIB_IMPORTED;MLIR_AGGREGATE_DEP_LIBS_IMPORTED"
185      MLIR_AGGREGATE_OBJECTS "${AGGREGATE_OBJECTS}"
186      MLIR_AGGREGATE_DEPS "${AGGREGATE_DEPS}"
187      MLIR_AGGREGATE_OBJECT_LIB_IMPORTED "${AGGREGATE_OBJECT_LIB}"
188      MLIR_AGGREGATE_DEP_LIBS_IMPORTED "${CURRENT_LINK_LIBRARIES}"
189    )
190
191    # In order for out-of-tree projects to build aggregates of this library,
192    # we need to install the OBJECT library.
193    if(MLIR_INSTALL_AGGREGATE_OBJECTS AND NOT ARG_DISABLE_INSTALL)
194      add_mlir_library_install(obj.${name})
195    endif()
196  endif()
197endfunction(add_mlir_library)
198
199# Sets a variable with a transformed list of link libraries such individual
200# libraries will be dynamically excluded when evaluated on a final library
201# which defines an MLIR_AGGREGATE_EXCLUDE_LIBS which contains any of the
202# libraries. Each link library can be a generator expression but must not
203# resolve to an arity > 1 (i.e. it can be optional).
204function(get_mlir_filtered_link_libraries output)
205  set(_results)
206  foreach(linklib ${ARGN})
207    # In English, what this expression does:
208    # For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
209    # on the context target (i.e. the executable or shared library being linked)
210    # and, if it is not in that list, emit the library name. Otherwise, empty.
211    list(APPEND _results
212      "$<$<NOT:$<IN_LIST:${linklib},$<GENEX_EVAL:$<TARGET_PROPERTY:MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${linklib}>"
213    )
214  endforeach()
215  set(${output} "${_results}" PARENT_SCOPE)
216endfunction(get_mlir_filtered_link_libraries)
217
218# Declares an aggregate library. Such a library is a combination of arbitrary
219# regular add_mlir_library() libraries with the special feature that they can
220# be configured to statically embed some subset of their dependencies, as is
221# typical when creating a .so/.dylib/.dll or a mondo static library.
222#
223# It is always safe to depend on the aggregate directly in order to compile/link
224# against the superset of embedded entities and transitive deps.
225#
226# Arguments:
227#   PUBLIC_LIBS: list of dependent libraries to add to the
228#     INTERFACE_LINK_LIBRARIES property, exporting them to users. This list
229#     will be transitively filtered to exclude any EMBED_LIBS.
230#   EMBED_LIBS: list of dependent libraries that should be embedded directly
231#     into this library. Each of these must be an add_mlir_library() library
232#     without DISABLE_AGGREGATE.
233#
234# Note: This is a work in progress and is presently only sufficient for certain
235# non nested cases involving the C-API.
236function(add_mlir_aggregate name)
237  cmake_parse_arguments(ARG
238    "SHARED;STATIC"
239    ""
240    "PUBLIC_LIBS;EMBED_LIBS"
241    ${ARGN})
242  set(_libtype)
243  if(ARG_STATIC)
244    list(APPEND _libtype STATIC)
245  endif()
246  if(ARG_SHARED)
247    list(APPEND _libtype SHARED)
248  endif()
249  set(_debugmsg)
250
251  set(_embed_libs)
252  set(_objects)
253  set(_deps)
254  foreach(lib ${ARG_EMBED_LIBS})
255    # We have to handle imported vs in-tree differently:
256    #   in-tree: To support arbitrary ordering, the generator expressions get
257    #     set on the dependent target when it is constructed and then just
258    #     eval'd here. This means we can build an aggregate from targets that
259    #     may not yet be defined, which is typical for in-tree.
260    #   imported: Exported properties do not support generator expressions, so
261    #     we imperatively query and manage the expansion here. This is fine
262    #     because imported targets will always be found/configured first and
263    #     do not need to support arbitrary ordering. If CMake every supports
264    #     exporting generator expressions, then this can be simplified.
265    set(_is_imported OFF)
266    if(TARGET ${lib})
267      get_target_property(_is_imported ${lib} IMPORTED)
268    endif()
269
270    if(NOT _is_imported)
271      # Evaluate the in-tree generator expressions directly (this allows target
272      # order independence, since these aren't evaluated until the generate
273      # phase).
274      # What these expressions do:
275      # In the context of this aggregate, resolve the list of OBJECTS and DEPS
276      # that each library advertises and patch it into the whole.
277      set(_local_objects $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_OBJECTS>>)
278      set(_local_deps $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_DEPS>>)
279    else()
280      # It is an imported target, which can only have flat strings populated
281      # (no generator expressions).
282      # Rebuild the generator expressions from the imported flat string lists.
283      if(NOT MLIR_INSTALL_AGGREGATE_OBJECTS)
284        message(SEND_ERROR "Cannot build aggregate from imported targets which were not installed via MLIR_INSTALL_AGGREGATE_OBJECTS (for ${lib}).")
285      endif()
286
287      get_property(_has_object_lib_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_OBJECT_LIB_IMPORTED SET)
288      get_property(_has_dep_libs_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_DEP_LIBS_IMPORTED SET)
289      if(NOT _has_object_lib_prop OR NOT _has_dep_libs_prop)
290        message(SEND_ERROR "Cannot create an aggregate out of imported ${lib}: It is missing properties indicating that it was built for aggregation")
291      endif()
292      get_target_property(_imp_local_object_lib ${lib} MLIR_AGGREGATE_OBJECT_LIB_IMPORTED)
293      get_target_property(_imp_dep_libs ${lib} MLIR_AGGREGATE_DEP_LIBS_IMPORTED)
294      set(_local_objects)
295      if(_imp_local_object_lib)
296        set(_local_objects "$<TARGET_OBJECTS:${_imp_local_object_lib}>")
297      endif()
298      # We should just be able to do this:
299      #   get_mlir_filtered_link_libraries(_local_deps ${_imp_dep_libs})
300      # However, CMake complains about the unqualified use of the one-arg
301      # $<TARGET_PROPERTY> expression. So we do the same thing but use the
302      # two-arg form which takes an explicit target.
303      foreach(_imp_dep_lib ${_imp_dep_libs})
304        # In English, what this expression does:
305        # For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
306        # on the context target (i.e. the executable or shared library being linked)
307        # and, if it is not in that list, emit the library name. Otherwise, empty.
308        list(APPEND _local_deps
309          "$<$<NOT:$<IN_LIST:${_imp_dep_lib},$<GENEX_EVAL:$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${_imp_dep_lib}>"
310        )
311      endforeach()
312    endif()
313
314    list(APPEND _embed_libs ${lib})
315    list(APPEND _objects ${_local_objects})
316    list(APPEND _deps ${_local_deps})
317
318    string(APPEND _debugmsg
319      ": EMBED_LIB ${lib}:\n"
320      "    OBJECTS = ${_local_objects}\n"
321      "    DEPS = ${_local_deps}\n\n")
322  endforeach()
323
324  # Unfortunately need to compile at least one source file, which is hard
325  # to guarantee, so just always generate one. We generate one vs using the
326  # LLVM common dummy.cpp because it works better out of tree.
327  set(_empty_src "${CMAKE_CURRENT_BINARY_DIR}/${name}__empty.cpp")
328  file(WRITE "${_empty_src}" "typedef int dummy;")
329
330  add_mlir_library(${name}
331    ${_libtype}
332    ${ARG_UNPARSED_ARGUMENTS}
333    PARTIAL_SOURCES_INTENDED
334    EXCLUDE_FROM_LIBMLIR
335    "${_empty_src}"
336    LINK_LIBS PRIVATE
337    ${_deps}
338    ${ARG_PUBLIC_LIBS}
339  )
340  target_sources(${name} PRIVATE ${_objects})
341  # TODO: Should be transitive.
342  set_target_properties(${name} PROPERTIES
343    MLIR_AGGREGATE_EXCLUDE_LIBS "${_embed_libs}")
344  if(MSVC)
345    set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
346  endif()
347
348  # Debugging generator expressions can be hard. Uncomment the below to emit
349  # files next to the library with a lot of debug information:
350  # string(APPEND _debugmsg
351  #   ": MAIN LIBRARY:\n"
352  #   "    OBJECTS = ${_objects}\n"
353  #   "    SOURCES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},SOURCES>>\n"
354  #   "    DEPS = ${_deps}\n"
355  #   "    LINK_LIBRARIES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},LINK_LIBRARIES>>\n"
356  #   "    MLIR_AGGREGATE_EXCLUDE_LIBS = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>\n"
357  # )
358  # file(GENERATE OUTPUT
359  #   "${CMAKE_CURRENT_BINARY_DIR}/${name}.aggregate_debug.txt"
360  #   CONTENT "${_debugmsg}"
361  # )
362endfunction(add_mlir_aggregate)
363
364# Adds an MLIR library target for installation.
365# This is usually done as part of add_mlir_library but is broken out for cases
366# where non-standard library builds can be installed.
367function(add_mlir_library_install name)
368  if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
369  get_target_export_arg(${name} MLIR export_to_mlirtargets UMBRELLA mlir-libraries)
370  install(TARGETS ${name}
371    COMPONENT ${name}
372    ${export_to_mlirtargets}
373    LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
374    ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
375    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
376    # Note that CMake will create a directory like:
377    #   objects-${CMAKE_BUILD_TYPE}/obj.LibName
378    # and put object files there.
379    OBJECTS DESTINATION lib${LLVM_LIBDIR_SUFFIX}
380  )
381
382  if (NOT LLVM_ENABLE_IDE)
383    add_llvm_install_targets(install-${name}
384                            DEPENDS ${name}
385                            COMPONENT ${name})
386  endif()
387  set_property(GLOBAL APPEND PROPERTY MLIR_ALL_LIBS ${name})
388  endif()
389  set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
390endfunction()
391
392# Declare an mlir library which is part of the public C-API.
393function(add_mlir_public_c_api_library name)
394  add_mlir_library(${name}
395    ${ARGN}
396    EXCLUDE_FROM_LIBMLIR
397    ENABLE_AGGREGATION
398    ADDITIONAL_HEADER_DIRS
399    ${MLIR_MAIN_INCLUDE_DIR}/mlir-c
400  )
401  # API libraries compile with hidden visibility and macros that enable
402  # exporting from the DLL. Only apply to the obj lib, which only affects
403  # the exports via a shared library.
404  set_target_properties(obj.${name}
405    PROPERTIES
406    CXX_VISIBILITY_PRESET hidden
407  )
408  target_compile_definitions(obj.${name}
409    PRIVATE
410    -DMLIR_CAPI_BUILDING_LIBRARY=1
411  )
412endfunction()
413
414# Declare the library associated with a dialect.
415function(add_mlir_dialect_library name)
416  set_property(GLOBAL APPEND PROPERTY MLIR_DIALECT_LIBS ${name})
417  add_mlir_library(${ARGV} DEPENDS mlir-headers)
418endfunction(add_mlir_dialect_library)
419
420# Declare the library associated with a conversion.
421function(add_mlir_conversion_library name)
422  set_property(GLOBAL APPEND PROPERTY MLIR_CONVERSION_LIBS ${name})
423  add_mlir_library(${ARGV} DEPENDS mlir-headers)
424endfunction(add_mlir_conversion_library)
425
426# Declare the library associated with a translation.
427function(add_mlir_translation_library name)
428  set_property(GLOBAL APPEND PROPERTY MLIR_TRANSLATION_LIBS ${name})
429  add_mlir_library(${ARGV} DEPENDS mlir-headers)
430endfunction(add_mlir_translation_library)
431
432# Verification tools to aid debugging.
433function(mlir_check_link_libraries name)
434  if(TARGET ${name})
435    get_target_property(type ${name} TYPE)
436    if (${type} STREQUAL "INTERFACE_LIBRARY")
437      get_target_property(libs ${name} INTERFACE_LINK_LIBRARIES)
438    else()
439      get_target_property(libs ${name} LINK_LIBRARIES)
440    endif()
441    # message("${name} libs are: ${libs}")
442    set(linking_llvm 0)
443    foreach(lib ${libs})
444      if(lib)
445        if(${lib} MATCHES "^LLVM$")
446          set(linking_llvm 1)
447        endif()
448        if((${lib} MATCHES "^LLVM.+") AND ${linking_llvm})
449          # This will almost always cause execution problems, since the
450          # same symbol might be loaded from 2 separate libraries.  This
451          # often comes from referring to an LLVM library target
452          # explicitly in target_link_libraries()
453          message("WARNING: ${name} links LLVM and ${lib}!")
454        endif()
455      endif()
456    endforeach()
457  endif()
458endfunction(mlir_check_link_libraries)
459
460function(mlir_check_all_link_libraries name)
461  mlir_check_link_libraries(${name})
462  if(TARGET ${name})
463    get_target_property(libs ${name} LINK_LIBRARIES)
464    # message("${name} libs are: ${libs}")
465    foreach(lib ${libs})
466      mlir_check_link_libraries(${lib})
467    endforeach()
468  endif()
469endfunction(mlir_check_all_link_libraries)
470