Debugging, packaging, INSTALL() command and symlink
Hi,
I'm aware that this is really redundant discussion, but this post will tackle many different
We cannot ignore anymore that developers want to bundle there application with all .so/DLL files on their system. The current trend in the industry (and in the open-source world) is to pack binaries alongside the programs (see flatpack and appimage).
Of course, for open-source software better is to integrate to a distro and/or compile from source. But many users, especially "non-power" ones simply wants to download, and execute. It is also much easier for company to support their clients when the environement execution is controlled.
Today, it is really complicated and challenging to develop cross-platform programs. Developers want reproducible builds. Debugging app, and delivering to a customer is a tedious and error prone process that need to be automatized using CI pipelines and right tools. Is CMake can achieve this without using an extra layer of indirection like conan and others?
More and more packages are able to generate CMakeConfig files, and there are many FindXXX.cmake available that create IMPORTED_TARGET, that is a really good practice IMHO.
Debugging with one-click
Today many developers need to copy by hand (at least on Windows) their DLL/.so files for starting debugging.
-
Linux: RPath must be set properly. Current support in CMake is pretty good for that. For Qt app is needed to know where its plugins are. Setting qt.conf or QT_PLUGIN_PATH is mandatory for starting the app.
-
Windows: binary must be next to all its DLL, or DLL must be in the PATH folder. For VS projects, a hack consists in adding all PATHS to the DLL to the VS_DEBUGGER_COMMAND. As VS_DEBUGGER_COMMAND supports generator expression, it is possible to use stuff like $<TARGET_FILE_DIR:my_imported_target>. But it does not prevent the DLL-Hell if something is in system32, and only works with imported target OR target built in cmake. Interesting article about CMake and RPATH here
Install target
On Windows, runtimes must be next to the binary, the following trick can be used:
install(FILES $<TARGET_FILE:my_imported_target> DESTINATION bin)
This trick cannot be used on Linux, because if $<TARGET_FILE:my_imported_target> is pointing to an symlink, the symlink will be copied WITHOUT the original file. Because of the limitation of the install command we CANNOT create a symlink using generator expression today.
Indeed on linux cmake differentiate SO_NAME from the real .so against your program is linked (see IMPORTED_SONAME). So for example you will link against QtCore.so.5.13.1 but at runtime, your program will search for QtCore.so.5.13.
I tried the following:
install(FILES $<TARGET_FILE:my_imported_target> DESTINATION bin RENAME $<TARGET_SONAME_FILE:my_imported_target>)
But generator expression does not seems to be supported for RENAME field.
Despite of that, the file command support FOLLOW_SYMLINK_CHAIN. Adding this to install would greatly help us:
install(FILES $<TARGET_FILE:my_imported_target> DESTINATION bin FOLLOW_SYMLINK_CHAIN)
But more generically, adding CREATE_LINK to the INSTALL command is the best option IMHO. Just type "cmake install symlink" in google to see how many people are trying to achieve that. Some people would arg that we should use the bundle utilities provided in CMake, but they can silently choose bad .so files. The information of SO files are AVAILABLE in many places in CMake (like IMPORTED_LOCATION), why not using them for deploying? I don't want to hardcode link name in a custom install(CODE).
Related to #18822 and many others.