install() with FILES_MATCHING PATTERN ignoring pattern and installing all - regex

I'm currently having a problem with the install() function of CMake v3.13.4. My code is as follows:
install(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DESTINATION ${CMAKE_INSTALL_PREFIX}
FILES_MATCHING PATTERN "*.cfg"
)
My understanding is that CMake will copy all files matching this pattern to my location given by ${CMAKE_INSTALL_PREFIX}, but all the subfolders in my current directory also get copied. Also, how is it possible to copy more than one file-ending pattern to the destination? Simply putting *.cfg | *.xyz or *.cfg || *.xyz does not work.
Edit:
Also tried to replace the FILES_MATCHING PATTERN with:
FILES_MATCHING REGEX "[a-zA-Z0-9]*.ate|[a-zA-Z0-9]*.reserved"
which only copies files *.reserved AND all folders again.

If any of the subfolders in your directory also contain .cfg files, CMake will copy those as well. You need to explicitly tell CMake to ignore these using the EXCLUDE directive. Also, you can concatenate multiple PATTERN directives for CMake to search for and install:
install(
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DESTINATION ${CMAKE_INSTALL_PREFIX}
FILES_MATCHING
PATTERN "*.cfg"
PATTERN "*.xyz"
PATTERN "subFolderA" EXCLUDE
)

Related

Force execution of CMake install directive

I have a CMakeLists.txt where I copy files in a specific order but the execution order seems random:
#First Installation
install(DIRECTORY ${SIT_AW_FIRST_WORKSPACE_DIR}/ DESTINATION ${WS_DESTINATION_DIR})
#Second Installation that should overwrite a subset of files
install(DIRECTORY ${SIT_AW_SECOND_WORKSPACE_DIR}/ DESTINATION ${WS_DESTINATION_DIR})
Output :
-- Installing: /opt/FOO/share/baz/xml/Login.xml
-- Up-to-date: /opt/FOO/share/baz/xml/Login.xml
The second file will not overwrite the first because they have the same timestamp and the same name, but they have different size. Is there a way to force the copy?
I think you may have better success by using the PATTERN and EXCLUDE options instead of trying to overwrite one file with another. You could try something like this:
#First Installation
install(DIRECTORY ${SIT_AW_FIRST_WORKSPACE_DIR}/ DESTINATION ${WS_DESTINATION_DIR}
PATTERN "Login.xml" EXCLUDE)
#Second Installation that should overwrite a subset of files
install(DIRECTORY ${SIT_AW_SECOND_WORKSPACE_DIR}/ DESTINATION ${WS_DESTINATION_DIR})
You can read the CMake docs here with the specifics here: https://cmake.org/cmake/help/v3.18/command/install.html#installing-directories

Create CMake target that copies files/dirs but excludes some items

