Skip to content

Commit 2c3ccb6

Browse files
author
Anton Pantyukhin
committed
Add CMake function to copy DLL and PDB to tests/examples binary directories when building for Windows
1 parent 886ae31 commit 2c3ccb6

File tree

5 files changed

+82
-0
lines changed

5 files changed

+82
-0
lines changed

cmake/silent_copy.cmake

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Script which does not fail when some of the files to be copied are missing.
2+
#
3+
# Usage: cmake -P silent_copy.cmake [files]... [dest]
4+
5+
math(EXPR dir_idx "${CMAKE_ARGC} - 1")
6+
set(first_file_idx ${dir_idx})
7+
8+
foreach(i RANGE ${dir_idx})
9+
if ("${CMAKE_ARGV${i}}" STREQUAL "-P")
10+
math(EXPR first_file_idx "${i} + 2")
11+
break()
12+
endif()
13+
endforeach()
14+
15+
if(first_file_idx GREATER_EQUAL dir_idx)
16+
return()
17+
endif()
18+
19+
math(EXPR last_file_idx "${dir_idx} - 1")
20+
set(dest ${CMAKE_ARGV${dir_idx}})
21+
set(files "")
22+
23+
foreach(i RANGE ${first_file_idx} ${last_file_idx})
24+
list(APPEND files "${CMAKE_ARGV${i}}")
25+
endforeach()
26+
27+
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${files} "${dest}" ERROR_QUIET)

cmake/utils.cmake

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,45 @@ macro(set_if_undefined variable)
66
set("${variable}" ${ARGN})
77
endif()
88
endmacro()
9+
10+
# win_copy_deps_to_target_dir(<target> [<target-dep>]...)
11+
#
12+
# Creates custom command to copy runtime dependencies to target's directory after building the target.
13+
# Function does nothing if platform is not Windows or current project is built as stand-alone (top-level)
14+
# project. Additionally, it ignores all dependencies except shared libraries.
15+
# On CMake 3.21 or newer, function uses TARGET_RUNTIME_DLLS generator expression to obtain list of runtime
16+
# dependencies. Specified dependencies (if any) are still used to find and copy PDB files for debug builds.
17+
function(win_copy_deps_to_target_dir target)
18+
if(NOT WIN32 OR "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
19+
return()
20+
endif()
21+
22+
set(has_runtime_dll_genex NO)
23+
24+
if(CMAKE_MAJOR_VERSION GREATER 3 OR CMAKE_MINOR_VERSION GREATER_EQUAL 21)
25+
set(has_runtime_dll_genex YES)
26+
27+
add_custom_command(TARGET ${target} POST_BUILD
28+
COMMAND ${CMAKE_COMMAND} -P "${mylib_SOURCE_DIR}/cmake/silent_copy.cmake"
29+
"$<TARGET_RUNTIME_DLLS:${target}>" "$<TARGET_FILE_DIR:${target}>"
30+
COMMAND_EXPAND_LISTS)
31+
endif()
32+
33+
foreach(dep ${ARGN})
34+
get_target_property(dep_type ${dep} TYPE)
35+
36+
if(dep_type STREQUAL "SHARED_LIBRARY")
37+
if(NOT has_runtime_dll_genex)
38+
add_custom_command(TARGET ${target} POST_BUILD
39+
COMMAND ${CMAKE_COMMAND} -P "${mylib_SOURCE_DIR}/cmake/silent_copy.cmake"
40+
"$<TARGET_FILE:${dep}>" "$<TARGET_PDB_FILE:${dep}>" "$<TARGET_FILE_DIR:${target}>"
41+
COMMAND_EXPAND_LISTS)
42+
else()
43+
add_custom_command(TARGET ${target} POST_BUILD
44+
COMMAND ${CMAKE_COMMAND} -P "${mylib_SOURCE_DIR}/cmake/silent_copy.cmake"
45+
"$<TARGET_PDB_FILE:${dep}>" "$<TARGET_FILE_DIR:${target}>"
46+
COMMAND_EXPAND_LISTS)
47+
endif()
48+
endif()
49+
endforeach()
50+
endfunction()

examples/add/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
cmake_minimum_required(VERSION 3.14)
22
project(mylib-add LANGUAGES CXX)
3+
include("../../cmake/utils.cmake")
34

45
find_package(mylib REQUIRED)
56

@@ -9,3 +10,4 @@ source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${sources})
910
add_executable(mylib-add)
1011
target_sources(mylib-add PRIVATE ${sources})
1112
target_link_libraries(mylib-add PRIVATE mylib::mylib)
13+
win_copy_deps_to_target_dir(mylib-add mylib::mylib)

examples/add/main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#include <mylib/mylib.h>
22

3+
#include <iostream>
4+
35
int main(int, char*[])
46
{
7+
auto sum = mylib::add(1, 1);
8+
std::cout << sum << std::endl;
59
return 0;
610
}

tests/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
cmake_minimum_required(VERSION 3.14)
22
project(mylib-tests)
3+
include("../cmake/utils.cmake")
34

45
#----------------------------------------------------------------------------------------------------------------------
56
# general settings and options
@@ -21,6 +22,10 @@ FetchContent_Declare(googletest URL https://github.com/google/googletest/archive
2122
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # do not override parent project's runtime settings on Windows
2223
set(INSTALL_GTEST OFF)
2324

25+
# For simplicity, always build googletest as static library. This prevents mylib-tests executable from
26+
# complaining about missing googletest DLLs on Windows.
27+
set(BUILD_SHARED_LIBS OFF)
28+
2429
FetchContent_MakeAvailable(googletest)
2530

2631
#----------------------------------------------------------------------------------------------------------------------
@@ -49,5 +54,7 @@ target_link_libraries(mylib-tests
4954
mylib::mylib
5055
gtest_main)
5156

57+
win_copy_deps_to_target_dir(mylib-tests mylib::mylib)
58+
5259
include(GoogleTest)
5360
gtest_discover_tests(mylib-tests)

0 commit comments

Comments
 (0)