diff --git a/setup/python/pdm.lock b/setup/python/pdm.lock index 24d4bbb0a54b..aeaabe933ebf 100644 --- a/setup/python/pdm.lock +++ b/setup/python/pdm.lock @@ -2,14 +2,24 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "test"] +groups = ["default", "test", "wheel"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:640eba7f25da1d28186cb1fb1eceb2fffaa31592d497b74fd776e2fcdc276a98" +content_hash = "sha256:6e0102fe5ea6c29e8888d56dfc6686fb1c73a2070f8dbff0e62ced5adb76a886" [[metadata.targets]] requires_python = ">=3.10" +[[package]] +name = "altgraph" +version = "0.17.4" +summary = "Python graph (network) package" +groups = ["wheel"] +files = [ + {file = "altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff"}, + {file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"}, +] + [[package]] name = "anyio" version = "4.7.0" @@ -122,7 +132,7 @@ name = "attrs" version = "24.3.0" requires_python = ">=3.8" summary = "Classes Without Boilerplate" -groups = ["default"] +groups = ["default", "wheel"] files = [ {file = "attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308"}, {file = "attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff"}, @@ -156,6 +166,20 @@ files = [ {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, ] +[[package]] +name = "bindepend" +version = "0.1" +summary = "Binary depedency analysis" +groups = ["wheel"] +marker = "sys_platform == \"win32\"" +dependencies = [ + "pefile", +] +files = [ + {file = "bindepend-0.1-py3-none-any.whl", hash = "sha256:8c3017b8d25b18c3865f55137656338312d06999b93b798b5be1a1d0176e6493"}, + {file = "bindepend-0.1.tar.gz", hash = "sha256:4a376a4a81d4812e85be9cf1b9b49c78bcf76a3278b94a9b080c22ac9c3ad1fd"}, +] + [[package]] name = "bleach" version = "6.2.0" @@ -497,6 +521,24 @@ files = [ {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, ] +[[package]] +name = "delocate" +version = "0.12.0" +requires_python = ">=3.7" +summary = "Move macOS dynamic libraries into package" +groups = ["wheel"] +dependencies = [ + "bindepend; sys_platform == \"win32\"", + "macholib", + "machomachomangler; sys_platform == \"win32\"", + "packaging>=20.9", + "typing-extensions", +] +files = [ + {file = "delocate-0.12.0-py3-none-any.whl", hash = "sha256:0da599c7561dcca2835149eaa4733e85408d71f249c6c4c43c3cb16cedb43a09"}, + {file = "delocate-0.12.0.tar.gz", hash = "sha256:e051660836a87b61c99b9b180344be363c31e1f2d9fdc94caebc854b6611335c"}, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -1140,6 +1182,33 @@ files = [ {file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"}, ] +[[package]] +name = "macholib" +version = "1.16.3" +summary = "Mach-O header analysis and editing" +groups = ["wheel"] +dependencies = [ + "altgraph>=0.17", +] +files = [ + {file = "macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c"}, + {file = "macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30"}, +] + +[[package]] +name = "machomachomangler" +version = "0.0.1" +summary = "Tools for mangling Mach-O and PE binaries" +groups = ["wheel"] +marker = "sys_platform == \"win32\"" +dependencies = [ + "attrs", +] +files = [ + {file = "machomachomangler-0.0.1-py3-none-any.whl", hash = "sha256:4fa66b8b65959399874f05a4d93abe1e49db46f71bef66a68a93e060d9ba0cb3"}, + {file = "machomachomangler-0.0.1.tar.gz", hash = "sha256:2acbad5bd465c5f386e5ceac8a8a1939a9789f503dd84f491e046292cf6e54a6"}, +] + [[package]] name = "markupsafe" version = "3.0.2" @@ -1470,7 +1539,7 @@ name = "packaging" version = "24.2" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["default"] +groups = ["default", "wheel"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, @@ -1498,6 +1567,18 @@ files = [ {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, ] +[[package]] +name = "pefile" +version = "2024.8.26" +requires_python = ">=3.6.0" +summary = "Python PE parsing module" +groups = ["wheel"] +marker = "sys_platform == \"win32\"" +files = [ + {file = "pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f"}, + {file = "pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632"}, +] + [[package]] name = "pexpect" version = "4.9.0" @@ -2047,7 +2128,7 @@ name = "setuptools" version = "75.6.0" requires_python = ">=3.9" summary = "Easily download, build, install, upgrade, and uninstall Python packages" -groups = ["default"] +groups = ["default", "wheel"] files = [ {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, @@ -2220,8 +2301,7 @@ name = "typing-extensions" version = "4.12.2" requires_python = ">=3.8" summary = "Backported and Experimental Type Hints for Python 3.8+" -groups = ["default"] -marker = "python_version < \"3.13\"" +groups = ["default", "wheel"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, @@ -2379,6 +2459,17 @@ files = [ {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, ] +[[package]] +name = "wheel" +version = "0.45.1" +requires_python = ">=3.8" +summary = "A built-package format for Python" +groups = ["wheel"] +files = [ + {file = "wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248"}, + {file = "wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729"}, +] + [[package]] name = "widgetsnbextension" version = "4.0.13" diff --git a/setup/python/pyproject.toml b/setup/python/pyproject.toml index d042440a4d16..ab21a4c64b07 100644 --- a/setup/python/pyproject.toml +++ b/setup/python/pyproject.toml @@ -2,12 +2,20 @@ # the "locked" pdm output file via: # # tools/workspace/python/venv_upgrade +# +# This file primarily defines the set of Python dependencies that are used by +# Drake in various ways and are managed by tools/workspace/python/venv_sync. +# It is the responsibility of tools/workspace/python/repository.bzl to decide +# which dependency groups need to be installed. [project] name = "drake" # The supported Python major/minor version should match the minimum listed in # the root CMakeLists.txt and doc/_pages/from_source.md. requires-python = ">=3.10" + +# Dependencies needed to build Drake. +# # WARNING for Drake Developers: This list must be kept in sync with # setup/mac/binary_distribution/requirements.txt. dependencies = [ @@ -20,12 +28,19 @@ dependencies = [ ] [dependency-groups] +# (Additional) dependencies needed to run Drake's tests. test = [ "flask", "six", "u-msgpack-python", "websockets", ] +# (Additional) dependencies needed to build a Drake wheel. +wheel = [ + "delocate", + "setuptools", + "wheel", +] [tool.pdm] distribution = false diff --git a/tools/wheel/image/provision-python.sh b/tools/wheel/image/provision-python.sh index 254f93a04991..84f397731c9b 100755 --- a/tools/wheel/image/provision-python.sh +++ b/tools/wheel/image/provision-python.sh @@ -47,8 +47,5 @@ pip install \ semantic-version \ setuptools \ wheel \ - auditwheel - -if [[ "$(uname)" == "Linux" ]]; then - pip install patchelf -fi + auditwheel \ + patchelf diff --git a/tools/wheel/macos/build-wheel.sh b/tools/wheel/macos/build-wheel.sh index 4661b1e5c044..a3e18436478e 100755 --- a/tools/wheel/macos/build-wheel.sh +++ b/tools/wheel/macos/build-wheel.sh @@ -82,38 +82,25 @@ ln -s "$(bazel info bazel-bin)" "$build_root"/bazel-bin find "$build_root" -type d -print0 | xargs -0 chmod u+w # ----------------------------------------------------------------------------- -# Set up a Python virtual environment. +# Obtain and activate Drake's Python virtual environment. # ----------------------------------------------------------------------------- -readonly pyvenv_root="/opt/drake-wheel-build/$python/python" +readonly drake_python="$(bazel info output_base).drake_python" +readonly venv_drake="$drake_python/venv.drake" -# NOTE: Xcode ships python3, make sure to use the one from brew. -"$python_executable" -m venv "$pyvenv_root" - -# We also need pythonX.Y-config, which isn't created as of writing (see also -# https://github.com/pypa/virtualenv/issues/169). Don't fail if it already -# exists, though, e.g. if the bug has been fixed. -ln -s "$python_prefix/bin/$python-config" \ - "$pyvenv_root/bin/$python-config" || true # Allowed to already exist. - -. "$pyvenv_root/bin/activate" +. "$venv_drake/bin/activate" # ----------------------------------------------------------------------------- -# Install tools to build the wheel. +# "Install" additional tools to build the wheel. # ----------------------------------------------------------------------------- -pip install --upgrade \ - delocate \ - setuptools \ - wheel - ln -s \ "$build_root/bazel-bin/external/drake+/tools/wheel/strip_rpath" \ - "$pyvenv_root/bin/strip_rpath" + "$venv_drake/bin/strip_rpath" ln -s \ "$build_root/bazel-bin/external/drake+/tools/wheel/change_lpath" \ - "$pyvenv_root/bin/change_lpath" + "$venv_drake/bin/change_lpath" # ----------------------------------------------------------------------------- # Build the Drake wheel. diff --git a/tools/wheel/wheel_builder/macos.py b/tools/wheel/wheel_builder/macos.py index 9a59e251d713..a0c843fbca8f 100644 --- a/tools/wheel/wheel_builder/macos.py +++ b/tools/wheel/wheel_builder/macos.py @@ -8,7 +8,7 @@ import shutil import subprocess -from .common import create_snopt_tgz, die, wheel_name +from .common import create_snopt_tgz, die, gripe, wheel_name from .common import build_root, resource_root, wheel_root, wheelhouse from .common import test_root, find_tests diff --git a/tools/workspace/python/repository.bzl b/tools/workspace/python/repository.bzl index 61d0520dd0eb..8d7d3121fd0c 100644 --- a/tools/workspace/python/repository.bzl +++ b/tools/workspace/python/repository.bzl @@ -41,6 +41,7 @@ load( "homebrew_prefix", "which", ) +load("//tools/workspace:os.bzl", "is_wheel_build") def _get_python_interpreter(repo_ctx): """Returns the tuple (python_interpreter_path, major_minor_version) based @@ -131,7 +132,9 @@ def _prepare_venv(repo_ctx, python): repo_ctx.watch(pdmlock) # Choose which dependencies to install. - if repo_ctx.attr.requirements_flavor == "test": + if is_wheel_build(repo_ctx): + repo_ctx.file("@pdm-install-args", content = "-G wheel") + elif repo_ctx.attr.requirements_flavor == "test": repo_ctx.file("@pdm-install-args", content = "-G test") else: repo_ctx.file("@pdm-install-args", content = "--prod")