@@ -112,6 +112,62 @@ macro(cpm_set_policies)
112
112
endmacro ()
113
113
cpm_set_policies ()
114
114
115
+ macro (cpm_generate_apply_patches_script )
116
+ set (_cpm_patch_script "${CPM_CURRENT_DIRECTORY} /cpm_apply_patches.cmake" )
117
+
118
+ if (NOT EXISTS "${_cpm_patch_script} " )
119
+ file (
120
+ WRITE "${_cpm_patch_script} "
121
+ [=[
122
+ # Auto-generated patch application script
123
+ separate_arguments(PATCH_FILES)
124
+
125
+ foreach(patch_file IN LISTS PATCH_FILES)
126
+ message(STATUS "Checking patch: ${patch_file}")
127
+
128
+ execute_process(
129
+ COMMAND "${PATCH_EXECUTABLE}" --dry-run -p1
130
+ INPUT_FILE "${patch_file}"
131
+ RESULT_VARIABLE dry_run_result
132
+ OUTPUT_VARIABLE dry_out
133
+ ERROR_VARIABLE dry_err
134
+ )
135
+
136
+ if(dry_run_result EQUAL 0)
137
+ message(STATUS "Applying patch: ${patch_file}")
138
+ execute_process(
139
+ COMMAND "${PATCH_EXECUTABLE}" -p1
140
+ INPUT_FILE "${patch_file}"
141
+ RESULT_VARIABLE apply_result
142
+ OUTPUT_VARIABLE apply_out
143
+ ERROR_VARIABLE apply_err
144
+ )
145
+ if(apply_result EQUAL 0)
146
+ message(STATUS "Applied patch: ${patch_file}")
147
+ else()
148
+ message(FATAL_ERROR "Patch failed: ${patch_file}\n${apply_err}")
149
+ endif()
150
+ else()
151
+ execute_process(
152
+ COMMAND "${PATCH_EXECUTABLE}" --dry-run -p1 --reverse
153
+ INPUT_FILE "${patch_file}"
154
+ RESULT_VARIABLE reverse_result
155
+ OUTPUT_VARIABLE reverse_out
156
+ ERROR_VARIABLE reverse_err
157
+ )
158
+ if(reverse_result EQUAL 0)
159
+ message(STATUS "Patch already applied: ${patch_file}")
160
+ else()
161
+ message(FATAL_ERROR "Patch cannot be applied and is not already applied: ${patch_file}\n${dry_err}")
162
+ endif()
163
+ endif()
164
+ endforeach()
165
+ ]=]
166
+ )
167
+ endif ()
168
+ endmacro ()
169
+ cpm_generate_apply_patches_script ()
170
+
115
171
option (CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies"
116
172
$ENV{CPM_USE_LOCAL_PACKAGES}
117
173
)
@@ -541,66 +597,69 @@ endfunction()
541
597
# then generates a `PATCH_COMMAND` appropriate for `ExternalProject_Add()`. This command is appended
542
598
# to the parent scope's `CPM_ARGS_UNPARSED_ARGUMENTS`.
543
599
function (cpm_add_patches )
544
- # Return if no patch files are supplied.
600
+ # Return early if no patch files are provided
545
601
if (NOT ARGN )
546
602
return ()
547
603
endif ()
548
604
549
- # Find the patch program.
605
+ # -----------------------------------------------------------------------------------------------
606
+ # Locate the 'patch' executable
607
+ # -----------------------------------------------------------------------------------------------
550
608
find_program (PATCH_EXECUTABLE patch )
609
+
551
610
if (CMAKE_HOST_WIN32 AND NOT PATCH_EXECUTABLE )
552
611
# The Windows git executable is distributed with patch.exe. Find the path to the executable, if
553
612
# it exists, then search `../usr/bin` and `../../usr/bin` for patch.exe.
554
613
find_package (Git QUIET )
555
614
if (GIT_EXECUTABLE )
556
- get_filename_component (extra_search_path ${GIT_EXECUTABLE} DIRECTORY )
557
- get_filename_component (extra_search_path_1up ${extra_search_path} DIRECTORY )
558
- get_filename_component (extra_search_path_2up ${extra_search_path_1up} DIRECTORY )
615
+ get_filename_component (_git_bin_dir "${GIT_EXECUTABLE} " DIRECTORY )
616
+ get_filename_component (_git_root_1up "${_git_bin_dir} " DIRECTORY )
617
+ get_filename_component (_git_root_2up "${_git_root_1up} " DIRECTORY )
618
+
559
619
find_program (
560
- PATCH_EXECUTABLE patch HINTS "${extra_search_path_1up} /usr/bin"
561
- "${extra_search_path_2up} /usr/bin"
620
+ PATCH_EXECUTABLE patch HINTS "${_git_root_1up} /usr/bin" "${_git_root_2up} /usr/bin"
562
621
)
563
622
endif ()
564
623
endif ()
624
+
565
625
if (NOT PATCH_EXECUTABLE )
566
626
message (FATAL_ERROR "Couldn't find `patch` executable to use with PATCHES keyword." )
567
627
endif ()
568
628
569
- # Create a temporary
570
- set (temp_list ${CPM_ARGS_UNPARSED_ARGUMENTS} )
629
+ # -----------------------------------------------------------------------------------------------
630
+ # Resolve and validate all patch file paths
631
+ # -----------------------------------------------------------------------------------------------
632
+ set (resolved_patch_files )
571
633
572
- # Ensure each file exists (or error out) and add it to the list.
573
- set (first_item True )
574
- foreach (PATCH_FILE ${ARGN} )
634
+ foreach (PATCH_FILE IN LISTS ARGN )
575
635
# Make sure the patch file exists, if we can't find it, try again in the current directory.
576
636
if (NOT EXISTS "${PATCH_FILE} " )
577
- if (NOT EXISTS "${CMAKE_CURRENT_LIST_DIR} /${PATCH_FILE} " )
637
+ set (_fallback_path "${CMAKE_CURRENT_LIST_DIR} /${PATCH_FILE} " )
638
+ if (NOT EXISTS "${_fallback_path} " )
578
639
message (FATAL_ERROR "Couldn't find patch file: '${PATCH_FILE} '" )
579
640
endif ()
580
- set (PATCH_FILE "${CMAKE_CURRENT_LIST_DIR} / ${PATCH_FILE } " )
641
+ set (PATCH_FILE "${_fallback_path } " )
581
642
endif ()
582
643
583
644
# Convert to absolute path for use with patch file command.
584
645
get_filename_component (PATCH_FILE "${PATCH_FILE} " ABSOLUTE )
585
-
586
- # The first patch entry must be preceded by "PATCH_COMMAND" while the following items are
587
- # preceded by "&&".
588
- if (first_item )
589
- set (first_item False )
590
- list (APPEND temp_list "PATCH_COMMAND" )
591
- else ()
592
- list (APPEND temp_list "&&" )
593
- endif ()
594
- # Add the patch command to the list
595
- list (APPEND temp_list "${PATCH_EXECUTABLE} " "-p1" "<" "${PATCH_FILE} " )
646
+ list (APPEND resolved_patch_files "${PATCH_FILE} " )
596
647
endforeach ()
597
648
598
- # Move temp out into parent scope.
649
+ # -----------------------------------------------------------------------------------------------
650
+ # Construct the patch command
651
+ # -----------------------------------------------------------------------------------------------
652
+ string (JOIN " " joined_patch_files ${resolved_patch_files} )
653
+
654
+ set (_patch_command cmake -D "PATCH_FILES=${joined_patch_files} " -D
655
+ "PATCH_EXECUTABLE=${PATCH_EXECUTABLE} " -P "${_cpm_patch_script} "
656
+ )
657
+
658
+ list (APPEND CPM_ARGS_UNPARSED_ARGUMENTS PATCH_COMMAND ${_patch_command} )
599
659
set (CPM_ARGS_UNPARSED_ARGUMENTS
600
- ${temp_list}
660
+ " ${CPM_ARGS_UNPARSED_ARGUMENTS} "
601
661
PARENT_SCOPE
602
662
)
603
-
604
663
endfunction ()
605
664
606
665
# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload
0 commit comments