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)

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;
 
 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);
 }

Reply via email to