https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/222397
>From 8a5ff01a74f0e3409c4963c4cf3db511cfeed355 Mon Sep 17 00:00:00 2001 From: Mehdi Amini <[email protected]> Date: Wed, 9 Sep 2026 06:07:45 -0700 Subject: [PATCH] [MLIR][CMake] Add HEADER_LIBS and document CMake infrastructure Add HEADER_LIBS as a flat list of literal library targets for generated headers included without a link relationship. Resolve aliases and forward references, accept imported libraries as already generated, follow nested HEADER_LIBS and link interfaces, and reject missing, executable, utility, or generator- expression entries with configure-time diagnostics. Represent header-only edges in the common internal INTERFACE graph, including cyclic relationships. Record links added by mlir_target_link_libraries for the same deferred ordering. Add explicit, commented HEADER_LIBS edges for every audited header-only include that is not covered by mlir-generic-headers, and keep this facility a rare layering escape hatch. Document dialects, interfaces, passes, PDLL, generated documentation, library visibility, C API aggregation, tools, exports, standalone consumers, and the generated-file model. Add a CMake fixture covering cycles, aliases, conditions, LINK_ONLY, imported and ignored items, post-hoc links, and invalid providers. Build each consumer independently from a clean state to verify transitive generated-header ordering without unrelated generators masking missing edges. Assisted-by: Codex Assisted-by: Claude Code Co-Authored-By: Claude Fable 5.1 <[email protected]> --- llvm/cmake/modules/AddLLVM.cmake | 5 +- mlir/cmake/modules/AddMLIR.cmake | 111 +++++- mlir/docs/CMakeInfrastructure.md | 343 ++++++++++++++++++ .../DefiningDialects/AttributesAndTypes.md | 2 +- .../lib/Conversion/SPIRVCommon/CMakeLists.txt | 4 + mlir/lib/Dialect/Arith/IR/CMakeLists.txt | 4 + mlir/lib/Dialect/Func/IR/CMakeLists.txt | 4 + mlir/lib/Dialect/LLVMIR/CMakeLists.txt | 8 + mlir/lib/Dialect/Linalg/IR/CMakeLists.txt | 4 + .../Dialect/Shape/Transforms/CMakeLists.txt | 4 +- mlir/lib/Dialect/Tensor/IR/CMakeLists.txt | 4 + mlir/lib/Dialect/Tosa/CMakeLists.txt | 4 + mlir/lib/Rewrite/CMakeLists.txt | 11 +- mlir/lib/Target/SPIRV/CMakeLists.txt | 4 + mlir/test/CMake/header-dependencies.test | 192 ++++++++++ mlir/test/CMake/lit.local.cfg | 7 + 16 files changed, 704 insertions(+), 7 deletions(-) create mode 100644 mlir/docs/CMakeInfrastructure.md create mode 100644 mlir/test/CMake/header-dependencies.test create mode 100644 mlir/test/CMake/lit.local.cfg diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index bc5f6dd46d5d2..03d90892c6a77 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -633,7 +633,10 @@ function(_llvm_generated_header_target output provider) # Only a provider's interface is transitive. PRIVATE implementation links # have already contributed to the provider's own compilation ordering. get_property(links TARGET "${provider}" PROPERTY INTERFACE_LINK_LIBRARIES) - foreach(item ${links}) + # MLIR uses this property for generated headers included without a link. + # Both kinds of edges belong to the same header interface graph. + get_property(header_libraries TARGET "${provider}" PROPERTY LLVM_HEADER_LIBS) + foreach(item ${links} ${header_libraries}) _llvm_link_item_targets(link_targets "${item}") foreach(link_target ${link_targets}) _llvm_generated_header_target(child_headers "${link_target}") diff --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake index d3f534a02f9de..945908649a3d6 100644 --- a/mlir/cmake/modules/AddMLIR.cmake +++ b/mlir/cmake/modules/AddMLIR.cmake @@ -273,6 +273,103 @@ function(_check_llvm_components_usage name) endforeach() endfunction() +# Normalize providers while directory-local targets are still visible. +function(_mlir_normalize_header_libraries) + get_property(consumers DIRECTORY PROPERTY MLIR_HEADER_LIBS_CONSUMERS) + list(REMOVE_DUPLICATES consumers) + foreach(consumer ${consumers}) + get_target_property(items "${consumer}" LLVM_HEADER_LIBS) + set(providers) + foreach(provider ${items}) + # Imported targets and their aliases may be visible only in this + # directory. Their headers already exist, so handle them before the + # top-level resolver runs. Waiting until the directory is complete also + # supports forward declarations of these local targets. + if(TARGET "${provider}") + _llvm_resolve_target_alias(provider "${provider}") + get_target_property(imported "${provider}" IMPORTED) + get_target_property(type "${provider}" TYPE) + if(imported AND type MATCHES + "^(STATIC|SHARED|MODULE|OBJECT|INTERFACE|UNKNOWN)_LIBRARY$") + continue() + endif() + endif() + list(APPEND providers "${provider}") + endforeach() + set_property(TARGET "${consumer}" PROPERTY LLVM_HEADER_LIBS "${providers}") + endforeach() +endfunction() + +# Record generated-header providers that are intentionally not linked. Resolve +# them after the full project has been declared so aliases and forward target +# references work and misspellings receive a useful diagnostic. +function(_mlir_add_header_libraries consumer) + if(NOT ARGN) + return() + endif() + set_property(TARGET "${consumer}" APPEND PROPERTY LLVM_HEADER_LIBS ${ARGN}) + set_property(DIRECTORY APPEND PROPERTY MLIR_HEADER_LIBS_CONSUMERS "${consumer}") + get_property(normalization_scheduled DIRECTORY PROPERTY + MLIR_HEADER_LIBS_NORMALIZATION_SCHEDULED) + if(NOT normalization_scheduled) + cmake_language(DEFER CALL _mlir_normalize_header_libraries) + set_property(DIRECTORY PROPERTY MLIR_HEADER_LIBS_NORMALIZATION_SCHEDULED TRUE) + endif() + set_property(GLOBAL APPEND PROPERTY MLIR_HEADER_LIBS_CONSUMERS "${consumer}") + get_property(scheduled GLOBAL PROPERTY MLIR_HEADER_LIBS_SCHEDULED) + if(NOT scheduled) + cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" + CALL _mlir_resolve_header_libraries) + set_property(GLOBAL PROPERTY MLIR_HEADER_LIBS_SCHEDULED TRUE) + endif() +endfunction() + +# Attach build-local header interfaces, which carry only generator ordering. +# CMake follows nested and cyclic interface relationships without depending on +# the provider libraries themselves. +function(_mlir_resolve_header_libraries) + get_property(consumers GLOBAL PROPERTY MLIR_HEADER_LIBS_CONSUMERS) + list(REMOVE_DUPLICATES consumers) + foreach(consumer ${consumers}) + get_target_property(providers "${consumer}" LLVM_HEADER_LIBS) + set(generated_headers) + foreach(provider ${providers}) + if(provider MATCHES "\\$<") + message(SEND_ERROR + "${consumer}: HEADER_LIBS '${provider}' is not a literal target name") + continue() + endif() + if(NOT TARGET "${provider}") + message(SEND_ERROR + "${consumer}: HEADER_LIBS '${provider}' is not a target") + continue() + endif() + + _llvm_resolve_target_alias(resolved_provider "${provider}") + get_target_property(type "${resolved_provider}" TYPE) + if(NOT type MATCHES + "^(STATIC|SHARED|MODULE|OBJECT|INTERFACE|UNKNOWN)_LIBRARY$") + message(SEND_ERROR + "${consumer}: HEADER_LIBS '${provider}' must name a library, not ${type}") + continue() + endif() + + _llvm_generated_header_target(provider_headers "${resolved_provider}") + list(APPEND generated_headers ${provider_headers}) + endforeach() + + list(REMOVE_DUPLICATES generated_headers) + if(generated_headers) + set_property(TARGET "${consumer}" APPEND PROPERTY LINK_LIBRARIES + ${generated_headers}) + if(TARGET "obj.${consumer}") + set_property(TARGET "obj.${consumer}" APPEND PROPERTY LINK_LIBRARIES + ${generated_headers}) + endif() + endif() + endforeach() +endfunction() + function(add_mlir_example_library name) cmake_parse_arguments(ARG "SHARED;DISABLE_INSTALL" @@ -325,11 +422,16 @@ endfunction() # are compatible with building an object library. # STANDALONE # Don't link against LLVMSupport. +# HEADER_LIBS +# A flat list of MLIR library targets whose generated headers are included +# without linking. This is a rare escape hatch for header-only or circular +# layering; linked libraries belong in LINK_LIBS and a library's own +# generators belong in DEPENDS. function(add_mlir_library name) cmake_parse_arguments(ARG "SHARED;INSTALL_WITH_TOOLCHAIN;EXCLUDE_FROM_LIBMLIR;DISABLE_INSTALL;ENABLE_AGGREGATION;OBJECT;STANDALONE" "" - "ADDITIONAL_HEADERS;DEPENDS;LINK_COMPONENTS;LINK_LIBS" + "ADDITIONAL_HEADERS;DEPENDS;HEADER_LIBS;LINK_COMPONENTS;LINK_LIBS" ${ARGN}) _set_mlir_additional_headers_as_srcs(${ARG_ADDITIONAL_HEADERS}) @@ -401,6 +503,7 @@ function(add_mlir_library name) # Add empty "phony" target add_custom_target(${name}) endif() + _mlir_add_header_libraries(${name} ${ARG_HEADER_LIBS}) set_target_properties(${name} PROPERTIES FOLDER "MLIR/Libraries") # Setup aggregate. @@ -748,6 +851,12 @@ endfunction(mlir_check_all_link_libraries) function(mlir_target_link_libraries target type) if (TARGET obj.${target}) target_link_libraries(obj.${target} ${type} ${ARGN}) + cmake_parse_arguments(LINK_LIBS_ARG "" "" "PUBLIC;PRIVATE;INTERFACE" + ${type} ${ARGN}) + _llvm_record_link_dependencies(obj.${target} + ${LINK_LIBS_ARG_PUBLIC} + ${LINK_LIBS_ARG_PRIVATE} + ${LINK_LIBS_ARG_UNPARSED_ARGUMENTS}) endif() if (MLIR_LINK_MLIR_DYLIB) diff --git a/mlir/docs/CMakeInfrastructure.md b/mlir/docs/CMakeInfrastructure.md new file mode 100644 index 0000000000000..a6fe8f6f87dea --- /dev/null +++ b/mlir/docs/CMakeInfrastructure.md @@ -0,0 +1,343 @@ +# CMake Infrastructure + +[TOC] + +MLIR extends LLVM's CMake infrastructure with helpers for TableGen, libraries, +dialects, interfaces, tools, installation, and aggregate libraries. This guide +describes the MLIR-specific conventions implemented by +[`AddMLIR.cmake`](../cmake/modules/AddMLIR.cmake). The LLVM CMake documentation +still applies to the underlying LLVM helpers. + +## Loading the MLIR CMake modules + +The monorepo build loads the required modules. An out-of-tree project using an +installed MLIR package normally starts with: + +~~~cmake +find_package(MLIR REQUIRED CONFIG) + +list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}") +list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") +include(TableGen) +include(AddLLVM) +include(AddMLIR) +include(HandleLLVMOptions) +~~~ + +The project under `mlir/examples/standalone` is the canonical out-of-tree +template. It demonstrates package discovery, generated files, libraries, +tools, tests, and installation without depending on the monorepo build. + +## Source and generated-file layout + +Public declarations normally live below `mlir/include/mlir`, with +implementations in the corresponding directory below `mlir/lib`. For example, +a dialect declared in `include/mlir/Dialect/Foo/IR` is normally implemented by +a library in `lib/Dialect/Foo/IR`. + +Generated target names such as `MLIRFooOpsIncGen` are build-tree details. The +library that compiles or publishes those generated files lists the target in +its own `DEPENDS`. Other libraries normally depend on the logical library +through `LINK_LIBS`, not on its private generation target. + +Generated source files are different from published generated headers. A +source-generation target, such as one created for sharded operations, remains +an explicit `DEPENDS` entry of the library compiling those sources. + +## TableGen + +Set `LLVM_TARGET_DEFINITIONS`, call `mlir_tablegen` once for each output, and +finish with the helper matching the output: + +| Helper | Intended output | +| --- | --- | +| `add_mlir_dialect` | Standard operation, type, and dialect fragments | +| `add_mlir_dialect_tablegen_target` | Other dialect-specific headers | +| `add_mlir_generic_tablegen_target` | Dialect-independent headers | +| `add_public_tablegen_target` | A library-specific header or source | + +For example: + +~~~cmake +set(LLVM_TARGET_DEFINITIONS FooPatterns.td) +mlir_tablegen(FooPatterns.h.inc -gen-rewriters) +add_public_tablegen_target(MLIRFooPatternsIncGen) +~~~ + +The library that includes `FooPatterns.h.inc` then lists +`MLIRFooPatternsIncGen` in `DEPENDS`. + +`mlir-generic-headers` collects dialect-independent public generation targets, +and every MLIR library depends on it. `mlir-headers` also includes +dialect-specific targets. The latter is a conservative compatibility aggregate +and should not replace precise library dependencies in new code. + +### Dialects + +The common dialect declaration is: + +~~~cmake +add_mlir_dialect(FooOps foo) +~~~ + +This generates operation, type, and dialect declaration and definition +fragments and creates `MLIRFooOpsIncGen`. The implementation library lists that +target explicitly: + +~~~cmake +add_mlir_dialect_library(MLIRFooDialect + FooDialect.cpp + FooOps.cpp + + DEPENDS + MLIRFooOpsIncGen + + LINK_LIBS PUBLIC + MLIRIR + ) +~~~ + +### Operation, type, and attribute interfaces + +`add_mlir_interface(FooOpInterface)` emits operation-interface declaration and +definition fragments. `add_mlir_type_interface(FooTypeInterface)` does the same +for a type interface. Attribute interfaces and specialized interface forms use +the corresponding `mlir_tablegen` generators followed by a dialect or generic +TableGen target. + +The library implementing an interface lists its generation target in +`DEPENDS`. A consumer links that interface library when its public or private +C++ interface uses the generated declarations. + +### Passes + +Pass declarations use `-gen-pass-decls`; C API fragments may be emitted from +the same `.td` file: + +~~~cmake +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name Foo) +mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header --prefix Foo) +mlir_tablegen(Passes.capi.cpp.inc -gen-pass-capi-impl --prefix Foo) +add_mlir_dialect_tablegen_target(MLIRFooPassIncGen) +~~~ + +The library that defines or publishes these passes keeps +`MLIRFooPassIncGen` in `DEPENDS`. A header-only consumer uses the logical pass +library through `HEADER_LIBS` only when linking it would be incorrect. + +### PDLL and generated documentation + +Use `add_mlir_pdll_library` to compile a PDLL source and make its generated +output available to another target. Use `add_mlir_doc` for generated dialect, +operation, type, attribute, interface, or pass documentation. Documentation +targets are collected under the `mlir-doc` aggregate and are not compilation +prerequisites unless a source target explicitly consumes their output. + +## Libraries + +`add_mlir_library` is the base helper for MLIR libraries: + +~~~cmake +add_mlir_library(MLIRFooTransforms + FooTransforms.cpp + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/Foo + + DEPENDS + MLIRFooTransformsIncGen + + LINK_COMPONENTS + Support + + LINK_LIBS PUBLIC + MLIRFooDialect + MLIRPass + ) +~~~ + +`LINK_COMPONENTS` names LLVM components. `LINK_LIBS` names CMake or MLIR +library targets. Keeping them separate allows LLVM and MLIR to substitute their +monolithic shared libraries correctly. + +Frequently used options include: + +| Option | Purpose | +| --- | --- | +| `SHARED` or `OBJECT` | Select a non-default library form | +| `INSTALL_WITH_TOOLCHAIN` | Install with the toolchain distribution | +| `EXCLUDE_FROM_LIBMLIR` | Exclude the library from monolithic MLIR | +| `DISABLE_INSTALL` | Omit standard installation rules | +| `ENABLE_AGGREGATION` | Make objects available to an MLIR aggregate | +| `STANDALONE` | Do not add the implicit `LLVMSupport` dependency | +| `ADDITIONAL_HEADERS` | Associate individual headers with the target | +| `ADDITIONAL_HEADER_DIRS` | Add public headers to IDE source groups | +| `DEPENDS` | Add the library's non-library build prerequisites | +| `HEADER_LIBS` | Order after generated headers without linking | + +Prefer the wrapper describing a library's role: + +| Helper | Additional behavior | +| --- | --- | +| `add_mlir_dialect_library` | Records a target in `MLIR_DIALECT_LIBS` | +| `add_mlir_conversion_library` | Records it in `MLIR_CONVERSION_LIBS` | +| `add_mlir_extension_library` | Records it in `MLIR_EXTENSION_LIBS` | +| `add_mlir_translation_library` | Records it in `MLIR_TRANSLATION_LIBS` | +| `add_mlir_example_library` | Applies the conventions to examples | +| `add_mlir_public_c_api_library` | Creates an aggregatable C API library | + +The global categories support tools and aggregates that intentionally collect +an entire class of libraries. Ordinary libraries should list only their actual +dependencies. + +### Link visibility + +Choose `LINK_LIBS` visibility from the C++ interface: + +| Declaration | Meaning | +| --- | --- | +| `PUBLIC A` | The target and its consumers use `A` | +| `PRIVATE A` | Only the target implementation uses `A` | +| `INTERFACE A` | Only consumers use `A` | + +Unqualified entries retain CMake's legacy signature behavior. New code should +use explicit visibility when the distinction matters. + +Use `mlir_target_link_libraries` when adding links after an MLIR target was +created, particularly for a library excluded from `libMLIR`. It applies +`MLIR_LINK_MLIR_DYLIB` substitution and also records the generated-header +ordering needed by an object-backed library. + +### Generated-header dependencies + +Three rules cover generated headers: + +1. A library lists its own TableGen and generated-source targets in `DEPENDS`. +2. `LINK_LIBS` orders compilation after the generated-header targets reachable + through the linked library's interface. PUBLIC, PRIVATE, and unqualified + direct links are considered; INTERFACE-only links are not used by the + current target's compilation. +3. `HEADER_LIBS` names a library whose generated header is included without a + link relationship. + +`HEADER_LIBS` is a rare layering escape hatch. It is appropriate when linking +the provider would be semantically wrong or would create a circular link +relationship. Keep it a flat list of literal target names and document the +source-level include that requires every entry: + +~~~cmake +# FooAnalysis.cpp includes mlir/Dialect/Bar/IR/BarOps.h. +HEADER_LIBS +MLIRBarDialect +~~~ + +Aliases and forward declarations are supported. Imported library targets are +accepted because their installed generated headers already exist. Misspelled +targets, generator expressions, executables, and utility targets are diagnosed +at configure time. Nested and cyclic `HEADER_LIBS` relationships are safe: the +resolver adds only generated-header leaf targets, never provider libraries. + +Libraries outside `add_mlir_library` do not accept `HEADER_LIBS`. A non-MLIR +header-only consumer should retain the relevant generator in `DEPENDS`. + +### How ordering is modeled + +`add_public_tablegen_target` marks generated-header utility targets. Each +`llvm_add_library` invocation records its exact `DEPENDS` list separately from +the cumulative `LLVM_COMMON_DEPENDS` directory state. After the full target +graph exists, a deferred traversal: + +* resolves aliases and forward references; +* follows direct implementation links and transitive link interfaces; +* follows nested `HEADER_LIBS` relationships; +* conservatively extracts targets from link generator expressions; and +* creates a build-local interface target for each header provider. + +These interface targets depend only on marked generators and link to other +header interfaces. CMake handles transitive ordering and cycles in that graph. +Consumers reference the header interfaces through their implementation links, +without publishing them in exported link interfaces. Provider objects and +archives are never added by this mechanism, so mutually linked static libraries +do not form strong build cycles. Disabled generator-expression arms may +generate extra headers. Imported libraries, paths, and flags require no +build-tree ordering. + +This target-level modeling works with all supported CMake generators. Ninja's +weaker ordering still completes a dependency's custom commands before compiling +the consumer, while generators with stronger target ordering see only the leaf +generator targets and do not wait for provider archives. + +## C API libraries and aggregation + +`add_mlir_public_c_api_library` creates an object-enabled MLIR library with the +visibility definitions needed by the C API. Use `add_mlir_aggregate` to build a +shared or static library from such components. `EMBED_LIBS` contribute their +objects; `PUBLIC_LIBS` remain normal exported link dependencies. + +Aggregation metadata is exported only for libraries created with +`ENABLE_AGGREGATION`. `MLIR_INSTALL_AGGREGATE_OBJECTS` controls whether the +object libraries needed by an out-of-tree aggregate are installed. Imported +components must have been installed with compatible aggregation metadata. + +## Tools, installation, and exports + +Use `add_mlir_tool` for MLIR command-line tools. It delegates to LLVM's tool +infrastructure and participates in the normal runtime and installation layout. + +`add_mlir_library` installs and exports its target by default. +`add_mlir_library_install` exposes the same rules for a non-standard library +construction path. `DISABLE_INSTALL` suppresses those rules, while +`INSTALL_WITH_TOOLCHAIN` includes the library when only the toolchain component +is installed. + +Installed packages contain generated headers already, so imported targets do +not contribute build-tree generator prerequisites. Exported logical library +interfaces, rather than private `*IncGen` target names, are the contract for +standalone consumers. + +## Validating dependency changes + +Generated-header correctness must be tested from empty generated-header state. +An incremental build can leave files behind, and a broad aggregate can generate +a missing header incidentally before its consumer compiles. + +Configure a fresh Ninja build and first build representative leaf libraries at +normal parallelism: + +~~~shell +cmake -S llvm -B <build> -G Ninja <configuration options> +cmake --build <build> --target \ + MLIRArmNeonDialect MLIRLinalgDialect --parallel 32 +~~~ + +Then build the broader graph to populate compiler dependency files. Only after +compilation succeeds, run: + +~~~shell +ninja -C <build> -t missingdeps +~~~ + +`missingdeps` compares generated-file producers with include relationships in +compiler depfiles. Running it before compilation cannot discover those +includes. The clean leaf build and populated-depfile audit cover different +failure modes. + +When changing the CMake infrastructure, also configure the focused CMake tests +with Ninja and Unix Makefiles, test the oldest supported CMake release, and +configure `mlir/examples/standalone` against an installed or build-tree MLIR +package. Inspect generated object-order rules to confirm they contain generator +targets and not provider archives. + +## Common mistakes + +* Depending on another library's `MLIRFooOpsIncGen` instead of linking + `MLIRFooDialect`. +* Using `HEADER_LIBS` where an ordinary link accurately models the C++ layer. +* Putting generator expressions or visibility keywords in `HEADER_LIBS`. +* Moving dialect-specific generators into `mlir-generic-headers` to hide a + missing logical dependency. +* Repairing a leaf race with the global `mlir-headers` aggregate without first + identifying the owning library. +* Running `missingdeps` before compiler depfiles have been populated. +* Validating only an incremental or broad aggregate build. diff --git a/mlir/docs/DefiningDialects/AttributesAndTypes.md b/mlir/docs/DefiningDialects/AttributesAndTypes.md index a339a763bd607..076b44b58f29c 100644 --- a/mlir/docs/DefiningDialects/AttributesAndTypes.md +++ b/mlir/docs/DefiningDialects/AttributesAndTypes.md @@ -192,7 +192,7 @@ mlir_tablegen(<Your Dialect>AttrDefs.h.inc -gen-attrdef-decls -attrdefs-dialect=<Your Dialect>) mlir_tablegen(<Your Dialect>AttrDefs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=<Your Dialect>) -add_public_tablegen_target(<Your Dialect>AttrDefsIncGen) +add_mlir_dialect_tablegen_target(<Your Dialect>AttrDefsIncGen) ``` The generated `<Your Dialect>AttrDefs.h.inc` will need to be included whereever diff --git a/mlir/lib/Conversion/SPIRVCommon/CMakeLists.txt b/mlir/lib/Conversion/SPIRVCommon/CMakeLists.txt index cd5a4c225efbf..7e2c426428361 100644 --- a/mlir/lib/Conversion/SPIRVCommon/CMakeLists.txt +++ b/mlir/lib/Conversion/SPIRVCommon/CMakeLists.txt @@ -3,4 +3,8 @@ add_mlir_conversion_library(MLIRSPIRVAttrToLLVMConversion DEPENDS MLIRSPIRVEnumsIncGen + + # AttrToLLVMConverter.h includes the generated SPIRVEnums.h. + HEADER_LIBS + MLIRSPIRVDialect ) diff --git a/mlir/lib/Dialect/Arith/IR/CMakeLists.txt b/mlir/lib/Dialect/Arith/IR/CMakeLists.txt index 3423e11a7d0f0..dae42285d02b0 100644 --- a/mlir/lib/Dialect/Arith/IR/CMakeLists.txt +++ b/mlir/lib/Dialect/Arith/IR/CMakeLists.txt @@ -23,6 +23,10 @@ add_mlir_dialect_library(MLIRArithDialect MLIRArithOpsIncGen MLIRArithOpsInterfacesIncGen + # ArithDialect.cpp includes generated Bufferization interfaces. + HEADER_LIBS + MLIRBufferizationDialect + LINK_LIBS PUBLIC MLIRCastInterfaces MLIRDialect diff --git a/mlir/lib/Dialect/Func/IR/CMakeLists.txt b/mlir/lib/Dialect/Func/IR/CMakeLists.txt index 329301c6fbafd..f23335800c9be 100644 --- a/mlir/lib/Dialect/Func/IR/CMakeLists.txt +++ b/mlir/lib/Dialect/Func/IR/CMakeLists.txt @@ -7,6 +7,10 @@ add_mlir_dialect_library(MLIRFuncDialect DEPENDS MLIRFuncOpsIncGen + # FuncOps.cpp includes generated Bufferization interfaces. + HEADER_LIBS + MLIRBufferizationDialect + LINK_LIBS PUBLIC MLIRCallInterfaces MLIRControlFlowInterfaces diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt index 50351fde8128f..df935dd681aee 100644 --- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt @@ -49,6 +49,10 @@ add_mlir_dialect_library(MLIRLLVMDialect BinaryFormat Core + # LLVMAttrs.cpp includes mlir/Dialect/Ptr/IR/PtrEnums.h. + HEADER_LIBS + MLIRPtrDialect + LINK_LIBS PUBLIC MLIRCallInterfaces MLIRControlFlowInterfaces @@ -121,6 +125,8 @@ add_mlir_dialect_library(MLIRROCDLDialect ${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/LLVMIR DEPENDS + # TODO: Migrate this IncGen dependency to HEADER_LIBS after refactoring + # MLIRGPUCompilationInterfaces into a separate link target. MLIRGPUCompilationAttrInterfacesIncGen MLIRROCDLOpsIncGen MLIRROCDLOpsShardGen @@ -165,6 +171,8 @@ add_mlir_dialect_library(MLIRXeVMDialect ${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/LLVMIR DEPENDS + # TODO: Migrate this IncGen dependency to HEADER_LIBS after refactoring + # MLIRGPUCompilationInterfaces into a separate link target. MLIRGPUCompilationAttrInterfacesIncGen MLIRXeVMOpsIncGen MLIRXeVMConversionsIncGen diff --git a/mlir/lib/Dialect/Linalg/IR/CMakeLists.txt b/mlir/lib/Dialect/Linalg/IR/CMakeLists.txt index fcba43785b6fd..960981d0e6f80 100644 --- a/mlir/lib/Dialect/Linalg/IR/CMakeLists.txt +++ b/mlir/lib/Dialect/Linalg/IR/CMakeLists.txt @@ -17,6 +17,10 @@ add_mlir_dialect_library(MLIRLinalgDialect MLIRShardingInterfaceIncGen MLIRRelayoutOpInterfaceIncGen + # LinalgDialect.cpp includes ShardingInterface.h for promised interfaces. + HEADER_LIBS + MLIRShardingInterface + LINK_LIBS PUBLIC MLIRAffineDialect MLIRArithDialect diff --git a/mlir/lib/Dialect/Shape/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Shape/Transforms/CMakeLists.txt index a51c6780c2866..89755a175495e 100644 --- a/mlir/lib/Dialect/Shape/Transforms/CMakeLists.txt +++ b/mlir/lib/Dialect/Shape/Transforms/CMakeLists.txt @@ -9,10 +9,8 @@ add_mlir_dialect_library(MLIRShapeOpsTransforms DEPENDS MLIRShapeTransformsIncGen - ) -target_link_libraries(MLIRShapeOpsTransforms - PUBLIC + LINK_LIBS PUBLIC MLIRArithDialect MLIRBufferizationDialect MLIRBufferizationTransforms diff --git a/mlir/lib/Dialect/Tensor/IR/CMakeLists.txt b/mlir/lib/Dialect/Tensor/IR/CMakeLists.txt index 66b73f9bead5d..493c2cd0efeb1 100644 --- a/mlir/lib/Dialect/Tensor/IR/CMakeLists.txt +++ b/mlir/lib/Dialect/Tensor/IR/CMakeLists.txt @@ -17,6 +17,10 @@ add_mlir_dialect_library(MLIRTensorDialect DEPENDS MLIRTensorOpsIncGen + # TensorDialect.cpp includes TransformInterfaces.h. + HEADER_LIBS + MLIRTransformDialectInterfaces + LINK_LIBS PUBLIC MLIRAffineDialect MLIRArithDialect diff --git a/mlir/lib/Dialect/Tosa/CMakeLists.txt b/mlir/lib/Dialect/Tosa/CMakeLists.txt index 6404ca8fc5a56..42bfc0837d2c3 100644 --- a/mlir/lib/Dialect/Tosa/CMakeLists.txt +++ b/mlir/lib/Dialect/Tosa/CMakeLists.txt @@ -16,6 +16,10 @@ add_mlir_dialect_library(MLIRTosaDialect MLIRTosaEnumsIncGen MLIRShardingInterfaceIncGen + # TosaOps.cpp includes ShardingInterface.h for promised interfaces. + HEADER_LIBS + MLIRShardingInterface + LINK_LIBS PUBLIC MLIRIR MLIRDialect diff --git a/mlir/lib/Rewrite/CMakeLists.txt b/mlir/lib/Rewrite/CMakeLists.txt index 15b3739e4c633..eefd3808c1409 100644 --- a/mlir/lib/Rewrite/CMakeLists.txt +++ b/mlir/lib/Rewrite/CMakeLists.txt @@ -1,5 +1,10 @@ set(LLVM_OPTIONAL_SOURCES ByteCode.cpp) +set(pdl_header_libraries) +if(MLIR_ENABLE_PDL_IN_PATTERNMATCH) + set(pdl_header_libraries MLIRPDLInterpDialect) +endif() + add_mlir_library(MLIRRewrite FrozenRewritePatternSet.cpp PatternApplicator.cpp @@ -11,6 +16,11 @@ add_mlir_library(MLIRRewrite mlir-generic-headers MLIRConversionPassIncGen + # FrozenRewritePatternSet.cpp includes PDLInterp and PDL when enabled. + # PDLInterp's public interface also provides the PDL generated headers. + HEADER_LIBS + ${pdl_header_libraries} + LINK_LIBS PUBLIC MLIRIR MLIRSideEffectInterfaces @@ -40,4 +50,3 @@ if(MLIR_ENABLE_PDL_IN_PATTERNMATCH) MLIRPDLToPDLInterp MLIRRewritePDL) endif() - diff --git a/mlir/lib/Target/SPIRV/CMakeLists.txt b/mlir/lib/Target/SPIRV/CMakeLists.txt index 1785cf92a9334..b65854e72ac31 100644 --- a/mlir/lib/Target/SPIRV/CMakeLists.txt +++ b/mlir/lib/Target/SPIRV/CMakeLists.txt @@ -10,6 +10,10 @@ set(LLVM_OPTIONAL_SOURCES add_mlir_translation_library(MLIRSPIRVBinaryUtils SPIRVBinaryUtils.cpp + # SPIRVBinaryUtils.h includes the generated SPIRVEnums.h. + HEADER_LIBS + MLIRSPIRVDialect + LINK_LIBS PUBLIC MLIRIR MLIRSupport diff --git a/mlir/test/CMake/header-dependencies.test b/mlir/test/CMake/header-dependencies.test new file mode 100644 index 0000000000000..cc1115b95e165 --- /dev/null +++ b/mlir/test/CMake/header-dependencies.test @@ -0,0 +1,192 @@ +# RUN: rm -rf %t +# RUN: split-file %s %t +# RUN: "%cmake_exe" -S %t/valid -B %t/valid-build -G "%cmake_generator" \ +# RUN: -DMLIR_DIR=%mlir_cmake_dir -DCMAKE_C_COMPILER=%host_cc \ +# RUN: -DCMAKE_CXX_COMPILER=%host_cxx 2>&1 \ +# RUN: | FileCheck %s --check-prefix=VALID +# RUN: "%cmake_exe" --build %t/valid-build --target obj.HeaderConsumer --parallel 4 +# RUN: "%cmake_exe" --build %t/valid-build --target clean +# RUN: "%cmake_exe" --build %t/valid-build --target obj.LinkConsumer --parallel 4 +# RUN: "%cmake_exe" --build %t/valid-build --target clean +# RUN: "%cmake_exe" --build %t/valid-build --target SharedHeaderConsumer --parallel 4 +# RUN: not "%cmake_exe" -S %t/invalid -B %t/invalid-build \ +# RUN: -G "%cmake_generator" -DMLIR_DIR=%mlir_cmake_dir \ +# RUN: -DCMAKE_C_COMPILER=%host_cc -DCMAKE_CXX_COMPILER=%host_cxx 2>&1 \ +# RUN: | FileCheck %s --check-prefix=INVALID + +# VALID: -- Generated header dependency checks passed +# INVALID-DAG: BadConsumer: HEADER_LIBS 'MisspelledProvider' is not a target +# INVALID-DAG: BadConsumer: HEADER_LIBS 'ProviderIncGen' must name a library, not UTILITY +# INVALID-DAG: BadConsumer: HEADER_LIBS 'NotALibrary' must name a library, not EXECUTABLE +# INVALID-DAG: BadConsumer: HEADER_LIBS '$<$<BOOL:1>:Provider>' is not a literal target + +#--- common.cmake +find_package(MLIR REQUIRED CONFIG) +list(APPEND CMAKE_MODULE_PATH "${MLIR_CMAKE_DIR}" "${LLVM_CMAKE_DIR}") +include(TableGen) +include(AddLLVM) +include(AddMLIR) +include(HandleLLVMOptions) +set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/bin) +set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/lib) + +foreach(target + Provider Base Conditional LinkOnly Disabled Plain InterfaceOnly + CycleA CycleB HeaderA HeaderB HeaderBase 3rdParty) + set(LLVM_COMMON_DEPENDS) + set(output ${CMAKE_CURRENT_BINARY_DIR}/${target}.h.inc) + add_custom_command(OUTPUT ${output} + COMMAND ${CMAKE_COMMAND} -E touch ${output}) + set(TABLEGEN_OUTPUT ${output}) + add_public_tablegen_target(${target}IncGen) +endforeach() +add_custom_target(SourceGenerator COMMAND ${CMAKE_COMMAND} -E false) +# Keep the fixture libraries from inheriting all preceding TableGen targets. +set(LLVM_COMMON_DEPENDS) + +#--- valid/CMakeLists.txt +cmake_minimum_required(VERSION 3.20) +project(HeaderDependencies LANGUAGES C CXX) +include(../common.cmake) + +add_library(Imported UNKNOWN IMPORTED) +set_target_properties(Imported PROPERTIES + IMPORTED_LOCATION /absolute/libimported.a) +add_library(ImportedAlias ALIAS Imported) + +# Consumers precede providers to exercise deferred forward resolution. +add_mlir_library(LinkConsumer empty.cpp DISABLE_INSTALL + LINK_LIBS PlainProvider /absolute/libunused.a -lpthread ImportedAlias + PRIVATE ProviderAlias "$<$<BOOL:0>:DisabledProvider>" + PUBLIC "$<$<BOOL:1>:ConditionalProvider>" "$<LINK_ONLY:LinkOnlyProvider>" + "$<$<BOOL:1>:3rdPartyProvider>" + INTERFACE InterfaceOnlyProvider) +add_mlir_library(CycleConsumer empty.cpp DISABLE_INSTALL + LINK_LIBS PRIVATE CycleA) +add_mlir_library(HeaderConsumer empty.cpp DISABLE_INSTALL + HEADER_LIBS HeaderAlias) +add_mlir_library(PostHocConsumer empty.cpp DISABLE_INSTALL) +add_mlir_library(PostHocInterfaceConsumer empty.cpp DISABLE_INSTALL) +add_mlir_library(SharedHeaderConsumer empty.cpp SHARED STANDALONE DISABLE_INSTALL + HEADER_LIBS HeaderAlias) +target_include_directories(SharedHeaderConsumer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_compile_definitions(SharedHeaderConsumer PRIVATE CHECK_HEADER_HEADERS) +target_include_directories(obj.HeaderConsumer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_compile_definitions(obj.HeaderConsumer PRIVATE CHECK_HEADER_HEADERS) +target_include_directories(obj.LinkConsumer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_compile_definitions(obj.LinkConsumer PRIVATE CHECK_LINK_HEADERS) + +add_mlir_library(Provider empty.cpp DISABLE_INSTALL + DEPENDS ProviderIncGen SourceGenerator + LINK_LIBS PUBLIC Base) +add_library(ProviderAlias ALIAS Provider) +add_mlir_library(Base empty.cpp DISABLE_INSTALL DEPENDS BaseIncGen) +add_mlir_library(ConditionalProvider empty.cpp DISABLE_INSTALL + DEPENDS ConditionalIncGen) +add_mlir_library(LinkOnlyProvider empty.cpp DISABLE_INSTALL + DEPENDS LinkOnlyIncGen) +add_mlir_library(DisabledProvider empty.cpp DISABLE_INSTALL + DEPENDS DisabledIncGen) +add_mlir_library(PlainProvider empty.cpp DISABLE_INSTALL + DEPENDS PlainIncGen) +add_mlir_library(InterfaceOnlyProvider empty.cpp DISABLE_INSTALL + DEPENDS InterfaceOnlyIncGen) +add_mlir_library(3rdPartyProvider empty.cpp DISABLE_INSTALL + DEPENDS 3rdPartyIncGen) + +# Mutual static-library links must not become strong target cycles. +add_mlir_library(CycleA empty.cpp DISABLE_INSTALL + DEPENDS CycleAIncGen LINK_LIBS PRIVATE CycleB) +add_mlir_library(CycleB empty.cpp DISABLE_INSTALL + DEPENDS CycleBIncGen LINK_LIBS CycleA) + +# HEADER_LIBS follows nested and link relationships while tolerating cycles. +add_mlir_library(HeaderA empty.cpp DISABLE_INSTALL + DEPENDS HeaderAIncGen + HEADER_LIBS HeaderB + LINK_LIBS PUBLIC HeaderBase) +add_library(HeaderAlias ALIAS HeaderA) +add_mlir_library(HeaderB empty.cpp DISABLE_INSTALL + DEPENDS HeaderBIncGen HEADER_LIBS HeaderA) +add_mlir_library(HeaderBase empty.cpp DISABLE_INSTALL + DEPENDS HeaderBaseIncGen) + +mlir_target_link_libraries(PostHocConsumer PRIVATE ProviderAlias + INTERFACE InterfaceOnlyProvider) +mlir_target_link_libraries(PostHocInterfaceConsumer INTERFACE InterfaceOnlyProvider) +add_subdirectory(local-providers) + +function(expect_header_libraries target expected) + get_target_property(actual ${target} LINK_LIBRARIES) + list(FILTER actual INCLUDE REGEX "^llvm\\.headers\\.") + list(SORT actual) + list(SORT expected) + if(NOT "${actual}" STREQUAL "${expected}") + message(FATAL_ERROR + "${target}: expected dependencies '${expected}', got '${actual}'") + endif() +endfunction() + +function(check_dependencies) + # Record direct header interfaces only. The subsequent clean object builds + # verify that CMake follows their transitive and cyclic dependencies. + expect_header_libraries(obj.LinkConsumer + "llvm.headers.3rdPartyProvider;llvm.headers.ConditionalProvider;llvm.headers.DisabledProvider;llvm.headers.LinkOnlyProvider;llvm.headers.PlainProvider;llvm.headers.Provider") + expect_header_libraries(obj.CycleConsumer "llvm.headers.CycleA") + expect_header_libraries(obj.HeaderConsumer "llvm.headers.HeaderA") + expect_header_libraries(HeaderConsumer "llvm.headers.HeaderA") + expect_header_libraries(obj.PostHocConsumer "llvm.headers.Provider") + expect_header_libraries(obj.PostHocInterfaceConsumer "") + expect_header_libraries(obj.LocalHeaderConsumer "") + expect_header_libraries(SharedHeaderConsumer "llvm.headers.HeaderA") + message(STATUS "Generated header dependency checks passed") +endfunction() +# The dependency resolvers were deferred first and therefore run before this. +cmake_language(DEFER CALL check_dependencies) + +#--- valid/empty.cpp +#ifdef CHECK_HEADER_HEADERS +#include "HeaderA.h.inc" +#include "HeaderB.h.inc" +#include "HeaderBase.h.inc" +#endif +#ifdef CHECK_LINK_HEADERS +#include "Provider.h.inc" +#include "Base.h.inc" +#include "Conditional.h.inc" +#include "LinkOnly.h.inc" +#include "Disabled.h.inc" +#include "Plain.h.inc" +#include "3rdParty.h.inc" +#endif +void empty() {} + +#--- valid/Provider.td +// Only configuration is under test. + +#--- valid/local-providers/CMakeLists.txt +# Non-global imported targets and aliases are visible only in this directory. +add_mlir_library(LocalHeaderConsumer empty.cpp DISABLE_INSTALL + HEADER_LIBS LocalImported LocalImportedAlias) +add_library(LocalImported INTERFACE IMPORTED) +add_library(LocalImportedAlias ALIAS LocalImported) + +#--- valid/local-providers/empty.cpp +void localEmpty() {} + +#--- invalid/CMakeLists.txt +cmake_minimum_required(VERSION 3.20) +project(HeaderDependenciesInvalid LANGUAGES C CXX) +include(../common.cmake) +add_executable(NotALibrary empty.cpp) +add_mlir_library(Provider empty.cpp DISABLE_INSTALL + DEPENDS ProviderIncGen) +add_mlir_library(BadConsumer empty.cpp DISABLE_INSTALL + HEADER_LIBS MisspelledProvider ProviderIncGen NotALibrary + "$<$<BOOL:1>:Provider>") + +#--- invalid/empty.cpp +void empty() {} + +#--- invalid/Provider.td +// Only configuration is under test. diff --git a/mlir/test/CMake/lit.local.cfg b/mlir/test/CMake/lit.local.cfg new file mode 100644 index 0000000000000..af315fd5da836 --- /dev/null +++ b/mlir/test/CMake/lit.local.cfg @@ -0,0 +1,7 @@ +if (config.host_cmake_generator == "Xcode" or + config.host_cmake_generator.startswith("Visual Studio")): + config.unsupported = True + +config.substitutions.append(("%cmake_exe", config.host_cmake)) +config.substitutions.append(("%cmake_generator", config.host_cmake_generator)) +config.substitutions.append(("%mlir_cmake_dir", config.mlir_cmake_dir)) _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
