MIDL compiler from CMAKE - cmake

I did as described
here
set(MIDL_OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/IFace.h
${CMAKE_CURRENT_BINARY_DIR}/GUIDS.c
${CMAKE_CURRENT_BINARY_DIR}/Proxy.c
${CMAKE_CURRENT_BINARY_DIR}/ProxyDll.c
)
set(MIDL_FILE
${CMAKE_CURRENT_LIST_DIR}/BookSku.idl
)
add_custom_command(
OUTPUT ${MIDL_OUTPUT}
COMMAND midl /h IFace.h /iid GUIDS.c /proxy Proxy.c /dlldata ProxyDll.c
${MIDL_FILE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${MIDL_FILE}
MAIN_DEPENDENCY ${MIDL_FILE}
VERBATIM
)
The output from the build of the IDL file is dependent many of the headers, so it needs to track if these have changed to determine if it should rebuild the type library. But when you change files, and pushing "Build" the project in VS2017 is not rebuilt. Need to push "Rebuild".
How to make file changes tracked?

Answer in Cmake.org
DEPENDS:
Specify files on which the command depends. Each argument is converted to a dependency as follows:

Related

How to copy files to the executable output directory in CMake [duplicate]

We use CMake for generating the Visual Studio files of our sources in our SVN. Now my tool requires some DLL files to be in the same folder as the executable. The DLL files are in a folder alongside the source.
How can I change my CMakeLists.txt such that the generated Visual Studio project will either have already the particular DLL files in the release/debug folders or will copy them upon compilation?
I'd use add_custom_command to achieve this along with cmake -E copy_if_different.... For full info run
cmake --help-command add_custom_command
cmake -E
So in your case, if you have the following directory structure:
/CMakeLists.txt
/src
/libs/test.dll
and your CMake target to which the command applies is MyTest, then you could add the following to your CMakeLists.txt:
add_custom_command(TARGET MyTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/libs/test.dll" # <--this is in-file
$<TARGET_FILE_DIR:MyTest>) # <--this is out-file path
If you just want the entire contents of the /libs/ directory copied, use cmake -E copy_directory:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs"
$<TARGET_FILE_DIR:MyTest>)
If you need to copy different dlls depending upon the configuration (Release, Debug, eg) then you could have these in subdirectories named with the corresponding configuration: /libs/Release, and /libs/Debug. You then need to inject the configuration type into the path to the dll in the add_custom_command call, like this:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I put these lines in my top-level CMakeLists.txt file. All the libraries and executables compiled by CMake will be placed in the top level of the build directory so that the executables can find the libraries and it is easy to run everything.
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
Note that this doesn't solve the OP's problem of copying precompiled binaries from the project's source directory.
I've had this problem today when tried to make a Windows build of my program. And I ended up doing some research myself since all these answers didn't satisfy me. There were three main issues:
I wanted debug builds to be linked with debug versions of libraries
and release builds to be linked with release builds of libraries,
respectively.
In addition to that, I wanted correct versions of DLL files
(Debug/Release) to be copied to output directories.
And I wanted to achieve all this without writing complex and fragile scripts.
After browsing some CMake manuals and some multiplatform projects at github I've found this solution:
Declare your library as a target with "IMPORTED" attribute, reference its debug and release .lib and .dll files.
add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")
Link this target with your project as usual
target_link_libraries(YourProg sdl2 ...)
Make custom build step to copy dll file to its destination if it has been altered somehow since previous build
add_custom_command ( TARGET YourProg POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
For Windows users, there is a new generator expression $<TARGET_RUNTIME_DLLS:tgt> in CMake 3.21+ and you could use this official snippet for copying all of the DLLs that a target depends on.
find_package(foo REQUIRED)
add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
COMMAND_EXPAND_LISTS
)
Moving files during build using install
I had this issue trying to follow the CMake official tutorial on Step 9. This was the location of the file I wanted to move:
src
|_build
|_Debug
- `MathFunctions.dll`
This was the location I wanted the file to be in:
src
|_build
|_install
|_bin
- `MathFunctions.dll`
Since this DLL was generated as a shared library, all I did was to include this line in the CMakeLists.txt in the subdirectory that contained the source code for the library src/Mathfunctions/CMakeLists.txt
install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)
Thanks to your answers I could think on this one. Is just one line, so I think is ok. The $<CONFIG> can have two values Debug or Release Depending on how the project is built, as the original question required.
You can also use the command find_library:
find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")
With a defined EXECUTABLE_PATH, for instance:
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
you could move the .dll files that your executable need, with
file(COPY ${<some_var>}
DESTINATION ${EXECUTABLE_OUTPUT_PATH})
An addendum to the accepted answer, added as a separate answer so I get code formatting:
If you are building your dlls in the same project, they will usually be in Release, Debug, etc. directories. You'll have to use the Visual Studio environment variables to correctly copy them. e.g.:
"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"
for the source and
"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"
for the destination. Note the escaping!
You can't use the CMake CMAKE_BUILD_TYPE variable for the configuration since it's resolved at VS project generation time and will always be whatever the default is.
This is useful for one of them
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/lib CACHE
PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/bin CACHE
PATH "Directory where .exe and .dll files are dumped." FORCE)
1. The most correct way: TARGET_RUNTIME_DLLS (CMake >= 3.21)
install(FILES $<TARGET_RUNTIME_DLLS:your_exe_here> TYPE BIN)
For this to work, your dependencies' CMake modules have to be well-written. In other words, they use CMake 3 targets with all their target properties set up correctly. If they set up everything right, all transitively-linked DLLs will be automagically gathered up and installed alongside your exe.
A big difference between this and the straight-up copy-the-files approach is that, because it goes through install(), CMake will actually know about them as files to-be-installed. CPack will know about your DLLs and include them in any installer you generate with it. CMake will automatically adjust what type of DLL (release vs debug) to match your target exe.
This is where CMake will be headed more in the future, and the way you should prefer if you have a choice.
2. The second most correct way: RUNTIME_DEPENDENCIES (CMake >= 3.21)
install(TARGETS your_exe_here
RUNTIME ARCHIVE LIBRARY RUNTIME FRAMEWORK BUNDLE PUBLIC_HEADER RESOURCE)
install(TARGETS your_exe_here
COMPONENT your_exe_here
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES $<TARGET_FILE_DIR:your_exe_here>)
The key here is RUNTIME_DEPENDENCIES.
Internally, RUNTIME_DEPENDENCIES calls file(GET_RUNTIME_DEPENDENCIES), which scans your executable binary, tries very hard to exactly replicate what actual dependency resolution would look like, and write down all the DLLs mentioned along the way. These are passed back up to install().
What this means is that this doesn't depend on your dependencies' CMake modules having their target properties set up correctly. Your actual executable binary is scanned. Everything will get picked up.
3. The third most correct way: install(DIRECTORY)
install(
DIRECTORY "${DIR_CONTAINING_YOUR_DLLS}"
TYPE BIN
FILES_MATCHING REGEX "[^\\\\/.]\\.[dD][lL][lL]$"
)
To use, put the DLLs appropriate for your build in $DIR_CONTAINING_YOUR_DLLS.
The trick here is that, unlike install(FILES), install(DIRECTORY) doesn't care what specific files are in the directory until install time. That means now we have all of configure time and compile time to get a list of your DLLs and stuff them in $DIR_CONTAINING_YOUR_DLLS. As long as the DLL files are in $DIR_CONTAINING_YOUR_DLLS by install time, install(DIRECTORY) will pick them up.
If you choose this method, it's becomes your responsibility to match DLLs to your build config. (Consider: static vs dynamic, debug vs release, import lib version vs DLL version, libs with optional multithreading, forgetting to remove DLLs you don't need anymore.)
If you choose this method, you might want to automate DLL finding and matching using something like what vcpkg's applocal.ps1 does.
Hint for vcpkg
If you use vpckg with VCPKG_APPLOCAL_DEPS enabled, vcpkg will locate and copy your DLLs into your $CMAKE_RUNTIME_OUTPUT_DIRECTORY for you, but without going through install(). You need to use the install(DIRECTORY) trick to get CMake to pick them up.
(Internally, vcpkg uses dumpbin, llvm-objdump, and objdump to scan your executable binary to get these filenames.)
You probably need to add custom target and make it depend on one of your executable targets.
To copy file using above function use:
COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
The following command from the currently top rated answer depends on the output being put in /libs/.
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I use the below command to do the copy, which works for me everywhere. Note that I'm only copying the output dll here, not the entire directory. Also note that I'm hard coding a destination /bin/ directory, which is specific to this project. But I wanted to share the $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}> syntax, which I think is neat:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
${CMAKE_CURRENT_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>)
I'm a CMake beginner, but still I wanted to shared my experience. In my case I needed a post-install copy so that all my binaries are in.
In the case of third-party binary that can be imported within CMake, the following works for me:
find_package( dependency REQUIRED )
if( MSVC )
# If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
# Create a bin directory in the install folder
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/)
# Copy the shared lib file
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()
Obviously IMPORTED_LOCATION_RELEASE can have variants depending on how the shared library was built / installed. Could be IMPORTED_LOCATION_DEBUG.
Maybe there's a better way to get that property name, I don't know.

