Skip to content

Move to Ubuntu 22.04, build shared libraries by default, simplified (smaller) python package.#7516

Open
ssheorey wants to merge 17 commits into
mainfrom
ss/dll
Open

Move to Ubuntu 22.04, build shared libraries by default, simplified (smaller) python package.#7516
ssheorey wants to merge 17 commits into
mainfrom
ss/dll

Conversation

@ssheorey

@ssheorey ssheorey commented Jul 6, 2026

Copy link
Copy Markdown
Member

Cherry-picks the shared-library-by-default and pybind-simplification work from copilot/separate-pybind-and-libopen3d without the host/device (libOpen3D vs libOpen3D_cuda/xpu) library split.

  • Update CI to Ubuntu 22.04. 20.04 is EOL.
  • BUILD_SHARED_LIBS now defaults to ON. Python package now uses a shared open3d library.
  • Single open3d.pybind module; CUDA/SYCL detected at runtime via core.cuda.is_available()/core.sycl.is_available() instead of shipping separate cpu/cuda package variants.
  • Device strings accept a bare type name (e.g. "cuda"), defaulting id to 0.
  • New utility::filesystem::GetSelfBinaryDirectory() helper; Logging.cpp print function is now a function-local static.
  • Renamed pybind/core/tensor_type_caster -> type_caster and added an implicit Device<->str caster.
  • Flattened ML custom-op output layout (no cpu/cuda subfolder) and fixed the torch/tf ops loaders to match.
  • Fixed a static-link ordering bug (curl/BoringSSL) exposed by building Open3D as a shared library, using CMake's LINK_GROUP:RESCAN genex.
  • Updated docs/compilation.rst to describe the dependency constraints while building Open3D.

Type

  • Bug fix (non-breaking change which fixes an issue): Fixes #
  • New feature (non-breaking change which adds functionality). Resolves #
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) Resolves #

Motivation and Context

Checklist:

  • I have run python util/check_style.py --apply to apply Open3D code style
    to my code.
  • This PR changes Open3D behavior or adds new functionality.
    • Both C++ (Doxygen) and Python (Sphinx / Google style) documentation is
      updated accordingly.
    • I have added or updated C++ and / or Python unit tests OR included test
      results
      (e.g. screenshots or numbers) here.
  • I will follow up and update the code if CI fails.
  • For fork PRs, I have selected Allow edits from maintainers.

Description

…ce strings

Cherry-picks the shared-library-by-default and pybind-simplification work
from copilot/separate-pybind-and-libopen3d without the host/device
(libOpen3D vs libOpen3D_cuda/xpu) library split.

- BUILD_SHARED_LIBS now defaults to ON.
- Single open3d.pybind module; CUDA/SYCL detected at runtime via
  core.cuda.is_available()/core.sycl.is_available() instead of shipping
  separate cpu/cuda package variants.
- Device strings accept a bare type name (e.g. "cuda"), defaulting id to 0.
- New utility::filesystem::GetSelfBinaryDirectory() helper; Logging.cpp
  print function is now a function-local static.
- Renamed pybind/core/tensor_type_caster -> type_caster and added an
  implicit Device<->str caster.
- Flattened ML custom-op output layout (no cpu/cuda subfolder) and fixed
  the torch/tf ops loaders to match.
- Fixed a static-link ordering bug (curl/BoringSSL) exposed by building
  Open3D as a shared library, using CMake's LINK_GROUP:RESCAN genex.
- Ported unrelated CI/Docker/WebRTC improvements from the source branch.
- Updated docs/compilation.rst to describe the single combined library.

Verified: BUILD_SHARED_LIBS=ON by default, cpp tests (Device, MemoryManager)
and python/test/core/test_core.py device tests pass, and python import/
smoke test shows no cpu/cuda subpackages.

Co-authored-by: Cursor <cursoragent@cursor.com>
@update-docs

update-docs Bot commented Jul 6, 2026

Copy link
Copy Markdown

