@@ -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
+ file (
119
+ WRITE "${_cpm_patch_script} "
120
+ [=[
121
+ # Auto-generated patch application script
122
+ separate_arguments(PATCH_FILES)
123
+
124
+ foreach(patch_file IN LISTS PATCH_FILES)
125
+ message(STATUS "Checking patch: ${patch_file}")
126
+
127
+ execute_process(
128
+ COMMAND "${PATCH_EXECUTABLE}" --dry-run -p1
129
+ INPUT_FILE "${patch_file}"
130
+ RESULT_VARIABLE dry_run_result
131
+ OUTPUT_VARIABLE dry_out
132
+ ERROR_VARIABLE dry_err
133
+ )
134
+
135
+ if(dry_run_result EQUAL 0)
136
+ message(STATUS "Applying patch: ${patch_file}")
137
+ execute_process(
138
+ COMMAND "${PATCH_EXECUTABLE}" -p1
139
+ INPUT_FILE "${patch_file}"
140
+ RESULT_VARIABLE apply_result
141
+ OUTPUT_VARIABLE apply_out
142
+ ERROR_VARIABLE apply_err
143
+ )
144
+ if(apply_result EQUAL 0)
145
+ message(STATUS "Applied patch: ${patch_file}")
146
+ else()
147
+ message(FATAL_ERROR "Patch failed: ${patch_file}\n${apply_err}")
148
+ endif()
149
+ else()
150
+ execute_process(
151
+ COMMAND "${PATCH_EXECUTABLE}" --dry-run -p1 --reverse
152
+ INPUT_FILE "${patch_file}"
153
+ RESULT_VARIABLE reverse_result
154
+ OUTPUT_VARIABLE reverse_out
155
+ ERROR_VARIABLE reverse_err
156
+ )
157
+ if(reverse_result EQUAL 0)
158
+ message(STATUS "Patch already applied: ${patch_file}")
159
+ else()
160
+ message(
161
+ FATAL_ERROR "Patch cannot be applied and is not already applied: ${patch_file}\n${dry_err}"
162
+ )
163
+ endif()
164
+ endif()
165
+ endforeach()
166
+ ]=]
167
+ )
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