CPack / CMake: Different installation prefixes per CPACK_GENERATOR - cmake

How can I specify different installation prefixes for the different CPACK_GENERATORs?
For example:
the DEB package should be installed to /opt/project
the TGZ archive should consist only of the project directory
From the documentation I understood that I would have to use the CPACK_PROJECT_CONFIG_FILE variable. Using that, it should be possible to achieve the desired goal. However, it did not work for me.
This is my CPack configuration:
set(CPACK_GENERATOR "DEB;TGZ")
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/cmake/package.linux.txt)
And this is my ${CMAKE_SOURCE_DIR}/cmake/package.linux.txt file:
IF (CPACK_GENERATOR MATCHES "DEB")
set(CPACK_NATIVE_INSTALL_DIRECTORY "/opt")
set(CMAKE_INSTALL_PREFIX "/opt")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
set(CPACK_INSTALL_DIRECTORY "/opt")
ELSEIF(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_NATIVE_INSTALL_DIRECTORY "")
set(CMAKE_INSTALL_PREFIX "")
set(CPACK_PACKAGING_INSTALL_PREFIX "")
set(CPACK_INSTALL_DIRECTORY "")
ENDIF()
I have made sure that all files get parsed using MESSAGE() directives, but the prefix of my packages is always /usr/local.

Finally, I found out what was wrong. I had the CPACK_SET_DESTDIR flag set. This makes CPACK append usr/local to the directory containing the binaries of the compilation. After removing the corresponding SET() directive, everything worked like a charm.
For the record I will provide you with my minimal working example.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(stripped-down C)
add_executable(main main.c)
install(TARGETS main
RUNTIME DESTINATION bin
)
set(CPACK_GENERATOR "DEB;TGZ")
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/package.txt)
set(CPACK_PACKAGE_CONTACT "Some One <some.one#somewhere.com>")
include(CPack)
${CMAKE_SOURCE_DIR}/package.txt:
IF (CPACK_GENERATOR MATCHES "DEB")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
ELSEIF(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_PACKAGING_INSTALL_PREFIX "")
ENDIF()

Related

Why is CMake inconsistent about copying dependent DLLs to my output?

Let's say I have a simple project like this:
find_package(SDL2 REQUIRED)
add_executable(test main.cpp)
target_link_libraries(test PUBLIC SDL2::SDL2 SDL2::SDL2main)
install(TARGETS test DESTINATION .)
If I build with CMAKE_BUILD_TYPE=Debug, I will find that the DLLs I depend on (sdl2d.dll in this case) will be copied correctly to the binary folder alongside my application.
However, in a CMAKE_BUILD_TYPE=Release build, this doesn't seem to be the case - forcing me to add directives like this throughout my project:
if (WIN32)
IF(CMAKE_BUILD_TYPE MATCHES Debug)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/SDL2d.dll ${CMAKE_CURRENT_BINARY_DIR}/zstdd.dll DESTINATION .)
else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/SDL2.dll ${CMAKE_CURRENT_BINARY_DIR}/zstd.dll DESTINATION .)
ENDIF()
install(FILES ${install_dir}/bin/assimp-vc142-mtd.dll DESTINATION .)
endif()
This is especially messy now that I'm trying to integrate error-reporting tools (i.e. Sentry) that need DLL and PDB files in order to see stack traces, etc. Is there any reason this behaves as such on windows, or some way to force it to act more consistently so that my builds or install outputs are actually in a form I can consistently zip up and release?

cmake cross-compile for raspberry pi