Thanks for submitting this pull request! The maintainers of this repository would appreciate if you could update the CHANGELOG.md based on your changes.

ssheorey and others added 2 commits July 6, 2026 21:25
Several bugs slipped through when cherry-picking CI/Docker changes and the
simplified single-pybind-module python packaging from
copilot/separate-pybind-and-libopen3d:

- python/open3d/__init__.py: _insert_pybind_names() stripped the "open3d."
  prefix (not just "pybind."), so e.g. "open3d.pybind.t" was registered as
  bare "t" instead of "open3d.t", breaking `import open3d.t` and any
  `from open3d.t... import ...`. This failed pytest collection on the
  Ubuntu and OpenBLAS CI jobs.
- .github/workflows/windows.yml: BUILD_WEBRTC was hardcoded to 'OFF', but
  main enables it for the STATIC_RUNTIME=ON + BUILD_SHARED_LIBS=OFF matrix
  cells, since our own prebuilt BoringSSL is built with the dynamic CRT and
  is only ABI-compatible when WebRTC (built with matching static CRT)
  supplies crypto/ssl symbols instead. Restored the conditional; this fixes
  LNK2001 "unresolved external symbol __imp_bsearch" failures in the three
  static-runtime build-lib jobs.
- .github/workflows/ubuntu-cuda.yml: GCE image family was bumped to
  "ubuntu-os-docker-gpu-2204-lts", which does not exist in the GCP project
  ("was not found" at instance-create time). Reverted to main's working
  "ubuntu-os-docker-gpu-2004-lts" (the GCE host image is independent of the
  Ubuntu version used inside the CI Docker container).
- .github/workflows/ubuntu-wheel.yml: the new split-out "build-lib" job
  calls docker_build.sh, which requires BUILD_TENSORFLOW_OPS/
  BUILD_PYTORCH_OPS to be set (bash `set -u`); these were set on the
  build-wheel job but missing on build-lib, causing "unbound variable".

Not fixed (pre-existing/flaky, reproduced identically on unrelated
branches, unrelated to this port): macOS gfortran symlink lookup failing
on macos-14 runners, and transient pyenv-installer network fetch failures
on ARM64/py313+ wheel builds.

Verified: reproduced the "open3d.t" ModuleNotFoundError from the CI logs
using a local minimal CPU-only build (BUILD_PYTHON_MODULE=ON, no GUI/tests/
ISPC/WebRTC) and confirmed `import open3d.t`, `from open3d.t.geometry
import Image`, and pytest collection of python/test/t/geometry/test_image.py
all work after the fix; python/test/core/test_core.py (279 tests) still
passes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ssheorey ssheorey added this to the v0.20 milestone Jul 7, 2026
@ssheorey ssheorey added the status / to merge Looks good, merge after minor updates. label Jul 7, 2026
ssheorey and others added 14 commits July 7, 2026 10:22
… artifacts

The new split "build-lib" + "build-wheel"/"build-wheel-per-python" CI job
architecture (ported from copilot/separate-pybind-and-libopen3d) reuses a
previously-built lib image/artifact as the starting point for wheel jobs
(Docker BASE_IMAGE, or an extracted build.tar.xz/zip). Two steps in the
common build scripts were not idempotent against that reuse:

- docker/Dockerfile.{ci,wheel,openblas}: pyenv-installer refuses to run if
  $PYENV_ROOT already exists, which is the case when BASE_IMAGE is a
  previously-built lib image (SYCL/CUDA/ARM64 wheel jobs) that already
  bootstrapped pyenv for its own (dummy) Python version. Only run the
  installer bootstrap if pyenv isn't already present; always pass
  `pyenv install -s` (skip-if-installed) and `ln -sf` so a second Python
  version can still be added on top of an existing pyenv installation.
