Skip to content

[mlir] Make MLIR Python sources idempotent #97167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2024
Merged

[mlir] Make MLIR Python sources idempotent #97167

merged 1 commit into from
Jul 2, 2024

Conversation

dukebw
Copy link
Contributor

@dukebw dukebw commented Jun 29, 2024

Make MLIR Python sources idempotent by moving the custom commands off the custom target for each source.
Previously, a custom target was created for each MLIR Python source file and a custom command added to symlink it to a destination path. However this causes the build to not be idempotent because custom targets always run.

Instead, this PR separates the symlink/copy to destination paths into custom commands and makes the custom target depend on the output. That prevents re-running them and restores idempotency.

Testing:

  • Build with -D MLIR_ENABLE_BINDINGS_PYTHON=ON. Prior to this change, the build is not idempotent (building twice re-runs the symlink/copy command for Python source targets). After this change it is idempotent.

Make MLIR Python sources idempotent by moving the custom commands off
the custom target for each source.
Previously, a custom target was created for each MLIR Python source file
and a custom command added to symlink it to a destination path.
However this causes the build to not be idempotent because custom
targets always run.

Instead, this PR separates the symlink/copy to destination paths into
custom commands and makes the custom target depend on the output.
That prevents re-running them and restores idempotency.

Testing:
- Build with `-D MLIR_ENABLE_BINDINGS_PYTHON=ON`.
  Prior to this change, the build is not idempotent (building twice
  re-runs the symlink/copy command for Python source targets).
  After this change it is idempotent.
@llvmbot llvmbot added the mlir label Jun 29, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 29, 2024

@llvm/pr-subscribers-mlir

Author: Brendan Duke (dukebw)

Changes

Make MLIR Python sources idempotent by moving the custom commands off the custom target for each source.
Previously, a custom target was created for each MLIR Python source file and a custom command added to symlink it to a destination path. However this causes the build to not be idempotent because custom targets always run.

Instead, this PR separates the symlink/copy to destination paths into custom commands and makes the custom target depend on the output. That prevents re-running them and restores idempotency.

Testing:

  • Build with -D MLIR_ENABLE_BINDINGS_PYTHON=ON. Prior to this change, the build is not idempotent (building twice re-runs the symlink/copy command for Python source targets). After this change it is idempotent.

Full diff: https://github.com/llvm/llvm-project/pull/97167.diff

1 Files Affected:

  • (modified) mlir/cmake/modules/AddMLIRPython.cmake (+11-6)
diff --git a/mlir/cmake/modules/AddMLIRPython.cmake b/mlir/cmake/modules/AddMLIRPython.cmake
index f030798a94ae9..7b91f43e2d57f 100644
--- a/mlir/cmake/modules/AddMLIRPython.cmake
+++ b/mlir/cmake/modules/AddMLIRPython.cmake
@@ -565,8 +565,6 @@ function(add_mlir_python_sources_target name)
     message(FATAL_ERROR "Unhandled arguments to add_mlir_python_sources_target(${name}, ... : ${ARG_UNPARSED_ARGUMENTS}")
   endif()
 
-  add_custom_target(${name})
-
   # On Windows create_symlink requires special permissions. Use copy_if_different instead.
   if(CMAKE_HOST_WIN32)
     set(_link_or_copy copy_if_different)
@@ -575,8 +573,6 @@ function(add_mlir_python_sources_target name)
   endif()
 
   foreach(_sources_target ${ARG_SOURCES_TARGETS})
-    add_dependencies(${name} ${_sources_target})
-
     get_target_property(_src_paths ${_sources_target} SOURCES)
     if(NOT _src_paths)
       get_target_property(_src_paths ${_sources_target} INTERFACE_SOURCES)
@@ -590,6 +586,8 @@ function(add_mlir_python_sources_target name)
       get_target_property(_root_dir ${_sources_target} INTERFACE_INCLUDE_DIRECTORIES)
     endif()
 
