install specific pattern files with cpack and cmake - cmake

assuming i have the next structure in my project:
src_dir\a
src_dir\b\b2
src_dir\c\c2\c3
and in each folders i have few types of files (.txt, .lib, .dll....)
i want to install only the dll files in directory X, so i tried:
install(
DIRECTORY src_dir
DESTINATION X/
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
it does work fine but it give me the full structure of my original structure (and i only want the dll files in X directory). the output it:
X/a/a.dll
X/b/b2/b.dll
X/c/c2/c3/c.dll
and i want it to be like that a.dll, b.dll and c.dll will be in X (without any sub-folders).
is there a way to do it without giving the full paths to every dll file i have in my project?
Thanks :)

You should be able to get the behaviour you want by listing each directory, not necessarily each DLL. If you include a trailing forward slash at the end of the DIRECTORY, it will omit the directory name when copying to the destination. I'd expect something like the following to achieve what you want:
install(
DIRECTORY src_dir/a/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
install(
DIRECTORY src_dir/b/b2/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
install(
DIRECTORY src_dir/c/c2/c3/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)

Related

CMake Install directory files without keeping the full directory top

Let's say I have the directory X which includes many files and I want to install it to some destination:
INSTALL(DIRECTORY x
Destination ${DEST}
)
When I run this command, the folder structure would look like this:
${DEST}/x/a
${DEST}/x/b
${DEST}/x/c
...
How can I make CMake to "Unpack" the directory structure and my output like this?
${DEST}/a
${DEST}/b
${DEST}/c
...
When you append a / to your directory x the contents of the directory is copied to the DESTINATION, i.e.
install(DIRECTORY x/
DESTINATION ${DEST}
)
The DESTINATION keyword has to be given upper case.
See CMake's install documentation for further details.

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

CMake + CPack: Install entire directory (including subfolders)

I'm trying to create an installation package with CMake and CPack. Everything works fine, but I would like to reduce the amount of code drastically by copying my resources folder entirely with one call instead of one for every subfolder.
So far, I do component wise installation the following way:
set(RESOURCES_CALIBRATION_DIR resources/calibration)
file(GLOB RESOURCES_CALIBRATION "${CMAKE_SOURCE_DIR}/${RESOURCES_CALIBRATION_DIR}/*")
install(FILES ${RESOURCES_CALIBRATION} DESTINATION ${RESOURCES_CALIBRATION_DIR} COMPONENT ResourcesCalibration)
set(RESOURCES_CURSORS_DIR resources/cursors)
file(GLOB RESOURCES_CURSORS "${CMAKE_SOURCE_DIR}/${RESOURCES_CURSORS_DIR}/*")
install(FILES ${RESOURCES_CURSORS} DESTINATION ${RESOURCES_CURSORS_DIR} COMPONENT ResourcesCursors)
...
... (repeat for every folder of my resources folder)
set(CPACK_COMPONENTS_ALL applications ResourcesCalibration ResourcesCursors ...)
set(CPACK_COMPONENT_RESOURCESCALIBRATION_GROUP "resources")
set(CPACK_COMPONENT_RESOURCESCURSORS_GROUP "resources")
...
...
Is there a clean way to copy / install the entire resources folder including all subfolders?
Command flow install(DIRECTORY) exists specifically for installing directory with its subdirectories and files.
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources/
DESTINATION resources
COMPONENT ResourcesCursors)
or even
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources
DESTINATION .
COMPONENT ResourcesCursors)
will copy resource directory in the source tree to the installation directory. See documentation on install for more info.

Install all files in a directory except folders in CMake

I want to install all files under a folder called scfg which contains .cfg, .xml files, and folders to another location which contains scfg. The code below installs correctly.
file(GLOB config_files "scfg/*.cfg")
install(FILES ${config_files} DESTINATION scfg)
file(GLOB xml_files "scfg/*.xml")
install(FILES ${xml_files} DESTINATION scfg)
But it is possible that there will be more files with types other than .cfg and .xml in the future. To prevent changing this file frequently, I am looking for a more generic solution, such as installing all file types other than folders. I have heard about the EXCLUDE keyword. But I don't know what PATTERN I should use for folders.
It should exclude subdirectories explicitly and then all other files will be installed correctly as usual.
install(DIRECTORY scfg/ DESTINATION scfg
PATTERN "scfg/config/" EXCLUDE
PATTERN "scfg/xml/" EXCLUDE
)