- util/ci_utils.sh build_pip_package(): skipped `cmake` configure entirely
  if CMakeCache.txt already existed, to support being invoked more than
  once. In practice it is only ever called once per job, and inheriting a
  build dir from a build-lib step (BUILD_PYTHON_MODULE=OFF) meant the
  Makefile never got a pip-package target, failing with
  "No rule to make target 'pip-package'" (macOS wheel job). Always run
  cmake with the current BUILD_PYTHON_MODULE value instead.
- util/ci_utils.sh build_pip_package(): the extra "open3d-cpu" companion
  wheel was built when BUILD_CUDA_MODULE==OFF instead of ==ON. A CPU-only
  build already *is* the CPU wheel; the companion wheel should only be
  built in addition to a CUDA-enabled build (matching main's original
  behavior). The inverted condition caused every CPU-only build (e.g. all
  macOS wheel jobs) to redundantly rebuild the whole project a second time
  for no reason.

Co-authored-by: Cursor <cursoragent@cursor.com>
… artifacts

The split "build-lib" + "build-wheel" jobs (ARM64, macOS, SYCL, CUDA wheel)
reuse a previously-configured build directory/image whose CMakeCache.txt was
generated for a different Python interpreter (e.g. build-lib's own "dummy"
Python version) and/or BUILD_PYTHON_MODULE=OFF. Simply re-invoking cmake
with new -D flags is not enough: find_package(Python3)/find_package(Torch)
still resolve to the stale cached Python3_EXECUTABLE, so the wheel-build's
freshly pip-installed torch for the *new* Python version is invisible
("ModuleNotFoundError: No module named 'torch'" from FindPytorch.cmake).

Use `cmake --fresh` (already used by windows.yml) everywhere a build
directory may be inherited from a build-lib artifact, so CMakeCache.txt is
discarded and all interpreter/library paths are rediscovered from scratch.
ccache (already configured in these jobs) keeps the ensuing rebuild fast
since object code for unchanged sources is still reused.

- util/ci_utils.sh build_pip_package(): `cmake --fresh` for the main build
  directory (used by macOS/ARM64/CUDA wheel jobs).
- docker/Dockerfile.openblas: `mkdir -p build` (was `mkdir build`, which
  failed outright when build/ already existed) and `cmake --fresh`.
- docker/Dockerfile.ci (SYCL/CUDA "Build all" step): `cmake --fresh`.

Co-authored-by: Cursor <cursoragent@cursor.com>
build-wheel-arm64 (Ubuntu OpenBLAS workflow) calls actions/attest@v4 to sign
the built wheel, which requires "id-token: write" and "attestations: write"
permissions. Every other build-wheel job (macOS, Ubuntu Wheel, Ubuntu SYCL,
Windows) already grants these; this one only had "contents: read", causing
it to fail with "missing id-token permission" after a successful build.

Co-authored-by: Cursor <cursoragent@cursor.com>
…TC=ON)

The Windows wheel build (shared libs) explicitly sets BUILD_WEBRTC=OFF
because no WebRTC DLL is available for Windows shared-lib builds yet, but
still requested BUILD_JUPYTER_EXTENSION=ON. CMakeLists.txt enforces
BUILD_JUPYTER_EXTENSION=ON requires BUILD_WEBRTC=ON, so configure failed.
main built this wheel as a static lib (BUILD_WEBRTC=ON is possible there);
our shared-lib-by-default wheel can't enable WebRTC yet, so disable the
Jupyter extension for it until WebRTC gains Windows shared-lib support.