I am cross-compiling a library (ORBSLAM3) on pc using /usr and /lib
from rpi4 (After using rsync). And I put them in a folder named "rootf".The prerequisite libraries have been installed before so they are now in ~/rootf/usr and ~/rootf/lib. I need to compile ORBSLAM3 using ~/rootf/ as the root.
The thing is I am not familiar with cmake so I have been struggling for a while.
The process of compiling is this:
using Toolchain-rpi.cmake for the CMakeLists.txt on the top level of ORBSLAM3.
In CMakeLists.txt, it finds pangolin by find_package(Pangolin REQUIRED)
find_package() is actually doing the right.
It successfully finds
/home/ethan/raspberrypi/rootfs/usr/local/lib/cmake/Pangolin/PangolinTargets.cmake
The CMAKE_PREFIX_PATH in this CMakeLists.txt is right, which is
/home/ethan/raspberrypi/rootfs/usr/local/lib;/home/ethan/raspberrypi/rootfs/usr/lib/arm-linux-gnueabihf
After I uninstall pangolin on ubuntu, I get this:
CMake Error at /home/ethan/raspberrypi/rootfs/usr/local/lib/cmake/Pangolin/PangolinTargets.cmake:80 (message):
The imported target "pangolin" references the file
"/usr/local/lib/libpangolin.so"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
Since Pangolin was originally installed on board, so on board libpangolin.so is at /usr/local/lib/libpangolin.so.
I guess when I use PangolinTargets.cmake, it is doing the same thing.
I output CMAKE_SYSROOT,CMAKE_PREFIX_PATH,_IMPORT_PREFIX in PangolinTargets.cmake. It's what I expect.
CMAKE_SYSROOT = /home/ethan/raspberrypi/rootfs
CMAKE_PREFIX_PATH = ;/home/ethan/raspberrypi/rootfs/usr/local/lib;/home/ethan/raspberrypi/rootfs/usr/lib/arm-linux-gnueabihf
_IMPORT_PREFIX = /home/ethan/raspberrypi/rootfs/usr/local
Even if I add /home/ethan/raspberrypi/rootfs as prefix to the below paths, nothing changed.
set_target_properties(pangolin PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3;${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "rt;pthread;/usr/lib/arm-linux-gnueabihf/libGL.so;/usr/lib/arm-linux-gnueabihf/libGLU.so;
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3"
)
Here is the content of PangolinTargets.cmake. I am not sure which parts leads to searching only /usr. Thanks all.
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget pangolin)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target pangolin
add_library(pangolin SHARED IMPORTED)
set_target_properties(pangolin PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3;${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "rt;pthread;/usr/lib/arm-linux-gnueabihf/libGL.so;/usr/lib/arm-linux-gnueabihf/libGLU.so;/usr/lib/arm-linux-gnueabihf/libGLEW.so;/usr/lib/arm-linux-gnueabihf/libEGL.so;/usr/lib/arm-linux-gnueabihf/libSM.so;/usr/lib/arm-linux-gnueabihf/libICE.so;/usr/lib/arm-linux-gnueabihf/libX11.so;/usr/lib/arm-linux-gnueabihf/libXext.so;rt;pthread;/usr/lib/arm-linux-gnueabihf/libdc1394.so;/usr/lib/arm-linux-gnueabihf/libpng.so;/usr/lib/arm-linux-gnueabihf/libz.so;/usr/lib/arm-linux-gnueabihf/libjpeg.so;/usr/lib/arm-linux-gnueabihf/libtiff.so;/usr/lib/arm-linux-gnueabihf/libIlmImf.so"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3"
)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
endif()
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/PangolinTargets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
if(NOT EXISTS "${file}" )
message(FATAL_ERROR "The imported target \"${target}\" references the file
\"${file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
how to show the path of the file for the one that we search using find_package( )?
CMAKE_PREFIX_PATH
Semicolon-separated list of directories specifying installation prefixes to be searched by the find_package()...
set(CMAKE_PREFIX_PATH /home/users/rootf/usr/local/lib)
# additionalllly I also do a precaution
set(CMAKE_IGNORE_PATH / /bin /include /usr/lib /usr/local/lib)
You might also to manipulate with CMAKE_FIND_USE_*_PATH variables.

Create CMake/CPack <Library>Config.cmake for shared library

I have the simplest possible c-library which builds and is packed using the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project (libfoo C)
add_library(foo SHARED impl.c)
target_link_libraries(foo)
install(TARGETS foo LIBRARY DESTINATION lib/)
install(FILES public_header.h DESTINATION include/libfoo)
set(CPACK_GENERATOR "TGZ")
include(CPack)
Working example is located here: https://github.com/bjarkef/cmake-simple/tree/master/libfoo
I execute mkdir -p build; (cd build/; cmake ../; make all package;) to build a .tar.gz package with the compiled shared library along with its public header file. This is all working fine.
Now I wish to modify the CMakeLists.txt to create the FooConfig.cmake and FooConfigVersion.cmake files needed for CMake find_package in a different project to find the foo library. How do I do this?
I have discovered I should used the CMakePackageConfigHelpers: configure_package_config_file and write_basic_package_version_file, and I should create a FooLibraryConfig.cmake.in file. However I cannot figure out how to put it all together.
Note that it is important the the resulting .cmake files only contains relative paths.
I have cmake module included in the top level CmakeList.txt:
# Generate and install package config files
include(PackageConfigInstall)
Within the generic PackageConfigInstall.cmake file, the config files are created from the cmake.in files, and installed. This module can be reused for other packages.
include(CMakePackageConfigHelpers)
# Generate package config cmake files
set(${PACKAGE_NAME}_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}${PACKAGE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
configure_package_config_file(${PACKAGE_NAME}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
PATH_VARS LIB_INSTALL_DIR INCLUDE_INSTALL_DIR APP_INCLUDE_INSTALL_DIR )
configure_file(${PACKAGE_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake #ONLY)
# Install package config cmake files
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake
DESTINATION
${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
COMPONENT
devel
)
You'll need a package file for your library, such as your_lib-config.cmake.in, which will become your_lib-config.cmake. This will contain the include and library variables that can be used.
get_filename_component(YOUR_LIB_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# flag required by CMakePackageConfigHelpers
#PACKAGE_INIT#
set_and_check(YOUR_LIB_INCLUDE_DIR #PACKAGE_YOUR_LIB_INCLUDE_INSTALL_DIR#/hal)
set_and_check(YOUR_LIB_LIBRARY #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
set_and_check(YOUR_LIB_LIBRARIES #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
You'll also want a config-version.cmake.in file like this:
set(PACKAGE_VERSION #PACKAGE_VERSION#)
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
There's quite a bit to the packaging scripts to get it all to work just right. I went through a lot of trial and error to finally get something that works on different targets (both linux server and embedded target). I might have left something out, so please just comment and I'll update answer.

How could I replace a find_package of CMakeList by its installation directory?

I need to install SFML by sources but I can't run cmake because a package is not installed (xcb-image)
I installed this packages by sources, but how can I tell CMake that this package is installed, and that it needs to look at a special directory?
if(NOT SFML_OPENGL_ES)
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
if(SFML_OS_LINUX OR SFML_OS_FREEBSD)
find_package(XCB COMPONENTS xlib_xcb image randr REQUIRED)
if(NOT LIBXCB_FOUND)
message(FATAL_ERROR "Xcb library not found")
endif()
include_directories(${LIBXCB_INCLUDE_DIRS})
endif()
endif()
I don't have root access.
Try adding your xcb /include and /lib directory to your CMakeLists, by adding the following lines :
INCLUDE_DIRECTORIES(/path/to/your/xcb/include)
LINK_DIRECTORIES(/path/to/your/xcb/lib)
Otherwise, if that didn't work and you have a cmake file for cxb (sth like xcb.cmake), Create a folder named cmake/Modules/ under your project root, add xcb.cmake under that folder, and in the root CMakeLists.txt, include the following code:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
For a better understanding, take a look at CMake:How To Find Libraries
Hope that helps !

cpack component level install

For the example CMakeLists.txt attached to CMake wiki. I also added below what is the actual make command to create just the component based TGZ. I am confused and not seeing any help in the documents.
CMakeLists.txt
cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
project(MyLib)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "Install path prefix prepended on to install directories." FORCE)
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CPACK_PACKAGE_NAME "MyLib")
set(CPACK_PACKAGE_VENDOR "CMake.org")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyLib - CPack Component Installation Example")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example")
add_library(mylib mylib.cpp)
add_executable(mylibapp mylibapp.cpp)
target_link_libraries(mylibapp mylib)
install(TARGETS mylib
ARCHIVE
DESTINATION lib
COMPONENT libraries)
install(TARGETS mylibapp
RUNTIME
DESTINATION bin
COMPONENT applications)
install(FILES mylib.h
DESTINATION include
COMPONENT headers)
set(CPACK_COMPONENTS_ALL applications libraries headers)
set(CPACK_COMPONENT_APPLICATIONS_DISPLAY_NAME "MyLib Application")
set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries")
set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")
set(CPACK_COMPONENT_APPLICATIONS_DESCRIPTION
"An extremely useful application that makes use of MyLib")
set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
"Static libraries used to build programs with MyLib")
set(CPACK_COMPONENT_HEADERS_DESCRIPTION
"C/C++ header files for use with MyLib")
set(CPACK_GENERATOR "TGZ")
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY OFF)
set(CPACK_SET_DESTDIR ON)
set(CPACK_PACKAGE_CONTACT "jhf")
# This must always be last!
include(CPack)
I have a similar CMakeLists.txt and when I do make package, I end up getting all my binaries and libraries in the TGZ. What should the make package command be if I need just a TGZ with application component from the above CMakeLists.txt?
It is simple.
Just set the CMAKE variable CPACK_COMPONENTS_ALL to the list of components you want to appear in the installation:
SET(CPACK_COMPONENTS_ALL applications) #only pack "applications" component
Take a look at CPackComponent.
I have exactly the same question with you.
I'm a beginner to cmake, and today I've try a whole day on this, just now I noticed a cmake module named CPackComponent which begins appeared in cmake 2.8.5 standard modules.
For now, I haven't made sure whether it is the reason yet. But the variables in the documents listed by you can be found in this module.
cmake 2.8.5 is the earliest version contained CPackComponent in its standard modules.
Have a check at http://www.cmake.org/cmake/help/v2.8.5/cmake.html#module:CPackComponent
And cmake 2.8.8 is the earliest version listed the variables you want. e.g. CPACK_COMPONENTS_ALL
Over here http://www.cmake.org/cmake/help/v2.8.8/cmake.html#module:CPackComponent
I'm sorry I'm a newbie too, could not help you any more.