xref: /llvm-project/mlir/cmake/modules/AddMLIR.cmake (revision 047e8e47c1f9d872aec835b915935802e195c555)
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
9  # Get the current set of include paths for this td file.
10  cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
11  get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
12  list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
13  # Filter out any empty include items.
14  list(REMOVE_ITEM tblgen_includes "")
15
16  # Build the absolute path for the current input file.
17  if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
18    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
19  else()
20    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TARGET_DEFINITIONS})
21  endif()
22
23  # Append the includes used for this file to the tablegen_compile_commands
24  # file.
25  file(APPEND ${CMAKE_BINARY_DIR}/tablegen_compile_commands.yml
26      "--- !FileInfo:\n"
27      "  filepath: \"${LLVM_TARGET_DEFINITIONS_ABSOLUTE}\"\n"
28      "  includes: \"${CMAKE_CURRENT_SOURCE_DIR};${tblgen_includes}\"\n"
29  )
30endfunction()
31
32# Clear out any pre-existing compile_commands file before processing. This
33# allows for generating a clean compile_commands on each configure.
34file(REMOVE ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml)
35
36# Declare a helper function/copy of tablegen rule for using tablegen without
37# additional tblgen specific flags when invoking PDLL generator.
38function(_pdll_tablegen project ofn)
39  cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
40  # Validate calling context.
41  if(NOT ${project}_TABLEGEN_EXE)
42    message(FATAL_ERROR "${project}_TABLEGEN_EXE not set")
43  endif()
44
45  # Use depfile instead of globbing arbitrary *.td(s) for Ninja.
46  if(CMAKE_GENERATOR MATCHES "Ninja")
47    # Make output path relative to build.ninja, assuming located on
48    # ${CMAKE_BINARY_DIR}.
49    # CMake emits build targets as relative paths but Ninja doesn't identify
50    # absolute path (in *.d) as relative path (in build.ninja)
51    # Note that tblgen is executed on ${CMAKE_BINARY_DIR} as working directory.
52    file(RELATIVE_PATH ofn_rel
53      ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${ofn})
54    set(additional_cmdline
55      -o ${ofn_rel}
56      -d ${ofn_rel}.d
57      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
58      DEPFILE ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.d
59      )
60    set(local_tds)
61    set(global_tds)
62  else()
63    file(GLOB local_tds "*.td")
64    file(GLOB_RECURSE global_tds "${LLVM_MAIN_INCLUDE_DIR}/llvm/*.td")
65    set(additional_cmdline
66      -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
67      )
68  endif()
69
70  if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
71    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
72  else()
73    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE
74      ${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TARGET_DEFINITIONS})
75  endif()
76
77  if (CMAKE_GENERATOR MATCHES "Visual Studio")
78    # Visual Studio has problems with llvm-tblgen's native --write-if-changed
79    # behavior. Since it doesn't do restat optimizations anyway, just don't
80    # pass --write-if-changed there.
81    set(tblgen_change_flag)
82  else()
83    set(tblgen_change_flag "--write-if-changed")
84  endif()
85
86  # We need both _TABLEGEN_TARGET and _TABLEGEN_EXE in the  DEPENDS list
87  # (both the target and the file) to have .inc files rebuilt on
88  # a tablegen change, as cmake does not propagate file-level dependencies
89  # of custom targets. See the following ticket for more information:
90  # https://cmake.org/Bug/view.php?id=15858
91  # The dependency on both, the target and the file, produces the same
92  # dependency twice in the result file when
93  # ("${${project}_TABLEGEN_TARGET}" STREQUAL "${${project}_TABLEGEN_EXE}")
94  # but lets us having smaller and cleaner code here.
95  get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
96  list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
97  # Filter out empty items before prepending each entry with -I
98  list(REMOVE_ITEM tblgen_includes "")
99  list(TRANSFORM tblgen_includes PREPEND -I)
100
101  set(tablegen_exe ${${project}_TABLEGEN_EXE})
102  set(tablegen_depends ${${project}_TABLEGEN_TARGET} ${tablegen_exe})
103
104  add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
105    COMMAND ${tablegen_exe} ${ARG_UNPARSED_ARGUMENTS} -I ${CMAKE_CURRENT_SOURCE_DIR}
106    ${tblgen_includes}
107    ${LLVM_TARGET_DEFINITIONS_ABSOLUTE}
108    ${tblgen_change_flag}
109    ${additional_cmdline}
110    # The file in LLVM_TARGET_DEFINITIONS may be not in the current
111    # directory and local_tds may not contain it, so we must
112    # explicitly list it here:
113    DEPENDS ${ARG_DEPENDS} ${tablegen_depends}
114      ${local_tds} ${global_tds}
115    ${LLVM_TARGET_DEFINITIONS_ABSOLUTE}
116    ${LLVM_TARGET_DEPENDS}
117    COMMENT "Building ${ofn}..."
118    )
119
120  # `make clean' must remove all those generated files:
121  set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${ofn})
122
123  set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn} PARENT_SCOPE)
124  set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${ofn} PROPERTIES
125    GENERATED 1)
126endfunction()
127
128# Declare a PDLL library in the current directory.
129function(add_mlir_pdll_library target inputFile ofn)
130  set(LLVM_TARGET_DEFINITIONS ${inputFile})
131
132  _pdll_tablegen(MLIR_PDLL ${ofn} -x=cpp ${ARGN})
133  set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
134      PARENT_SCOPE)
135
136  # Get the current set of include paths for this pdll file.
137  cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
138  get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
139  list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
140  # Filter out any empty include items.
141  list(REMOVE_ITEM tblgen_includes "")
142
143  # Build the absolute path for the current input file.
144  if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
145    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${inputFile})
146  else()
147    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${inputFile})
148  endif()
149
150  # Append the includes used for this file to the pdll_compilation_commands
151  # file.
152  file(APPEND ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml
153      "--- !FileInfo:\n"
154      "  filepath: \"${LLVM_TARGET_DEFINITIONS_ABSOLUTE}\"\n"
155      "  includes: \"${CMAKE_CURRENT_SOURCE_DIR};${tblgen_includes}\"\n"
156  )
157
158  add_public_tablegen_target(${target})
159endfunction()
160
161# Declare a dialect in the include directory
162function(add_mlir_dialect dialect dialect_namespace)
163  set(LLVM_TARGET_DEFINITIONS ${dialect}.td)
164  mlir_tablegen(${dialect}.h.inc -gen-op-decls)
165  mlir_tablegen(${dialect}.cpp.inc -gen-op-defs)
166  mlir_tablegen(${dialect}Types.h.inc -gen-typedef-decls -typedefs-dialect=${dialect_namespace})
167  mlir_tablegen(${dialect}Types.cpp.inc -gen-typedef-defs -typedefs-dialect=${dialect_namespace})
168  mlir_tablegen(${dialect}Dialect.h.inc -gen-dialect-decls -dialect=${dialect_namespace})
169  mlir_tablegen(${dialect}Dialect.cpp.inc -gen-dialect-defs -dialect=${dialect_namespace})
170  add_public_tablegen_target(MLIR${dialect}IncGen)
171  add_dependencies(mlir-headers MLIR${dialect}IncGen)
172endfunction()
173
174# Declare sharded dialect operation declarations and definitions
175function(add_sharded_ops ops_target shard_count)
176  set(LLVM_TARGET_DEFINITIONS ${ops_target}.td)
177  mlir_tablegen(${ops_target}.h.inc -gen-op-decls -op-shard-count=${shard_count})
178  mlir_tablegen(${ops_target}.cpp.inc -gen-op-defs -op-shard-count=${shard_count})
179  set(LLVM_TARGET_DEFINITIONS ${ops_target}.cpp)
180  foreach(index RANGE ${shard_count})
181    set(SHARDED_SRC ${ops_target}.${index}.cpp)
182    list(APPEND SHARDED_SRCS ${SHARDED_SRC})
183    tablegen(MLIR_SRC_SHARDER ${SHARDED_SRC} -op-shard-index=${index})
184    set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${SHARDED_SRC})
185  endforeach()
186  add_public_tablegen_target(MLIR${ops_target}ShardGen)
187  set(SHARDED_SRCS ${SHARDED_SRCS} PARENT_SCOPE)
188endfunction()
189
190# Declare a dialect in the include directory
191function(add_mlir_interface interface)
192  set(LLVM_TARGET_DEFINITIONS ${interface}.td)
193  mlir_tablegen(${interface}.h.inc -gen-op-interface-decls)
194  mlir_tablegen(${interface}.cpp.inc -gen-op-interface-defs)
195  add_public_tablegen_target(MLIR${interface}IncGen)
196  add_dependencies(mlir-generic-headers MLIR${interface}IncGen)
197endfunction()
198
199
200# Generate Documentation
201function(add_mlir_doc doc_filename output_file output_directory command)
202  set(LLVM_TARGET_DEFINITIONS ${doc_filename}.td)
203  # The MLIR docs use Hugo, so we allow Hugo specific features here.
204  tablegen(MLIR ${output_file}.md ${command} -allow-hugo-specific-features ${ARGN})
205  set(GEN_DOC_FILE ${MLIR_BINARY_DIR}/docs/${output_directory}${output_file}.md)
206  add_custom_command(
207          OUTPUT ${GEN_DOC_FILE}
208          COMMAND ${CMAKE_COMMAND} -E copy
209                  ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md
210                  ${GEN_DOC_FILE}
211          DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${output_file}.md)
212  add_custom_target(${output_file}DocGen DEPENDS ${GEN_DOC_FILE})
213  set_target_properties(${output_file}DocGen PROPERTIES FOLDER "MLIR/Tablegenning/Docs")
214  add_dependencies(mlir-doc ${output_file}DocGen)
215endfunction()
216
217# Sets ${srcs} to contain the list of additional headers for the target. Extra
218# arguments are included into the list of additional headers.
219function(_set_mlir_additional_headers_as_srcs)
220  set(srcs)
221  if(MSVC_IDE OR XCODE)
222    # Add public headers
223    file(RELATIVE_PATH lib_path
224      ${MLIR_SOURCE_DIR}/lib/
225      ${CMAKE_CURRENT_SOURCE_DIR}
226    )
227    if(NOT lib_path MATCHES "^[.][.]")
228      file( GLOB_RECURSE headers
229        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.h
230        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.def
231      )
232      set_source_files_properties(${headers} PROPERTIES HEADER_FILE_ONLY ON)
233
234      file( GLOB_RECURSE tds
235        ${MLIR_SOURCE_DIR}/include/mlir/${lib_path}/*.td
236      )
237      source_group("TableGen descriptions" FILES ${tds})
238      set_source_files_properties(${tds}} PROPERTIES HEADER_FILE_ONLY ON)
239
240      if(headers OR tds)
241        set(srcs ${headers} ${tds})
242      endif()
243    endif()
244  endif(MSVC_IDE OR XCODE)
245  if(srcs OR ARGN)
246    set(srcs
247      ADDITIONAL_HEADERS
248      ${srcs}
249      ${ARGN} # It may contain unparsed unknown args.
250      PARENT_SCOPE
251      )
252  endif()
253endfunction()
254
255# Checks that the LLVM components are not listed in the extra arguments,
256# assumed to be coming from the LINK_LIBS variable.
257function(_check_llvm_components_usage name)
258  # LINK_COMPONENTS is necessary to allow libLLVM.so to be properly
259  # substituted for individual library dependencies if LLVM_LINK_LLVM_DYLIB
260  # Perhaps this should be in llvm_add_library instead?  However, it fails
261  # on libclang-cpp.so
262  get_property(llvm_component_libs GLOBAL PROPERTY LLVM_COMPONENT_LIBS)
263  foreach(lib ${ARGN})
264    if(${lib} IN_LIST llvm_component_libs)
265      message(SEND_ERROR "${name} specifies LINK_LIBS ${lib}, but LINK_LIBS cannot be used for LLVM libraries.  Please use LINK_COMPONENTS instead.")
266    endif()
267  endforeach()
268endfunction()
269
270function(add_mlir_example_library name)
271  cmake_parse_arguments(ARG
272    "SHARED;DISABLE_INSTALL"
273    ""
274    "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS"
275    ${ARGN})
276  _set_mlir_additional_headers_as_srcs(${ARG_ADDITIONAL_HEADERS})
277  if (ARG_SHARED)
278    set(LIBTYPE SHARED)
279  else()
280    if(BUILD_SHARED_LIBS)
281      set(LIBTYPE SHARED)
282    else()
283      set(LIBTYPE STATIC)
284    endif()
285  endif()
286
287  # MLIR libraries uniformly depend on LLVMSupport.  Just specify it once here.
288  list(APPEND ARG_LINK_COMPONENTS Support)
289  _check_llvm_components_usage(${name} ${ARG_LINK_LIBS})
290
291  list(APPEND ARG_DEPENDS mlir-generic-headers)
292
293  llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs} DEPENDS ${ARG_DEPENDS} LINK_COMPONENTS ${ARG_LINK_COMPONENTS} LINK_LIBS ${ARG_LINK_LIBS})
294  set_target_properties(${name} PROPERTIES FOLDER "MLIR/Examples")
295  if (LLVM_BUILD_EXAMPLES AND NOT ${ARG_DISABLE_INSTALL})
296    add_mlir_library_install(${name})
297  else()
298    set_target_properties(${name} PROPERTIES EXCLUDE_FROM_ALL ON)
299  endif()
300endfunction()
301
302# Declare an mlir library which can be compiled in libMLIR.so
303# In addition to everything that llvm_add_library accepts, this
304# also has the following option:
305# EXCLUDE_FROM_LIBMLIR
306#   Don't include this library in libMLIR.so.  This option should be used
307#   for test libraries, executable-specific libraries, or rarely used libraries
308#   with large dependencies.  When using it, please link libraries included
309#   in libMLIR via mlir_target_link_libraries(), to ensure that the library
310#   does not pull in static dependencies when MLIR_LINK_MLIR_DYLIB=ON is used.
311# OBJECT
312#   The library's object library is referenced using "obj.${name}". For this to
313#   work reliably, this flag ensures that the OBJECT library exists.
314# ENABLE_AGGREGATION
315#   Exports additional metadata,
316#   and installs additional object files needed to include this as part of an
317#   aggregate shared library.
318#   TODO: Make this the default for all MLIR libraries once all libraries
319#   are compatible with building an object library.
320function(add_mlir_library name)
321  cmake_parse_arguments(ARG
322    "SHARED;INSTALL_WITH_TOOLCHAIN;EXCLUDE_FROM_LIBMLIR;DISABLE_INSTALL;ENABLE_AGGREGATION;OBJECT"
323    ""
324    "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS"
325    ${ARGN})
326  _set_mlir_additional_headers_as_srcs(${ARG_ADDITIONAL_HEADERS})
327
328  # Determine type of library.
329  if(ARG_SHARED)
330    set(LIBTYPE SHARED)
331  else()
332    # llvm_add_library ignores BUILD_SHARED_LIBS if STATIC is explicitly set,
333    # so we need to handle it here.
334    if(BUILD_SHARED_LIBS)
335      set(LIBTYPE SHARED)
336    else()
337      set(LIBTYPE STATIC)
338    endif()
339  endif()
340
341  # Is an object library needed...?
342  # Note that the XCode generator doesn't handle object libraries correctly and
343  # usability is degraded in the Visual Studio solution generators.
344  # llvm_add_library may also itself decide to create an object library.
345  set(NEEDS_OBJECT_LIB OFF)
346  if(ARG_OBJECT)
347    # Yes, because the target "obj.${name}" is referenced.
348    set(NEEDS_OBJECT_LIB ON)
349  endif ()
350  if(LLVM_BUILD_LLVM_DYLIB AND NOT ARG_EXCLUDE_FROM_LIBMLIR AND NOT XCODE)
351    # Yes, because in addition to the shared library, the object files are
352    # needed for linking into libMLIR.so (see mlir/tools/mlir-shlib/CMakeLists.txt).
353    # For XCode, -force_load is used instead.
354    # Windows is not supported (LLVM_BUILD_LLVM_DYLIB=ON will cause an error).
355    set(NEEDS_OBJECT_LIB ON)
356    set_property(GLOBAL APPEND PROPERTY MLIR_STATIC_LIBS ${name})
357    set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${ARG_LINK_COMPONENTS})
358    set_property(GLOBAL APPEND PROPERTY MLIR_LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS})
359  endif ()
360  if(ARG_ENABLE_AGGREGATION AND NOT XCODE)
361    # Yes, because this library is added to an aggergate library such as
362    # libMLIR-C.so which is links together all the object files.
363    # For XCode, -force_load is used instead.
364    set(NEEDS_OBJECT_LIB ON)
365  endif()
366  if (NOT ARG_SHARED AND NOT ARG_EXCLUDE_FROM_LIBMLIR AND NOT XCODE AND NOT MSVC_IDE)
367    # Yes, but only for legacy reasons. Also avoid object libraries for
368    # Visual Studio solutions.
369    set(NEEDS_OBJECT_LIB ON)
370  endif()
371  if(NEEDS_OBJECT_LIB)
372    list(APPEND LIBTYPE OBJECT)
373  endif()
374
375  # MLIR libraries uniformly depend on LLVMSupport.  Just specify it once here.
376  list(APPEND ARG_LINK_COMPONENTS Support)
377  _check_llvm_components_usage(${name} ${ARG_LINK_LIBS})
378
379  list(APPEND ARG_DEPENDS mlir-generic-headers)
380  llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs} DEPENDS ${ARG_DEPENDS} LINK_COMPONENTS ${ARG_LINK_COMPONENTS} LINK_LIBS ${ARG_LINK_LIBS})
381
382  if(TARGET ${name})
383    target_link_libraries(${name} INTERFACE ${LLVM_COMMON_LIBS})
384    if(NOT ARG_DISABLE_INSTALL)
385      add_mlir_library_install(${name})
386    endif()
387  else()
388    # Add empty "phony" target
389    add_custom_target(${name})
390  endif()
391  set_target_properties(${name} PROPERTIES FOLDER "MLIR/Libraries")
392
393  # Setup aggregate.
394  if(ARG_ENABLE_AGGREGATION)
395    # Compute and store the properties needed to build aggregates.
396    set(AGGREGATE_OBJECTS)
397    set(AGGREGATE_OBJECT_LIB)
398    set(AGGREGATE_DEPS)
399    if(XCODE)
400      # XCode has limited support for object libraries. Instead, add dep flags
401      # that force the entire library to be embedded.
402      list(APPEND AGGREGATE_DEPS "-force_load" "${name}")
403    elseif(TARGET obj.${name})
404      # FIXME: *.obj can also be added via target_link_libraries since CMake 3.12.
405      list(APPEND AGGREGATE_OBJECTS "$<TARGET_OBJECTS:obj.${name}>")
406      list(APPEND AGGREGATE_OBJECT_LIB "obj.${name}")
407    else()
408      message(SEND_ERROR "Aggregate library not supported on this platform")
409    endif()
410
411    # For each declared dependency, transform it into a generator expression
412    # which excludes it if the ultimate link target is excluding the library.
413    set(NEW_LINK_LIBRARIES)
414    get_target_property(CURRENT_LINK_LIBRARIES  ${name} LINK_LIBRARIES)
415    get_mlir_filtered_link_libraries(NEW_LINK_LIBRARIES ${CURRENT_LINK_LIBRARIES})
416    set_target_properties(${name} PROPERTIES LINK_LIBRARIES "${NEW_LINK_LIBRARIES}")
417    list(APPEND AGGREGATE_DEPS ${NEW_LINK_LIBRARIES})
418    set_target_properties(${name} PROPERTIES
419      EXPORT_PROPERTIES "MLIR_AGGREGATE_OBJECT_LIB_IMPORTED;MLIR_AGGREGATE_DEP_LIBS_IMPORTED"
420      MLIR_AGGREGATE_OBJECTS "${AGGREGATE_OBJECTS}"
421      MLIR_AGGREGATE_DEPS "${AGGREGATE_DEPS}"
422      MLIR_AGGREGATE_OBJECT_LIB_IMPORTED "${AGGREGATE_OBJECT_LIB}"
423      MLIR_AGGREGATE_DEP_LIBS_IMPORTED "${CURRENT_LINK_LIBRARIES}"
424    )
425
426    # In order for out-of-tree projects to build aggregates of this library,
427    # we need to install the OBJECT library.
428    if(TARGET "obj.${name}" AND MLIR_INSTALL_AGGREGATE_OBJECTS AND NOT ARG_DISABLE_INSTALL)
429      add_mlir_library_install(obj.${name})
430    endif()
431  endif()
432endfunction(add_mlir_library)
433
434macro(add_mlir_tool name)
435  llvm_add_tool(MLIR ${ARGV})
436endmacro()
437
438# Sets a variable with a transformed list of link libraries such individual
439# libraries will be dynamically excluded when evaluated on a final library
440# which defines an MLIR_AGGREGATE_EXCLUDE_LIBS which contains any of the
441# libraries. Each link library can be a generator expression but must not
442# resolve to an arity > 1 (i.e. it can be optional).
443function(get_mlir_filtered_link_libraries output)
444  set(_results)
445  foreach(linklib ${ARGN})
446    # In English, what this expression does:
447    # For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
448    # on the context target (i.e. the executable or shared library being linked)
449    # and, if it is not in that list, emit the library name. Otherwise, empty.
450    list(APPEND _results
451      "$<$<NOT:$<IN_LIST:${linklib},$<GENEX_EVAL:$<TARGET_PROPERTY:MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${linklib}>"
452    )
453  endforeach()
454  set(${output} "${_results}" PARENT_SCOPE)
455endfunction(get_mlir_filtered_link_libraries)
456
457# Declares an aggregate library. Such a library is a combination of arbitrary
458# regular add_mlir_library() libraries with the special feature that they can
459# be configured to statically embed some subset of their dependencies, as is
460# typical when creating a .so/.dylib/.dll or a mondo static library.
461#
462# It is always safe to depend on the aggregate directly in order to compile/link
463# against the superset of embedded entities and transitive deps.
464#
465# Arguments:
466#   PUBLIC_LIBS: list of dependent libraries to add to the
467#     INTERFACE_LINK_LIBRARIES property, exporting them to users. This list
468#     will be transitively filtered to exclude any EMBED_LIBS.
469#   EMBED_LIBS: list of dependent libraries that should be embedded directly
470#     into this library. Each of these must be an add_mlir_library() library
471#     without DISABLE_AGGREGATE.
472#
473# Note: This is a work in progress and is presently only sufficient for certain
474# non nested cases involving the C-API.
475function(add_mlir_aggregate name)
476  cmake_parse_arguments(ARG
477    "SHARED;STATIC"
478    ""
479    "PUBLIC_LIBS;EMBED_LIBS"
480    ${ARGN})
481  set(_libtype)
482  if(ARG_STATIC)
483    list(APPEND _libtype STATIC)
484  endif()
485  if(ARG_SHARED)
486    list(APPEND _libtype SHARED)
487  endif()
488  set(_debugmsg)
489
490  set(_embed_libs)
491  set(_objects)
492  set(_deps)
493  foreach(lib ${ARG_EMBED_LIBS})
494    # We have to handle imported vs in-tree differently:
495    #   in-tree: To support arbitrary ordering, the generator expressions get
496    #     set on the dependent target when it is constructed and then just
497    #     eval'd here. This means we can build an aggregate from targets that
498    #     may not yet be defined, which is typical for in-tree.
499    #   imported: Exported properties do not support generator expressions, so
500    #     we imperatively query and manage the expansion here. This is fine
501    #     because imported targets will always be found/configured first and
502    #     do not need to support arbitrary ordering. If CMake every supports
503    #     exporting generator expressions, then this can be simplified.
504    set(_is_imported OFF)
505    if(TARGET ${lib})
506      get_target_property(_is_imported ${lib} IMPORTED)
507    endif()
508
509    if(NOT _is_imported)
510      # Evaluate the in-tree generator expressions directly (this allows target
511      # order independence, since these aren't evaluated until the generate
512      # phase).
513      # What these expressions do:
514      # In the context of this aggregate, resolve the list of OBJECTS and DEPS
515      # that each library advertises and patch it into the whole.
516      set(_local_objects $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_OBJECTS>>)
517      set(_local_deps $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${lib},MLIR_AGGREGATE_DEPS>>)
518    else()
519      # It is an imported target, which can only have flat strings populated
520      # (no generator expressions).
521      # Rebuild the generator expressions from the imported flat string lists.
522      if(NOT MLIR_INSTALL_AGGREGATE_OBJECTS)
523        message(SEND_ERROR "Cannot build aggregate from imported targets which were not installed via MLIR_INSTALL_AGGREGATE_OBJECTS (for ${lib}).")
524      endif()
525
526      get_property(_has_object_lib_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_OBJECT_LIB_IMPORTED SET)
527      get_property(_has_dep_libs_prop TARGET ${lib} PROPERTY MLIR_AGGREGATE_DEP_LIBS_IMPORTED SET)
528      if(NOT _has_object_lib_prop OR NOT _has_dep_libs_prop)
529        message(SEND_ERROR "Cannot create an aggregate out of imported ${lib}: It is missing properties indicating that it was built for aggregation")
530      endif()
531      get_target_property(_imp_local_object_lib ${lib} MLIR_AGGREGATE_OBJECT_LIB_IMPORTED)
532      get_target_property(_imp_dep_libs ${lib} MLIR_AGGREGATE_DEP_LIBS_IMPORTED)
533      set(_local_objects)
534      if(_imp_local_object_lib)
535        set(_local_objects "$<TARGET_OBJECTS:${_imp_local_object_lib}>")
536      endif()
537      # We should just be able to do this:
538      #   get_mlir_filtered_link_libraries(_local_deps ${_imp_dep_libs})
539      # However, CMake complains about the unqualified use of the one-arg
540      # $<TARGET_PROPERTY> expression. So we do the same thing but use the
541      # two-arg form which takes an explicit target.
542      foreach(_imp_dep_lib ${_imp_dep_libs})
543        # In English, what this expression does:
544        # For each link library, resolve the property MLIR_AGGREGATE_EXCLUDE_LIBS
545        # on the context target (i.e. the executable or shared library being linked)
546        # and, if it is not in that list, emit the library name. Otherwise, empty.
547        list(APPEND _local_deps
548          "$<$<NOT:$<IN_LIST:${_imp_dep_lib},$<GENEX_EVAL:$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>>>:${_imp_dep_lib}>"
549        )
550      endforeach()
551    endif()
552
553    list(APPEND _embed_libs ${lib})
554    list(APPEND _objects ${_local_objects})
555    list(APPEND _deps ${_local_deps})
556
557    string(APPEND _debugmsg
558      ": EMBED_LIB ${lib}:\n"
559      "    OBJECTS = ${_local_objects}\n"
560      "    DEPS = ${_local_deps}\n\n")
561  endforeach()
562
563  add_mlir_library(${name}
564    ${_libtype}
565    ${ARG_UNPARSED_ARGUMENTS}
566    PARTIAL_SOURCES_INTENDED
567    EXCLUDE_FROM_LIBMLIR
568    LINK_LIBS PRIVATE
569    ${_deps}
570    ${ARG_PUBLIC_LIBS}
571  )
572  target_sources(${name} PRIVATE ${_objects})
573
574  # Linux defaults to allowing undefined symbols in shared libraries whereas
575  # many other platforms are more strict. We want these libraries to be
576  # self contained, and we want any undefined symbols to be reported at
577  # library construction time, not at library use, so make Linux strict too.
578  # We make an exception for sanitizer builds, since the AddressSanitizer
579  # run-time doesn't get linked into shared libraries.
580  if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND (NOT LLVM_USE_SANITIZER))
581    target_link_options(${name} PRIVATE
582      "LINKER:-z,defs"
583    )
584  endif()
585
586  # TODO: Should be transitive.
587  set_target_properties(${name} PROPERTIES
588    MLIR_AGGREGATE_EXCLUDE_LIBS "${_embed_libs}")
589  if(WIN32)
590    set_property(TARGET ${name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON)
591  endif()
592
593  # Debugging generator expressions can be hard. Uncomment the below to emit
594  # files next to the library with a lot of debug information:
595  # string(APPEND _debugmsg
596  #   ": MAIN LIBRARY:\n"
597  #   "    OBJECTS = ${_objects}\n"
598  #   "    SOURCES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},SOURCES>>\n"
599  #   "    DEPS = ${_deps}\n"
600  #   "    LINK_LIBRARIES = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},LINK_LIBRARIES>>\n"
601  #   "    MLIR_AGGREGATE_EXCLUDE_LIBS = $<TARGET_GENEX_EVAL:${name},$<TARGET_PROPERTY:${name},MLIR_AGGREGATE_EXCLUDE_LIBS>>\n"
602  # )
603  # file(GENERATE OUTPUT
604  #   "${CMAKE_CURRENT_BINARY_DIR}/${name}.aggregate_debug.txt"
605  #   CONTENT "${_debugmsg}"
606  # )
607endfunction(add_mlir_aggregate)
608
609# Adds an MLIR library target for installation.
610# This is usually done as part of add_mlir_library but is broken out for cases
611# where non-standard library builds can be installed.
612function(add_mlir_library_install name)
613  if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
614  get_target_export_arg(${name} MLIR export_to_mlirtargets UMBRELLA mlir-libraries)
615  install(TARGETS ${name}
616    COMPONENT ${name}
617    ${export_to_mlirtargets}
618    LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
619    ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
620    RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
621    # Note that CMake will create a directory like:
622    #   objects-${CMAKE_BUILD_TYPE}/obj.LibName
623    # and put object files there.
624    OBJECTS DESTINATION lib${LLVM_LIBDIR_SUFFIX}
625  )
626
627  if (NOT LLVM_ENABLE_IDE)
628    add_llvm_install_targets(install-${name}
629                            DEPENDS ${name}
630                            COMPONENT ${name})
631  endif()
632  set_property(GLOBAL APPEND PROPERTY MLIR_ALL_LIBS ${name})
633  endif()
634  set_property(GLOBAL APPEND PROPERTY MLIR_EXPORTS ${name})
635endfunction()
636
637# Declare an mlir library which is part of the public C-API.
638function(add_mlir_public_c_api_library name)
639  add_mlir_library(${name}
640    ${ARGN}
641    OBJECT
642    EXCLUDE_FROM_LIBMLIR
643    ENABLE_AGGREGATION
644    ADDITIONAL_HEADER_DIRS
645    ${MLIR_MAIN_INCLUDE_DIR}/mlir-c
646  )
647  # API libraries compile with hidden visibility and macros that enable
648  # exporting from the DLL. Only apply to the obj lib, which only affects
649  # the exports via a shared library.
650  set_target_properties(obj.${name}
651    PROPERTIES
652    CXX_VISIBILITY_PRESET hidden
653  )
654  target_compile_definitions(obj.${name}
655    PRIVATE
656    -DMLIR_CAPI_BUILDING_LIBRARY=1
657  )
658endfunction()
659
660# Declare the library associated with a dialect.
661function(add_mlir_dialect_library name)
662  set_property(GLOBAL APPEND PROPERTY MLIR_DIALECT_LIBS ${name})
663  add_mlir_library(${ARGV} DEPENDS mlir-headers)
664endfunction(add_mlir_dialect_library)
665
666# Declare the library associated with a conversion.
667function(add_mlir_conversion_library name)
668  set_property(GLOBAL APPEND PROPERTY MLIR_CONVERSION_LIBS ${name})
669  add_mlir_library(${ARGV} DEPENDS mlir-headers)
670endfunction(add_mlir_conversion_library)
671
672# Declare the library associated with an extension.
673function(add_mlir_extension_library name)
674  set_property(GLOBAL APPEND PROPERTY MLIR_EXTENSION_LIBS ${name})
675  add_mlir_library(${ARGV} DEPENDS mlir-headers)
676endfunction(add_mlir_extension_library)
677
678# Declare the library associated with a translation.
679function(add_mlir_translation_library name)
680  set_property(GLOBAL APPEND PROPERTY MLIR_TRANSLATION_LIBS ${name})
681  add_mlir_library(${ARGV} DEPENDS mlir-headers)
682endfunction(add_mlir_translation_library)
683
684# Verification tools to aid debugging.
685function(mlir_check_link_libraries name)
686  if(TARGET ${name})
687    get_target_property(type ${name} TYPE)
688    if (${type} STREQUAL "INTERFACE_LIBRARY")
689      get_target_property(libs ${name} INTERFACE_LINK_LIBRARIES)
690    else()
691      get_target_property(libs ${name} LINK_LIBRARIES)
692    endif()
693    # message("${name} libs are: ${libs}")
694    set(linking_llvm 0)
695    foreach(lib ${libs})
696      if(lib)
697        if(${lib} MATCHES "^LLVM$")
698          set(linking_llvm 1)
699        endif()
700        if((${lib} MATCHES "^LLVM.+") AND ${linking_llvm})
701          # This will almost always cause execution problems, since the
702          # same symbol might be loaded from 2 separate libraries.  This
703          # often comes from referring to an LLVM library target
704          # explicitly in target_link_libraries()
705          message("WARNING: ${name} links LLVM and ${lib}!")
706        endif()
707      endif()
708    endforeach()
709  endif()
710endfunction(mlir_check_link_libraries)
711
712function(mlir_check_all_link_libraries name)
713  mlir_check_link_libraries(${name})
714  if(TARGET ${name})
715    get_target_property(libs ${name} LINK_LIBRARIES)
716    # message("${name} libs are: ${libs}")
717    foreach(lib ${libs})
718      mlir_check_link_libraries(${lib})
719    endforeach()
720  endif()
721endfunction(mlir_check_all_link_libraries)
722
723# Link target against a list of MLIR libraries. If MLIR_LINK_MLIR_DYLIB is
724# enabled, this will link against the MLIR dylib instead of the static
725# libraries.
726#
727# This function should be used instead of target_link_libraries() when linking
728# MLIR libraries that are part of the MLIR dylib. For libraries that are not
729# part of the dylib (like test libraries), target_link_libraries() should be
730# used.
731function(mlir_target_link_libraries target type)
732  if (TARGET obj.${target})
733    target_link_libraries(obj.${target} ${ARGN})
734  endif()
735
736  if (MLIR_LINK_MLIR_DYLIB)
737    target_link_libraries(${target} ${type} MLIR)
738  else()
739    target_link_libraries(${target} ${type} ${ARGN})
740  endif()
741endfunction()
742