|
| 1 | +# ============================================================ |
| 2 | +# CFDesktop Desktop Overlay |
| 3 | +# ============================================================ |
| 4 | +# Two-phase overlay deployment: |
| 5 | +# |
| 6 | +# Phase A: Runtime overlay (settings/, config/, logger/) |
| 7 | +# -> ${CMAKE_BINARY_DIR}/bin/ |
| 8 | +# |
| 9 | +# Phase B: Desktop root overlay (Home/, Desktop/, Documents/, |
| 10 | +# Downloads/, Music/, Pictures/, Videos/, Apps/, Runtime/) |
| 11 | +# -> ${CFDESKTOP_DEFAULT_ROOT} |
| 12 | +# |
| 13 | +# Overlay directory structure (source): |
| 14 | +# cmake/desktop_overlay/ <- Generic overlay (all platforms) |
| 15 | +# cmake/desktop_overlay/windows/ <- Windows-specific overlay |
| 16 | +# cmake/desktop_overlay/linux/ <- Linux-specific overlay |
| 17 | +# |
| 18 | +# Priority: platform-specific > generic (platform overlay wins) |
| 19 | +# |
| 20 | +# The runtime's "skip if exists" logic in EarlyConfigStage naturally |
| 21 | +# picks up overlay files — no C++ code changes needed. |
| 22 | +# |
| 23 | +# To force overwrite existing files, set: |
| 24 | +# -DCFDESKTOP_OVERLAY_FORCE=ON |
| 25 | +# |
| 26 | +# Cross-compilation deployment: |
| 27 | +# cmake --install <build_dir> --prefix <deploy_dir> |
| 28 | +# ============================================================ |
| 29 | + |
| 30 | +# Runtime-related directories (go to bin/) |
| 31 | +set(_CF_RUNTIME_DIRS "settings" "config" "logger") |
| 32 | + |
| 33 | +# Desktop root directories (go to CFDESKTOP_DEFAULT_ROOT) |
| 34 | +set(_CF_DESKTOP_ROOT_DIRS "Home" "Desktop" "Documents" "Downloads" |
| 35 | + "Music" "Pictures" "Videos" "Apps" "Runtime") |
| 36 | + |
| 37 | +# Reserved subdirectory names for platform-specific overlays |
| 38 | +set(_CF_PLATFORM_DIRS "windows" "linux" "darwin") |
| 39 | + |
| 40 | + |
| 41 | +# ============================================================ |
| 42 | +# Phase A: Runtime overlay -> ${CMAKE_BINARY_DIR}/bin/ |
| 43 | +# ============================================================ |
| 44 | +# Copies runtime files (settings/, config/, logger/) to the build |
| 45 | +# output directory. Called from check_pre_configure.cmake. |
| 46 | +# ============================================================ |
| 47 | +function(cf_apply_desktop_overlay) |
| 48 | + set(OVERLAY_BASE "${CMAKE_SOURCE_DIR}/cmake/desktop_overlay") |
| 49 | + |
| 50 | + if(NOT IS_DIRECTORY "${OVERLAY_BASE}") |
| 51 | + log_info("DesktopOverlay" "Overlay directory not found, skipping") |
| 52 | + return() |
| 53 | + endif() |
| 54 | + |
| 55 | + set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/bin") |
| 56 | + set(COPIED 0) |
| 57 | + |
| 58 | + # Apply generic overlay (runtime dirs only) |
| 59 | + _cf_overlay_copy_layer("${OVERLAY_BASE}" "${OUTPUT_DIR}" _CF_RUNTIME_DIRS COPIED) |
| 60 | + |
| 61 | + # Apply platform-specific overlay (overrides generic) |
| 62 | + _cf_apply_platform_overlay("${OVERLAY_BASE}" "${OUTPUT_DIR}" COPIED) |
| 63 | + |
| 64 | + if(COPIED GREATER 0) |
| 65 | + log_info("DesktopOverlay" "Applied ${COPIED} runtime overlay file(s)") |
| 66 | + else() |
| 67 | + log_info("DesktopOverlay" "No runtime overlay files to apply") |
| 68 | + endif() |
| 69 | +endfunction() |
| 70 | + |
| 71 | + |
| 72 | +# ============================================================ |
| 73 | +# Phase B: Desktop root overlay -> ${CFDESKTOP_DEFAULT_ROOT} |
| 74 | +# ============================================================ |
| 75 | +# Copies desktop root content (Home/, Desktop/, etc.) to the |
| 76 | +# configured desktop root path. Called AFTER cf_generate_desktop_settings(). |
| 77 | +# ============================================================ |
| 78 | +function(cf_apply_desktop_root_overlay) |
| 79 | + set(OVERLAY_BASE "${CMAKE_SOURCE_DIR}/cmake/desktop_overlay") |
| 80 | + |
| 81 | + if(NOT IS_DIRECTORY "${OVERLAY_BASE}") |
| 82 | + return() |
| 83 | + endif() |
| 84 | + |
| 85 | + # CFDESKTOP_DEFAULT_ROOT is exported by cf_generate_desktop_settings() |
| 86 | + if(NOT DEFINED CFDESKTOP_DEFAULT_ROOT) |
| 87 | + log_info("DesktopOverlay" "CFDESKTOP_DEFAULT_ROOT not set, skipping desktop root overlay") |
| 88 | + return() |
| 89 | + endif() |
| 90 | + |
| 91 | + # Skip if default root contains unresolved env vars (cross-compile edge case) |
| 92 | + string(FIND "${CFDESKTOP_DEFAULT_ROOT}" [[$ENV{]] _HAS_ENV_VAR) |
| 93 | + if(NOT _HAS_ENV_VAR EQUAL -1) |
| 94 | + log_info("DesktopOverlay" "Desktop root contains unresolved env vars, skipping: ${CFDESKTOP_DEFAULT_ROOT}") |
| 95 | + return() |
| 96 | + endif() |
| 97 | + |
| 98 | + set(COPIED 0) |
| 99 | + |
| 100 | + # Apply generic desktop root overlay |
| 101 | + _cf_overlay_copy_layer("${OVERLAY_BASE}" "${CFDESKTOP_DEFAULT_ROOT}" _CF_DESKTOP_ROOT_DIRS COPIED) |
| 102 | + |
| 103 | + # Apply platform-specific desktop root overlay |
| 104 | + _cf_apply_platform_overlay("${OVERLAY_BASE}" "${CFDESKTOP_DEFAULT_ROOT}" COPIED) |
| 105 | + |
| 106 | + if(COPIED GREATER 0) |
| 107 | + log_info("DesktopOverlay" "Applied ${COPIED} desktop root overlay file(s) -> ${CFDESKTOP_DEFAULT_ROOT}") |
| 108 | + else() |
| 109 | + log_info("DesktopOverlay" "No desktop root overlay files to apply") |
| 110 | + endif() |
| 111 | +endfunction() |
| 112 | + |
| 113 | + |
| 114 | +# ============================================================ |
| 115 | +# Platform-specific overlay dispatch |
| 116 | +# ============================================================ |
| 117 | +function(_cf_apply_platform_overlay OVERLAY_BASE OUTPUT_DIR RESULT_COUNT) |
| 118 | + if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32) |
| 119 | + return() |
| 120 | + endif() |
| 121 | + |
| 122 | + if(WIN32) |
| 123 | + set(PLATFORM_NAME "windows") |
| 124 | + else() |
| 125 | + string(TOLOWER "${CMAKE_SYSTEM_NAME}" PLATFORM_NAME) |
| 126 | + endif() |
| 127 | + |
| 128 | + set(PLATFORM_OVERLAY "${OVERLAY_BASE}/${PLATFORM_NAME}") |
| 129 | + if(NOT IS_DIRECTORY "${PLATFORM_OVERLAY}") |
| 130 | + return() |
| 131 | + endif() |
| 132 | + |
| 133 | + log_info("DesktopOverlay" "Applying platform overlay: ${PLATFORM_NAME}") |
| 134 | + |
| 135 | + # Platform overlay overwrites generic (FORCE behavior) |
| 136 | + set(_SAVED_FORCE ${CFDESKTOP_OVERLAY_FORCE}) |
| 137 | + set(CFDESKTOP_OVERLAY_FORCE ON) |
| 138 | + _cf_overlay_copy_layer("${PLATFORM_OVERLAY}" "${OUTPUT_DIR}" "" COPIED) |
| 139 | + set(CFDESKTOP_OVERLAY_FORCE ${_SAVED_FORCE}) |
| 140 | + |
| 141 | + math(EXPR TOTAL "${${RESULT_COUNT}} + ${COPIED}") |
| 142 | + set(${RESULT_COUNT} ${TOTAL} PARENT_SCOPE) |
| 143 | +endfunction() |
| 144 | + |
| 145 | + |
| 146 | +# ============================================================ |
| 147 | +# Internal helper: copy one overlay layer |
| 148 | +# ============================================================ |
| 149 | +# LAYER_DIR - source overlay directory |
| 150 | +# OUTPUT_DIR - destination directory |
| 151 | +# FILTER_DIRS - variable name containing dir names to include |
| 152 | +# (empty string = include all) |
| 153 | +# RESULT_COUNT - variable to accumulate copied file count |
| 154 | +# ============================================================ |
| 155 | +function(_cf_overlay_copy_layer LAYER_DIR OUTPUT_DIR FILTER_DIRS RESULT_COUNT) |
| 156 | + file(GLOB_RECURSE OVERLAY_FILES RELATIVE "${LAYER_DIR}" "${LAYER_DIR}/*") |
| 157 | + list(LENGTH OVERLAY_FILES FILE_COUNT) |
| 158 | + |
| 159 | + if(FILE_COUNT EQUAL 0) |
| 160 | + return() |
| 161 | + endif() |
| 162 | + |
| 163 | + set(_LOCAL_COPIED 0) |
| 164 | + |
| 165 | + foreach(REL_PATH ${OVERLAY_FILES}) |
| 166 | + # Skip placeholder and VCS files |
| 167 | + get_filename_component(FILENAME "${REL_PATH}" NAME) |
| 168 | + if(FILENAME STREQUAL ".gitkeep" OR FILENAME STREQUAL ".gitignore") |
| 169 | + continue() |
| 170 | + endif() |
| 171 | + |
| 172 | + # Skip platform subdirectories (handled by _cf_apply_platform_overlay) |
| 173 | + get_filename_component(FIRST_SEG "${REL_PATH}" DIRECTORY) |
| 174 | + if(FIRST_SEG) |
| 175 | + string(FIND "${FIRST_SEG}" "/" _SLASH_POS) |
| 176 | + if(_SLASH_POS EQUAL 0) |
| 177 | + string(SUBSTRING "${FIRST_SEG}" 0 ${_SLASH_POS} _TOP_DIR) |
| 178 | + else() |
| 179 | + set(_TOP_DIR "${FIRST_SEG}") |
| 180 | + endif() |
| 181 | + list(FIND _CF_PLATFORM_DIRS "${_TOP_DIR}" _IS_PLATFORM) |
| 182 | + if(NOT _IS_PLATFORM EQUAL -1) |
| 183 | + continue() |
| 184 | + endif() |
| 185 | + endif() |
| 186 | + |
| 187 | + # Filter by directory scope if specified |
| 188 | + if(FILTER_DIRS) |
| 189 | + # Extract top-level directory name |
| 190 | + get_filename_component(_TOP_LEVEL "${REL_PATH}" DIRECTORY) |
| 191 | + if(_TOP_LEVEL) |
| 192 | + string(REPLACE "/" ";" _PATH_PARTS "${_TOP_LEVEL}") |
| 193 | + list(GET _PATH_PARTS 0 _DIR_NAME) |
| 194 | + else() |
| 195 | + set(_DIR_NAME "${REL_PATH}") |
| 196 | + endif() |
| 197 | + |
| 198 | + list(FIND ${FILTER_DIRS} "${_DIR_NAME}" _MATCHED) |
| 199 | + if(_MATCHED EQUAL -1) |
| 200 | + continue() |
| 201 | + endif() |
| 202 | + endif() |
| 203 | + |
| 204 | + set(SRC "${LAYER_DIR}/${REL_PATH}") |
| 205 | + set(DST "${OUTPUT_DIR}/${REL_PATH}") |
| 206 | + |
| 207 | + # Ensure destination directory exists |
| 208 | + get_filename_component(DST_DIR "${DST}" DIRECTORY) |
| 209 | + file(MAKE_DIRECTORY "${DST_DIR}") |
| 210 | + |
| 211 | + # Copy file |
| 212 | + if(NOT EXISTS "${DST}" OR CFDESKTOP_OVERLAY_FORCE) |
| 213 | + file(COPY "${SRC}" DESTINATION "${DST_DIR}") |
| 214 | + math(EXPR _LOCAL_COPIED "${_LOCAL_COPIED} + 1") |
| 215 | + log_info("DesktopOverlay" " -> ${REL_PATH}") |
| 216 | + endif() |
| 217 | + endforeach() |
| 218 | + |
| 219 | + math(EXPR TOTAL "${${RESULT_COUNT}} + ${_LOCAL_COPIED}") |
| 220 | + set(${RESULT_COUNT} ${TOTAL} PARENT_SCOPE) |
| 221 | +endfunction() |
| 222 | + |
| 223 | + |
| 224 | +# ============================================================ |
| 225 | +# Install rule: package for cross-compile deployment |
| 226 | +# ============================================================ |
| 227 | +# Usage: cmake --install <build_dir> --prefix <deploy_dir> |
| 228 | +# Result: <deploy_dir>/bin/ <- executable + runtime overlay |
| 229 | +# <deploy_dir>/desktop/ <- desktop root overlay |
| 230 | +# ============================================================ |
| 231 | +function(cf_install_desktop_overlay) |
| 232 | + set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/bin") |
| 233 | + |
| 234 | + # Install runtime output (binaries + runtime overlay) |
| 235 | + install(DIRECTORY "${OUTPUT_DIR}/" |
| 236 | + DESTINATION bin |
| 237 | + USE_SOURCE_PERMISSIONS |
| 238 | + PATTERN "*.pdb" EXCLUDE |
| 239 | + ) |
| 240 | + |
| 241 | + # Install desktop root overlay (if CFDESKTOP_DEFAULT_ROOT has content) |
| 242 | + if(DEFINED CFDESKTOP_DEFAULT_ROOT AND IS_DIRECTORY "${CFDESKTOP_DEFAULT_ROOT}") |
| 243 | + install(DIRECTORY "${CFDESKTOP_DEFAULT_ROOT}/" |
| 244 | + DESTINATION desktop |
| 245 | + USE_SOURCE_PERMISSIONS |
| 246 | + PATTERN "*.log" EXCLUDE |
| 247 | + ) |
| 248 | + endif() |
| 249 | + |
| 250 | + log_info("DesktopOverlay" "Install rule configured") |
| 251 | +endfunction() |
0 commit comments