Template
feat(gen): generate --help and argument parsing
Replace the v1 minimal preamble in the generated ./configure with the
full argument-parsing section (src/gen/args.{h,c}): -h/--help usage,
--version, --prefix/--exec-prefix/--host/--build in = and space forms,
per-DSL-option --enable-<name>/--disable-<name> (default from the
option's default property), generic positional VAR=VALUE overrides
(identifier-validated, single-quote-escaped eval assignment), unknown
--* -> usage on stderr + exit 1, cross_compiling=yes when --host differs
from --build. The substitution set gains exec_prefix/host/build/
cross_compiling plus one enable_<name> per option. Option names are
validated as shell identifiers at generation time.
Tests: 12 new /gen/args/* cases (help lists --prefix/--enable-debug/
--disable-debug; CC=clang positional + env; enable/debug default;
cross_compiling observable; --bogus/--bogus=1/--enable- errors;
--prefix missing/empty; space form; exec_prefix defaulting; VAR=VALUE
injection inert; hostile option name errors at generation) - 28/28
green, three-shell -n + banned-construct sweep clean.
This commit is contained in:
+40
-42
@@ -20,6 +20,7 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "gen/args.h"
|
||||
#include "gen/config.h"
|
||||
#include "gen/configure.h"
|
||||
|
||||
@@ -205,39 +206,6 @@ name_equals(const struct st_kdl_token_ref *name, const char *s, bool *out)
|
||||
/* The `%` in `printf '... %s ...'` is why these are emitted with
|
||||
* st_sh_emit_str (verbatim), not fprintf (which would eat `%s`). */
|
||||
|
||||
static const char PREAMBLE[] =
|
||||
"\n"
|
||||
"# --- PREAMBLE ---\n"
|
||||
"# v1 MINIMAL argument handling. todo 18 replaces this whole section\n"
|
||||
"# with the full --help / --enable-*/--with-*/VAR=VALUE parser.\n"
|
||||
"prefix=/usr/local\n"
|
||||
"srcdir=.\n"
|
||||
"build=\n"
|
||||
"host=\n"
|
||||
"cross_compiling=no\n"
|
||||
"\n"
|
||||
"# VAR=VALUE overrides reach configure as environment variables (the\n"
|
||||
"# invoking shell exported them, e.g. `CC=clang ./configure`), so v1\n"
|
||||
"# needs no handling here. The positional form (`./configure CC=clang`)\n"
|
||||
"# is accepted but ignored until todo 18 exports it.\n"
|
||||
"for st_arg in \"$@\"; do\n"
|
||||
" case \"$st_arg\" in\n"
|
||||
" --prefix=*) prefix=${st_arg#--prefix=} ;;\n"
|
||||
" --build=*) build=${st_arg#--build=} ;;\n"
|
||||
" --host=*) host=${st_arg#--host=} ;;\n"
|
||||
" *=*) : ;;\n"
|
||||
" *)\n"
|
||||
" printf 'configure: error: unrecognized option %s\\n' \"$st_arg\" >&2\n"
|
||||
" exit 1\n"
|
||||
" ;;\n"
|
||||
" esac\n"
|
||||
"done\n"
|
||||
"\n"
|
||||
"# cross-compiling when --host differs from --build (both set)\n"
|
||||
"if [ -n \"$host\" ] && [ \"$host\" != \"$build\" ]; then\n"
|
||||
" cross_compiling=yes\n"
|
||||
"fi\n";
|
||||
|
||||
static const char HOST_DETECT_PRE[] =
|
||||
"\n"
|
||||
"# --- host detection ---\n";
|
||||
@@ -601,6 +569,7 @@ st_gen_configure_emit(FILE *out, const struct st_kdl_document *doc,
|
||||
size_t i;
|
||||
struct st_error *err = NULL;
|
||||
const struct st_kdl_node *node;
|
||||
struct st_gen_args args;
|
||||
char **subst_names = NULL;
|
||||
size_t n_subst = 0;
|
||||
char **feat_names = NULL;
|
||||
@@ -610,19 +579,27 @@ st_gen_configure_emit(FILE *out, const struct st_kdl_document *doc,
|
||||
if (out == NULL || doc == NULL || ctx == NULL) {
|
||||
return st_error_usage("st_gen_configure_emit: NULL argument");
|
||||
}
|
||||
memset(&args, 0, sizeof args);
|
||||
err = st_gen_args_collect(doc, &args);
|
||||
if (err != NULL) {
|
||||
goto done;
|
||||
}
|
||||
reg = st_ext_var_registry(ctx);
|
||||
if (reg == NULL) {
|
||||
return st_error_usage("st_gen_configure_emit: ctx has no variable "
|
||||
"registry");
|
||||
err = st_error_usage("st_gen_configure_emit: ctx has no variable "
|
||||
"registry");
|
||||
goto done;
|
||||
}
|
||||
n_reg = st_registry_var_count(reg);
|
||||
|
||||
/* collect the full @VAR@ substitution set: registered vars + the
|
||||
* built-ins LIBS/prefix/srcdir */
|
||||
n_subst = n_reg + 3;
|
||||
* built-ins LIBS/prefix/exec_prefix/srcdir/host/build/cross_compiling
|
||||
* + one enable_<name> per DSL option (todo 18) */
|
||||
n_subst = n_reg + 7 + args.option_count;
|
||||
subst_names = calloc(n_subst, sizeof(*subst_names));
|
||||
if (subst_names == NULL) {
|
||||
return st_error_internal("out of memory building substitution set");
|
||||
err = st_error_internal("out of memory building substitution set");
|
||||
goto done;
|
||||
}
|
||||
for (i = 0; i < n_reg; i++) {
|
||||
const char *name = st_registry_var_name(reg, i);
|
||||
@@ -640,7 +617,20 @@ st_gen_configure_emit(FILE *out, const struct st_kdl_document *doc,
|
||||
}
|
||||
subst_names[n_reg + 0] = "LIBS";
|
||||
subst_names[n_reg + 1] = "prefix";
|
||||
subst_names[n_reg + 2] = "srcdir";
|
||||
subst_names[n_reg + 2] = "exec_prefix";
|
||||
subst_names[n_reg + 3] = "srcdir";
|
||||
subst_names[n_reg + 4] = "host";
|
||||
subst_names[n_reg + 5] = "build";
|
||||
subst_names[n_reg + 6] = "cross_compiling";
|
||||
for (i = 0; i < args.option_count; i++) {
|
||||
subst_names[n_reg + 7 + i] = strbuild("enable_%s",
|
||||
args.options[i].name);
|
||||
if (subst_names[n_reg + 7 + i] == NULL) {
|
||||
err = st_error_internal("out of memory building substitution "
|
||||
"set");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* 1. shebang + header comment */
|
||||
if (st_sh_emit_str(out, "#!/bin/sh\n") < 0 ||
|
||||
@@ -651,9 +641,9 @@ st_gen_configure_emit(FILE *out, const struct st_kdl_document *doc,
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* 2. preamble (minimal args; todo 18 replaces it) */
|
||||
if (st_sh_emit_str(out, PREAMBLE) < 0) {
|
||||
err = st_error_io("I/O error emitting preamble");
|
||||
/* 2. preamble: full argument parsing (todo 18) */
|
||||
err = st_gen_args_emit(out, &args);
|
||||
if (err != NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -787,7 +777,15 @@ done:
|
||||
free(feat_names[i]);
|
||||
}
|
||||
free(feat_names);
|
||||
/* the enable_<name> entries are owned (strbuild); the rest of
|
||||
* subst_names holds borrowed literals/registry pointers */
|
||||
if (subst_names != NULL && n_reg + 7 <= n_subst) {
|
||||
for (i = n_reg + 7; i < n_subst; i++) {
|
||||
free(subst_names[i]);
|
||||
}
|
||||
}
|
||||
free(subst_names);
|
||||
st_gen_args_free(&args);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user