CMake configure_file and Debug/Release directory [duplicate]

We use CMake for generating the Visual Studio files of our sources in our SVN. Now my tool requires some DLL files to be in the same folder as the executable. The DLL files are in a folder alongside the source.
How can I change my CMakeLists.txt such that the generated Visual Studio project will either have already the particular DLL files in the release/debug folders or will copy them upon compilation?
I'd use add_custom_command to achieve this along with cmake -E copy_if_different.... For full info run
cmake --help-command add_custom_command
cmake -E
So in your case, if you have the following directory structure:
/CMakeLists.txt
/src
/libs/test.dll
and your CMake target to which the command applies is MyTest, then you could add the following to your CMakeLists.txt:
add_custom_command(TARGET MyTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/libs/test.dll" # <--this is in-file
$<TARGET_FILE_DIR:MyTest>) # <--this is out-file path
If you just want the entire contents of the /libs/ directory copied, use cmake -E copy_directory:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs"
$<TARGET_FILE_DIR:MyTest>)
If you need to copy different dlls depending upon the configuration (Release, Debug, eg) then you could have these in subdirectories named with the corresponding configuration: /libs/Release, and /libs/Debug. You then need to inject the configuration type into the path to the dll in the add_custom_command call, like this:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I put these lines in my top-level CMakeLists.txt file. All the libraries and executables compiled by CMake will be placed in the top level of the build directory so that the executables can find the libraries and it is easy to run everything.
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
Note that this doesn't solve the OP's problem of copying precompiled binaries from the project's source directory.
I've had this problem today when tried to make a Windows build of my program. And I ended up doing some research myself since all these answers didn't satisfy me. There were three main issues:
I wanted debug builds to be linked with debug versions of libraries
and release builds to be linked with release builds of libraries,
respectively.
In addition to that, I wanted correct versions of DLL files
(Debug/Release) to be copied to output directories.
And I wanted to achieve all this without writing complex and fragile scripts.
After browsing some CMake manuals and some multiplatform projects at github I've found this solution:
Declare your library as a target with "IMPORTED" attribute, reference its debug and release .lib and .dll files.
add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")
Link this target with your project as usual
target_link_libraries(YourProg sdl2 ...)
Make custom build step to copy dll file to its destination if it has been altered somehow since previous build
add_custom_command ( TARGET YourProg POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
For Windows users, there is a new generator expression $<TARGET_RUNTIME_DLLS:tgt> in CMake 3.21+ and you could use this official snippet for copying all of the DLLs that a target depends on.
find_package(foo REQUIRED)
add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
COMMAND_EXPAND_LISTS
)
Moving files during build using install
I had this issue trying to follow the CMake official tutorial on Step 9. This was the location of the file I wanted to move:
src
|_build
|_Debug
- `MathFunctions.dll`
This was the location I wanted the file to be in:
src
|_build
|_install
|_bin
- `MathFunctions.dll`
Since this DLL was generated as a shared library, all I did was to include this line in the CMakeLists.txt in the subdirectory that contained the source code for the library src/Mathfunctions/CMakeLists.txt
install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)
Thanks to your answers I could think on this one. Is just one line, so I think is ok. The $<CONFIG> can have two values Debug or Release Depending on how the project is built, as the original question required.
You can also use the command find_library:
find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")
With a defined EXECUTABLE_PATH, for instance:
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
you could move the .dll files that your executable need, with
file(COPY ${<some_var>}
DESTINATION ${EXECUTABLE_OUTPUT_PATH})
An addendum to the accepted answer, added as a separate answer so I get code formatting:
If you are building your dlls in the same project, they will usually be in Release, Debug, etc. directories. You'll have to use the Visual Studio environment variables to correctly copy them. e.g.:
"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"
for the source and
"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"
for the destination. Note the escaping!
You can't use the CMake CMAKE_BUILD_TYPE variable for the configuration since it's resolved at VS project generation time and will always be whatever the default is.
This is useful for one of them
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/lib CACHE
PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/bin CACHE
PATH "Directory where .exe and .dll files are dumped." FORCE)
1. The most correct way: TARGET_RUNTIME_DLLS (CMake >= 3.21)
install(FILES $<TARGET_RUNTIME_DLLS:your_exe_here> TYPE BIN)
For this to work, your dependencies' CMake modules have to be well-written. In other words, they use CMake 3 targets with all their target properties set up correctly. If they set up everything right, all transitively-linked DLLs will be automagically gathered up and installed alongside your exe.
A big difference between this and the straight-up copy-the-files approach is that, because it goes through install(), CMake will actually know about them as files to-be-installed. CPack will know about your DLLs and include them in any installer you generate with it. CMake will automatically adjust what type of DLL (release vs debug) to match your target exe.
This is where CMake will be headed more in the future, and the way you should prefer if you have a choice.
2. The second most correct way: RUNTIME_DEPENDENCIES (CMake >= 3.21)
install(TARGETS your_exe_here
RUNTIME ARCHIVE LIBRARY RUNTIME FRAMEWORK BUNDLE PUBLIC_HEADER RESOURCE)
install(TARGETS your_exe_here
COMPONENT your_exe_here
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES $<TARGET_FILE_DIR:your_exe_here>)
The key here is RUNTIME_DEPENDENCIES.
Internally, RUNTIME_DEPENDENCIES calls file(GET_RUNTIME_DEPENDENCIES), which scans your executable binary, tries very hard to exactly replicate what actual dependency resolution would look like, and write down all the DLLs mentioned along the way. These are passed back up to install().
What this means is that this doesn't depend on your dependencies' CMake modules having their target properties set up correctly. Your actual executable binary is scanned. Everything will get picked up.
3. The third most correct way: install(DIRECTORY)
install(
DIRECTORY "${DIR_CONTAINING_YOUR_DLLS}"
TYPE BIN
FILES_MATCHING REGEX "[^\\\\/.]\\.[dD][lL][lL]$"
)
To use, put the DLLs appropriate for your build in $DIR_CONTAINING_YOUR_DLLS.
The trick here is that, unlike install(FILES), install(DIRECTORY) doesn't care what specific files are in the directory until install time. That means now we have all of configure time and compile time to get a list of your DLLs and stuff them in $DIR_CONTAINING_YOUR_DLLS. As long as the DLL files are in $DIR_CONTAINING_YOUR_DLLS by install time, install(DIRECTORY) will pick them up.
If you choose this method, it's becomes your responsibility to match DLLs to your build config. (Consider: static vs dynamic, debug vs release, import lib version vs DLL version, libs with optional multithreading, forgetting to remove DLLs you don't need anymore.)
If you choose this method, you might want to automate DLL finding and matching using something like what vcpkg's applocal.ps1 does.
Hint for vcpkg
If you use vpckg with VCPKG_APPLOCAL_DEPS enabled, vcpkg will locate and copy your DLLs into your $CMAKE_RUNTIME_OUTPUT_DIRECTORY for you, but without going through install(). You need to use the install(DIRECTORY) trick to get CMake to pick them up.
(Internally, vcpkg uses dumpbin, llvm-objdump, and objdump to scan your executable binary to get these filenames.)
You probably need to add custom target and make it depend on one of your executable targets.
To copy file using above function use:
COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
The following command from the currently top rated answer depends on the output being put in /libs/.
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I use the below command to do the copy, which works for me everywhere. Note that I'm only copying the output dll here, not the entire directory. Also note that I'm hard coding a destination /bin/ directory, which is specific to this project. But I wanted to share the $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}> syntax, which I think is neat:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
${CMAKE_CURRENT_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>)
I'm a CMake beginner, but still I wanted to shared my experience. In my case I needed a post-install copy so that all my binaries are in.
In the case of third-party binary that can be imported within CMake, the following works for me:
find_package( dependency REQUIRED )
if( MSVC )
# If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
# Create a bin directory in the install folder
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/)
# Copy the shared lib file
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()
Obviously IMPORTED_LOCATION_RELEASE can have variants depending on how the shared library was built / installed. Could be IMPORTED_LOCATION_DEBUG.
Maybe there's a better way to get that property name, I don't know.