+    # Initialize an empty list of all Python source destination paths.
+    set(all_dest_paths "")
     foreach(_src_path ${_src_paths})
       file(RELATIVE_PATH _source_relative_path "${_root_dir}" "${_src_path}")
       set(_dest_path "${ARG_OUTPUT_DIRECTORY}/${_source_relative_path}")
@@ -598,13 +596,17 @@ function(add_mlir_python_sources_target name)
       file(MAKE_DIRECTORY "${_dest_dir}")
 
       add_custom_command(
-        TARGET ${name} PRE_BUILD
+        OUTPUT "${_dest_path}"
+        PRE_BUILD
         COMMENT "Copying python source ${_src_path} -> ${_dest_path}"
         DEPENDS "${_src_path}"
-        BYPRODUCTS "${_dest_path}"
         COMMAND "${CMAKE_COMMAND}" -E ${_link_or_copy}
             "${_src_path}" "${_dest_path}"
       )
+
+      # Track the symlink or copy command output.
+      list(APPEND all_dest_paths "${_dest_path}")
+
       if(ARG_INSTALL_DIR)
         # We have to install each file individually because we need to preserve
         # the relative directory structure in the install destination.
@@ -621,6 +623,9 @@ function(add_mlir_python_sources_target name)
       endif()
     endforeach()
   endforeach()
+
+  # Create a new custom target that depends on all symlinked or copied sources.
+  add_custom_target("${name}" DEPENDS ${all_dest_paths})
 endfunction()
 
 ################################################################################

Copy link
Contributor

@akirchhoff-modular akirchhoff-modular left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I was initially confused why we were creating a list of paths to use as DEPENDS later rather than using add_dependencies as we go, but I now see in the CMake documentation that add_dependencies is only for top-level targets to depend on other top-level targets, so a list is in fact needed and this PR as-is makes sense.

@stellaraccident
Copy link
Contributor

Looks good to me. I was initially confused why we were creating a list of paths to use as DEPENDS later rather than using add_dependencies as we go, but I now see in the CMake documentation that add_dependencies is only for top-level targets to depend on other top-level targets, so a list is in fact needed and this PR as-is makes sense.

Yes, cmake is very fiddly for mixed file/target dependencies.

@dukebw dukebw merged commit 1846523 into llvm:main Jul 2, 2024
9 checks passed
lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
Make MLIR Python sources idempotent by moving the custom commands off
the custom target for each source.
Previously, a custom target was created for each MLIR Python source file
and a custom command added to symlink it to a destination path. However
this causes the build to not be idempotent because custom targets always
run.

Instead, this PR separates the symlink/copy to destination paths into
custom commands and makes the custom target depend on the output. That
prevents re-running them and restores idempotency.

Testing:
- Build with `-D MLIR_ENABLE_BINDINGS_PYTHON=ON`. Prior to this change,
the build is not idempotent (building twice re-runs the symlink/copy
command for Python source targets). After this change it is idempotent.
kbluck pushed a commit to kbluck/llvm-project that referenced this pull request Jul 6, 2024
Make MLIR Python sources idempotent by moving the custom commands off
the custom target for each source.
Previously, a custom target was created for each MLIR Python source file
and a custom command added to symlink it to a destination path. However
this causes the build to not be idempotent because custom targets always
run.

Instead, this PR separates the symlink/copy to destination paths into
custom commands and makes the custom target depend on the output. That
prevents re-running them and restores idempotency.

Testing:
- Build with `-D MLIR_ENABLE_BINDINGS_PYTHON=ON`. Prior to this change,
the build is not idempotent (building twice re-runs the symlink/copy
command for Python source targets). After this change it is idempotent.
mikeurbach added a commit to llvm/circt that referenced this pull request Jul 20, 2024
This specific dependency no longer works after an upstream change:
llvm/llvm-project#97167. Furthermore, we never
actually wanted this dependency, since we don't actually do anything
with the builtin dialect ops. We only used this to convince the MLIR
bindings to do the automatic downcasting for builtin dialect types and
attributes, which required the builtin dialect to be registered (even
though it always is) until this change went in:
llvm/llvm-project#72338. Now that these
changes are behind us, we can remove our workaround and avoid the
issues that ensue by depending on a target no one usually depends on.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants