#7556·Open3D

Bundled static curl and BoringSSL archive grouping is ineffective in Linux source link

Author: mstoelzleCreated Sep 9, 2026Updated Sep 9, 2026

Checklist

  • Clean upstream checkout at the exact reported revision.
  • Reached the shared-library link and preserved the failing import.
  • Captured the generated link order and compared only the concrete-archive LINK_GROUP:RESCAN correction.

Environment

Ubuntu 26.04.1 LTS, x86_64
Linux 7.0.0-31-generic
Python 3.12.13
CMake 4.2.3; Ninja 1.13.2; GCC 15.2.0
Open3D 1a9eb990f9a20936c30c428568c602bdef760744
Clean checkout status before configure: empty

Exact reproduction

bash
cmake -S . -B build-link -G Ninja \
  -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
  -DBUILD_GUI=ON -DBUILD_WEBRTC=OFF -DBUILD_CUDA_MODULE=OFF \
  -DUSE_SYSTEM_CURL=OFF -DUSE_SYSTEM_OPENSSL=OFF \
  -DPython3_EXECUTABLE=/path/to/python

set -o pipefail
cmake --build build-link --target pip-package --parallel 24 --verbose 2>&1 \
  | tee build-original.log
status=${PIPESTATUS[0]}
printf '\nExit status: %s\n' "$status" | tee -a build-original.log

Separately recorded prerequisites

The first generated graph was blocked by #7555's prebuilt-Filament variant (lib/*.a declared versus lib/x86_64/*.a imported and installed). I corrected the archive-directory declaration in both Filament external-project files before testing this link issue. GCC 15 also required the unrelated host workaround -DCMAKE_CXX_FLAGS=-include cstdint. Neither changes curl/BoringSSL order or semantics.

Original generated link order

The shared-library link completed, but CMake placed an empty group immediately after liblzf while the concrete bundled archives appeared later ungrouped:

... libOpen3D_3rdparty_liblzf.a -Wl,-\( -Wl,-\) ...
... boringssl/src/ext_boringssl/lib/libssl.a
    boringssl/src/ext_boringssl/lib/libcrypto.a
    curl/lib/libcurl.a ...

The full generated command is reproducible without relying on shell history:

bash
ninja -C build-link -t commands lib/Release/libOpen3D.so.0.19.0 | tail -n 1

Because this is a shared link, GNU ld permitted unresolved references. The resulting library was:

aaa45a944532fa3128df9eec8c3dd03e11793b2024f9311ec8889acce469477f  libOpen3D.so.0.19.0

nm -D --undefined-only showed strong bundled-curl TLS references including BIO_free, EVP_PKEY_free, SSL_CTX_new, and X509_INFO_free. Importing the generated package produced the target failure:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/tmp/open3d-audit-7556-build/lib/python_package/open3d/__init__.py", line 79, in <module>
    from open3d.pybind import (
ImportError: /tmp/open3d-audit-7556-build/lib/python_package/open3d/libOpen3D.so.0.19: undefined symbol: X509_INFO_free

Exit status: 1

libcrypto.a defines X509_INFO_free; the archive was simply scanned before the later libcurl.a introduced the reference.

Isolated concrete-archive control

The control grouped the concrete archive paths on the build interface:

cmake
set(_curl_openssl_archives
    "${CURL_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${CURL_LIBRARIES}${CMAKE_STATIC_LIBRARY_SUFFIX}")
foreach(_library IN LISTS BORINGSSL_LIBRARIES)
    list(APPEND _curl_openssl_archives
        "${BORINGSSL_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${_library}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endforeach()
set(_curl_iface_libs
    "$<BUILD_INTERFACE:$<LINK_GROUP:RESCAN,${_curl_openssl_archives}>>")
set_property(TARGET 3rdparty_curl PROPERTY INTERFACE_LINK_LIBRARIES
    "${_curl_iface_libs}")

The regenerated final command contains the actual archives inside one rescan group (order is curl, ssl, crypto):

... -Wl,--start-group
    curl/lib/libcurl.a
    boringssl/src/ext_boringssl/lib/libssl.a
    boringssl/src/ext_boringssl/lib/libcrypto.a
    -Wl,--end-group ...

The separate MKL archive group remains intact. pip-package completes with exit status 0. The control library and wheel are:

d75d25012b9c3592c624675eae9c0e9dc06302dfce1b6010a86bcaf217bc7e3c  libOpen3D.so.0.19.0
b79867388b29b9abc24ef1b7c5e854e4a159fd605e3ee8761965f7c8fe931d7d  open3d_cpu-0.19.0+1a9eb99-cp312-cp312-manylinux_2_43_x86_64.whl

The only remaining OPENSSL_* entries in nm -D --undefined-only are the three expected weak memory hooks. Import now succeeds:

0.19.0+1a9eb99
Exit status: 0

Result

Confirmed. Grouping INTERFACE targets produced an empty group and left the actual bundled curl/BoringSSL archives subject to one-pass ordering. Applying LINK_GROUP:RESCAN to the concrete archive paths emits a real group, removes the strong TLS undefined symbols, and makes the generated Python package importable.