my_project |—> static linking perceptualdiff |—> (static linking with dynamic loading) FreeImage (built as a shared library)
I can correctly build perceptualdiff on its own. It will generate FreeImage.dll and FreeImage.lib in out/build/x64-Debug/_deps/freeimage-build.
And I can correctly build my_project as well. It will generate:
pdiff.lib in build/NinjaMultiConfig/test/_deps/perceptualdiff-build/Debug.
FreeImage.dll and FreeImage.lib in build/NinjaMultiConfig/test/_deps/freeimage-build/Debug.
However, when I try to run my project.exe, it won’t be able to find FreeImage.dll.
I understand I’m only adding pdiff.lib’s folder to my_project’s library path. How can I tell perceptualdiff’s CMake to “export” FreeImage.dll’s folder to whoever-links-against-pdiff’s library path?
Windows does not have an RPATH equivalent; the PATH environment variable just needs to be set up properly. Instead, you might consider copying the DLL as needed using file(GET_RUNTIME_DEPENDENCIES) or the $<TARGET_RUNTIME_DLLS> generator expression.
Many thanks! Using $<TARGET_RUNTIME_DLLS> worked like a charm. Now, what would be the solution if I wanted my project to compile in non-Windows systems as well?
In case anyone wants to know the exact details of what worked for me, I just added the following lines:
at the CMakeLists.txt where I was creating my_project binary, and
after all the add_executable, target_compile_features, target_link_libraries, and target_compile_options commands:
# Copy DLLs the target depends on
add_custom_command(
TARGET ${PROJECT_NAME}_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:${PROJECT_NAME}_test> $<TARGET_FILE_DIR:${PROJECT_NAME}_test>
COMMAND_EXPAND_LISTS
)
macOS and Linux (or any ELF platform) have different strategies. On macOS, the library ID dictates this (it’s complicated, but rpath only takes effect if @rpath/ is actually used). On Linux, “rpath” is the term to look for. Basically, libraries say “I need libA.so.4” and the rpaths are searched for a library with that name.
That is, for Linux, setting CMAKE_INSTALL_RPATH_USE_LINK_PATH to TRUE worked for the situation described in this post. As far as I understand the effects of enabling this variable, it appends to the runtime search path (rpath) of all the targets the directories containing the binaries of the libraries that are linked against. In this case, it appends to my_project’s rpath the folder where FreeImage.so lives.
I faced a problem when using CMAKE_INSTALL_RPATH_USE_LINK_PATH.
I was building a docker, including a binary, the_modern_c++_challenge_test, which made use of a shared library, libFreeImage.so. I was placing both in a directory in the docker. When I tried executing the binary, it would fail with an error saying it couldn’t find the shared library. ldd the_modern_c++_challenge_test would report libFreeImage.so was expected to be found at an absolute path in my machine, where I had built the project (something like /home/rturrado/projects/the_modern_c++_challenge/out/build.../_deps/free-image-build/Release/libFreeImage.so).
The “fix” I used was to directly add ./ to the runtime path via the linker properties. I am not completely sure this is a proper fix, but it works for this particular case, because it tells the OS to go and search for the shared library at the same directory where the binary lives (as I said in the previous answer, I haven’t tested this on MacOS).
Sorry about that. You explained it perfectly fine in your first answer but I didn’t read it correctly.
I had tried setting $ORIGIN before: LINK_FLAGS "-Wl,-rpath,$ORIGIN/"
The objdump was showing (notice the / and the blank before it): RPATH /:<absolute path to libFreeImage.so folder>
And it obviously didn’t work in systems where the absolute path wasn’t valid.
I’ve retried now, after doing some research on how to correctly set $ORIGIN (notice the single quotes around $ORIGIN): LINK_FLAGS "-Wl,-rpath,'$ORIGIN/'"
The objdump now shows: RPATH $ORIGIN/:<absolute path to libFreeImage.so folder>
And it works.