Skip to content

[conan-center] Add a hook to check whether installed shared libs are relocatable on Linux & macOS #376

@SpaceIm

Description

@SpaceIm

Currently, many recipes don't produce state of the art relocatable shared libs on macOS.

It would be nice to check whether shared libs on macOS properly have @rpath/<shared> in install tree (@rpath token is supported since macOS 10.5 Leopard, so since 2007...).
It must not be <shared> or <absolute/path/to/shared> (many binaries produced by conan-center recipes on macOS have the former actually, it's bad).
see https://cmake.org/cmake/help/latest/prop_tgt/MACOSX_RPATH.html#prop_tgt:MACOSX_RPATH

Moreover, rpath should be empty in installed shared libs.
Usually, in a default CMake configuration, binaries produced in build tree have absolute paths of dependencies (direct & transitive) libs folder in their rpath, so that you can run your executable for free (on macOS, it only works if external shared libs also have @rpath token, so proper relocatable binaries), then it is cleared by CMake during installation.

It also means that all CMake based recipe must:

  • use conan_basic_setup(KEEP_RPATHS)

  • recipe should ensure that https://cmake.org/cmake/help/latest/policy/CMP0042.html#policy:CMP0042 is enabled (either by injection CMAKE_POLICY_DEFAULT_CMP0042 NEW, or ensuring cmake_minimum_required(VERSION 3.0) or higher in upstream CMakeLists).

  • recipe should call install target, not manually copying files (it can be allowed if target os is Windows), so that CMake can:

    • eventually replace absolute path set in shared libs of the build tree with @rpath for shared libs in install tree (usually it's already @rpath in the build tree, but not always).
    • clear rpath (and it's also important on Linux). To do so, CMAKE_INSTALL_RPATH & CMAKE_INSTALL_RPATH_USE_LINK_PATH should not be manipulated.

    If manual copy can't be avoided, something like this at the end of package() may allow to add @rpath token into dylib files :

     if tools.is_apple_os(self.settings.os):
         with tools.chdir(os.path.join(self.package_folder, "lib")):
             for dylib in glob.glob("*.dylib"):
                 command = "install_name_tool -id {0} @rpath/{1}".format(os.path.basename(dylib), dylib)
                 self.run(command)

I suspect that many issues consumers have with "all shared" builds (-o *:shared=True) on macOS would be solved. Default behavior of conan_basic_setup on macOS is really harmful.

see conan-io/conan-center-index#9052
also conan-io/conan#1238 or conan-io/conan#10253
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html
https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling#mac-os-x-and-the-rpath
https://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions