11#! /usr/bin/env zsh
2+ # File: ci/create_doxygen.sh
3+ #
24# Purpose:
3- # - Generate an up-to-date base Doxyfile from `doxygen -g` (cached per doxygen version )
4- # - Sanitize that base deterministically on every run (fixes template multi-line lists)
5- # - Emit a tiny per-module Doxyfile that @INCLUDEs that sanitized base
5+ # - Generate a fresh base Doxyfile from `doxygen -g` on every run (NO .cache usage )
6+ # - Sanitize that base deterministically (fixes template multi-line lists)
7+ # - Emit a per-module Doxyfile that INLINES the sanitized base + module overrides
68#
79# Usage:
810# ./ci/create_doxygen.sh <module_name>
@@ -15,14 +17,9 @@ die() { print -u2 -- "ERROR: $*"; exit 2; }
1517mod=" $1 "
1618
1719script_dir=" ${0: A: h} "
18- cache_dir=" $script_dir /doxygen/.cache"
19- mkdir -p " $cache_dir "
20-
21- base_pure=" $cache_dir /Doxyfile.pure"
22- base_file=" $cache_dir /Doxyfile.base"
23- ver_file=" $cache_dir /doxygen.version"
2420
25- doxver=" $( doxygen --version) "
21+ doxver=" $( doxygen --version 2> /dev/null || true) "
22+ [[ -n " $doxver " ]] || die " doxygen not found in PATH"
2623
2724# Portable in-place sed (BSD/macOS vs GNU)
2825inplace_sed () {
@@ -35,30 +32,33 @@ inplace_sed() {
3532 fi
3633}
3734
38-
3935# Replace a doxygen list key that may be written as a multi-line block:
4036# KEY = *.a \
4137# *.b \
4238# with a single-line canonical:
4339# KEY = value
4440#
45- # We remove the KEY line and its following "indented *..." continuation lines,
46- # then append the canonical KEY line. Appending is semantically fine for doxygen.
41+ # Strategy:
42+ # - Remove KEY line and continuation lines that follow it
43+ # - Append canonical KEY line at end (Doxygen accepts last-one-wins)
4744replace_doxy_list_key_single_line () {
4845 local file=" $1 "
4946 local key=" $2 "
5047 local value=" $3 "
5148
5249 # Remove existing KEY line + template continuation lines that follow it.
50+ # Continuations from `doxygen -g` are often indented and may start with "*.ext".
5351 awk -v key=" ^" key" [[:space:]]*=" '
5452 BEGIN{skip=0}
55- $0 ~ key { skip=1; next } # drop the KEY = ... line
56- skip && $0 ~ /^[[:space:]]+\*/ { next } # drop indented "*.ext \" lines
57- skip { skip=0 } # first non-continuation after block
53+ $0 ~ key { skip=1; next } # drop the KEY = ... line
54+ skip && $0 ~ /^[[:space:]]+\*/ { next } # drop indented "*..." lines
55+ skip && $0 ~ /^[[:space:]]+\*\.[^[:space:]]/ { next } # (extra defensive)
56+ skip && $0 ~ /^[[:space:]]+[^#[:space:]].*\\$/ { next } # drop generic "\" continuation lines
57+ skip { skip=0 } # first non-continuation after block
5858 { print }
5959 ' " $file " > " $file .tmp" && mv " $file .tmp" " $file "
6060
61- # Defensive: remove any stray KEY lines that might still exist (shouldn't) .
61+ # Defensive: remove any stray KEY lines that might still exist.
6262 if grep -qE " ^${key} [[:space:]]*=" " $file " ; then
6363 inplace_sed " /^${key} [[:space:]]*=/d" " $file "
6464 fi
@@ -88,7 +88,6 @@ sanitize_base() {
8888 inplace_sed ' s|^QUIET[[:space:]]*=.*|QUIET = YES|g' " $f "
8989 inplace_sed ' s|^WARNINGS[[:space:]]*=.*|WARNINGS = YES|g' " $f "
9090
91-
9291 replace_doxy_list_key_single_line " $f " " FILE_PATTERNS" \
9392 " *.h *.hh *.hpp *.hxx *.c *.cc *.cpp *.cxx *.C *.H"
9493
@@ -106,34 +105,29 @@ sanitize_base() {
106105 inplace_sed ' /^HTML_OUTPUT[[:space:]]*=/d' " $f "
107106 inplace_sed ' /^GENERATE_TAGFILE[[:space:]]*=/d' " $f "
108107 inplace_sed ' /^TAGFILES[[:space:]]*=/d' " $f "
109- }
110108
111- # ---- (re)generate base if missing or doxygen version changed ----
112- need_regen=0
113- if [[ ! -f " $base_pure " || ! -f " $base_file " || ! -f " $ver_file " ]]; then
114- need_regen=1
115- elif [[ " $( cat " $ver_file " ) " != " $doxver " ]]; then
116- need_regen=1
117- fi
109+ # Defensive: remove any stray lines that start with "*" (cause: broken multi-line list blocks)
110+ inplace_sed ' /^[[:space:]]*\*/d' " $f "
111+ }
118112
119- if (( need_regen )) ; then
120- print -- " [create_doxygen] Generating base for doxygen $doxver "
121- doxygen -g " $base_pure " > /dev/null 2>&1
122- cp -f " $base_pure " " $base_file "
123- print -- " $doxver " > " $ver_file "
124- fi
113+ # ---- Generate fresh base every run (no .cache usage) ----
114+ tmp_pure=" $( mktemp " ${TMPDIR:-/ tmp} /Doxyfile.pure.XXXXXX" ) "
115+ tmp_base=" $( mktemp " ${TMPDIR:-/ tmp} /Doxyfile.base.XXXXXX" ) "
116+ cleanup () { rm -f -- " $tmp_pure " " $tmp_base " ; }
117+ trap cleanup EXIT
125118
126- # Always sanitize (fixes stale/broken cache contents too)
127- [[ -f " $base_file " ]] || die " Missing base file ' $base_file ' "
128- sanitize_base " $base_file "
119+ print -- " [create_doxygen] Generating base for doxygen $doxver "
120+ doxygen -g " $tmp_pure " > /dev/null 2>&1
121+ cp -f " $tmp_pure " " $tmp_base "
129122
130- # Emit tiny module Doxyfile that includes the generated base.
131- # Use absolute path so it works regardless of where the module lives.
132- base_abs=" $base_file "
123+ sanitize_base " $tmp_base "
133124
134- cat > Doxyfile << EOF
135- @INCLUDE = $base_abs
125+ # Emit a module Doxyfile by inlining the sanitized base, then overriding.
126+ {
127+ cat " $tmp_base "
128+ cat << EOF
136129
130+ # ---- module overrides ----
137131PROJECT_NAME = "$mod "
138132INPUT = .
139133OUTPUT_DIRECTORY = ../pages
@@ -143,6 +137,7 @@ HTML_EXTRA_STYLESHEET = mydoxygen.css
143137
144138# TAGFILES is injected by ci/doxygen.sh in pass 2
145139EOF
140+ } > Doxyfile
146141
147142# Optional: keep local copy for debugging/inspection
148143cp -f Doxyfile DoxyfilePure 2> /dev/null || true
0 commit comments