macOS: linking application with ParaView libraries and NOT depending on DYLD_LIBRARY_PATH

Hi,

on macOS ParaView libs are not yet build with @rpath but with @executable_path as install path. How is one to link these libraries in an application without having to depend on DYLD_LIBRARY_PATH. Depending on DYLD_LIBRARY_PATH is problematic in case the application is executed via a system() call on macOS which clears DYLD_LIBRARY_PATH before executing the program (for security reasons). If all ParaView libs would have @rpath in their install path an application could link the libs specifying the -rpath and DYLD_LIBRARY_PATH would not be needed anymore at run-time. The support for an @rpath install path is properly supported in cmake. Why is this not used? Has anybody tried this? Or is there another way to no depend on DYLD_LIBRARY_PATH?

Thanks, Fons.

Is this in the main package shipped or a custom build of ParaView?

It is a custom build. I realized it was build with
-DPARAVIEW_DO_UNIX_STYLE_INSTALLS:BOOL=ON
could that be the cause, because I’ve seen many ninja files using install_name_tool to change the install path from @rpath to a full absolute path.

Note that the build tree is going to use absolute paths much of the time. Does the install tree use @rpath? Note that the CMake settings to use @rpath might be necessary. I remember doing some of this work, but I don’t remember what the end result was (@rpath and CMake is a complete mess for actual use due to usage requirements for it not being present in CMake :confused: ).

I work on a simulation framework and with the following settings is the main CMakeList.txt file, I got the build I want, relocatable using @rpath for macOS and $ORIGIN on Linux and optionally with absolute path names for a fixed install. This are the cmake settings that work, for me:

#  When building, don't use the install RPATH already (but later on when installing)
set(CMAKE_SKIP_BUILD_RPATH FALSE)         # don't skip the full RPATH for the build tree
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) # use always the build RPATH for the build tree
set(CMAKE_MACOSX_RPATH TRUE)              # use RPATH for MacOSX
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # point to directories outside the build tree to the install RPATH

# Check whether to add RPATH to the installation (the build tree always has the RPATH enabled)
if(rpath)
  set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_FULL_LIBDIR}) # install LIBDIR
  set(CMAKE_SKIP_INSTALL_RPATH FALSE)          # don't skip the full RPATH for the install tree
elseif(APPLE)
  set(CMAKE_INSTALL_NAME_DIR "@rpath")
  set(CMAKE_INSTALL_RPATH "@loader_path/../lib")  # self relative LIBDIR
  set(CMAKE_SKIP_INSTALL_RPATH FALSE)          # don't skip the full RPATH for the install tree
else()
  set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE)       # skip the full RPATH for the install tree
  set(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib")   # self relative LIBDIR
  set(CMAKE_SKIP_INSTALL_RPATH FALSE)          # don't skip the full RPATH for the install tree
endif()

with -Drpath=ON to get explicitly the fixed absolute path install (not default).

Using the super build, will these cmake setting propagate down the chain?

Note that your CMAKE_INSTALL_FULL_LIBDIR setting likely makes the install tree non-relocatable as (I’m guessing) the absolute path of the install prefix is embedded into the binaries. We do not want this for ParaView’s packages.

As for the superbuild, it doesn’t forward these along because not everything uses CMake. Instead, we basically try to get everything to use absolute paths and then fix everything up during the packaging process (for which @executable_path and @loader_path is perfectly usable).

Yes the option using CMAKE_INSTALL_FULL_LIBDIR makes the tree non-relocatable, this is only for a fixed install in, say, /opt/local or /usr/local.

Yes, I studied the fixed up script and saw you go from @rpath to fixed path and then in the fixup script you go to @executable_path and @loader_path. The problem is how do I use use these libs then without DYLD_LIBRARY_PATH because my executable, or plugin, never will live in the ParaView build tree. If you would patch all libraries to have @rpath all executables can be made to work by defining the right -rpath,<to-paraviev-libs> linker options. With that in mind the cmake options I specified above work fine and all macOS libs have @rpath install names.

macOS apps are meant to be self-contained, so that’s what we do. We could make frameworks, but that needs work into investigating how we should do that at the VTK/ParaView level (I suspect a framework per “kit” rather than library, but I don’t know). If you want your own executable on macOS, I suggest one of:

  • making your own ParaView installation tree using the superbuild (you can set superbuild_install_location to make the superbuild install everything to that place rather than $builddir/install)
    • this is not normal ParaView usage and as such not documented there, but CMB does have use cases for it
    • it will be highly non-relocatable, but it seems that might be sufficient for you?
  • make a full package for your executable based on paraview.bundle.cmake
  • if you make your own plugin, @executable_path is what you want anyways because any executable loading a ParaView plugin should be bringing its own ParaView libraries as well. You then use @loader_path for any libraries specific to your plugin.

See this very clear overview @rpath vs the rest of the different macOS install path name choices. As you can see @execuable_path and @loader_path are relics that are superseded by the much more flexible @rpath. With an @rpath install name, libs can be used by many more applications than the one in the self-contained app bundle. Have a look in any of the app bundles on a mac and you will see that all libraries now use @rpath. Anyway, I think this could be simply achieved by modifying the python fixup script to change everything to an @rpath. I’ll see what I can do.

Note that not all libraries have room to add a new entry to the rpath which is, IIRC, the problem we ran into before when trying that. Other than that, we really need CMake to use usage requirements to fill in rpath entries. Without that, things end up not working because with @rpath, one needs an rpath entry to load the library.

Note that we are using $ORIGIN on Linux, but that’s because directory search and library names are disjoint there; macOS made the decision to only apply RPATH entries to explicit usages of @rpath/ and for @rpath/ to be used to actually make any RPATH entry useful.

As I said for two of our projects, ROOT (3MLOC+150libs) and BioDynaMo, we use the cmake options as I described below and these are sufficient to built both projects correctly with @rpath based libs and without any need to fix paths a-posteriori. But I am aware that PV and it’s superbuild is a quite complex build environment and things might not be that straight forward.

The typical problem is along the lines of “make boost use sensible rpath entries” or “make ffmpeg use rpaths” and then compounded by the fact that CMake doesn’t add the required rpath entries for us (which is admittedly a very complex question with different answers for the build tree, install tree, per-project install tree, and macOS bundle layouts). Doing this has worked for us so far, so I’ve been hesitant to touch it now :slight_smile: . That said, VTK/ParaView should not be forcing rpath settings anywhere, so doing such things from the -D line should work. The superbuild is a bit more opinionated and inflexible about this stuff though since it is juggling a bunch of different build systems.