Files
stupidtools/src/gen/config.h
T

93 lines
4.4 KiB
C

/*
* 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_<feature>=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_<FEATURE> 1` per feature whose have_<feature>
* 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_<name> and
* #define HAVE_<NAME> 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 <stddef.h>
#include <stdio.h>
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_<name>=%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 */