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 ...
Related
I have a shared library in my project with a cmake config file. How can I make it available in the build tree such that I don't have to install it before using find_package?
The mechanism I was looking for is export(PACKAGE <PackageName>). Note that since 3.15 the command does nothing by default because populating the user package registry has effects outside the source and build trees. You have to set the CMAKE_EXPORT_PACKAGE_REGISTRY variable to add build directories to the CMake user package registry.
I was able to get things working like this:
install(
TARGETS ${TARGET_LIB}
EXPORT TARGET_LIB_EXPORTS # Define exports
FILE "${PROJECT_NAME}-targets.cmake"
…
)
# Create targets file in build tree
export(
EXPORT TARGET_LIB_EXPORTS
FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}-targets.cmake"
NAMESPACE ${PROJECT_NAME}::
)
# Create config file in build tree
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/${PROJECT_NAME}-config.cmake.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
)
# Create version config file in build tree
write_basic_package_version_file(
"${PROJECT_NAME}-config-version.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
# Export the package to make find_package work in build
set(CMAKE_EXPORT_PACKAGE_REGISTRY true)
export(PACKAGE ${PROJECT_NAME})
A basic config file would look like this:
#PACKAGE_INIT#
include("${CMAKE_CURRENT_LIST_DIR}/#PROJECT_NAME#-targets.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()
I have a Library Project that is exported so consumers can use it like so:
find_package(myLibrary)
target_link_libraries(theirLibrary PUBLIC myNamespace::myLibrary)
MyLibrary is the main product but it lives alongside two other projects in our repository, and the layout looks like this:
MyRepository/
MyLibrary/
CMakeLists.txt
include/ //public headers
MyLibrary/ //sources and private headers
MyDependentLibrary/ //another library project
CMakeLists.txt
etc..
MyExample //executable project
CMakeLists.txt
etc..
The dependencies for each project are like so:
MyLibrary: None
MyDependentLibrary: MyLibrary
MyExample: MyLibrary, MyDependentLibrary
MyLibrary and MyDependentLibrary are both set up with install and build directory exports to be compatible with the find_package() command. So to build everthing you:
configure/build MyLibrary
configure MyDependantLibrary setting MyLibrary_DIR when prompted, then build it
configure MyExample setting MyLibrary_DIR and MyDependentLibrary_DIR when prompted, then build it
This workflow is great, most of the time we only want to package MyLibrary without the other projects when we send to customers, but occasionally we want to give them the source for all 3 projects so they have more examples to look at.
For that reason I would love to add a top level CMakeLists.txt file that would I imagine look something like this:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(MyCombinedProject VERSION 1.0.0 LANGUAGES CXX)
add_subdirectory(MyLibrary)
add_subdirectory(MyDependentLibrary)
add_subdirectory(MyExample)
However this doesn't work. When configuring the "combined" project, MyDependentLibrary is unable to find MyLibrary_DIR, which makes sense, as MyLibrary hasn't been built yet.
Is there a way to add an export to each of the libraries so they can be found when added in this manner in addition to the find_package()? I really don't want to move any CMake code required to build MyLibrary into the top level CMakeLists.txt, as 90% of the time it will be delivered on its own.
You may ship the sources of your library (MyLibrary) with a pseudo config file, which just provides myNamespace::myLibrary target as alias for myLibrary.
MyLibrary/CMakeLists.txt:
# Assuming you create a library
add_library(mylibrary ...)
# Install and export it
install(TARGETS mylibrary EXPORT mylibraryTargets ...)
# and install the file which describes this installation
install(EXPORT mylibraryTargets NAMESPACE myNamespace ...)
# Then you install config file for your library:
install(FILES myLibrary.cmake ...)
# Then just set `MyLibrary_DIR` variable to point into in-source version of config file.
set(MyLibrary_DIR CACHE INTERNAL "A directory with the in-source config file"
${CMAKE_CURRENT_SOURCE_DIR}/cmake
)
And write that in-source config file as follows:
MyLibrary/cmake/MyLibraryConfig.cmake:
add_library(myNamespace::mylibrary ALIAS mylibrary)
That way, find_package(MyLibrary) will work if it is issued after configuring sources of your library (add_subdirectory(MyLibrary)).
I am completely stuck :/. I created a simple test "library" with two
files fruits.cpp and fruits.h.
Then I created this CMakeLists.txt (following this tutorial)
cmake_minimum_required(VERSION 3.16)
project(fruits_Lib)
add_library(fruits_Lib STATIC)
target_sources(fruits_Lib
PRIVATE
"fruits.cpp"
)
set(include_dest "include/fruits-1.0")
set(main_lib_dest "lib/fruits-1.0")
set(lib_dest "${main_lib_dest}/${CMAKE_BUILD_TYPE}")
target_include_directories(fruits_Lib
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${include_dest}>"
)
add_library(fruits::fruits ALIAS fruits_Lib)
install(TARGETS fruits_Lib EXPORT fruits DESTINATION "${main_lib_dest}")
install(FILES "include/fruits/fruits.h" DESTINATION "${include_dest}")
install(EXPORT fruits DESTINATION "${lib_dest}")
This works in that it compiles and installs etc, and I can even use
it as a add_subdirectory in a parent project.
In fact, the files that this installs are:
lib/fruits-1.0/libfruits_Lib.a
lib/fruits-1.0/Debug/fruits-debug.cmake
lib/fruits-1.0/Debug/fruits.cmake
lib/fruits-1.0/libfruits_Libd.a
lib/fruits-1.0/Release/fruits-release.cmake
lib/fruits-1.0/Release/fruits.cmake
include/fruits-1.0/fruits.h
However, when I try to do the following in the parent project:
find_package(fruits CONFIG REQUIRED)
I get the error:
CMake Error at CMakeLists.txt:21 (find_package):
Could not find a package configuration file provided by "fruits" with any
of the following names:
fruitsConfig.cmake
fruits-config.cmake
Those files are definitely not created or installed by the above CMakeLists.txt :/.
What am I doing wrong? How can I create a static library that provides such config file
so that I can use it (after installation) with a find_package(fruits CONFIG) ?
I think find_package() is for locating and using external and already installed components/libraries so you'll have to install the library first.
I have a project structured like below:
\build
\deps
\src
CMakeLists.txt
clean.cmake
There are some library dependencies located in deps. All these libraries have CMake install command.
After install, the output files will be put in build directory:
\build\fin\bin
\build\fin\lib
\build\fin\include
In my case, I will run cmake package to generate a binary install package, it generates something similar in _CPack_Packages.
The problem is I don't need lib and include to be included in the binary. But I haven't found a solution yet.
I tried the following methods:
CPACK_SOURCE_IGNORE_FILES and CPACK_SOURCE_STRIP_FILES.
These are for packaging the source I think, not working for my case.
Use post install script instal(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/clean.cmake") to remove the unnecessary files/dirs.
In clean.cmake, if(EXISTS "${CMAKE_INSTALL_PREFIX}/bin/ProjectA.lib") returned FALSE, there is nothing in the ${CMAKE_INSTALL_PREFIX} directory when the script was running, but I can find the files after it finished.
Try to modify install_manifest.txt. I haven't found a way to access this file correctly. I'm not sure this would work.
Thank you for your help!
Edit:
The install command like below:
install(TARGETS ${INS_TARGETS}
RUNTIME DESTINATION bin COMPONENT applications
LIBRARY DESTINATION lib COMPONENT libraries
ARCHIVE DESTINATION lib COMPONENT libraries
)
Try to use component install.
Add component label for each install command:
install(TARGET app DESTINATION ... COMPONENT applications)
install(TARGET library DESTINATION ... COMPONENT libraries)
install(FILES <headers> DESTINATION ... COMPONENT headers)
Turn on component install in CPack and list components you want to install:
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
set(CPACK_COMPONENTS_ALL applications)
include(CPack)
More information : http://www.cmake.org/Wiki/CMake:Component_Install_With_CPack