Skip to content

Commit 004a5e6

Browse files
authored
Stage python sources per file instead of copying the tree (NVIDIA#4875)
CopyPythonFiles copied all of python/ into the build directory with a single always-run command. That copy raced the MLIR machinery's symlink rules for cudaq/mlir (intermittent "failed to create symbolic link ...: File exists" in parallel builds), declared no per-file outputs so ninja could neither order it nor reject duplicate producers, re-copied every file on every build, and spilled extension/ sources into binary directories. Stage the cudaq package and tests with one declared rule per file (cudaq_stage_python_sources, modeled on add_mlir_python_sources_target without its install and export machinery), and generate _metadata.py from a command with a declared output. cudaq/mlir stays owned solely by the MLIR staging. Content with no build-tree consumers (metapackages, README, extension/ sources) is no longer copied; wheels take pure python sources from the source tree via wheel.packages and non-wheel installs use install(DIRECTORY), both unchanged. See the failure at: https://github.com/NVIDIA/cuda-quantum/actions/runs/28880392782/job/85669399820 --------- Signed-off-by: mitchdz <mitch_dz@hotmail.com> Signed-off-by: mdzurick <mitch_dz@hotmail.com>
1 parent 331b833 commit 004a5e6

2 files changed

Lines changed: 61 additions & 10 deletions

File tree

cmake/modules/BuildHelpers.cmake

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,31 @@ function(add_target_libs_to_wheel nvqir_backend_lib_or_config)
9292
message(WARNING "Unknown file extension of ${nvqir_backend_lib_or_config} file. It will be ignored.")
9393
endif()
9494
endfunction()
95+
96+
# Stage python sources into the build tree, one symlink rule per file.
97+
# Modeled on MLIR's add_mlir_python_sources_target minus its install and
98+
# export machinery; these sources are installed through other mechanisms.
99+
function(cudaq_stage_python_sources name)
100+
cmake_parse_arguments(ARG "" "ROOT_DIR;OUTPUT_DIRECTORY" "SOURCES" ${ARGN})
101+
if(ARG_UNPARSED_ARGUMENTS)
102+
message(FATAL_ERROR "Unhandled arguments to cudaq_stage_python_sources(${name}): ${ARG_UNPARSED_ARGUMENTS}")
103+
endif()
104+
105+
set(_dest_paths "")
106+
foreach(_rel_path ${ARG_SOURCES})
107+
set(_src_path "${ARG_ROOT_DIR}/${_rel_path}")
108+
set(_dest_path "${ARG_OUTPUT_DIRECTORY}/${_rel_path}")
109+
get_filename_component(_dest_dir "${_dest_path}" DIRECTORY)
110+
file(MAKE_DIRECTORY "${_dest_dir}")
111+
add_custom_command(
112+
OUTPUT "${_dest_path}"
113+
COMMENT "Staging python source ${_rel_path}"
114+
DEPENDS "${_src_path}"
115+
COMMAND "${CMAKE_COMMAND}" -E create_symlink
116+
"${_src_path}" "${_dest_path}"
117+
)
118+
list(APPEND _dest_paths "${_dest_path}")
119+
endforeach()
120+
121+
add_custom_target(${name} DEPENDS ${_dest_paths})
122+
endfunction()

python/CMakeLists.txt

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ set(CMAKE_PLATFORM_NO_VERSIONED_SONAME 1)
2424

2525
add_subdirectory(extension)
2626

27-
file(GLOB_RECURSE PYTHON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.py")
28-
2927
if (CUDA_FOUND)
3028
enable_language(CUDA)
3129
find_package(CUDAToolkit REQUIRED)
@@ -38,21 +36,46 @@ else()
3836
endif()
3937

4038
set(METADATA_FILE "${CMAKE_BINARY_DIR}/python/cudaq/_metadata.py" )
41-
add_custom_target(
42-
CopyPythonFiles ALL
43-
COMMAND ${CMAKE_COMMAND} -E copy_directory
44-
${CMAKE_CURRENT_SOURCE_DIR}
45-
${CMAKE_BINARY_DIR}/python
39+
add_custom_command(
40+
OUTPUT "${METADATA_FILE}"
4641
COMMAND ${CMAKE_COMMAND}
4742
-DMETADATA_FILE="${METADATA_FILE}"
4843
-DCUDA_VERSION_MAJOR=${CUDAToolkit_VERSION_MAJOR}
4944
-DASSERTIONS_ENABLED=${CUDAQ_ASSERTIONS_ENABLED}
5045
-P ${CMAKE_CURRENT_SOURCE_DIR}/metadata.cmake
51-
DEPENDS ${PYTHON_SOURCES}
52-
BYPRODUCTS "${METADATA_FILE}"
46+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/metadata.cmake
5347
)
5448

55-
add_dependencies(CUDAQuantumPythonModules CopyPythonFiles)
49+
# cudaq/mlir is excluded: the MLIR machinery in extension/ stages it, and
50+
# a second producer for the same outputs races it. No CONFIGURE_DEPENDS:
51+
# a mid-ctest reconfigure relinks libraries under running tests. Adding a
52+
# python file requires a reconfigure.
53+
file(GLOB_RECURSE _cudaq_package_sources
54+
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/cudaq"
55+
"${CMAKE_CURRENT_SOURCE_DIR}/cudaq/*.py")
56+
list(FILTER _cudaq_package_sources EXCLUDE REGEX "^mlir/")
57+
cudaq_stage_python_sources(CUDAQPythonPackageStaging
58+
ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cudaq"
59+
OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/cudaq"
60+
SOURCES ${_cudaq_package_sources})
61+
62+
# The pycudaq-mlir lit suite and the interop pytest run from the build tree.
63+
# mlir/generated holds artifacts lit writes into the source tree at config
64+
# load; they are discovered from there, not staged.
65+
file(GLOB_RECURSE _cudaq_test_sources
66+
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/tests"
67+
"${CMAKE_CURRENT_SOURCE_DIR}/tests/*")
68+
list(FILTER _cudaq_test_sources EXCLUDE REGEX
69+
"^mlir/generated/|__pycache__|\\.pyc$|\\.DS_Store$")
70+
cudaq_stage_python_sources(CUDAQPythonTestStaging
71+
ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests"
72+
OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/tests"
73+
SOURCES ${_cudaq_test_sources})
74+
75+
add_custom_target(CUDAQPythonStaging ALL DEPENDS "${METADATA_FILE}")
76+
add_dependencies(CUDAQPythonStaging
77+
CUDAQPythonPackageStaging CUDAQPythonTestStaging)
78+
add_dependencies(CUDAQuantumPythonModules CUDAQPythonStaging)
5679

5780
add_subdirectory(runtime/cudaq/domains/plugins)
5881

0 commit comments

Comments
 (0)