I am trying to generate a CMake target for a C++ project using add_custom_target that copies the contents of the directory in which the CMakeLists.txt resides into ${CMAKE_BINARY_DIR}, but excludes a given list of files.
While it looks like a quite easy task, I'm facing problems here. My attempts so far:
1) Generate a list of all files/dirs, remove the items to be excluded and use the CMake copy command:
file(GLOB files_to_copy LIST_DIRECTORIES TRUE *)
list(REMOVE_ITEM files_to_copy
${CMAKE_CURRENT_SOURCE_DIR}/file_to_exclude.txt
${CMAKE_CURRENT_SOURCE_DIR}/dir_to_exclude
# ...
)
add_custom_target(my-target
COMMAND ${CMAKE_COMMAND} -E copy ${files_to_copy} ${CMAKE_BINARY_DIR}
)
Problems:
Removing items this way works on a string comparison level, which could lead to problems when using symbolic links, for example
The copy command line tool apparently supports copying directories, however it doesn't seem to work on my machine, therefore directories do not get copied.
2) Use the file command to copy the files, excluding some files
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION ${CMAKE_BINARY_DIR}
PATTERN "file_to_exclude.txt" EXCLUDE
PATTERN "dir_to_exclude" EXCLUDE
)
Problems:
This does exactly what I want, except that the command is not bound to a target and therefore is always executed. But I only need the copy operation to be a target.
Is there any possibility to bind the file(COPY ...) command to a target? Or any other straightforward solution to achieve what I want?
Please note that I only want to use CMake built-in tools and not execute any OS-specific shell commands (working on a cross-platform project).
CMake scripting commands work only in CMake context and are executed immediately.
But a COMMAND in add_custom_command (or add_custom_target) is executed in the context of a build tool (e.g. Makefile), not in CMake context.
However, you may put CMake scripting commands into separate CMake script, and call this script from the COMMAND. This solution has the same platform-independent properties as CMakeLists.txt itself.
You may parameterize separate script either:
With configure_file CMake command.
By passing -D parameters to CMake when call the script.
The first approach is quite simple: you write the script as would you write CMakeLists.txt itself. But it generates additional files for every parametrization set.
The second approach is useful for multi-purpose (or multi-usable) scripts, as it doesn't create additional copy of the script for every usage. But it requires some design of the parameters.
Using 'configure_file'
copy_sources.cmake.in (as if commands are written in CMakeLists.txt):
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/" DESTINATION ${CMAKE_BINARY_DIR}
PATTERN "file_to_exclude.txt" EXCLUDE
PATTERN "dir_to_exclude" EXCLUDE
)
CMakeLists.txt:
# Instantiate the parameterized script in the binary directory.
configure_file(copy_sources.cmake.in copy_sources.cmake)
add_custom_target(my-target
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/copy_sources.cmake
)
Using '-D' parameters
copy_sources.cmake:
# Expect the script to be called from the source directory.
# This saves one parameter.
#
# DEST_DIR denotes the directory for copy to.
file(COPY "${CMAKE_SOURCE_DIR}/" DESTINATION ${DEST_DIR}
PATTERN "file_to_exclude.txt" EXCLUDE
PATTERN "dir_to_exclude" EXCLUDE
)
CMakeLists.txt:
add_custom_target(my-target
COMMAND ${CMAKE_COMMAND}
-DDEST_DIR=${CMAKE_BINARY_DIR} # all '-D' options should preceed '-P' one
-P ${CMAKE_CURRENT_SOURCE_DIR}/copy_sources.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} # The script assumes proper current directory
)

CMake change forced DESTINATION directory name (install target)

I'm trying to add install target to my library. I have my source code & header files located in sub-directories under src/.
Relevant chunk of my CMakeLists.txt file:
install(
TARGETS "${PROJECT_NAME}"
EXPORT ionir-config LIBRARY
DESTINATION ${CMAKE_INSTALL_LIBDIR} # Destination is relative to ${CMAKE_INSTALL_PREFIX}.
)
install(
EXPORT ionir-config
NAMESPACE ionir::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ionir
)
install(
DIRECTORY src
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h" PATTERN "LICENSE" # Match only header files & LICENSE file.
)
The problem is that once installed, the output directory's name is src:
I would like it to be ionir, otherwise I'd have to import files like this:
#include <ionir/src/something/file.h>
^^^
How can I accomplish this?
For avoid adding directory name to installation path, terminate the directory with a slash (/):
install(
DIRECTORY src/
...
)
This is explicitly stated in the documentation for install command:
The last component of each directory name is appended to the destination directory but a trailing slash may be used to avoid this because it leaves the last component empty.

How to transfer version number from a git tag to the CPack-generated source package?