Executable cannot find .dll after building correctly [duplicate]

We use CMake for generating the Visual Studio files of our sources in our SVN. Now my tool requires some DLL files to be in the same folder as the executable. The DLL files are in a folder alongside the source.
How can I change my CMakeLists.txt such that the generated Visual Studio project will either have already the particular DLL files in the release/debug folders or will copy them upon compilation?
I'd use add_custom_command to achieve this along with cmake -E copy_if_different.... For full info run
cmake --help-command add_custom_command
cmake -E
So in your case, if you have the following directory structure:
/CMakeLists.txt
/src
/libs/test.dll
and your CMake target to which the command applies is MyTest, then you could add the following to your CMakeLists.txt:
add_custom_command(TARGET MyTest POST_BUILD # Adds a post-build event to MyTest
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..."
"${PROJECT_SOURCE_DIR}/libs/test.dll" # <--this is in-file
$<TARGET_FILE_DIR:MyTest>) # <--this is out-file path
If you just want the entire contents of the /libs/ directory copied, use cmake -E copy_directory:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs"
$<TARGET_FILE_DIR:MyTest>)
If you need to copy different dlls depending upon the configuration (Release, Debug, eg) then you could have these in subdirectories named with the corresponding configuration: /libs/Release, and /libs/Debug. You then need to inject the configuration type into the path to the dll in the add_custom_command call, like this:
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I put these lines in my top-level CMakeLists.txt file. All the libraries and executables compiled by CMake will be placed in the top level of the build directory so that the executables can find the libraries and it is easy to run everything.
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
Note that this doesn't solve the OP's problem of copying precompiled binaries from the project's source directory.
I've had this problem today when tried to make a Windows build of my program. And I ended up doing some research myself since all these answers didn't satisfy me. There were three main issues:
I wanted debug builds to be linked with debug versions of libraries
and release builds to be linked with release builds of libraries,
respectively.
In addition to that, I wanted correct versions of DLL files
(Debug/Release) to be copied to output directories.
And I wanted to achieve all this without writing complex and fragile scripts.
After browsing some CMake manuals and some multiplatform projects at github I've found this solution:
Declare your library as a target with "IMPORTED" attribute, reference its debug and release .lib and .dll files.
add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")
Link this target with your project as usual
target_link_libraries(YourProg sdl2 ...)
Make custom build step to copy dll file to its destination if it has been altered somehow since previous build
add_custom_command ( TARGET YourProg POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)
For Windows users, there is a new generator expression $<TARGET_RUNTIME_DLLS:tgt> in CMake 3.21+ and you could use this official snippet for copying all of the DLLs that a target depends on.
find_package(foo REQUIRED)
add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:exe> $<TARGET_FILE_DIR:exe>
COMMAND_EXPAND_LISTS
)
Moving files during build using install
I had this issue trying to follow the CMake official tutorial on Step 9. This was the location of the file I wanted to move:
src
|_build
|_Debug
- `MathFunctions.dll`
This was the location I wanted the file to be in:
src
|_build
|_install
|_bin
- `MathFunctions.dll`
Since this DLL was generated as a shared library, all I did was to include this line in the CMakeLists.txt in the subdirectory that contained the source code for the library src/Mathfunctions/CMakeLists.txt
install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)
Thanks to your answers I could think on this one. Is just one line, so I think is ok. The $<CONFIG> can have two values Debug or Release Depending on how the project is built, as the original question required.
You can also use the command find_library:
find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")
With a defined EXECUTABLE_PATH, for instance:
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
you could move the .dll files that your executable need, with
file(COPY ${<some_var>}
DESTINATION ${EXECUTABLE_OUTPUT_PATH})
An addendum to the accepted answer, added as a separate answer so I get code formatting:
If you are building your dlls in the same project, they will usually be in Release, Debug, etc. directories. You'll have to use the Visual Studio environment variables to correctly copy them. e.g.:
"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"
for the source and
"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"
for the destination. Note the escaping!
You can't use the CMake CMAKE_BUILD_TYPE variable for the configuration since it's resolved at VS project generation time and will always be whatever the default is.
This is useful for one of them
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/lib CACHE
PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${PROJECT_SOURCE_DIR}/bin CACHE
PATH "Directory where .exe and .dll files are dumped." FORCE)
1. The most correct way: TARGET_RUNTIME_DLLS (CMake >= 3.21)
install(FILES $<TARGET_RUNTIME_DLLS:your_exe_here> TYPE BIN)
For this to work, your dependencies' CMake modules have to be well-written. In other words, they use CMake 3 targets with all their target properties set up correctly. If they set up everything right, all transitively-linked DLLs will be automagically gathered up and installed alongside your exe.
A big difference between this and the straight-up copy-the-files approach is that, because it goes through install(), CMake will actually know about them as files to-be-installed. CPack will know about your DLLs and include them in any installer you generate with it. CMake will automatically adjust what type of DLL (release vs debug) to match your target exe.
This is where CMake will be headed more in the future, and the way you should prefer if you have a choice.
2. The second most correct way: RUNTIME_DEPENDENCIES (CMake >= 3.21)
install(TARGETS your_exe_here
RUNTIME ARCHIVE LIBRARY RUNTIME FRAMEWORK BUNDLE PUBLIC_HEADER RESOURCE)
install(TARGETS your_exe_here
COMPONENT your_exe_here
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES $<TARGET_FILE_DIR:your_exe_here>)
The key here is RUNTIME_DEPENDENCIES.
Internally, RUNTIME_DEPENDENCIES calls file(GET_RUNTIME_DEPENDENCIES), which scans your executable binary, tries very hard to exactly replicate what actual dependency resolution would look like, and write down all the DLLs mentioned along the way. These are passed back up to install().
What this means is that this doesn't depend on your dependencies' CMake modules having their target properties set up correctly. Your actual executable binary is scanned. Everything will get picked up.
3. The third most correct way: install(DIRECTORY)
install(
DIRECTORY "${DIR_CONTAINING_YOUR_DLLS}"
TYPE BIN
FILES_MATCHING REGEX "[^\\\\/.]\\.[dD][lL][lL]$"
)
To use, put the DLLs appropriate for your build in $DIR_CONTAINING_YOUR_DLLS.
The trick here is that, unlike install(FILES), install(DIRECTORY) doesn't care what specific files are in the directory until install time. That means now we have all of configure time and compile time to get a list of your DLLs and stuff them in $DIR_CONTAINING_YOUR_DLLS. As long as the DLL files are in $DIR_CONTAINING_YOUR_DLLS by install time, install(DIRECTORY) will pick them up.
If you choose this method, it's becomes your responsibility to match DLLs to your build config. (Consider: static vs dynamic, debug vs release, import lib version vs DLL version, libs with optional multithreading, forgetting to remove DLLs you don't need anymore.)
If you choose this method, you might want to automate DLL finding and matching using something like what vcpkg's applocal.ps1 does.
Hint for vcpkg
If you use vpckg with VCPKG_APPLOCAL_DEPS enabled, vcpkg will locate and copy your DLLs into your $CMAKE_RUNTIME_OUTPUT_DIRECTORY for you, but without going through install(). You need to use the install(DIRECTORY) trick to get CMake to pick them up.
(Internally, vcpkg uses dumpbin, llvm-objdump, and objdump to scan your executable binary to get these filenames.)
You probably need to add custom target and make it depend on one of your executable targets.
To copy file using above function use:
COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`
The following command from the currently top rated answer depends on the output being put in /libs/.
add_custom_command(TARGET MyTest POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
$<TARGET_FILE_DIR:MyTest>)
I use the below command to do the copy, which works for me everywhere. Note that I'm only copying the output dll here, not the entire directory. Also note that I'm hard coding a destination /bin/ directory, which is specific to this project. But I wanted to share the $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}> syntax, which I think is neat:
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
${CMAKE_CURRENT_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>)
I'm a CMake beginner, but still I wanted to shared my experience. In my case I needed a post-install copy so that all my binaries are in.
In the case of third-party binary that can be imported within CMake, the following works for me:
find_package( dependency REQUIRED )
if( MSVC )
# If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
# Create a bin directory in the install folder
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/bin/)
# Copy the shared lib file
add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()
Obviously IMPORTED_LOCATION_RELEASE can have variants depending on how the shared library was built / installed. Could be IMPORTED_LOCATION_DEBUG.
Maybe there's a better way to get that property name, I don't know.

add_custom_command is not generating a target

Perhaps this is impossible and I'm misreading the cmake 3.2 documentation, but I though creating a custom command would create a custom "target" in the Makefile so that I could build the target by invoking the name of the output file. The CMake docs says:
In makefile terms this creates a new target in the following form:
OUTPUT: MAIN_DEPENDENCY DEPENDS
COMMAND
so I thought I could then run make OUTPUT. Perhaps the documentation is confusing CMake targets with Makefile targets?
For example,
add_custom_command(OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
I would like to do
make foo_out
and it will make foo_out. However, if I do this, I get
make: **** No rule to make target `foo_out`. Stop.
and sure enough, the word "foo_out" doesn't exist anywhere in any file in the cmake binary output directory. If I change it to this
add_custom_target(bar DEPENDS foo_out)
add_custom_command(OUTPUT foo_out COMMAND post_process foo_in > foo_out)
Then I can do
make bar
and I can do
make foo_in
but I still can't do
make foo_out
The problem with make bar is that it is unintuitive, as the actual file output is foo_out not bar.
How do I do this?
In my case, I need to run a special processing step to the standard executable target which inserts optional resources into the ELF file. I would like the ability to have both executables as Makefile targets, so I can build the naked ELF executable as well as the resource-injected ELF executable.
If I was writing a custom Makefile, this is trivial to do!
foo_in: foo.c
$(CC) $< -o $#
foo_out: foo_in
post_process $< > $#
And I can do make foo_in and make foo_out.
add_custom_command does not create a new target. You have to define targets explicitly by add_executable, add_library or add_custom_target in order to make them visible to make.
If you have to fix things up for deployment, you could
1. use the install command (somewhere in your CMakeLists.txt) like this:
install(SCRIPT <dir>/post_install.cmake)
to store commands which are executed only when you run make install in a separate .cmake file. Or if the install target is already reserved for other things or you have more complex stuff going on:
2. manually define a deploy target. Once you got that, you can create a custom post-build command which is only executed when you explicitly run make on your deploy target. This allows you to execute commands through a separate target.
In your CMakeLists.txt this could look like:
cmake_minimum_required(VERSION 3.0)
add_executable("App" <sources>)
# option 1: do deployment stuff only when installing
install(SCRIPT <dir>/post_install.cmake)
# option 2: define a deploy target and add post-build commands
add_custom_target("deploy")
add_custom_command(TARGET "deploy" POST_BUILD <some command>)
Both approaches allow you to separate dev builds from expensive ready-to-deploy builds (if I understand correctly, that's the goal here). I would recommend option 1 since it's just cleaner.
Hope this helps!
Documentation Unclear
CMake's documentation is unclear here. The Makefiles generators of CMake do create the source file make rules in sub Makefiles which are not visible in the main Makefile. In the main Makefile you will find only the PHONY rules for your CMake targets. The only exception I know of is the Ninja
Makefiles generator which puts all build rules into single file.
Translating Post-Processing Steps into CMake
From my experience - if post_process is a script - you should probably think about rewriting your post-processing steps with/inside the CMake scripts, because CMake should know about all the file dependencies and variables used for post-processing (it then will e.g. handle all the necessary re-build or clean-up steps for you).
Here is a simplified/modified version of what I do:
function(my_add_elf _target)
set(_source_list ${ARGN})
add_executable(${_target}_in ${_source_list})
set_target_properties(
${_target}_in
PROPERTIES
POSITION_INDEPENDENT_CODE 0
SUFFIX .elf
)
add_custom_command(
OUTPUT ${_target}_step1.elf
COMMAND some_conversion_cmd $<TARGET_FILE:${_target}_in> > ${_target}_step1.elf
DEPENDS ${_target}_in
)
add_custom_target(
${_target}_step1
DEPENDS
${_target}_step1.elf
)
add_custom_command(
OUTPUT ${_target}_out.elf
COMMAND final_post_process_cmd ${_target}_step1.elf > ${_target}_out.elf
DEPENDS ${_target}_step1
)
add_custom_target(
${_target}_out
DEPENDS
${_target}_out.elf
)
# alias / PHONY target
add_custom_target(${_target} DEPENDS ${_target}_out)
endfunction(my_add_elf)
and then call
my_add_elf(foo foo.c)
It's only an example, but I hope it gives the idea: you could call make foo for the final ELF output, make foo_in or make foo_step1 for one of the other steps. And I think all steps are transparent for the user and CMake.
Can't give your Target the same name as one of the Outputs
When you're trying to give a custom target the same name as one of its outputs e.g. like this:
add_executable(foo_in foo.c)
add_custom_command(
OUTPUT foo_out
COMMAND post_process foo_in > foo_out
DEPENDS foo_in
)
add_custom_target(foo_out DEPENDS foo_out)
You end-up with invalid make files. I've raised an issue about this in the hope that there could be a possible solution by extending CMake itself and got the following reply:
CMake is not intended to produce specific content in a Makefile.
Top-level target names created by add_custom_target are always logical
(i.e. phony) names. It is simply not allowed to have a file of the
same name.
Posible Workarounds
So there are some workarounds, but they all have one or the other disadvantage.
1. Shortest Version:
macro(my_add_elf_we _target)
add_executable(${_target}_in ${ARGN})
add_custom_target(
${_target}_out
COMMAND post_process $<TARGET_FILE:${_target}_in> > ${_target}_out
DEPENDS ${_target}_in
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target}_out)
endmacro(my_add_elf_we)
You can't declare OUTPUTs in the add_custom_target() itself, but in this case you don't want to (because you don't want to have any naming confusions). But if you don't declare any outputs:
The target will always considered out-of-date
You need to add the "invisible" outputs the clean build rule
2. Force Output Name Version
Here is a version of the above macro that forces target and output names to given values:
macro(my_add_elf_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_custom_target(
${_target_out}
COMMAND post_process ${_target_in} > ${_target_out}
DEPENDS ${_target_in}
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${_target_out})
endmacro(my_add_elf_in_out)
You call it with:
my_add_elf_in_out(foo_in.elf foo_out.elf foo.c)
3. Object Libary Version
The following version uses object libraries, but the system will not reuse the foo_in target linkage:
macro(my_add_elf_obj_in_out _target_in _target_out)
add_library(${_target_in}_obj OBJECT ${ARGN})
add_executable(${_target_in} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} $<TARGET_OBJECTS:${_target_in}_obj>)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
EXCLUDE_FROM_ALL 1
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
endmacro(my_add_elf_obj_in_out)
4. Last and Final Version
And one final version that definitely works only for with Makefile generators and that got me posting the issue at CMake's bug tracker:
macro(my_add_elf_ext_in_out _target_in _target_out)
add_executable(${_target_in} ${ARGN})
set_target_properties(
${_target_in}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_in}"
)
add_executable(${_target_out} NotExisting.c)
set_source_files_properties(
NotExisting.c
PROPERTIES
GENERATED 1
HEADER_FILE_ONLY 1
)
set_target_properties(
${_target_out}
PROPERTIES
SUFFIX ""
OUTPUT_NAME "${_target_out}"
RULE_LAUNCH_LINK "# "
)
add_custom_command(
TARGET ${_target_out}
POST_BUILD
COMMAND post_process ${_target_in} > ${_target_out}
)
add_dependencies(${_target_out} ${_target_in})
endmacro(my_add_elf_ext_in_out)
Some references
CMake add_custom_command/_target in different directories for cross-compilation
CMake: how do i depend on output from a custom target?
cmake add_custom_command
How do I use CMake to build LaTeX documents?
Turning around the dependencies, and using the second signature of add_custom_command, this should work:
add_custom_target(foo_out DEPENDS foo_in)
add_custom_command(TARGET foo_out POST_BUILD COMMAND post_process foo_in > foo_out)
Note: Adding BYPRODUCTS foo_out will cause (for example) ninja to say
multiple rules generate foo_out. builds involving this target will not be correct; continuing anyway

"make dist" equivalent in CMake

According to FAQ, CMake doesn't create a make dist target and source package can be created using CPack. But CPack just makes a tarball of the source directory with all files that don't match patterns in CPACK_SOURCE_IGNORE_FILES.
On the other hand, make dist generated by autotools bundles only files it knows about, mostly sources needed for compilation.
Anyone has a smart way of making a source package with only files that are specified in CMakeLists.txt (and its dependencies)?
I've been thinking about this for a while and I won't pretend I can simulate a make dist without having this directly supported by CMake itself.
The problem is that you can add a lot of file dependencies with CMake on the one side (e.g. to pre-build libraries) and on the other side CMake does not know about dependencies directly checked by the generated build environment itself (e.g. any header dependencies).
So here is a code that just collects all CMakeList.txt and source files given with any build targets:
function(make_dist_creator _variable _access _value _current_list_file _stack)
if (_access STREQUAL "MODIFIED_ACCESS")
# Check if we are finished (end of main CMakeLists.txt)
if (NOT _current_list_file)
get_property(_subdirs GLOBAL PROPERTY MAKE_DIST_DIRECTORIES)
list(REMOVE_DUPLICATES _subdirs)
foreach(_subdir IN LISTS _subdirs)
list(APPEND _make_dist_sources "${_subdir}/CMakeLists.txt")
get_property(_targets DIRECTORY "${_subdir}" PROPERTY BUILDSYSTEM_TARGETS)
foreach(_target IN LISTS _targets)
get_property(_sources TARGET "${_target}" PROPERTY SOURCES)
foreach(_source IN LISTS _sources)
list(APPEND _make_dist_sources "${_subdir}/${_source}")
endforeach()
endforeach()
endforeach()
add_custom_target(
dist
COMMAND "${CMAKE_COMMAND}" -E tar zcvf "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.tar.gz" -- ${_make_dist_sources}
COMMENT "Make distribution ${PROJECT_NAME}.tar.gz"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
)
message("_make_dist_sources = ${_make_dist_sources}")
else()
# else collect subdirectories in my source dir
file(RELATIVE_PATH _dir_rel "${CMAKE_SOURCE_DIR}" "${_value}")
if (NOT _dir_rel MATCHES "\.\.")
set_property(GLOBAL APPEND PROPERTY MAKE_DIST_DIRECTORIES "${_value}")
endif()
endif()
endif()
endfunction()
variable_watch("CMAKE_CURRENT_LIST_DIR" make_dist_creator)
Note: The used BUILDSYSTEM_TARGETS property needs at least CMake version 3.7
I see the code above as an starting point and prove of concept. You could add libraries, headers, etc. on a need-by basis, but you should probably just tweak cpack to do your bidding.
As a starting point see e.g. the link #usr1234567 provided in the comments.
References
Get all source files a target depends on in CMake
Simon is correct above but does not give a full answer. With git you can generate a compatible tar ball archive with the git archive command.
This example with the version is compatible with make dist of yesteryear.
git archive --format=tar.gz -o my-repo-0.01.tar.gz --prefix=my-repo-0.01/ master
See: https://gist.github.com/simonw/a44af92b4b255981161eacc304417368