Including external libraries in cpack output - c++

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.

Related

Cmake how to manage two package include same sub-project

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?

How to add_dependencies between projects in cmake

include_directories(${CMAKE_CURRENT_SOURCE_DIR})
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} source)
project(abc)
#a_certain_source_file.cpp is a generated file built by another project.
add_library(${PROJECT_NAME} STATIC ${source} ${xyz_BIN_DIR}/a_certain_source_file.cpp)
add_dependencies(${PROJECT_NAME} xyz)
target_link_libraries(${PROJECT_NAME} PRIVATE xyz)
# include xyz_SOURCE_DIR directory to include a_certain_source_file.cpp
target_include_directories(${PROJECT_NAME} PRIVATE ${xyz_SOURCE_DIR})
# Installation
install(TARGETS ${PROJECT_NAME} DESTINATION ${DST_LIB_DIR})
I have a CMakeLists.txt as above. Trying to build project abc. But to build it, I also need "a_certain_source_file.cpp" which is an auto generated source file from another project called xyz. If xyz had been built from this same CMakeLists.txt, there would have been no problem in add_dependencies working. I am unable to get the dependency on "a_certain_source_file.cpp" resolved with the way i have my CMakeLists.txt right now. Any CMake Enthusiasts or specialists that can help ?
I also saw a close match here - cmake: add_dependencies does not work with external projects but I don't need anything downloaded. So am not sure if this is what I need.
Create custom command with add_custom_command marking ${xyz_BIN_DIR}/a_certain_source_file.cpp as OUTPUT and make it depend on a xyz target. This will teach CMake that ${xyz_BIN_DIR}/a_certain_source_file.cpp is a generated file, and what should it do to generate it.

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?

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).

splitting a project into a library and a application

I'm using cmake for my project. No I want to split some parts into a library and use this for 2 different applications.
Now I don't how how to do this subprojects in cmake. My first attempt was to use the add_subdirectory command:
cmake_minimum_required(VERSION 2.8)
add_subdirectory(MSI)
message("Building MsiQtWizard with: ${MSI_INCLUDE_DIR}")
add_subdirectory(MsiQtWizard)
So MSI would be my library. Inside the MSI folder is another cmakelists which is basically a standalone list for building the library. I thought I could make the MsiQtWizard project also a standalone cmakelists, so I could theoretically build MSI and use the library to build MsiQtWizard (and other projects).
The cmakelists in the root directory would just be a helper to build the library and the GUI in one single step.
The problem is, for building MsiQtWizard, I need the include path to msi and the static library binaries. I tried to do something like that at the end of MIS/CMakelists.txt:
### Set variables, other scripts may use ###
SET(MSI_INCLUDE_DIR include)
MESSAGE("Include directory is: ${MSI_INCLUDE_DIR}")
and in the MsiQtWizard/CMakelists:
##### external libraries #####
#MSI
find_path(MSI_INCLUDE_DIR REQUIRED msi/Image.hpp
PATH_SUFFIXES MSI/include include)
My intend is, that MsiQtWizard will search for msi, if the varaible was not previously set (so that you could use this cmakelists as a standalone). When building MSI, I want to save the include path (and later binary locations) and pass it to MsiQtWizard - but the value is gone as soon as I'm back in my root cmakelists.
So that is, what I tried. My Question is now: How would I correctly split my project into a library and a (later multiple) application and can I do it in a way that I can also build them independently?
Or, more specific: How can I pass values from a node CMakelist to the root CMakeList (like I tried with MSI_INCLUDE_DIR)?
If your building a library - its best to completely separate it from the application build. Otherwise you are coupling your library with your application with cmake, which in my view defeats the purpose of building a library.
When building your library you will want something like
project (MSILibrary)
ADD_LIBRARY(MSILibrary src/MSI1.cpp src/MSI2.cpp)
install (TARGETS MSILibrary DESTINATION lib)
where src contains your library code. You can then make then sudo make install your library to your standard library location (e.g. /usr/lib).
You can then use your library in any subsequent project. Put these in a new directory and create a new CMakeLists.txt for them.
You will want something like,
#include find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
project (MSI-project-1)
find_package(MSILibrary REQUIRED)
IF(MSILibrary_FOUND)
include_directories(${MSILibrary_INCLUDE_DIRS}
ENDIF(MSILibrary_FOUND )
target_link_libraries (MSI-project-1 ${MSILibrary_LIBRARIES})
install (TARGETS MSI-project-1 DESTINATION bin)
Now all you need to do is help cmake find you library.
You can include a module for this. In the file ./cmake/Modules/FindMSILibrary.cmake type something like:
# - Try to find MSILibrary library
# Once done, this will define
#
# MSILibrary_FOUND - system has MSILibrary
# MSILibrary_INCLUDE_DIRS - the MSILibrary include directories
# MSILibrary_LIBRARIES - link these to use MSILibrary
## Google this script (I think its fairly standard, but was not bundled with my CMAKE) - it helps find the macros.
include(LibFindMacros)
# Dependencies
libfind_package(MSILibrary)
# Use pkg-config to get hints about paths
libfind_pkg_check_modules(MSILibrary_PKGCONF MSILibrary)
# Include dir
find_path(MSILibrary_INCLUDE_DIR
NAMES MSI.hpp
PATHS ${MSI_Library_PKGCONF_INCLUDE_DIRS}
)
# Finally the library itself
find_library(MSILibrary_LIBRARY
NAMES MSILibrary
PATHS ${MSILibrary_PKGCONF_LIBRARY_DIRS}
)
# Set the include dir variables and the libraries and let libfind_process do the rest.
# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
set(MSILibrary_PROCESS_INCLUDES MSILibrary_INCLUDE_DIR MSILibrary_INCLUDE_DIRS)
set(MSILibrary_PROCESS_LIBS MSILibrary_LIBRARY MSILibrary_LIBRARIES)
libfind_process(MSILibrary)
That should be it.
EDIT:
If you really want to package your applications with your library (perhaps some example applications), then you can do something like so:
In your root CMakeLists.txt
cmake_minimum_required (VERSION 2.6)
project (MSIProject)
# The version number.
set (MSIProject_VERSION_MAJOR 0)
set (MSIProject_VERSION_MINOR 1)
set (MSIProject_PATCH_LEVEL 3 )
# project options
OPTION( BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON )
OPTION( BUILD_EXAMPLES "Set to OFF to skip building the examples" ON )
# Put the libaries and binaries that get built into directories at the
# top of the build tree rather than in hard-to-find leaf
# directories.
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
##########################################################################
# Build the library
##########################################################################
add_subdirectory(MSI-src)
##################
# Build your example Apps if requested
############
IF( BUILD_EXAMPLES )
add_subdirectory(example/MSI-project-1)
add_subdirectory(example/MSI-project-2)
ENDIF( BUILD_EXAMPLES )
Your library MSI-src/CMakeFiles.txt will be as before, and your example/MSI-project-1/CMakeLists.txt will be something like
## Make the InferData example project
project (MSI-project-1)
#include MSI library
include_directories ("${MSILibrary_SOURCE_DIR}/include")
#include the includes of this project
include_directories ("${MSI-project-1_SOURCE_DIR}/../include")
#build
add_executable(MSI-project-1 src/P1.cpp)
target_link_libraries (MSI-project-1 MSILibrary) #link
install (TARGETS MSI-project-1 DESTINATION bin)