Why CPack generates an empty package? - cmake

There are exists one cmake project that creates one console application.
I add the ability of package generation to that cmake project:
# ... above cmake code for one console application creation
# below code that I add:
#install
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "C:/Apps/Consolas" COMPONENT applications)
# pack
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VENDOR "MyOrg")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "CPack Component Installation Example")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "ZIP")
include(CPack)
The package creation passes without any errors, (!) but the package is empty.
Why it happens and how to fix this issue? (I used cmake 3.12.0)

DESTINATION should be a relative directory within the package.
Consider the following instead:
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION "bin" COMPONENT applications)
Explanation: CPack will create the ZIP file after installing the project into a subdirectory of <build-dir>/_CPack_Packages. By specifying an absolute path, no file will be installed in the expected subdirectory and the package will be empty.

Related

Flatpak specific commands in CMake

I try to create a Flatpak package for my application, that is called AppName afterwards. Its uses CMake/make for configuration and compilation.
When I compile normally my application (without using Flatpak), it uses a configuration file that has to be placed in the $HOME/.local/share/AppName/config folder.
I place this file in this folder using this CMake command
install(FILES ${PROJECT_SOURCE_DIR}/config/config.ini DESTINATION $ENV{HOME}/.local/share/AppName)
It works well. Now, when when I create the Flatpak package, it looks for the configuration file in $HOME/.var/app/org.flatpak.AppName/data/AppName/config.ini"
How could I design my CMakeLists.txt so that it uses $ENV{HOME}/.local/share/AppName when I do not use Flatpak and $HOME/.var/app/org.flatpak.AppName/data/AppName when I create a Flatpak package?
In short, I am looking for a CMake snippet like
if(FLATPAK)
install(FILES ${PROJECT_SOURCE_DIR}/config/config.ini DESTINATION $ENV{HOME}/.var/app/org.flatpak.AppName/data/AppName)
else()
install(FILES ${PROJECT_SOURCE_DIR}/config/config.ini DESTINATION $ENV{HOME}/.local/share/AppName)
endif()

How to install runtime files of Imported shared library in cmake

In my project I use an external library, that is integrated as a shared imported library. This library has some files, which are required at runtime. These files and also the license file should be installed when deploying the application.
The cmake of the imported libarary (MyImportedLibConfig.cmake) looks like this:
add_library(MyImportedLib SHARED IMPORTED)
set_target_properties(MyImportedLib PROPERTIES
IMPORTED_LOCATION "3rdparty/MyImportedLib /dev/lib/myimportedlib${CMAKE_SHARED_LIBRARY_SUFFIX}"
IMPORTED_IMPLIB "3rdparty/MyImportedLib/dev/lib/myimportedlib.lib"
INTERFACE_INCLUDE_DIRECTORIES "3rdparty/MyImportedLib/dev/include"
)
My initial approach for installing the files was this (also in MyImportedLibConfig.cmake):
# install license file
install(FILES "3rdparty/MyImportedLib/license.rtf" DESTINATION ${CMAKE_INSTALL_PREFIX}/licenses/MyImportedLib COMPONENT Runtime)
# install binary files
install(DIRECTORY "3rdparty/MyImportedLib/dev/bin/" DESTINATION ${CMAKE_INSTALL_PREFIX}/bin COMPONENT Runtime)
install(DIRECTORY "3rdparty/MyImportedLib/dev/bin/" DESTINATION ${CMAKE_INSTALL_PREFIX}/UnitTests COMPONENT Runtime)
This works on my local build, but the paths are not reliable (i.e. they are wrong when doing a package build).
What would be the proper way to handle this in CMake?
[Update]
I have been able to fix the messed up installation paths by avoiding the use of CMAKE_INSTALL_PREFIX.
# install license file
install(FILES "3rdparty/MyImportedLib/license.rtf" DESTINATION licenses/MyImportedLib COMPONENT Runtime)
# install binary files
install(DIRECTORY "3rdparty/MyImportedLib/dev/bin/" DESTINATION bin COMPONENT Runtime)
install(DIRECTORY "3rdparty/MyImportedLib/dev/bin/" DESTINATION UnitTests COMPONENT Runtime)
This is still not perfect, but it does the job.

CMake copy dll transitively

Basically I want CMake to copy dependency's dll to the same directory of the executable. Suppose I have the following directory structure:
my-project/
CMakeLists.txt
lib/
CMakeLists.txt
... # Some source files
app/
CMakeLists.txt
... # Some source files
The library lib depends on some third party dll, say foo.dll. The executable in app, say app.exe, depends on lib.
I've written a FindFOO.cmake to make the third party library foo.dll an imported target named foo.
Now when I compile app, in order to run the executable, foo.dll is required to be in the same directory as app.exe. How can this be achieved automatically with cmake? And what if I want to use CPack to package the application into an installer?
CMAKE_RUNTIME_OUTPUT_DIRECTORY is your friend.
If this variable is created before creating some target, if the target is RUNTIME, it will define where the output of the target will be placed.
In your case, it can be used to force foo.dll and app.exe to be in the same folder. Your root CMakeLists.txt should look like this:
cmake_minimum_required(VERSION 3.15)
project(foo_and_app)
# app.exe and foo.dll will be in bin subfolder of build dir
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_subdirectory(lib)
add_subdirectory(app)
#not connected to placement, but only to package creation
include(CPack)
It should be noted that this variable is used to initialize the properties of the targets added, meaning that everything may also be achieved by directly manipulating appropriate target properties.
Regarding packaging, what you ask is possible, regardless of the placement of runtime targets, by using install cmake statement. In lib/CMakeLists.txt you should add something like this:
# suppose that the target named `foo`,
# i.e. it is added by add_library(foo SHARED .....)
install(TARGETS foo
RUNTIME DESTINATION bin
)
same should be done for app/CMakeLists.txt:
# suppose that the target named `app`,
# i.e. it is added by add_executable(app .....)
install(TARGETS app
RUNTIME DESTINATION bin
)
If you have these install statements, the final destination will be bin folder within the chosen install folder.
In the end, here are the links for CMake documentation describing:
CMAKE_RUNTIME_OUTPUT_DIRECTORY variable
RUNTIME cmake targets
install(TARGETS ...)

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.

Install a custom file generated during compilation in CMake

I'd like to install a custom file which is generated during compilation of a CMake project:
In my project the file SampleDictionary_rdict.pcm is generated by a command from an external module during compilation, and I would like to have it copied to $CMAKE_INSTALL_PREFIX/lib with make install
The issue I'm running into is all the variants of install(...) I've tried require the file to exist before compilation.
The command from an external module that generates the file is:
ROOT_GENERATE_DICTIONARY(
SampleDictionary
...
)
This generates SampleDictionary_rdict.pcm in my build directory.
For example, if I try to add:
install(TARGETS SampleDictionary DESTINATION "${CMAKE_INSTALL_PREFIX}/lib")
to the end of my CMakeLists.txt I have the issue of the file not existing.
install(TARGETS ... is used to install targets built within the project. You want to install the file SampleDictionary_rdict.pcm so you need a variant for files: install(FILES ...