AcademySoftwareFoundation / OpenTimelineIO

Open Source API and interchange format for editorial timeline information.
http://opentimeline.io
Apache License 2.0
1.48k stars 294 forks source link

Python `_otio` extension module incorrectly links against external `Imath` library #1662

Open nrusch opened 1 year ago

nrusch commented 1 year ago

I'm building OTIO against an external Imath distribution (i.e. OTIO_FIND_IMATH=ON), and it looks like the _otio Python extension module is being linked directly against the Imath lib, leading to the following runtime error:

> python -c 'import opentimelineio'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/luma/dev/ruschn/rez-release/opentimelineio/0.0.cxx17/platform-linux/gcc-9.3.1/python-3.9/python/opentimelineio/__init__.py", line 14, in <module>
    from . import (
  File "/luma/dev/ruschn/rez-release/opentimelineio/0.0.cxx17/platform-linux/gcc-9.3.1/python-3.9/python/opentimelineio/opentime.py", line 4, in <module>
    from . _opentime import ( # noqa
ImportError: libImath-3_1.so.29: cannot open shared object file: No such file or directory

Here is the patchelf output for the _otio library:

>>> patchelf --print-needed /luma/dev/ruschn/rez-release/opentimelineio/0.0.cxx17/platform-linux/gcc-9.3.1/python-3.9/python/opentimelineio/_otio.cpython-39-x86_64-linux-gnu.so 
libopentimelineio.so
libopentime.so
libImath-3_1.so.29
libstdc++.so.6
libm.so.6
libgcc_s.so.1
libc.so.6

If I manually remove the direct dependency on libImath-3_1.so.29, the error is resolved:

> patchelf --remove-needed libImath-3_1.so.29 /luma/dev/ruschn/rez-release/opentimelineio/0.0.cxx17/platform-linux/gcc-9.3.1/python-3.9/python/opentimelineio/_otio.cpython-39-x86_64-linux-gnu.so  

Looking at the CMake build configuration, I'm fairly certain this is because Imath is included in the public link interface for the opentimelineio target (https://github.com/AcademySoftwareFoundation/OpenTimelineIO/blob/main/src/opentimelineio/CMakeLists.txt#L88-L89), and thus becomes a transitive dependency when the opentimelineio-bindings target is linked against it.

To Reproduce

Versions

CMake Arguments

cmake \
        -D CMAKE_INSTALL_PREFIX=/path/to/install_prefix \
        -D CMAKE_EXE_LINKER_FLAGS=-Wl,--enable-new-dtags \
        -D CMAKE_SHARED_LINKER_FLAGS=-Wl,--enable-new-dtags \
        -D CMAKE_CXX_STANDARD=17 \
        -D CMAKE_CXX_EXTENSIONS=OFF \
        -D CMAKE_CXX_FLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" \
        -D OTIO_PYTHON_INSTALL=ON \
        -D OTIO_DEPENDENCIES_INSTALL=OFF \
        -D OTIO_FIND_IMATH=ON \
        /path/to/source_dir

Imath is being located via the CMAKE_PREFIX_PATH environment variable, which includes the directory containing the Imath/ImathConfig.cmake file.

Additional Note: It looks like the opentime Python extension module may (unnecessarily?) link against libopentimelineio. This may warrant a separate issue.

meshula commented 1 year ago

You are right, opentime should't link against opentimelineio. I haven't seen that reported before, I wonder what's up.

The transitive dependence should be specifically that the include path to Imath is public ~ does cmake have a way to do that?

If you have answers to these feel free to create a PR.

nrusch commented 1 year ago

You are right, opentime should't link against opentimelineio. I haven't seen that reported before, I wonder what's up.

Yeah, this one is a bit of a mystery, and may be due to the revision I'm building from. I'll keep poking around and open a separate issue if I can prove it. :)

The transitive dependence should be specifically that the include path to Imath is public ~ does cmake have a way to do that?

In an Imath 3.x-only world, you could use Imath::ImathConfig instead of Imath::Imath as the public link target, and then Imath::Imath as a private target, though the redundancy is unfortunate.

Supporting both IlmBase and Imath 3.x will take a bit more footwork. I would point to OpenImageIO as a good example of how to support them in tandem and distill things down to a common set of CMake variables: https://github.com/OpenImageIO/oiio/blob/master/src/cmake/modules/FindOpenEXR.cmake

Currently, the ${IMATH_INCLUDES} variable is not set when using Imath 3.x, otherwise I think you could do something like this:


target_include_directories(opentimelineio
    PUBLIC       "${IMATH_INCLUDES}"
    PRIVATE       "${PROJECT_SOURCE_DIR}/src"
                  "${PROJECT_SOURCE_DIR}/src/deps"
                  "${PROJECT_SOURCE_DIR}/src/deps/optional-lite/include"
                  "${PROJECT_SOURCE_DIR}/src/deps/rapidjson/include")

target_link_libraries(opentimelineio 
    PUBLIC opentime
    PRIVATE ${OTIO_IMATH_TARGETS})