Warning, /acts/cmake/ActsCodegen.cmake is written in an unsupported language. File is not indexed.
0001 include_guard(GLOBAL)
0002
0003 if(NOT ACTS_USE_SYSTEM_LIBS)
0004 message(STATUS "Configuring codegen: preparing uv")
0005
0006 find_program(uv_exe uv)
0007
0008 set(_uv_version "0.7.19")
0009 set(_base_url
0010 "https://github.com/astral-sh/uv/releases/download/${_uv_version}"
0011 )
0012
0013 if(uv_exe STREQUAL "uv_exe-NOTFOUND")
0014 message(STATUS "uv not found, installing it")
0015
0016 if(NOT APPLE AND NOT UNIX)
0017 message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
0018 endif()
0019
0020 if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
0021 if(APPLE)
0022 set(UV_NAME "${_base_url}/uv-x86_64-apple-darwin.tar.gz")
0023 set(UV_HASH
0024 "SHA256=698d24883fd441960fb4bc153b7030b89517a295502017ff3fdbba2fb0a0aa67"
0025 )
0026 elseif(UNIX)
0027 set(UV_URL "${_base_url}/uv-x86_64-unknown-linux-musl.tar.gz")
0028 set(UV_HASH
0029 "SHA256=6236ed00a7442ab2c0f56f807d5a3331f3fb5c7640a357482fbc8492682641b2"
0030 )
0031 endif()
0032 elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm)|(ARM)|(aarch64)")
0033 if(APPLE)
0034 set(UV_URL "${_base_url}/uv-aarch64-apple-darwin.tar.gz")
0035 set(UV_HASH
0036 "SHA256=698d24883fd441960fb4bc153b7030b89517a295502017ff3fdbba2fb0a0aa67"
0037 )
0038 elseif(UNIX)
0039 set(UV_URL "${_base_url}/uv-aarch64-unknown-linux-musl.tar.gz")
0040 set(UV_HASH
0041 "SHA256=e83c7c6d86c8e7456078c736a72550ce20222df8083f9317fc58cd49422ce5eb"
0042 )
0043 endif()
0044 else()
0045 message(
0046 FATAL_ERROR
0047 "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}"
0048 )
0049 endif()
0050
0051 message(STATUS "Downloading uv from ${UV_URL}")
0052 set(UV_DIR "${CMAKE_BINARY_DIR}/uv")
0053 file(DOWNLOAD ${UV_URL} ${UV_DIR}/uv.tar.gz EXPECTED_HASH ${UV_HASH})
0054
0055 file(ARCHIVE_EXTRACT INPUT ${UV_DIR}/uv.tar.gz DESTINATION ${UV_DIR})
0056
0057 file(REMOVE ${UV_DIR}/uv.tar.gz)
0058
0059 file(GLOB uv_extracted ${UV_DIR}/uv*)
0060 message(STATUS "Extracted uv: ${uv_extracted}")
0061
0062 find_program(uv_exe uv PATHS ${uv_extracted} REQUIRED NO_DEFAULT_PATH)
0063 endif()
0064
0065 message(STATUS "Found uv: ${uv_exe}")
0066
0067 execute_process(
0068 COMMAND ${uv_exe} --version
0069 OUTPUT_VARIABLE uv_version
0070 OUTPUT_STRIP_TRAILING_WHITESPACE
0071 )
0072 message(STATUS "uv version: ${uv_version}")
0073 else()
0074 message(
0075 STATUS
0076 "Configuring codegen in offline mode: preparing virtual environment"
0077 )
0078
0079 find_package(Python REQUIRED COMPONENTS Interpreter)
0080
0081 # The idea of the following code is to create a "nested" Python
0082 # environment; we grab the source of the packages in the current env
0083 # whether that is a virtual environment, a system environment, or a Spack
0084 # environment, and copy that into a newly created virtual environment.
0085 # This strategy comes from https://stackoverflow.com/a/75545634
0086 # First, we grab the Python package directory for the outside environment.
0087 execute_process(
0088 COMMAND
0089 ${Python_EXECUTABLE} -c
0090 "import sysconfig; print(sysconfig.get_paths()['purelib'])"
0091 OUTPUT_VARIABLE _python_package_dir
0092 OUTPUT_STRIP_TRAILING_WHITESPACE
0093 )
0094
0095 # Then we create a new virtual env using the venv package which is built
0096 # into Python these days.
0097 execute_process(
0098 COMMAND ${Python_EXECUTABLE} -m venv ${CMAKE_BINARY_DIR}/codegen_venv
0099 )
0100 # Now, we get the package directory for the newly created virtual
0101 # environment.
0102 execute_process(
0103 COMMAND
0104 ${CMAKE_BINARY_DIR}/codegen_venv/bin/python -c
0105 "import sysconfig; print(sysconfig.get_paths()['purelib'])"
0106 OUTPUT_VARIABLE _python_nested_package_dir
0107 OUTPUT_STRIP_TRAILING_WHITESPACE
0108 )
0109
0110 # Finally, we write the path found in the outside virtual env into the
0111 # new virtual env as described in the StackOverflow answer.
0112 file(
0113 WRITE
0114 "${_python_nested_package_dir}/_base_packages.pth"
0115 ${_python_package_dir}
0116 )
0117
0118 message(
0119 STATUS
0120 "Virtual environment based on ${_python_package_dir} created in ${CMAKE_BINARY_DIR}/codegen_venv/"
0121 )
0122 endif()
0123
0124 function(acts_code_generation)
0125 set(options ISOLATED)
0126 set(oneValueArgs ADD_TO_TARGET PYTHON PYTHON_VERSION OUTPUT)
0127 set(multiValueArgs DEPENDS WITH_REQUIREMENTS WITH)
0128 cmake_parse_arguments(
0129 PARSE_ARGV
0130 0
0131 ARGS
0132 "${options}"
0133 "${oneValueArgs}"
0134 "${multiValueArgs}"
0135 )
0136
0137 if(NOT DEFINED ARGS_PYTHON_VERSION)
0138 set(ARGS_PYTHON_VERSION "3.13")
0139 endif()
0140
0141 if(NOT DEFINED ARGS_PYTHON)
0142 message(SEND_ERROR "No python script specified")
0143 return()
0144 endif()
0145
0146 if(NOT EXISTS ${ARGS_PYTHON})
0147 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_PYTHON})
0148 set(ARGS_PYTHON ${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_PYTHON})
0149 else()
0150 message(SEND_ERROR "Python script not found: ${ARGS_PYTHON}")
0151 return()
0152 endif()
0153 endif()
0154
0155 set(_arg_isolated "")
0156 if(ARGS_ISOLATED)
0157 set(_arg_isolated "--isolated")
0158 endif()
0159
0160 set(_depends "${ARGS_PYTHON}")
0161 set(_with_args "")
0162 foreach(_requirement ${ARGS_WITH_REQUIREMENTS})
0163 list(APPEND _depends ${_requirement})
0164 list(APPEND _with_args "--with-requirements;${_requirement}")
0165 endforeach()
0166
0167 foreach(_requirement ${ARGS_WITH})
0168 list(APPEND _with_args "--with;${_requirement}")
0169 if(IS_DIRECTORY ${_requirement})
0170 if(NOT ACTS_USE_SYSTEM_LIBS)
0171 file(GLOB_RECURSE _depends_py ${_requirement}/*)
0172 list(APPEND _depends ${_depends_py})
0173 else()
0174 # If we are not using uv, then we use pip to install the
0175 # package into the virtual environment in the build directory.
0176 # The --no-build-isolation flag ensures that we don't
0177 # automatically download setuptools. The --no-index flag
0178 # ensures that nothing can be downloaded ever, and the
0179 # --no-deps is necessary to convince pip that the dependencies
0180 # are already in the environment.
0181 execute_process(
0182 COMMAND
0183 ${CMAKE_BINARY_DIR}/codegen_venv/bin/python -m pip
0184 install --no-build-isolation --no-index --no-deps
0185 ${_requirement}
0186 OUTPUT_QUIET
0187 )
0188 endif()
0189 endif()
0190 endforeach()
0191
0192 get_filename_component(_output_name ${ARGS_OUTPUT} NAME)
0193
0194 string(SHA1 _output_hash ${_output_name})
0195
0196 set(_codegen_root ${CMAKE_CURRENT_BINARY_DIR}/codegen/${_output_hash})
0197 set(_output_file ${_codegen_root}/${ARGS_OUTPUT})
0198
0199 get_filename_component(_output_dir ${_output_file} DIRECTORY)
0200 file(MAKE_DIRECTORY ${_output_dir})
0201
0202 if(NOT ACTS_USE_SYSTEM_LIBS)
0203 add_custom_command(
0204 OUTPUT ${_output_file}
0205 COMMAND
0206 env -i UV_NO_CACHE=1 ${uv_exe} run --quiet --python
0207 ${ARGS_PYTHON_VERSION} --no-project ${_arg_isolated}
0208 ${_with_args} ${ARGS_PYTHON} ${_output_file}
0209 DEPENDS ${_depends}
0210 COMMENT "Generating ${ARGS_OUTPUT}"
0211 VERBATIM
0212 )
0213 else()
0214 # If not using uv, just run Python from the virtual environment that
0215 # we created above.
0216 add_custom_command(
0217 OUTPUT ${_output_file}
0218 COMMAND
0219 ${CMAKE_BINARY_DIR}/codegen_venv/bin/python ${ARGS_PYTHON}
0220 ${_output_file}
0221 DEPENDS ${_depends}
0222 COMMENT "Generating ${ARGS_OUTPUT}"
0223 VERBATIM
0224 )
0225 endif()
0226
0227 set(_internal_target codegen_${_output_hash}_Internal)
0228 add_custom_target(${_internal_target} DEPENDS ${_output_file})
0229
0230 add_dependencies(${ARGS_ADD_TO_TARGET} ${_internal_target})
0231 target_include_directories(${ARGS_ADD_TO_TARGET} PRIVATE ${_codegen_root})
0232 endfunction()