/* * config.h - emitters for the configure-time auxiliary artifacts * (todo 17): config.log, config.h and config.status. * * MODEL: like everything in src/gen/, these functions are PURE CODE * GENERATORS. They emit POSIX-sh sections INTO the generated ./configure; * the artifacts themselves are written AT CONFIGURE TIME by the generated * script, so their contents always reflect the actual probe results and * the actual invocation - never the generator's guesses. * * THE FOUR SECTIONS (see also gen/configure.h for their placement in the * generated script): * * st_gen_config_log_init_emit after the preamble: capture the * original invocation (st_orig_args="$@", st_configure_path=$0, * plus single-quote-escaped copies built with sed) and truncate- * write the transcript header (created-by line, original * arguments, timestamp, host, shell) into $config_log. $config_log * is defaulted here with `:=`, idempotently with todo 12's cache * boilerplate. Probe snippets (todo 12) append their compiler * stdout/stderr to the same file. * st_gen_config_results_emit after the probe section: append a * `## results` block to $config_log with one * `have_=yes|no` line per top-level feature. * st_gen_config_h_emit after the probe section: write * ./config.h with the ST_CONFIG_H guard and one * `#define HAVE_ 1` per feature whose have_ * resolved to "yes" at configure time (the feature name upper- * cased; a failed feature gets no define). * st_gen_config_status_emit at the very end (after Makefile * substitution, before exit 0): write ./config.status - a * standalone POSIX-sh script with the captured arguments baked in * as quoted literals (so nothing in them is ever re-expanded when * config.status runs) - and chmod +x it. Its arms: ''/--recheck -> * `exec "${SHELL:-sh}" "$st_configure_path" $st_orig_args`; * --config -> print the original args; --help -> brief usage; * anything else -> error + exit 1. * * SECURITY (the sed-quote bake-in): the captured args/path are rewritten * with `sed "s/'/'\\''/g"` (every `'` becomes `'\''`) and stored in * st_orig_args_q / st_configure_path_q. config.status assigns them as * single-quoted literals (`st_orig_args='...'`), so a value containing * `$(...)`, backticks, spaces or `&` is inert both when configure writes * config.status (here-document expansion never re-parses expansion * results) and when config.status runs (the quotes are real script text * there). Proven by the injection test (todo 17, case f). * * KNOWN v1 LIMITATIONS (documented, deliberately simple): * - the recheck arm expands $st_orig_args UNQUOTED, so positional args * containing spaces or glob characters are not preserved through * --recheck (the v1 surface is --prefix/--host/--build); * - st_configure_path is captured verbatim ($0), so config.status must * be run from the same directory configure was run from; * - args containing literal newlines are pathological (they would break * the one-line bake-in). * * ERRORS: NULL arguments and feature names that are not valid POSIX shell * identifiers return ST_ERR_USAGE (the names land in have_ and * #define HAVE_ positions, which cannot be shell-quoted); stream * write failures return ST_ERR_IO. * * Copyright (c) 2026 huntedbytheirs * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ST_GEN_CONFIG_H #define ST_GEN_CONFIG_H #include #include struct st_error; /* Emit the config.log init + original-args capture section. */ struct st_error *st_gen_config_log_init_emit(FILE *out); /* Emit the post-probe `## results` summary appended to $config_log. * `features` holds the top-level feature names (validated identifiers), * one emitted `have_=%s` line per entry. */ struct st_error *st_gen_config_results_emit(FILE *out, const char *const *features, size_t count); /* Emit the ./config.h writer (ST_CONFIG_H guard + per-feature defines). */ struct st_error *st_gen_config_h_emit(FILE *out, const char *const *features, size_t count); /* Emit the ./config.status writer (+ chmod +x). */ struct st_error *st_gen_config_status_emit(FILE *out); #endif /* ST_GEN_CONFIG_H */