How to exclude files/dirs from CPack binary using CMake - cmake

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

Related

SET(CPACK_COMPONENTS_ALL ...) with ExternalProject Installing Additional Components

I use the ExtrenalProject cmake module to add 3rd party or internal dependencies to my build. I then use the CPack module with components to install only components from the current code base in the following manner.
set(CPACK_COMPONENTS_ALL
common-lib
common-include
common-depends
)
An example of one of these components declared in CMake is:
install(TARGETS common
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
COMPONENT common-lib
)
However, other projects added using add_subdirectory such as google test or other internal libraries also declare install targets. When I run
make package
and then list the contents of the .deb or .tar generated, I see the contents of other components not set in the CPACK_COMPONENTS_ALL variable.
What is the proper way to get CMake and CPack to only install the components requested?
You can just add the argument EXCLUDE_FROM_ALL to the end of the add_subdirectory() call. This will essentially disable all of the include() calls made in the added subdirectories.

CMake package configuration files for upstream projects using Qt5 problems

I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)

CMake subdirectory install/uninstall targets

I've got a project with two subdirectory projects (added with add_subdirectory), each with their own libraries, binaries and install/uninstall targets. So:
main_project
|
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with binary target, install()
|
|--project_a
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
|
|--project_b
|--CMakeLists.txt
|--src/
|--CMakeLists.txt (with library, install())
I'd like for the top-level project (main_project) to automatically install the libraries a and b (included in main_project from target_link_libraries()). So, I'd like to be able to go:
cd main_project/build
cmake ..
make
sudo make install
and have the main_project binary and project_a/b libraries installed automatically. I've tried this:
main_project/src/CMakeLists.txt
...
install(FILES main project_a project_b DESTINATION bin
LIBRARY DESTINATION lib)
but a cmake .. results in
install TARGETS given target "project_a" which does not exist in this directory.
as expected.
I've also tried specifying a path:
main_project/src/CMakeLists.txt
...
install(FILES main ${CMAKE_SOURCE_DIR}/project_a/ ${CMAKE_SOURCE_DIR}/project_b DESTINATION bin
LIBRARY DESTINATION lib)
which also complains that project_a/b are not in this directory (also expected, I guess?)
I've also tried installing the libraries "manually" with the FILES option in install(), and that works just fine, but that seems very kludgy considering there are perfectly good install()s in the subprojects.
One additional issue: since project_a and project_b also have uninstall() custom targets, I can't add an uninstall target to the main_project without CMake complaining about the custom target already existing. When I try adding an uninstall directive to the top dir CMakeLists:
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
But, since my project_a has an uninstall directive, I get:
CMake Error at CMakeLists.txt:37 (add_custom_target):
add_custom_target cannot create target "uninstall" because another
target with the same name already exists. The existing target is a
custom target created in source directory "/main_project/project_a".
See documentation for policy CMP0002 for more details.
So, how do I install and uninstall the necessary library files from my subproject alongside my main_project?
I found the problem. I am adding the subdirectory I want to install with EXCLUDE_FROM_ALL such that it doesn't build everything in the subdirectory, only the library I need. That flag seems to prevent the subdirectory install() from happening. Perhaps ExternalProject_Add is indeed the best way to go here...
Also, RE overriding custom targets, this worked for me: http://public.kitware.com/pipermail/cmake/2011-July/045269.html

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

Use external DLL in cmake build

I'm working on the cmake scripts for my project and I've run into a problem:
My project uses a 3rd party library (FreeImage), which has its own Makefile-based build system. I can build FreeImage just fine by simply running "make" (I'm using gnuwin32), which will build FreeImage using MinGW and produce:
FreeImage.lib
FreeImage.dll
Now my problem is twofold:
I want to execute "make" from my cmake script.
I want to link to the import lib (FreeImage.lib), and also make sure the DLL gets copied to the correct place so the EXE will run.
I know how to link to the LIB file, but I'm lost on the rest.
The folder structure is like this:
MyProject # main directory
MyProject/Libs/FreeImage # FreeImage root directory
MyProject/Libs/FreeImage/Dist # This is where FreeImage outputs go (LIB and DLL)
BTW: I'm running on Windows 7. I plan to build my project both with MSVC and MinGW.
Thanks!
EDIT:
I'm now trying to use ExternalProject_Add like so:
ExternalProject_Add(
FreeImage
PREFIX ./Libs/FreeImage
URL ./Libs/FreeImage
BUILD_COMMAND make
)
This gets me part of the way there, but doesn't totally work... it tries to configure things for me and tries to use nmake... ugh
In my opinion, there are two options:
In case you have put your FreeImage sources in your projects' source-tree, the easiest option may be to use the execute_process() command. Assuming FreeImage is in your projects' source-tree in "3rdparty/FreeImage/" you can do something like,
execute_process( COMMAND make WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage )
Optionally, you can copy the dll from 3rdParty/FreeImage/bin into you own bin directory. And then you can write a FreeImageConfig.cmake for importing the library:
add_library( FreeImage IMPORTED )
set_target_properties( FreeImage PROPERTIES IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/3rdParty/FreeImage/lib )
...
The other option is to make use of the ExternalProject module. You can also take a look at this article from Kitware for an overview of this module. In essence, you specify the full chain of commands needed to get the source, configure the build, build the source and install it. All in your own CMakeLists.txt