一键导入
apply-third-party-patch
CMake mechanism for idempotent, reproducible patches to third-party dependencies (inspired by PaddlePaddle)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
CMake mechanism for idempotent, reproducible patches to third-party dependencies (inspired by PaddlePaddle)
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Add device information query functions through HAL → ins:: API → language bindings
Add --device all/--timer/--info CLI flags to demos across all languages for competition scoring
Add composite signal operators using existing primitives (no dedicated backend kernels needed)
How to port a cusignal Python/CUDA module to ins::signal C++ using Insight7 primitives and HAL
Profile and optimize binding language (Lua/Julia/Python) demo performance to match or exceed C++ baseline
busted loads _insight.so from ~/.luarocks/lib first, not build/ — must copy .so after rebuild
| name | apply-third-party-patch |
| description | CMake mechanism for idempotent, reproducible patches to third-party dependencies (inspired by PaddlePaddle) |
| source | auto-skill |
| extracted_at | 2026-05-30T17:30:00.000Z |
Third-party libraries fetched via FetchContent or cloned locally may have GCC/Clang compatibility bugs. Patches must be:
cd third_party/matplotplusplus
# Make changes to fix compilation errors
git diff > patches/matplotplusplus/gcc-compat.patch
cmake/ApplyPatch.cmake — 3 fallback methodsfunction(apply_patch SOURCE_DIR PATCH_FILE)
if(NOT EXISTS "${PATCH_FILE}")
message(WARNING "Patch file not found: ${PATCH_FILE}")
return()
endif()
get_filename_component(PATCH_NAME "${PATCH_FILE}" NAME_WE)
set(PATCH_STAMP "${SOURCE_DIR}/.patch_applied_${PATCH_NAME}")
if(EXISTS "${PATCH_STAMP}")
message(STATUS "Patch ${PATCH_NAME} already applied to ${SOURCE_DIR}")
return()
endif()
message(STATUS "Applying patch ${PATCH_NAME} to ${SOURCE_DIR}")
# Method 1: git apply (preferred for git repos)
execute_process(
COMMAND git apply --check "${PATCH_FILE}"
WORKING_DIRECTORY "${SOURCE_DIR}"
RESULT_VARIABLE GIT_CHECK OUTPUT_QUIET ERROR_QUIET
)
if(GIT_CHECK EQUAL 0)
execute_process(
COMMAND git apply "${PATCH_FILE}"
WORKING_DIRECTORY "${SOURCE_DIR}"
RESULT_VARIABLE GIT_APPLY ERROR_VARIABLE GIT_ERROR
)
if(GIT_APPLY EQUAL 0)
file(WRITE "${PATCH_STAMP}" "Applied via git apply")
message(STATUS "Patch ${PATCH_NAME} applied successfully (git apply)")
return()
endif()
endif()
# Method 2: patch -p1 (fallback, works without git)
execute_process(
COMMAND patch -p1 --forward --dry-run
INPUT_FILE "${PATCH_FILE}"
WORKING_DIRECTORY "${SOURCE_DIR}"
RESULT_VARIABLE PATCH_CHECK OUTPUT_QUIET ERROR_QUIET
)
if(PATCH_CHECK EQUAL 0)
execute_process(
COMMAND patch -p1 --forward
INPUT_FILE "${PATCH_FILE}"
WORKING_DIRECTORY "${SOURCE_DIR}"
RESULT_VARIABLE PATCH_APPLY ERROR_VARIABLE PATCH_ERROR
)
if(PATCH_APPLY EQUAL 0)
file(WRITE "${PATCH_STAMP}" "Applied via patch -p1")
message(STATUS "Patch ${PATCH_NAME} applied successfully (patch -p1)")
return()
endif()
endif()
# Method 3: Check if already applied (reverse dry-run)
execute_process(
COMMAND patch -p1 --forward -R --dry-run
INPUT_FILE "${PATCH_FILE}"
WORKING_DIRECTORY "${SOURCE_DIR}"
RESULT_VARIABLE REVERSE_CHECK OUTPUT_QUIET ERROR_QUIET
)
if(REVERSE_CHECK EQUAL 0)
file(WRITE "${PATCH_STAMP}" "Already applied")
message(STATUS "Patch ${PATCH_NAME} already applied (detected via reverse check)")
return()
endif()
# All methods failed — FATAL_ERROR stops the build (patch is required)
message(FATAL_ERROR
"[patch] ${PATCH_NAME}: FAILED to apply!\n"
" Source: ${SOURCE_DIR}\n"
" Patch: ${PATCH_FILE}\n"
" git apply error: ${E1}\n"
" patch -p1 error: ${E2}\n"
" This must be fixed — the patch is required for headless CI.")
endfunction()
Why 3 methods: git apply fails on some FetchContent shallow clones.
patch -p1 works without git. Reverse check detects already-applied patches.
Why FATAL_ERROR: If a patch fails silently, the build continues with unpatched source, causing runtime crashes (e.g., gnuplot segfault in headless CI). A loud cmake error is always better than a silent runtime crash.
CRITICAL: Patches must be applied BEFORE add_subdirectory, not after.
This matches PaddlePaddle's ExternalProject_Add + PATCH_COMMAND pattern.
include(cmake/ApplyPatch.cmake)
# Inside the local/FetchContent branches — NOT after endif()!
if(EXISTS "${LOCAL_MATPLOT}/CMakeLists.txt")
# Local: patch FIRST, then add_subdirectory
apply_patch("${LOCAL_MATPLOT}"
"${CMAKE_CURRENT_SOURCE_DIR}/patches/matplotplusplus/gcc-compat.patch")
apply_patch("${LOCAL_MATPLOT}"
"${CMAKE_CURRENT_SOURCE_DIR}/patches/matplotplusplus/gnuplot-unknown-terminal.patch")
add_subdirectory("${LOCAL_MATPLOT}" "${CMAKE_CURRENT_BINARY_DIR}/matplotplusplus")
else()
# FetchContent: Populate → patch → add_subdirectory (NOT MakeAvailable!)
FetchContent_Declare(matplotplusplus
GIT_REPOSITORY "https://github.com/alandefreitas/matplotplusplus"
GIT_TAG "v1.2.1"
GIT_SHALLOW TRUE
)
set(MATPLOTPP_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
FetchContent_Populate(matplotplusplus) # Step 1: Download only
apply_patch("${matplotplusplus_SOURCE_DIR}" ... # Step 2: Apply patches
"${CMAKE_CURRENT_SOURCE_DIR}/patches/matplotplusplus/gcc-compat.patch")
add_subdirectory("${matplotplusplus_SOURCE_DIR}" # Step 3: Process patched source
"${matplotplusplus_BINARY_DIR}")
endif()
Why NOT
FetchContent_MakeAvailable: It callsadd_subdirectoryimmediately, registering targets BEFORE patches are applied. The patches modify source files but cmake's internal state may cache the unpatched timestamps.
FetchContent_Populatedownloads source only. You then apply patches and calladd_subdirectorymanually — same as PaddlePaddle'sPATCH_COMMAND.
Insight7/
├── cmake/
│ └── ApplyPatch.cmake
├── patches/
│ └── matplotplusplus/
│ └── gcc-compat.patch
└── third_party/
└── matplotplusplus/ (cloned or fetched)
.patch_applied_<name> in source dir prevents re-applicationgit apply --check: Tests if patch applies cleanly before committingpatches/ are tracked in gitThe project .gitignore has *.cmake which ignores ALL .cmake files in any directory. This silently prevents cmake/ApplyPatch.cmake (and other cmake modules) from being committed.
Fix: Add !cmake/*.cmake after *.cmake in .gitignore:
*.cmake
!CMakeLists.txt
!cmake/*.cmake
How to detect: git check-ignore cmake/ApplyPatch.cmake returns the filename (exit 0) if ignored.
Symptom in CI: CMake Error at CMakeLists.txt:344 (include): include could not find requested file: cmake/ApplyPatch.cmake
When CMakeLists.txt has if(local)/else(FetchContent), the source directory differs:
third_party/<name>/ (the LOCAL_<NAME> variable)_deps/<name>-src/ (the <name>_SOURCE_DIR variable)If apply_patch is called after endif() with only the LOCAL path, FetchContent builds silently skip the patch (WARNING but no error).
Fix: Move apply_patch into each branch:
if(local)
add_subdirectory(...)
apply_patch("${LOCAL_PATH}" ...)
else()
FetchContent_MakeAvailable(...)
apply_patch("${<name>_SOURCE_DIR}" ...)
endif()
Symptom: Template compilation errors in the patched file (e.g., wrong number of template arguments) even though the patch is committed. The patch was never applied to the FetchContent source.
When a third-party library has a build error:
third_party/git diff to generate patchpatches/<library>/<fix-name>.patchapply_patch() call in CMakeLists.txtcmake/ApplyPatch.cmake is tracked: git ls-files cmake/ApplyPatch.cmakecmake .. shows "applied successfully"cmake .. shows "already applied"git checkout -- .) and re-run cmakePatch files have strict format requirements (hunk headers with exact line counts,
context lines with correct indentation). Editing by hand almost always produces
a corrupt patch that git apply rejects with corrupt patch at line N.
Correct way to update a patch:
cd third_party/<lib> && git checkout -- <file>cd third_party/<lib> && git diff -- <file> > patches/<lib>/<name>.patchgit apply --check patches/<lib>/<name>.patch must print nothingcd third_party/<lib> && git checkout -- <file> && patch -p1 --dry-run < patches/<lib>/<name>.patchSymptom of corrupt patch: git apply --check prints error: corrupt patch at line N.
The patch silently fails in CI (stamp is written, error is swallowed).
The stamp mechanism must be:
git apply --check succeeds → apply → write stampgit apply --check fails → try reverse check (git apply --check -R)