How can I suppress CMake's warning about RPATH or tell it to ignore implicit directories?

I’ve recently converted a large mature project from qmake to CMake. On Ubuntu 20.04, CMake 3.21.0

After configuration is complete (so during generation I assume) CMake reports the following error for several of the shared objects and exes we build:

CMake Warning at SurgeryCase/CMakeLists.txt:7 (add_library):
  Cannot generate a safe runtime search path for target SurgeryCase because
  files in some directories may conflict with libraries in implicit
  directories:

    runtime library [libpng16.so.16] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
      /home/steve/Projects/NaviGo/build/ExtLibraries/libpng/Installed/Release/lib
    runtime library [libz.so.1] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
      /home/steve/Projects/NaviGo/build/ExtLibraries/zlib/Installed/Release/lib

  Some of these libraries may not be found correctly.

This is for an embedded system and we already have a mature install process that correctly gathers all the needed libraries from the build tree. So warning about a potential conflict with libraries in ld’s default/implicit locations on the developer’s workstation is not relevant for us. We keep all libraries our build tree to ensure version consistency across developers, and prevent problems caused by installations/upgrades to the workstation.

How can I either suppress this warning or tell CMake not to consider the default locations when checking for this potential problem.

I’ve discovered that I can eliminate the warning by setting CMAKE_SKIP_BUILD_RPATH to true, but that’s not workable because we rely on the build rpath values to run inside the IDE for development.

I’ve tried setting CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES to “” with no effect.

I’ve tried setting LD_LIBRARY_PATH to the build tree folder containing the desired version of the library in the environment before starting CMAKE (on the assumption that CMake is invoking ldd to discover where libraries will be found at load time) - with no effect.

This happens because your targets are consuming libraries from both the system (/usr) and your staging area (…/Installed/Release/lib). CMake is saying that there is no rpath it can generate that will guarantee that the libraries which live in both can be sorted properly to ensure the libraries passed on the link line will be used at runtime. I would suggest ensuring that all libraries are in the ExtLibraries and nothing comes from the system. Some of the cross-compilation toggles may come in handy here (namely the CMAKE_FIND_USE_* family of variables).

But it is using a host toolchain? Is there cross-compilation involved at all?

If the CMAKE_FIND_* toggles aren’t sufficient, I think the easiest thing to do would be to somehow convince the linker to ignore its default directories and only use those specified explicitly (or make it think it’s in an alternate sysroot with only the bits you need).

Thanks for the reply.

First to the question, yes it’s all host toolchain. Our embedded system uses a standard x86 motherboard so we use build servers built with that motherboard to guarantee identical architecture and don’t need to cross-compile.

I have changed all the RPATH values in our compiled code point at our ExtLibraries locations. None of those files refer to the “wrong” version (implicit location) of libpng or libz any longer - as reported by lddtree. However, we link to Qt5 libraries which do link to libz in the /usr/lib… folder. The RUNPATH value of those libraries is $ORIGIN. I’m not sure it’s reasonable to try to change that. Also, libpng is still reported in the warning, but I can find no reference to it in the wrong location any longer.

My understanding of the process boils down to this

  1. .so (ELF) files do not have a path associated with libraries that are listed as NEEDED.
  2. RPATH/RUNPATH is the only thing in the ELF file with any paths.
  3. ld has a search order which includes RPATH and RUNPATH among other things.

So which copy of a library file gets links is not strictly a function of what is in the exe/so file, but of ld’s search. Which is why I would like to understand how CMake performs this check (so maybe I can fake it out). I would have thought it would invoke ldd, but my attempt to affect it with LD_LIBRARY_PATH did not work.

It seems like being able to just suppress the warning would be much simpler.

The issue is that you’re linking to libraries which coexist in each other’s directories. Here’s the basic setup:

/prefix/a/lib/
  - liba.so
  - libb.so
/prefix/b/lib/
  - liba.so
  - libb.so

You’ve asked CMake to link to /prefix/a/lib/liba.so and /prefix/b/lib/libb.so. The warning is saying that there is no rpath that will guarantee that this works at runtime because one of /prefix/a/lib and /prefix/b/lib needs to be first in the rpath entry. Whichever wins will provide both liba.so and libb.so.

In your case, you have libpng16.so and libz.so in two places where you’ve asked CMake to link to libraries. To fix the warning, you need to either make a single prefix and have everything found in that one place or remove the conflicting libraries in one of the prefixes. Given the setup, I would recommend making another prefix which contains exactly what you need from /usr/lib and use that prefix instead of re-using the host copies.