Bypass block on installing IMPORTED libraries

[Unfortunately ] cmake doesn’t allow installation of IMPORTED libraries probably in assumption that if a project built and formed installation package, this package needs only newly built libraries and consumer of this package will directly import any dependencies. However this approach forces the package consumer to know all details of external dependencies of the package they want to consume. So if more consumer-friendlier approach is adopted, the installation package should contain all the dependencies-internal and external. It would create exported target list file (e.g. myprojectTargets.cmake with install(TARETS…, install(EXPORT …) ) which would have all instructions for the consuming project to add external libraries as IMPORTED with add_library(…IMPORTED…) statements so the consumer project 's CMakeLists.txt could use find_package() which would import all targets from the installation package.
One way to make such package is (for each external library dependency) to create internal INTERFACE target for each IMPORTED target, link them and then install internal INTERFACE target (see example below).

  1. What is the recommended approach for creation of fully contain packages ?
  2. Is there a way to add external dependency library as INTERFACE library and then specify location of library (.so|.a|.dll|dll.a) file(s) (maybe via set_target_property() or target_link_libraries,.etc)?
  3. Why is the type combination “INTERFACE IMPORTED” in the add_library () command still does not allow installation of library?
  4. Is special/separate set of properies required for building and installing Windows .dll|dll.a like for IMPORTED library, instead of IMPORTED_LOCATION we have to use IMPORTED_IMPLIB?

find_package(myimported )
add_library(myimported INTERFACE ) #or INTERFACE IMPORTED?
add_library(myinterface INTERFACE)
target_link_libraries(myinterface INTERFACE myimported)
install(TARGETS myinterface EXPORT myinterface_targets_name …)


What you should do instead is add a find_package call for your dependencies in your mypkg-config.cmake file. They’re finding you. You find your dependencies for them on their behalf. There’s the CMakeFindDependencyMacro for you to use that eases some of the pain.

You won’t need to faff about with interfaces to imported targets or anything like that. Note that you really shouldn’t try to install your IMPORTED targets because then if someone uses that external one, you’re going to conflict with it when you bring in your copy of your dependencies.

A) How is adding find_package() to (resulting on generation of for consuming project) better than built-in cmake own facility to generate add_library(…IMPORTED…) it writes into mypkgTargets.cmake? It seems much more work since then I need to supply Findmypkg.cmake as well.
B) Neither mechanism a)find_package() in mypkgConfig.cmake or b) cmake own generated add_library(…IMPORTED…) in mypkgConfig.cmake addresses the issue of installing IMPORTED libraries. There is no issue with “if someone uses that external one”. cmake detects conflict well and generates message that it can’t find proper lib for link files because of conflicting locations for the same library. Besides there are other easy checks that could be put into consuming projects interacting with mypkgConfig.cmake code to ensure proper version of library is used where it is needed. So could you please look at the issue assuming there is a requirement to isolate consuming projects from consumed project dependencies so all they need to do to import it, just have find_package() in their CMakeLists.txt, and consumed project export file have to have all IMPORTED libs dependencies in the package and added as target automatically.

Installing IMPORTED targets is a problem because you also have to install what they point to or fix up their install interfaces for a disjoint prefix. Let’s say your install prefix is /prefix/myproj and you’re using a dependency installed with a prefix of /prefix/dep1. You’re going to install targets referring to /prefix/dep1 and CMake is going to have to either assume that the relative structure between your two prefixes is stable or embed the absolute path to /prefix/dep1. The install interface paths are all generated relative to the projects own install prefix, so CMake will have to dig in again to compute a new prefix for all of these things. Now if dep1 has its own IMPORTED targets, this needs to be done recursively (and you’ll need to install them too).

This is a problem for which there is no easy solution from the CMake side because the problem space is just too large. The best way is to just find the dependency again when you’re being found. You can provide all kinds of help via variables such as dep1_ROOT or dep1_DIR if you like as well.

yes, since it is required to make self-contained package so consuming project does not need to be aware of its dependencies, the package created by myprojhas to include all libraries IMPORTED by the project. However there is no problem with duplicity in the installation prefix. So there is no need to make any assumptions because I specify installation directory arguments such that results in ${CMAKE_INSTALL_PREFIX} equal to single myproject/install dir. Each sub-project or being built creates directory set to its ${PROJECT_NAME}/include, ${PROJECT_NAME}/lib under this directory as per relative path setting in INSTALL_INTERFACE, INCLUDES DESTINATION, PUBLIC_HEADER DESTINATION, etc variables. The same install destination is maintained for IMPORTED or INTERFACE libraries. So they all are under one dir tree.
Again, I am using approach with creating INTERFACE wrapper for each IMPORTED target and there is issue that you mentioned. cmake writes myprojectTargets.cmake such that for each INTERFACE wrapper there is add_library(…INTERFACE IMPORTED)… This is still better than asking my consumers to track all few dozens of dependencies themselves. Again the goal is for consumer to focus only on their project and receive all myproj dependency via find_package().
I am thinking of another alternative - to add add_library(…INTERFACE IMPORTED) for each IMPORTED lib into myprojectTargets.cmake 9similar to your suggestion to use find_package() there). This again much more efforts comparing to disabling cmake block on install(TARGETS myimported …) for IMPORTED libraries. BTW cmake error message is wrong for this case. The error message is like installing target which does not exists, while simple check if (TARGET myimported) shows it does exists.
Finally my question still remains and it is about another approach - using INTERFACE instead of IMPORTED in add_library() command to “import” library. Then the target library could be installed. However how could the library file LOCATION property be set ? There is no issue for include directory since it is done via target_include_directories() command (sets INTERFACE_INCLUDE_DIRECTORIES) but there is no “target_lib_directories” command and LOCATION property is not set by target_link_libraries , I think…?