How can I install a hierarchy of files using CMake?

I've created a list of files using:
file(GLOB_RECURSE DEPLOY_FILES "${PROJECT_SOURCE_DIR}/install/*")
I want to install all of these files in /usr/myproject/, but I want to maintain the file tree on the installed folder:
install/junk
install/other/junk2
install/other/junk3
If I use:
install(FILES ${DEPLOY_FILES} DESTINATION "usr/myproject")
All the files end up in /usr/myproject as:
/usr/myproject/junk
/usr/myproject/junk2
/usr/myproject/junk3
How can I make the install command keep track of relative paths?
I've worked around the issue by doing it manually in a for loop:
set(BASE "${PROJECT_SOURCE_DIR}/install")
foreach(ITEM ${DEPLOY_FILES})
get_filename_component(ITEM_PATH ${ITEM} PATH)
string(REPLACE ${BASE} "" ITEM_PATH ${ITEM_PATH})
install(FILES ${ITEM} DESTINATION "usr/myproject${ITEM_PATH}")
endforeach()
...but this is annoying to do. Surely there's an easier way?
(I can't see anything in the install documentation though...)
The simplest way to install everything from a given directory is:
install(DIRECTORY mydir/ DESTINATION dir/newname)
Trailing '/' is significant.
Without it mydir would be installed to newname/mydir.
From the CMake documentation:
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.
I am assuming you have a list of files, let's say INCLUDE_FILES. Possibly a selection of files spread over a number of subdirectories, e.g. header files from across the source tree, as opposed to everything in a single subdir like in the other answers.
You can loop over the file list and use get_filename_component() to extract the directory part, then use that in a subsequent install() to set the DESTINATION subdirectory:
foreach ( file ${INCLUDE_FILES} )
get_filename_component( dir ${file} DIRECTORY )
install( FILES ${file} DESTINATION include/${dir} )
endforeach()
Done. ;-)
Edit: If all the files you want to install that way match a particular file pattern -- e.g. "all header files" -- then brno's answer has the edge over this one.
Use:
INSTALL( DIRECTORY <directory> DESTINATION usr/myproject )
(See here for details: http://www.cmake.org/cmake/help/v2.8.8/cmake.html#command:install)
INSTALL( DIRECTORY ... ) preserves the directory structure. But, if you use install as <directory>, you would end up with usr/myproject/install/.... which is not what you want.
There are two ways to do this:
Use INSTALL( FILES .... DESTINATION usr/myproject) to install the files that lie directly in install/, then use INSTALL( DIRECTORY .... DESTINATION usr/myproject) and manually list the directories to install.
Use your globbing command in your original post, and then determine which entries are files, which are directories, move the directory entries to a separate list, feed the lists to INSTALL( FILES ...) and INSTALL( DIRECTORY ...), respectively.
file(GLOB DEPLOY_FILES_AND_DIRS "${PROJECT_SOURCE_DIR}/install/*")
foreach(ITEM ${DEPLOY_FILES_AND_DIRS})
IF( IS_DIRECTORY "${ITEM}" )
LIST( APPEND DIRS_TO_DEPLOY "${ITEM}" )
ELSE()
LIST( APPEND FILES_TO_DEPLOY "${ITEM}" )
ENDIF()
endforeach()
INSTALL( FILES ${FILES_TO_DEPLOY} DESTINATION usr/myproject )
INSTALL( DIRECTORY ${DIRS_TO_DEPLOY} DESTINATION usr/myproject )
Note: Depending on the type of files you install, other INSTALL( ...) commands might be more appropriate (for example, INSTALL( TARGETS .... ) to install your libraries/executables.
Since globbing is not recommended, and running loops in CMakeLists.txt files is clunky, a pattern matching option of DIRECTORY did the trick for me.
install(DIRECTORY src/ DESTINATION include FILES_MATCHING PATTERN "*.h")
This took the entire folder structure inside src/ and reproduced it within <INSTALL_DIR>/include, header files only.