On Mon, Aug 07, 2023 at 04:42:54PM +0200, Marc Espie wrote: > I think it could be occasionally useful to know which variables have > been defined in make. > > Incidentally, this DOES exist in GNU make, so I've reused the same name > for basically the same functionality. > > I haven't checked whether NetBSD/FreeBSD introduced something similar. > > This is a fairly straightforward patch, introduces .VARIABLES corresponding > to the full list of global variables (from the command line and the Makefile) > that have been defined. > > (^ says the guy who had to remember a few details from his own(!) var.c > implementation from a few years ago) > > I just took var_get_value offline from the old macro, for readability, > even though it's likely the compiler may still decide to inline it. > > For efficiency, that list is only computed as needed, since it is > somewhat long. > > For debugging purposes, this can come in fairly handy, and I see at > least another application in ports. > > Comments and nits welcome. > > Note that the list is completely unsorted. This could be sorted through > since we already have the code for dumping purposes, but it would be even > more expensive (the order will be "random", as per the hash)
I can't judge all the implications of this, but can speak to that I compiled it and that I get a very long list of variables with: $ make show=.VARIABLES > Index: var.c > =================================================================== > RCS file: /cvs/src/usr.bin/make/var.c,v > retrieving revision 1.104 > diff -u -p -r1.104 var.c > --- var.c 9 Jun 2022 13:13:14 -0000 1.104 > +++ var.c 7 Aug 2023 14:33:42 -0000 > @@ -104,6 +104,8 @@ static char varNoError[] = ""; > bool errorIsOkay; > static bool checkEnvFirst; /* true if environment should be searched for > * variables before the global context */ > + /* do we need to recompute varname_list */ > +static bool varname_list_changed = true; I assume the comment /* do we need to recompute varname_list */ is not meant to be contiguous with the 2 comment lines above (/* true if... * variables before...). I suggest using whitespace (newline?) to make that clearer. I looked through the file and it seems that varname_list_changed is never set to anything but true. Is there a bit missing, like down lower in varname_list_retrieve()? > > void > Var_setCheckEnvFirst(bool yes) > @@ -228,9 +230,12 @@ typedef struct Var_ { > */ > #define POISONS (POISON_NORMAL | POISON_EMPTY | POISON_NOT_DEFINED) > /* Defined in var.h */ > +#define VAR_IS_NAMES 1024 /* Very expensive, only defined when needed */ > char name[1]; /* the variable's name */ > } Var; > > +/* for GNU make compatibility */ > +#define VARNAME_LIST ".VARIABLES" > > static struct ohash_info var_info = { > offsetof(Var, name), > @@ -245,10 +250,11 @@ static void fill_from_env(Var *); > static Var *create_var(const char *, const char *); > static void var_set_initial_value(Var *, const char *); > static void var_set_value(Var *, const char *); > -#define var_get_value(v) ((v)->flags & VAR_EXEC_LATER ? \ > - var_exec_cmd(v) : \ > - Buf_Retrieve(&((v)->val))) > -static char *var_exec_cmd(Var *); > +static char *var_get_value(Var *); > +static void var_exec_cmd(Var *); > +static void varname_list_retrieve(Var *); > + > + > static void var_append_value(Var *, const char *); > static void poison_check(Var *); > static void var_set_append(const char *, const char *, const char *, int, > bool); > @@ -423,6 +429,7 @@ var_set_initial_value(Var *v, const char > len = strlen(val); > Buf_Init(&(v->val), len+1); > Buf_AddChars(&(v->val), len, val); > + varname_list_changed = true; > } > > /* Normal version of var_set_value(), to be called after variable is fully > @@ -440,6 +447,16 @@ var_set_value(Var *v, const char *val) > } > } > > +static char * > +var_get_value(Var *v) > +{ > + if (v->flags & VAR_IS_NAMES) > + varname_list_retrieve(v); > + else if (v->flags & VAR_EXEC_LATER) > + var_exec_cmd(v); > + return Buf_Retrieve(&(v->val)); > +} > + > /* Add to a variable, insert a separating space if the variable was already > * defined. > */ > @@ -628,6 +645,7 @@ Var_Deletei(const char *name, const char > > ohash_remove(&global_variables, slot); > delete_var(v); > + varname_list_changed = true; > } > > /* Set or add a global variable, either to VAR_CMD or VAR_GLOBAL. > @@ -687,7 +705,7 @@ Var_Appendi_with_ctxt(const char *name, > var_set_append(name, ename, val, ctxt, true); > } > > -static char * > +static void > var_exec_cmd(Var *v) > { > char *arg = Buf_Retrieve(&(v->val)); > @@ -699,7 +717,27 @@ var_exec_cmd(Var *v) > var_set_value(v, res1); > free(res1); > v->flags &= ~VAR_EXEC_LATER; > - return Buf_Retrieve(&(v->val)); > +} > + > +static void > +varname_list_retrieve(Var *v) > +{ > + unsigned int i; > + void *e; > + bool first = true; > + > + for (e = ohash_first(&global_variables, &i); e != NULL; > + e = ohash_next(&global_variables, &i)) { > + Var *v2 = e; > + if (v2->flags & VAR_DUMMY) > + continue; > + > + if (first) > + var_set_value(v, v2->name); > + else > + var_append_value(v, v2->name); > + first = false; > + } > } > > /* XXX different semantics for Var_Valuei() and Var_Definedi(): > @@ -1339,6 +1377,19 @@ set_magic_shell_variable() > v->flags = VAR_IS_SHELL | VAR_SEEN_ENV; > } > > +static void > +set_magic_name_list_variable() > +{ > + const char *name = VARNAME_LIST; > + const char *ename = NULL; > + uint32_t k; > + Var *v; > + > + k = ohash_interval(name, &ename); > + v = find_global_var_without_env(name, ename, k); > + var_set_initial_value(v, ""); > + v->flags = VAR_IS_NAMES; > +} > /* > * Var_Init > * Initialize the module > @@ -1348,11 +1399,10 @@ Var_Init(void) > { > ohash_init(&global_variables, 10, &var_info); > set_magic_shell_variable(); > - > + set_magic_name_list_variable(); > > errorIsOkay = true; > Var_setCheckEnvFirst(false); > - > VarModifiers_Init(); > Buf_Init(&subst_buffer, MAKE_BSIZE); > } >