|
40 | 40 |
|
41 | 41 | EXTRA_DIST = libhttpserver.pc.in $(DX_CONFIG) scripts/extract-release-notes.sh scripts/validate-version.sh \ |
42 | 42 | test/headers/consumer_direct.cpp test/headers/consumer_detail.cpp test/headers/consumer_umbrella.cpp \ |
43 | | - test/headers/consumer_post_umbrella.cpp |
| 43 | + test/headers/consumer_post_umbrella.cpp \ |
| 44 | + test/headers/consumer_umbrella_no_backend.cpp |
44 | 45 |
|
45 | 46 | # --------------------------------------------------------------------------- |
46 | 47 | # Header-hygiene checks (TASK-002) |
@@ -131,45 +132,160 @@ CHECK_INSTALL_STAGE = $(abs_top_builddir)/.install-stage |
131 | 132 |
|
132 | 133 | check-install-layout: |
133 | 134 | @echo "=== check-install-layout: staged install must hide details/ and *_impl.hpp ===" |
134 | | - @rm -rf $(CHECK_INSTALL_STAGE) |
135 | | - @$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(CHECK_INSTALL_STAGE) >check-install.log 2>&1 || { \ |
136 | | - echo "FAIL: staged install failed"; \ |
137 | | - cat check-install.log; \ |
138 | | - rm -f check-install.log; \ |
| 135 | + @if test "$(CHECK_INSTALL_SHARED)" != "yes"; then \ |
139 | 136 | rm -rf $(CHECK_INSTALL_STAGE); \ |
140 | | - exit 1; \ |
141 | | - } |
142 | | - @rm -f check-install.log |
| 137 | + $(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(CHECK_INSTALL_STAGE) >check-install.log 2>&1 || { \ |
| 138 | + echo "FAIL: staged install failed"; \ |
| 139 | + cat check-install.log; \ |
| 140 | + rm -f check-install.log; \ |
| 141 | + rm -rf $(CHECK_INSTALL_STAGE); \ |
| 142 | + exit 1; \ |
| 143 | + }; \ |
| 144 | + rm -f check-install.log; \ |
| 145 | + fi |
143 | 146 | @leaked_details=`find $(CHECK_INSTALL_STAGE) -type d -name details 2>/dev/null`; \ |
144 | 147 | if test -n "$$leaked_details"; then \ |
145 | 148 | echo "FAIL: details/ directory leaked into install:"; \ |
146 | 149 | echo "$$leaked_details"; \ |
147 | | - rm -rf $(CHECK_INSTALL_STAGE); \ |
| 150 | + if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \ |
148 | 151 | exit 1; \ |
149 | 152 | fi |
150 | 153 | @leaked_impl=`find $(CHECK_INSTALL_STAGE) -name '*_impl.hpp' 2>/dev/null`; \ |
151 | 154 | if test -n "$$leaked_impl"; then \ |
152 | 155 | echo "FAIL: *_impl.hpp file leaked into install:"; \ |
153 | 156 | echo "$$leaked_impl"; \ |
154 | | - rm -rf $(CHECK_INSTALL_STAGE); \ |
| 157 | + if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \ |
155 | 158 | exit 1; \ |
156 | 159 | fi |
157 | 160 | @umbrella_count=`find $(CHECK_INSTALL_STAGE) -name 'httpserver.hpp' | wc -l | tr -d ' '`; \ |
158 | 161 | if test "$$umbrella_count" != "1"; then \ |
159 | 162 | echo "FAIL: expected exactly 1 installed httpserver.hpp, got $$umbrella_count"; \ |
160 | | - rm -rf $(CHECK_INSTALL_STAGE); \ |
| 163 | + if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi; \ |
161 | 164 | exit 1; \ |
162 | 165 | fi |
163 | | - @rm -rf $(CHECK_INSTALL_STAGE) |
| 166 | + @if test "$(CHECK_INSTALL_SHARED)" != "yes"; then rm -rf $(CHECK_INSTALL_STAGE); fi |
164 | 167 | @echo " PASS: staged install layout is clean" |
165 | 168 |
|
166 | | -check-local: check-headers check-install-layout |
| 169 | +# --------------------------------------------------------------------------- |
| 170 | +# Header-hygiene preprocessor gate (TASK-007). |
| 171 | +# |
| 172 | +# This is the preprocessor-grep half of the TASK-007 enforcement (the |
| 173 | +# compile-time half lives as `header_hygiene` in test/Makefile.am). |
| 174 | +# |
| 175 | +# Procedure: |
| 176 | +# 1. Stage `make install DESTDIR=$(CHECK_HYGIENE_STAGE)` to get a |
| 177 | +# pristine public include tree -- exactly what packagers and |
| 178 | +# downstream consumers see. |
| 179 | +# 2. Preprocess test/headers/consumer_umbrella_no_backend.cpp using |
| 180 | +# ONLY -I$(CHECK_HYGIENE_STAGE)$(includedir) plus $(CPPFLAGS) (so |
| 181 | +# e.g. /opt/homebrew/include is on the search path -- the grep |
| 182 | +# below NEEDS to resolve <microhttpd.h> if the umbrella pulls it |
| 183 | +# in, otherwise we couldn't detect the leak). |
| 184 | +# 3. Grep the cpp output for `# <line> "<file>"` line markers that |
| 185 | +# name any forbidden backend header. The line-marker filter |
| 186 | +# avoids false positives from substrings in code or comments. |
| 187 | +# |
| 188 | +# HEADER_HYGIENE_STRICT controls whether a leak is fatal: |
| 189 | +# - "no" (default until M5): leaks are reported as EXPECTED-FAIL |
| 190 | +# and exit 0. This keeps `make check` green during M2-M5 |
| 191 | +# while making M2-M5 progress visible in CI logs. |
| 192 | +# - "yes" (TASK-020 close-out): leaks are fatal. Set this from the |
| 193 | +# command line (`make check-hygiene HEADER_HYGIENE_STRICT=yes`) |
| 194 | +# or flip the default below. |
| 195 | +# |
| 196 | +# Cross-reference: keep HEADER_HYGIENE_FORBIDDEN in sync with the |
| 197 | +# #ifdef ladder in test/unit/header_hygiene_test.cpp. |
| 198 | +# --------------------------------------------------------------------------- |
| 199 | + |
| 200 | +HEADER_HYGIENE_FORBIDDEN = microhttpd\.h|pthread\.h|gnutls/gnutls\.h|sys/socket\.h|sys/uio\.h |
| 201 | +CHECK_HYGIENE_STAGE = $(abs_top_builddir)/.hygiene-stage |
| 202 | +CHECK_HYGIENE_CXX = $(CXX) -std=c++20 -E -I$(CHECK_HYGIENE_STAGE)$(includedir) $(CPPFLAGS) |
| 203 | +HEADER_HYGIENE_STRICT ?= no |
| 204 | + |
| 205 | +# Sentinel file: only re-run the staged install when headers have changed. |
| 206 | +# This is an mtime gate used exclusively for standalone `make check-hygiene` |
| 207 | +# invocations — it avoids paying a full `make install` cost on every |
| 208 | +# repeated standalone run. When check-local drives check-hygiene it sets |
| 209 | +# CHECK_HYGIENE_SHARED=yes and passes CHECK_HYGIENE_STAGE pointing at its |
| 210 | +# own pre-built shared stage, so this stamp target is bypassed entirely. |
| 211 | +HYGIENE_STAMP = $(CHECK_HYGIENE_STAGE)/.hygiene-stamp |
167 | 212 |
|
168 | | -.PHONY: check-headers check-install-layout |
| 213 | +$(HYGIENE_STAMP): $(wildcard $(top_srcdir)/src/httpserver/*.hpp) |
| 214 | + @rm -rf $(CHECK_HYGIENE_STAGE) |
| 215 | + @$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(CHECK_HYGIENE_STAGE) >check-hygiene-install.log 2>&1 || { \ |
| 216 | + echo "FAIL: staged install failed"; cat check-hygiene-install.log; \ |
| 217 | + rm -f check-hygiene-install.log; rm -rf $(CHECK_HYGIENE_STAGE); exit 1; } |
| 218 | + @rm -f check-hygiene-install.log |
| 219 | + @touch $(HYGIENE_STAMP) |
| 220 | + |
| 221 | +check-hygiene: |
| 222 | + @echo "=== check-hygiene: <httpserver.hpp> must not transitively include backend headers ===" |
| 223 | + @if test "$(CHECK_HYGIENE_SHARED)" != "yes"; then \ |
| 224 | + $(MAKE) $(AM_MAKEFLAGS) $(HYGIENE_STAMP); \ |
| 225 | + else \ |
| 226 | + if ! test -d "$(CHECK_HYGIENE_STAGE)"; then \ |
| 227 | + echo "FAIL: CHECK_HYGIENE_SHARED=yes but stage dir '$(CHECK_HYGIENE_STAGE)' does not exist."; \ |
| 228 | + echo " Always pair CHECK_HYGIENE_SHARED=yes with CHECK_HYGIENE_STAGE=<valid-dir>."; \ |
| 229 | + exit 1; \ |
| 230 | + fi; \ |
| 231 | + fi |
| 232 | + @status=0; \ |
| 233 | + if ! $(CHECK_HYGIENE_CXX) $(top_srcdir)/test/headers/consumer_umbrella_no_backend.cpp >check-hygiene.i 2>check-hygiene.err; then \ |
| 234 | + if test "$(HEADER_HYGIENE_STRICT)" = "yes"; then \ |
| 235 | + echo "FAIL: preprocessor failed"; cat check-hygiene.err; \ |
| 236 | + status=1; \ |
| 237 | + else \ |
| 238 | + echo "EXPECTED-FAIL (informational until M5): preprocessor failed against staged install."; \ |
| 239 | + echo " This is expected while M2-M5 are in flight (e.g. webserver.hpp still"; \ |
| 240 | + echo " references private detail headers that aren't shipped)."; \ |
| 241 | + echo " Tail of preprocessor diagnostics:"; \ |
| 242 | + sed 's/^/ /' check-hygiene.err | tail -10; \ |
| 243 | + fi; \ |
| 244 | + else \ |
| 245 | + leaks=`grep -hE '^# [0-9]+ "[^"]*/($(HEADER_HYGIENE_FORBIDDEN))"' check-hygiene.i | awk '{print $$3}' | sort -u`; \ |
| 246 | + if test -n "$$leaks"; then \ |
| 247 | + if test "$(HEADER_HYGIENE_STRICT)" = "yes"; then \ |
| 248 | + echo "FAIL: forbidden headers leaked through <httpserver.hpp>:"; \ |
| 249 | + echo "$$leaks"; \ |
| 250 | + status=1; \ |
| 251 | + else \ |
| 252 | + echo "EXPECTED-FAIL (informational until M5): forbidden headers currently leak through <httpserver.hpp>:"; \ |
| 253 | + echo "$$leaks"; \ |
| 254 | + fi; \ |
| 255 | + else \ |
| 256 | + echo " PASS: no forbidden headers reached the consumer TU"; \ |
| 257 | + fi; \ |
| 258 | + fi; \ |
| 259 | + rm -f check-hygiene.i check-hygiene.err; \ |
| 260 | + exit $$status |
| 261 | + |
| 262 | +# check-local runs check-install-layout and check-hygiene against a single |
| 263 | +# shared staged install to avoid paying two full `make install` costs on |
| 264 | +# every `make check`. Both sub-checks can still be invoked standalone (they |
| 265 | +# will do their own install when CHECK_*_SHARED is not set). |
| 266 | +check-local: check-headers |
| 267 | + @echo "=== Shared staged install for check-install-layout and check-hygiene ===" |
| 268 | + @rm -rf $(abs_top_builddir)/.shared-check-stage |
| 269 | + @$(MAKE) $(AM_MAKEFLAGS) install DESTDIR=$(abs_top_builddir)/.shared-check-stage >check-shared-install.log 2>&1 || { \ |
| 270 | + echo "FAIL: shared staged install failed"; cat check-shared-install.log; \ |
| 271 | + rm -f check-shared-install.log; rm -rf $(abs_top_builddir)/.shared-check-stage; exit 1; } |
| 272 | + @rm -f check-shared-install.log |
| 273 | + @$(MAKE) $(AM_MAKEFLAGS) check-install-layout \ |
| 274 | + CHECK_INSTALL_STAGE=$(abs_top_builddir)/.shared-check-stage \ |
| 275 | + CHECK_INSTALL_SHARED=yes |
| 276 | + @$(MAKE) $(AM_MAKEFLAGS) check-hygiene \ |
| 277 | + CHECK_HYGIENE_STAGE=$(abs_top_builddir)/.shared-check-stage \ |
| 278 | + CHECK_HYGIENE_SHARED=yes |
| 279 | + @rm -rf $(abs_top_builddir)/.shared-check-stage |
| 280 | + |
| 281 | +.PHONY: check-headers check-install-layout check-hygiene |
169 | 282 |
|
170 | 283 | MOSTLYCLEANFILES = $(DX_CLEANFILES) *.gcda *.gcno *.gcov |
171 | 284 | DISTCLEANFILES = DIST_REVISION |
172 | 285 |
|
| 286 | +clean-local: |
| 287 | + rm -rf $(CHECK_HYGIENE_STAGE) $(abs_top_builddir)/.shared-check-stage $(CHECK_INSTALL_STAGE) |
| 288 | + |
173 | 289 | pkgconfigdir = $(libdir)/pkgconfig |
174 | 290 | pkgconfig_DATA = libhttpserver.pc |
175 | 291 |
|
|
0 commit comments