Once CMake has successfully built an executable which requires some shared libraries, by using 'ldd', we can easily get the list of shared library dependencies and where we can find them.
For instance, libstdc++ is here: /usr/lib64/libstdc++.so.6
Now we want to make a package (e.g. a .tgz package), we need to include those shared libraries with no doubt.
We can do:
set(DEPENDENCIES /usr/lib64/libstdc++.so.6 /usr/lib64/[libname2] /usr/lib64/[libname3])
foreach(DEPENDENCY ${DEPENDENCIES})
install(PROGRAMS "${DEPENDENCY}" DESTINATION lib)
endforeach()
Is there a smarter way to achieve the same purpose?
Instead of manually specifying path to all libraries, can we make it an automatic process? Given CMake already knows all the dependencies and the according library path in the link stage, should it be straightforward?
Related
My cmake project builds against external libraries, e.g. Boost. I would now like to advise cmake to generate "make install code" that causes all used external libraries to be added to the installation package.
My hope is that cmake can inspect the built shared objects and executables, e.g. using ldd, to find out which external libraries are required and add them without explicit naming of the individual libraries in the CMakeLists.txt.
Of course there is the other case in which the built code expicitly loads the external libaries (dlopen(), ...), e.g. as done by Intel IPP. In this case I would probably somehow need to explicitly name the libraries to install, e.g. using some variables set by the FindXXX cmake scripts.
This question asks how to install a shared library with cmake which has been imported rather than being built by the current project:
Can I install shared imported library?
To repeat the issue:
add_library(libfoobar SHARED IMPORTED)
# this install command is illegal
install(TARGET libfoobar LIBRARY DESTINATION "${RPMBUILDROOT}${LIBDIR}")
This was raised as a [https://gitlab.kitware.com/cmake/cmake/issues/14311|issue] with cmake that has been closed, effectively with a resolution of will not fix. The grounds are, quite reasonably, that cmake does not know enough about an imported target to reliably install it.
One point the answer to that question misses is that install(TARGET) will automagically create links from libfoo.so to libfoo.so.major and libfoo.so.minor version on GNU/Linux and other unix-like platforms where this is required.
Is there a way to hijack cmake into treating a custom target as if it was built by the project or otherwise persuade it to create those links?
Something like:
add_library(libfoobar SHARED IMPORTED)
#? add_custom_target(X libfoobar)
install(TARGET X LIBRARY DESTINATION "${RPMBUILDROOT}${LIBDIR}")
What is a canonical way to do this?
When a library is built by CMake, it is CMake who assigns soversion numbers to it (according to project's settings).
When a library isn't built by CMake, CMake doesn't know soversion, so it cannot create symlinks for you.
If you bother about that CMake actually installs symlink instead of file, resolve symlinks before installing, like in that question.
Well, you may ask CMake to guess soversion of the library (e.g. by resolving symlinks and checking their names). But why you ever need symlinks?
The main purpose of soversion symlink is to resolve compatibility issues with the future library's updates. But updates are possible only when the library is installed by the project who creates it.
If your project installs library produced by other project, it is unlikely that you want to support updates for the local library's installation. So there is no needs for you to support soversions.
I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)
I am trying to build an executable which links to a shared library (named 'caffe'). The shared library is dependent on another shared library (named 'cblas'). When I try to link to caffe in my CMake file it shows the following error:
libcblas.so.3, needed by libcaffe.so, not found (try using -rpath or
-rpath-link)
I am using the following statements in my CMakeLists.txt:
link_directories(${BINARIES}/lib)
add_library(CAFFE_LIBRARY SHARED IMPORTED)
set_target_properties(CAFFE_LIBRARY PROPERTIES IMPORTED_LOCATION ${BINARIES}/lib/libcaffe.so)
target_link_libraries(${PROJECT_NAME} CAFFE_LIBRARY)
Both 'cblas' and 'caffe' libraries are present in ${BINARIES}/lib folder.
Do I need to add cblas.so to target_link_libraries also? Also, i am not building caffe.so so building it via CMake and keeping it as a dependency is not an option
Is there any other feasible solution for the same problem where dependency tree of shared library needs to be resolved while linking?
Browsing through the library's GitHub tree, it seems to me that it provides a package config file. Therefore, if you have installed it in the normal way, you should be able to find it as a package, instead of defining the imported target yourself:
find_package(Caffe)
include_directories(${Caffe_INCLUDE_DIRS})
add_definitions(${Caffe_DEFINITIONS}) # ex. -DCPU_ONLY
add_executable(caffeinated_application main.cpp)
target_link_libraries(caffeinated_application ${Caffe_LIBRARIES})
The example above comes from the Caffe documentation on the topic.
Is it possible to get CMake to gather up all the package libraries used during compilation, recursively grab their required libraries, and then put them all in a single directory?
As an example if my application requires gtk it would grab glib and its required libraries libiconv, gettext, and libffi.
You can use the GetPrerequesites CMake module.
See here for more information