In a CMake project, I am using git tags for version numbers. Using the approach from https://github.com/iPenguin/version_git, I am able to get the version number into the source codes (that is, CMake creates a version.cpp file with a const string containing the version number that I can then use in my C++ source codes). The problem is that when I create a source package using CPack, I exclude the .git directory and when compiling the sources extracted from the package, the version number is not available.
How to make CPack put the version number into the source package?
I have the following requirements:
I do not want the build directory to be included in my source package. It is important to note that I do out-of-source builds from a directory under the project root. That is, if my toplevel CMakeLists.txt is in directory my_project, then I run "cmake .." and "make" in directory my_project/build.
I do not want to include the .git directory in my source package.
I want all the files generated by cmake and "make package_source" to be inside the build directory. Additionally, I don't want cmake to modify or delete any file outside of the build directory.
I do not want to use undocumented behavior of cmake and cpack, in particular the paths used by cpack.
So far I was not able to find a solution that would satisfy all my requirements. Here is what I have tried:
I let cmake create a file versionForSourcePackage.cmake, which, when later included by cmake, will set the VERSION variable. Then I want to put this file into the source package, so that when cmake is run in the extracted package, it will have the VERSION variable set. This file is created under the build directory, but I do not know how to properly let CPack copy it to the source packages.
The first possibility is a slight modification of https://github.com/iPenguin/version_git, but it does not satisfy my requirement number 4. Full example is at https://github.com/josefcibulka/version_git.
When building from repository, I get the version number from git and save it in ${PROJECT_BINARY_DIR}/versionForSourcePackage.cmake. Then I use CPACK_INSTALL_COMMANDS to let CPack copy this file to ${PROJECT_BINARY_DIR}/_CPack_Packages/Linux-Source/${CPACK_SOURCE_GENERATOR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}/ so that it is included in the package. This violates the requirement number 4 and moreover, if I want to create both TGZ and ZIP packages in the future, I need to make some changes. Is there some variable that I could use within CPACK_INSTALL_COMMANDS to get the path to the directory where CPack is preparing the contents of the package?
CMakeLists.txt looks like:
cmake_minimum_required(VERSION 2.8)
project("version_from_git")
# Appends the cmake/modules path to MAKE_MODULE_PATH variable.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
# When in the extracted package, use the previously generated file, otherwise get the current version from git.
if(EXISTS "${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake")
include("${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake")
else()
include(GetGitRevisionDescription)
git_describe(VERSION --tags --dirty=-dirty)
endif()
# Parse the version information into pieces.
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VERSION}")
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+(.*)" "\\1" VERSION_SHA1 "${VERSION}")
set(VERSION_SHORT "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}")
# The following will copy the version file to the source package.
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_SHORT}-Source")
set(CPACK_INSTALL_COMMANDS "${CMAKE_COMMAND} -E make_directory \
${PROJECT_BINARY_DIR}/_CPack_Packages/Linux-Source/${CPACK_SOURCE_GENERATOR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}/"
"${CMAKE_COMMAND} -E copy \
${PROJECT_BINARY_DIR}/versionForSourcePackage.cmake \
${PROJECT_BINARY_DIR}/_CPack_Packages/Linux-Source/${CPACK_SOURCE_GENERATOR}/${CPACK_SOURCE_PACKAGE_FILE_NAME}/")
# Exclude the build and .git directory from the source package.
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_SOURCE_DIR}/.git/;${PROJECT_BINARY_DIR}/;${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/version.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
# Prepare the versionForSourcePackage.cmake file that will be included in the source package.
configure_file(
${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake.in
${PROJECT_BINARY_DIR}/versionForSourcePackage.cmake #ONLY)
set(version_file "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
set(source_files "${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp")
#Add the version_file to the project build.
add_executable(${PROJECT_NAME} ${source_files} ${version_file})
The file versionForSourcePackage.cmake.in:
set(VERSION "v#VERSION_SHORT#")
The second possibility is the approach used at https://github.com/lcw/cmake_git_version. Full example is in the second_possibility branch in https://github.com/josefcibulka/version_git. The file versionForSourcePackage.cmake is placed to the subdirectory version_file of the build directory and this directory is added among CPACK_SOURCE_INSTALLED_DIRECTORIES. This works well when the project and build directory are at the same level.
The problem is that if the build directory is under the project directory, I add the build directory to CPACK_SOURCE_IGNORE_FILES to satisfy requirement 1. Then, even when I set CPACK_SOURCE_INSTALLED_DIRECTORIES to include the version_file directory, it will be ignored. It can be done so that I ignore only everything in the build directory except for the version_file directory. Then the build directory in the source package contains only the version_file directory, which is better than the whole build directory, but still not perfect.
Update: It seems that requirement 4 is not satisfied either, because I cannot find CPACK_SOURCE_INSTALLED_DIRECTORIES in the CMake documentation.
The differences from the first possibility are, in CMakeLists.txt:
# The following will transfer the version from git to the source package.
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${PROJECT_SOURCE_DIR};/;${PROJECT_BINARY_DIR}/version_file;/")
# Exclude the build and .git directory from the source package.
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_SOURCE_DIR}/.git/;${PROJECT_BINARY_DIR}/([^v].*|v[^e].*|ve[^r].*|ver[^s].*|vers[^i].*|vers[^i].*|versi[^o].*|versio[^n].*|version[^_].*|version_[^f].*|version_f[^i].*|version_fi[^l].*|version_fil[^e].*);${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/version.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
configure_file(
${PROJECT_SOURCE_DIR}/versionForSourcePackage.cmake.in
${PROJECT_BINARY_DIR}/version_file/versionForSourcePackage.cmake #ONLY)
At the end, I am using a modification of the first possibility, but the issues are solved only partially.
Instead of CPACK_INSTALL_COMMANDS, I use CPACK_INSTALL_SCRIPT and a CMake script. This script is executed for every package that is being created and the nice thing is that inside of this script, CMAKE_CURRENT_BINARY_DIR points to the directory where the contents of the package are being gathered. That is, whatever I copy to that directory will get inside the package.
This, however, looks to be an undocumented behavior of CMAKE_CURRENT_BINARY_DIR. For example, the CMAKE_BINARY_DIR and PROJECT_BINARY_DIR are empty when used in a CMake script executed by CPack. So maybe in some other version of CMake, CMAKE_CURRENT_BINARY_DIR will also be empty when executed by CPack.
Another issue is that I do want the version file to be copied only to source packages and not to binary packages. The way how I do the distinction is that if CMAKE_CURRENT_BINARY_DIR ends with "Source", I assume that the script is running during the preparation of a source package.
Full example is in the using_cpack_install_script branch of https://github.com/josefcibulka/version_git. The changed parts of CMakeLists.txt:
# The following will transfer the version from git to the source package.
set(CPACK_INSTALL_SCRIPT "${CMAKE_BINARY_DIR}/versionNumberToPackage.cmake")
configure_file(${CMAKE_SOURCE_DIR}/versionNumberToPackage.cmake.in
${CMAKE_BINARY_DIR}/versionNumberToPackage.cmake #ONLY)
The contents of versionNumberToPackage.cmake.in are:
# Copies VersionForSourcePackage.cmake to the source package (it should not be copied to binary package).
# Detection if this is the source package is that the path ends with "Source" and an optional slash.
if("${CMAKE_CURRENT_BINARY_DIR}" MATCHES "Source/?$")
file(COPY #CMAKE_BINARY_DIR#/versionForSourcePackage.cmake DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
endif()

remove INSTALL project from llvm built using cmake

I am using cmake to build llvm and the problem is that annoying little INSTALL project getting generated. I don't know how to remove that project.I don't want to install my built components. Can anybody help me not generating INSTALL project through cmake ? I tried to edit the CmakeLists.txt provided by llvm and commented out the install specific lines as follows :
#install(DIRECTORY include/
# DESTINATION include
# FILES_MATCHING
# PATTERN "*.def"
# PATTERN "*.h"
# PATTERN "*.td"
# PATTERN "*.inc"
# PATTERN "LICENSE.TXT"
# PATTERN ".svn" EXCLUDE
# )
#install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
# DESTINATION include
# FILES_MATCHING
# PATTERN "*.def"
# PATTERN "*.h"
# PATTERN "*.gen"
# PATTERN "*.inc"
# Exclude include/llvm/CMakeFiles/intrinsics_gen.dir, matched by "*.def"
# PATTERN "CMakeFiles" EXCLUDE
# PATTERN ".svn" EXCLUDE
# )
But that doesn't help either. Any inputs ?
There are several places in the llvm sources where CMake's install command is used. You need to remove every instance to get rid of the INSTALL target entirely.
To find these places, try doing a recursive search of all .txt files and all .cmake files:
cd <path to root of llvm sources>
findstr /ins install( *.txt
findstr /ins install( *.cmake