Cmake how to manage two package include same sub-project - c++

I wrote an shared library project. The CMakeLists.txt in this project:
install(TARGETS ${library_name}
LIBRARY DESTINATION "lib"
)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/lib/libxxx.so
DESTINATION "lib"
)
install(DIRECTORY
data
DESTINATION "/opt/${project_name}"
)
Then, I have two project include that
add_subdirectory(module/xxx)
I use Cpack generate pkg1.deb pkg2.deb;
on installation time error occurred, trying to overwrite "libxxx.so", which is also in package "pkg1.deb", install package failed;
Now, I use dpkg with --force-overwrite temporarily solve this;
Is there a solution to manange this with cmake?

Related

macOS cmake display"install TARGETS given no ARCHIVE DESTINATION for static library target "SO_kolev"."

When My MacBook run cmake, it display
install TARGETS given no ARCHIVE DESTINATION for static library target
"SO_kolev".
How can I fix it?
The following is my cmake file:
# Create shared library with a generated dictionary.
add_library(SO_${PROJECT_NAME} ${SOURCES} D_${PROJECT_NAME}.cxx)
# Link against shared library and list of ROOT libraries
target_link_libraries(SO_${PROJECT_NAME} PUBLIC ${LIB_NAMES})
# Find location of the enrty point file (main.c*)
file(GLOB_RECURSE MAIN ${CMAKE_CURRENT_SOURCE_DIR}/*.cxx ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
list(FILTER MAIN INCLUDE REGEX "main\\.c")
# message(STATUS "Found entry point file: ${MAIN}")
# Create the main program using the library.
add_executable(${PROJECT_NAME} ${MAIN})
target_link_libraries(${PROJECT_NAME} SO_${PROJECT_NAME})
# Compose the install target
install(TARGETS ${PROJECT_NAME} SO_${PROJECT_NAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION ${ROOTSYS}/lib)
install(FILES ${PROJECT_BINARY_DIR}/libD_${PROJECT_NAME}.rootmap
DESTINATION $ENV{ROOTSYS}/lib)
install(FILES ${PROJECT_BINARY_DIR}/libD_${PROJECT_NAME}_rdict.pcm
DESTINATION /usr/local/bin)
When installed with install(TARGETS) command, a static library is treated as ARCHIVE kind of artifact, so CMake needs to know into which directory to install such kind of artifacts.
This directory is specified with DESTINATION argument, but your install command has only directories for RUNTIME and LIBRARY artifacts. So you need to add appropriate argument for ARCHIVE:
install(TARGETS ${PROJECT_NAME} SO_${PROJECT_NAME}
RUNTIME DESTINATION bin
LIBRARY DESTINATION ${ROOTSYS}/lib
ARCHIVE DESTINATION ${ROOTSYS}/lib)
Since CMake 3.14 some kind of artifacts has default values for installation directories, so DESTINATION argument for them is no longer required. This is explicitely noted in the documentation:
For regular executables, static libraries and shared libraries, the DESTINATION argument is not required. For these target types, when DESTINATION is omitted, a default destination will be taken from the appropriate variable from GNUInstallDirs, or set to a built-in default value if that variable is not defined.

CMake LibXML Runtime library not found. Windows

I try to create an automated build of Scram (CI yaml file, CMakeLists.txt) for Windows. The project uses CMake to create the build files. Building of the project worked already, but the runtime libraries of libxml and boost get not bundled into the package.
As compiler mingw64 is used.
Libxml2 will be installed by the CI in a previous step and the install prefix is passed to the scram cmake.
In the CMakeLists.txt libxml is included as:
find_package(LibXml2 REQUIRED)
1
I tried then to install the libxmllibraries as:
install(FILES ${LIBXML2_LIBRARIES} DESTINATION bin)
The problem is that LIBXML2_LIBRARIES points to the .dll.a files in the libxml2_install_prefix/lib and not to the .dll files in the libxml2_install_prefix/bin folder. So only the .dll.a files are bundled into the exe and therefore the application does not work.
2
get_target_property(LIB_XML2_RUNTIME_OUTPUT_DIRECTORY LibXml2::LibXml2 RUNTIME_OUTPUT_DIRECTORY)
get_target_property(LIB_XML2_RUNTIME_OUTPUT_NAME LibXml2::LibXml2 RUNTIME_OUTPUT_NAME)
message(STATUS "XX LIB_XML2_RUNTIME_OUTPUT_DIRECTORY: ${LIB_XML2_RUNTIME_OUTPUT_DIRECTORY}")
message(STATUS "XX LIB_XML2_RUNTIME_OUTPUT_NAME: ${LIB_XML2_RUNTIME_OUTPUT_NAME}")
install (FILES
${LIBXML2_LIBRARIES}
"${LIB_XML2_RUNTIME_OUTPUT_DIRECTORY}/${LIB_XML2_RUNTIME_OUTPUT_NAME}"
DESTINATION bin
COMPONENT libraries)
In this case LIB_XML2_RUNTIME_OUTPUT_NAME and LIB_XML2_RUNTIME_OUTPUT_DIRECTORY are "-NOT_FOUND"
This seems to be a problem because cmake does not know the runtime directory for imported targets (
3
I tried than also install(IMPORTED_RUNTIME_ARTIFACTS LibXml2::LibXml2) which failed with: install IMPORTED_RUNTIME_ARTIFACTS given target "LibXml2::LibXml2" which is not an executable, library, or module.
Also described here: CMake Gitlab repository
4
install(TARGETS LibXml2::LibXml2 RUNTIME_DEPENDENCIES)
failed with the following message: install TARGETS given target "LibXml2::LibXml2" which does not exist.
From CMake Docu:
Note: Imported Targets are supported only if they know the location of their .dll files. An imported SHARED or MODULE library must have IMPORTED_LOCATION set to its .dll file. See the add_library imported libraries section for details. Many Find Modules produce imported targets with the UNKNOWN type and therefore will be ignored.
Probably LibXml2 is imported as unknown and therefore there is no DLL path specified. How to come around this issue and installing the dlls?
5
I tried
install(FILES $<TARGET_RUNTIME_DLLS:LibXml2::LibXml2> DESTINATION bin COMPONENT libraries)
but here I get the error message:
Objects of target "LibXml2::LibXml2" referenced but is not one of the allowed target types (EXECUTABLE, SHARED, MODULE).. Probably because the target is imported and not created by this cmake
6
get_target_property(libxml2_imported_location LibXml2::LibXml2 IMPORTED_LOCATION) points also to the .dll.a file
7 Working Hack (Ugly)
Find out where the .dll is located. For libXml2 it is in the bin folder, for boost it is in the same folder as the .dll.a
Use the imported location and replace the path to match the path to the .dll
get_target_property(libxml2_imported_location LibXml2::LibXml2 IMPORTED_LOCATION)
string(REPLACE "/lib/" "/bin/" libxml2_imported_location ${libxml2_imported_location})
string(REPLACE ".dll.a" ".dll" libxml2_imported_location ${libxml2_imported_location})
message(STATUS "XX libxml2_imported_location3 ${libxml2_imported_location}")
install(FILES ${libxml2_imported_location} DESTINATION bin COMPONENT libraries)

How to link a target which might be a shared library when installing a library with CMake

I have a library that can be build as shared or static and uses another library that is already on the system and can be either shared or static too. The former is a C++ wrapper for the latter, which is a C library
What would the correct target_link_libraries call be?
If I do target_link_libraries(cpplib PUBLIC clib) then I'm also propagating the include directories of clib to consumers of cpplib but those should only use the interface provided by the C++ library which has no mention of the clib in its headers.
If I do target_link_libraries(cpplib PRIVATE clib) then the include path of consumers is clearer, but when I now do the export-install-install_exports dance of installing a CMake project with its config file and *targets.cmake then I have a problem: If both libraries are SHARED then the installed targets of cpplib have no mention of clib and linking against that consequently fails with libc.so, needed by libcpp.so, not found and many undefined references.
Both libraries use targets and especially under Windows there is no way to find whether clib is shared or not.
What is the idiomatic way?
CMakeLists.txt
cmake_minimum_required(VERSION 3.8.0)
project(cpplib)
find_package(clib REQUIRED)
add_library(cpplib SHARED cpplib.cpp)
target_link_libraries(cpplib PRIVATE clib::clib)
target_include_directories(cpplib PUBLIC $<INSTALL_INTERFACE:include/cpplib>)
include(CMakePackageConfigHelpers)
set(PROJECT_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/cpplibConfig.cmake")
configure_package_config_file("Config.cmake.in" ${PROJECT_CONFIG_FILE} INSTALL_DESTINATION "lib/cmake")
install(
TARGETS cpplib
EXPORT cpplibTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
)
install(FILES cpplib.h DESTINATION include/cpplib)
install(FILES ${PROJECT_CONFIG_FILE} DESTINATION "share/cpplib")
install(EXPORT cpplibTargets NAMESPACE "cpplib::" DESTINATION "share/cpplib")
Config.cmake.in
#PACKAGE_INIT#
find_package(BZip2 REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/#PROJECT_NAME#Targets.cmake")
check_required_components("#PROJECT_NAME#")
"user" project CMakeLists.txt
cmake_minimum_required(VERSION 3.8.0)
project(user)
find_package(cpplib REQUIRED)
add_executable(user main.cpp)
target_link_libraries(user cpplib::cpplib)
Edit: As I found it strange, that it works, when I add the executable in the same CMakeLists as the library (so not using the installed version) I dug deeper: I just noticed that CMake clears the rpath on installing:
-- Installing: /tmp/install/lib/cpplib.so
-- Set runtime path of "/tmp/install/lib/cpplib.so" to ""
Found this while comparing the output of ldd of the installed library and the one in the build tree where the latter is able to resolve the clib. Why is that?

Including external libraries in cpack output

Im currently working on a cmake project which is making use of external libraries which are being imported through the find_package function. My question revolves around cpack and how I am supposed to go about adding the found packages into the cpack output. For example if I use this
find_package(OpenGL REQUIRED)
add_executable(Example_App MACOSX_BUNDLE src/main.cpp)
target_include_directories(Example_App SYSTEM PUBLIC ${OPENGL_INCLUDE_DIR})
target_link_libraries(Example_App PUBLIC ${OPENGL_LIBRARIES})
install(TARGETS Example_App
BUNDLE DESTINATION "."
RUNTIME DESTINATION bin)
If I then run cmake .. followed by make and make package my output from cpack (I can include an example of my cpack code if needed too) would then be.
ExampleApp-linux.tar.bz2
- bin
-- Example_App
- Share
-- Resource files
Rather than something like:
- bin
-- Example_App
- Lib
-- OpenGL.a
- Share
-- Resource files
Any help would be much appreciated!
You would have to explicitly add an install rule for the external project libraries.
For example:
install(FILES ${OPENGL_LIBRARIES}
RUNTIME DESTINATION bin COMPONENT RuntimeLibraries
LIBRARY DESTINATION bin COMPONENT RuntimeLibraries
ARCHIVE DESTINATION Lib COMPONENT Development
)
Or you could use a specific library reference like ${OPENGL_gl_LIBRARY} instead of ${OPENGL_LIBRARIES}. See Modules/FindOpenGL.cmake for more details.

CMAKE: How to install the dependencies of a target

I am trying to install an executable using cmake. My real problem here is: how to install the executable and its dependencies.
Here an example:
I want to install one executable that depend on two libraries of my cmake and one 3rdparty (pre-compiled).
set(EXECUTABLE_NAME MyExecutable)
file(GLOB_RECURSE ${EXECUTABLE_NAME}_SOURCES *.cpp)
add_executable(${EXECUTABLE_NAME} ${${EXECUTABLE_NAME}_SOURCES})
target_link_libraries(${EXECUTABLE_NAME} MyLibrary1
MyLibrary2
${Boost_PROGRAM_OPTIONS_LIBRARY})
install(TARGETS ${EXECUTABLE_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT ${EXECUTABLE_NAME})
At the end I would like to find with this kind of CMakeLists.txt my two libraries, my executable and Boost_PROGRAM_OPTIONS_LIBRARY in the install folder and in my package.
What I have found, but I did not succeed to use:
BundleUtilities.cmake, here an example: https://cmake.org/Wiki/BundleUtilitiesExample.
As you can see it seems to do the perfect jobs, but it's complaining about "external prerequisites". I personally found that normal and I don't understand how to fix that. (Note: it succeeds in finding and copying the dependencies into a same folder before failing, Doc: https://cmake.org/cmake/help/v3.5/module/BundleUtilities.html)
GetPrerequisites.cmake. get_prerequisites is a lower level function that allow you to get the dependencies. The thing is, I don't any good way/best practice to use it.
Thanks,
I personally would make a library out of all of your dependencies with add_library(MyLibrary1 STATIC/SHARED/INTERFACE) and for boost most probably add_library(boost INTERFACE) followed by adding any include directories and linking the .as or .sos to them.
I would then link all my dependencies to MyExecutable as you have above. And at any point you can call the install function on all of these targets one at a time.
If you don't like repeating
install(TARGETS target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT target
)
then you could break it out in to a function, something like this
function(INSTALL_CUSTOM target
install(TARGETS target
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
COMPONENT target
)
endfunction()
and then you could just call INSTALL_CUSTOM(MyLibrary1) or INSTALL_CUSTOM(boost).