Co-authored-by: Cursor <cursoragent@cursor.com>
Same class of bug as the pyenv/build-dir issues: when BASE_IMAGE is a
previously-built lib image (build-lib mode / CI's split lib+wheel jobs),
/root/Open3D-ML was already cloned there, so cloning again into the same
non-empty directory fails with "destination path already exists". Skip the
clone if the repo is already present.

Co-authored-by: Cursor <cursoragent@cursor.com>
Same class of bug as the other reused-build-lib-artifact issues: BASE_IMAGE
may already have /etc/apt/keyrings/nodesource.gpg from build-lib's own run
of this step. Without --yes, gpg --dearmor tries to interactively prompt
whether to overwrite the existing file, which fails with "cannot open
'/dev/tty'" in a non-interactive Docker build step.

Co-authored-by: Cursor <cursoragent@cursor.com>
- visualization/CMakeLists.txt: add_dependencies(visualization_impl
  ext_vkmemalloc ext_vmahpp) so the Vulkan gaussian-splat sources always
  build after the vk_mem_alloc headers are available. OBJECT library
  target_link_libraries doesn't reliably enforce build order for
  ExternalProject targets on the VS generator, which caused
  vk_mem_alloc.hpp not found when building the narrower "pip-package"
  target (Windows wheel build).
- util/ci_utils.sh build_pip_package(): replace `cmake --fresh` with a
  normal reconfigure that force-overrides Python3_EXECUTABLE (and unsets
  stale Python3/Torch cache vars) to fix the stale interpreter left over
  from a previous BUILD_PYTHON_MODULE=OFF "build-lib" stage. `--fresh`
  wipes CMakeFiles/ which, on Docker union-filesystem layers stacked on
  an already-built base image, doesn't reclaim space and was exhausting
  runner disk (Ubuntu CUDA wheel job).

Co-authored-by: Cursor <cursoragent@cursor.com>
…regex

- util/ci_utils.sh build_pip_package(): the companion open3d-cpu wheel's
  cmake call put -DBUILD_CUDA_MODULE=OFF before "${cmakeOptions[@]}",
  which already contains -DBUILD_CUDA_MODULE=ON from the main CUDA build
  above. CMake resolves repeated -D flags left-to-right with the last one
  winning, so the "CPU-only" wheel was actually being built with CUDA
  enabled. Reorder so the OFF override comes last. Verified locally that
  cmake's last-flag-wins behavior reproduces/fixes this with a minimal
  project.
- docker/docker_build.sh sycl-shared_export_env(): the python-version
  regex expected undotted "py310" but the SYCL wheel workflow passes
  dotted "py3.10" (py${{ matrix.python_version }}), so the branch setting
  PYTHON_VERSION/BUILD_PYTHON_MODULE was dead code (masked by the
  PYTHON_VERSION:-3.12 fallback picking up the workflow's own env var).
  Fix the regex to match the dotted form.

Co-authored-by: Cursor <cursoragent@cursor.com>
`docker/Dockerfile.wheel` had `rm -rf build_cpu build_cuda` but `build_cuda`
doesn't exist under the new design (the main build directory is just `build`),
and more importantly, the quotes in the condition `if [ ${CI:-}a != a ]`
were unquoted, which shellcheck/bash could evaluate incorrectly. Cleaned up
and formatted the cleanup block.

Co-authored-by: Cursor <cursoragent@cursor.com>
When compiling Open3D, CMake produced several "dev" warnings:
  The feature 'RESCAN', specified as part of a generator-expression
  '$<LINK_GROUP:RESCAN>', will not be applied to the INTERFACE library
  '3rdparty_curl'.

This is because CMake's modern `<LINK_GROUP:feature, ...>` is only
officially supported on targets with a linkable binary file (such as
static or shared library targets, or imported targets with
IMPORTED_LOCATION), and explicit warnings are emitted when applied to
logical INTERFACE targets.

Replace the generator expression with explicit linker flags
`-Wl,--start-group` and `-Wl,--end-group` for UNIX (non-Apple) systems.
This resolves the developer warnings while achieving the identical linking
behavior to resolve mutual dependencies between curl and openssl static
archives during library linkage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reusing a stripped Docker build tree caused overlay ENOSPC and forced
3rdparty recompiles in wheel jobs. Package CPU/CUDA devel (+ viewer) once,
run C++ tests in parallel with per-Python wheels on stock nvidia/cuda, and
compile Torch/TF ops only in the wheel stage where their ABI belongs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status / to merge Looks good, merge after minor updates.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant