[PATCH 1/6] * expand.c (variable_name_extract): extract variable name and strip prefix.

2014-08-14 Thread Macpaul Lin
Variables used in conditional lines usually has '$',
'(', and ')' prefix, and etc.
We can use vairable_name_extract() to extract pure variable
name without these prefix.

Signed-off-by: Macpaul Lin 
---
 expand.c | 72 
 1 file changed, 72 insertions(+)

diff --git a/expand.c b/expand.c
index e4b08f1..0ef5c0e 100644
--- a/expand.c
+++ b/expand.c
@@ -181,6 +181,78 @@ reference_variable (char *o, const char *name, unsigned 
int length)
   return o;
 }
 
+/* Parse P (a null-terminated string) to get the variable name.
+
+   Get rid of $(..) related symbols to get variable name as an
+   a-zA-Z0-9 string. */
+char *
+variable_name_extract (char *p, char **ps)
+{
+  char *p2 = NULL;
+  char *p3 = NULL;
+
+  while (1)
+{
+  int c = *p++;
+
+  if (!STOP_SET (c, MAP_VARIABLE))
+return (char *)p2;
+
+  if (c == '$')
+{
+  /* This begins a variable expansion reference.  Make sure we don't
+ treat chars inside the reference as assignment tokens.  */
+  char closeparen;
+  int count;
+  c = *p++;
+  if (c == '(')
+{
+  closeparen = ')';
+  p2 = p;
+}
+  else if (c == '{')
+{
+  closeparen = '}';
+}
+  else
+/* '$$' or '$X'.  Either way, nothing special to do here.  */
+continue;
+
+  /* P now points past the opening paren or brace.
+ Count parens or braces until it is matched.  */
+  count = 0;
+  for (; *p != '\0'; ++p)
+{
+  if (*p == c)
+{
+  ++count;
+  p2 = p+1;
+}
+  else if (*p == closeparen)
+{
+  --count;
+  if (count < 0)
+{
+  if (!p3)
+p3 = p;
+*ps = p3;
+}
+  else
+{
+  if (!p3)
+  p3 = p;
+}
+  ++p;
+  break;
+}
+}
+  continue;
+}
+}
+
+  return (char *)p2;
+}
+
 /* Scan STRING for variable references and expansion-function calls.  Only
LENGTH bytes of STRING are actually scanned.  If LENGTH is -1, scan until
a null byte is found.
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH 6/6] * main.c: add --dep parameter for print variable dependency

2014-08-14 Thread Macpaul Lin
(print_dependency): print each value_record and parent_record of a variable.

Signed-off-by: Macpaul Lin 
---
 main.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/main.c b/main.c
index 0508ae1..abbcb28 100644
--- a/main.c
+++ b/main.c
@@ -53,6 +53,7 @@ void remote_setup (void);
 void remote_cleanup (void);
 RETSIGTYPE fatal_error_signal (int sig);
 
+void print_variable_dependency (void);
 void print_variable_data_base (void);
 void print_dir_data_base (void);
 void print_rule_data_base (void);
@@ -180,6 +181,11 @@ int ignore_errors_flag = 0;
 
 int print_data_base_flag = 0;
 
+/* Nonzero means don't remake anything, just print the dependency
+   of variables reading from the makefile (-dep).  */
+
+int print_dependency_flag = 0;
+
 /* Nonzero means don't remake anything; just return a nonzero status
if the specified targets are not up to date (-q).  */
 
@@ -321,6 +327,8 @@ static const char *const usage[] =
 N_("\
   -d  Print lots of debugging information.\n"),
 N_("\
+  --depPrint dependency of variables extracted from 
Makefile.\n"),
+N_("\
   --debug[=FLAGS] Print various types of debugging 
information.\n"),
 N_("\
   -e, --environment-overrides\n\
@@ -407,6 +415,7 @@ static const struct command_switch switches[] =
 { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 },
 { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" },
 { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" },
+{ 'P', flag, &print_dependency_flag, 1, 1, 0, 0, 0, "print-dependency" },
 { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" },
 { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" },
 { 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0,
@@ -462,6 +471,7 @@ static struct option long_option_aliases[] =
 { "dry-run",no_argument,0, 'n' },
 { "recon",  no_argument,0, 'n' },
 { "makefile",   required_argument,  0, 'f' },
+{ "dep",no_argument,0, 'P' },
   };
 
 /* List of goal targets.  */
@@ -2610,7 +2620,7 @@ handle_non_switch_argument (const char *arg, int env)
 /* Ignore plain '-' for compatibility.  */
 return;
 
-  v = try_variable_definition (0, arg, o_command, 0);
+  v = try_variable_definition (0, arg, o_command, 0, NULL);
   if (v != 0)
 {
   /* It is indeed a variable definition.  If we don't already have this
@@ -3275,6 +3285,24 @@ print_version (void)
   fflush (stdout);
 }
 
+/* Print a bunch of information about dependency between variables.  */
+
+static void
+print_dependency ()
+{
+  time_t when = time ((time_t *) 0);
+
+  print_version ();
+
+  printf (_("\n# Make dependency from data base, printed on %s"), ctime 
(&when));
+
+  print_variable_dependency ();
+  strcache_print_stats ("#");
+
+  when = time ((time_t *) 0);
+  printf (_("\n# Finished Make dependency from data base on %s\n"), ctime 
(&when));
+}
+
 /* Print a bunch of information about this and that.  */
 
 static void
@@ -3403,6 +3431,9 @@ die (int status)
   if (print_data_base_flag)
 print_data_base ();
 
+  if (print_dependency_flag)
+print_dependency ();
+
   if (verify_flag)
 verify_file_data_base ();
 
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH 3/6] * variable.c: Add support for constructing value_records and parent_records

2014-08-14 Thread Macpaul Lin
(define_variable_in_set): assign NULL as initial value of a pointer to
value_record.
(free_parent_record): free all parent_records which were assigned.
(free_variable_record): free all value_records and related parent_records
belongs to a variable.
(free_variable_name_and_value): add free_variable_record to when variable
is going to be destoryed.
(initialize_file_variables): parameters change when do_variable_definition
is called.
(alloc_parent_record): allocate memory for a parent_record.
(do_assign_parent_record): assign a parent_record to its value_record.
(do_assign_value_record): assign a value_record to related variable.
(do_variable_definition): add parent_record related processing to construct
information for a variable.
(assign_variable_definition): add parent_record as a parameter of this wrapper.
(try_variable_definition): add parent_record as a parameter of
do_variable_definition
(print_variable): dump value_record and parent_record for a variable
(print_variable_dep_set): dump dependency of value_record, parent_record of a
variable from a set.

Signed-off-by: Macpaul Lin 
---
 variable.c | 201 +++--
 1 file changed, 196 insertions(+), 5 deletions(-)

diff --git a/variable.c b/variable.c
index 3f57e7d..6ca5b56 100644
--- a/variable.c
+++ b/variable.c
@@ -254,6 +254,7 @@ define_variable_in_set (const char *name, unsigned int 
length,
   v->append = 0;
   v->private_var = 0;
   v->export = v_default;
+  v->v_records = NULL;
 
   v->exportable = 1;
   if (*name != '_' && (*name < 'A' || *name > 'Z')
@@ -279,11 +280,47 @@ define_variable_in_set (const char *name, unsigned int 
length,
variable (makefile, command line or environment). */
 
 static void
+free_parent_record (struct parent_record *record)
+{
+  struct parent_record *pr;
+
+  pr = record;
+  if (pr != NULL)
+{
+  if (pr->next != NULL)
+ free_parent_record (pr->next);
+  free (pr);
+}
+}
+
+static void
+free_variable_record (struct value_record *record)
+{
+  struct value_record *vr;
+
+  vr = record;
+  if (vr != NULL)
+{
+  if (vr->next != NULL)
+ free_variable_record (vr->next);
+
+  if (vr->p_records != NULL)
+ free_parent_record (vr->p_records);
+
+  free (vr->value);
+  free (vr);
+}
+}
+
+static void
 free_variable_name_and_value (const void *item)
 {
   struct variable *v = (struct variable *) item;
   free (v->name);
   free (v->value);
+
+  if (v->v_records)
+free_variable_record(v->v_records);
 }
 
 void
@@ -608,7 +645,7 @@ initialize_file_variables (struct file *file, int reading)
   v = do_variable_definition (
 &p->variable.fileinfo, p->variable.name,
 p->variable.value, p->variable.origin,
-p->variable.flavor, 1);
+p->variable.flavor, 1, NULL);
 }
 
   /* Also mark it as a per-target and copy export status. */
@@ -1125,17 +1162,68 @@ shell_result (const char *p)
   return result;
 }
 
+/* Given a variable as a "parent variable" which defines a value for another
+   variable.
+   This function will allocate a struct of parent_record to link these 
parents. */
+struct parent_record *
+alloc_parent_record (struct variable *parent)
+{
+  struct parent_record *pr;
+
+  pr = xmalloc(sizeof(struct parent_record));
+  pr->parent = parent;
+  pr->next = NULL;
+
+  return pr;
+}
+/* Given a defined value_record, and a parent_record, link the parents to this 
value_record. */
+void
+do_assign_parent_record (struct value_record *vr, struct parent_record 
*parents)
+{
+  struct parent_record *pr;
+ 
+  /* find the last parent_record */
+  pr = vr->p_records;
+
+  if (pr == NULL)
+vr->p_records = parents;
+  else
+{
+  while (pr->next != NULL)
+pr = pr->next;
+  pr->next = parents;
+}
+}
+
+/* Given a value of variable, return a point to a valuei_record. */
+struct value_record *
+do_assign_value_record (const char *value)
+{
+  struct value_record *vr;
+
+  vr = xmalloc(sizeof(struct value_record));
+  vr->value = xmalloc (strlen (value) + 1);
+  memcpy (vr->value, value, strlen (value));
+  vr->value[strlen (value)] = '\0';
+  vr->p_records = NULL;
+  vr->next = NULL;
+
+  return vr;
+}
+
 /* Given a variable, a value, and a flavor, define the variable.
See the try_variable_definition() function for details on the parameters. */
 
 struct variable *
 do_variable_definition (const gmk_floc *flocp, const char *varname,
 const char *value, enum variable_origin origin,
-enum variable_flavor flavor, int target_var)
+enum variable_flavor flavor, int target_var,
+struct parent_record *parents)
 

[PATCH 4/6] * read.c: Construct the dependency chain between parent and target variable

2014-08-14 Thread Macpaul Lin
(eval_makefile): deal with new parent_records paremeter for API consistancy,
(eval): assign related parent_records to target variable, and construct
tempoaray parent_records when ifdef/ifeq conditional_line is parsed.
(conditional_line): when ifdef/ifeq conditional_line is encountered,
construct tempoaray parent_records for later dependency chain assignment for
the target variable.

Signed-off-by: Macpaul Lin 
---
 read.c | 75 +-
 1 file changed, 65 insertions(+), 10 deletions(-)

diff --git a/read.c b/read.c
index 6ac66f4..8eca0ce 100644
--- a/read.c
+++ b/read.c
@@ -142,7 +142,8 @@ static void do_undefine (char *name, enum variable_origin 
origin,
  struct ebuffer *ebuf);
 static struct variable *do_define (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
-static int conditional_line (char *line, int len, const gmk_floc *flocp);
+static int conditional_line (char *line, int len, const gmk_floc *flocp,
+  struct parent_record **parents);
 static void record_files (struct nameseq *filenames, const char *pattern,
   const char *pattern_percent, char *depstr,
   unsigned int cmds_started, char *commands,
@@ -432,7 +433,7 @@ eval_makefile (const char *filename, int flags)
 
   /* Add this makefile to the list. */
   do_variable_definition (&ebuf.floc, "MAKEFILE_LIST", filename, o_file,
-  f_append, 0);
+  f_append, 0, NULL);
 
   /* Evaluate the makefile */
 
@@ -591,6 +592,7 @@ eval (struct ebuffer *ebuf, int set_default)
   const char *pattern_percent;
   gmk_floc *fstart;
   gmk_floc fi;
+  struct parent_record *parents = NULL;
 
 #define record_waiting_files()\
   do  \
@@ -749,7 +751,11 @@ eval (struct ebuffer *ebuf, int set_default)
   else if (vmod.define_v)
 v = do_define (p, origin, ebuf);
   else
-v = try_variable_definition (fstart, p, origin, 0);
+{
+  v = try_variable_definition (fstart, p, origin, 0, parents);
+  /* parents linked with variable, reset this temp parent_record  
*/
+  parents = NULL;
+}
 
   assert (v != NULL);
 
@@ -782,7 +788,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
   /* Check for conditional state changes.  */
   {
-int i = conditional_line (p, wlen, fstart);
+int i = conditional_line (p, wlen, fstart, &parents);
 if (i != -2)
   {
 if (i == -1)
@@ -1549,7 +1555,7 @@ do_define (char *name, enum variable_origin origin, 
struct ebuffer *ebuf)
 definition[idx - 1] = '\0';
 
   v = do_variable_definition (&defstart, name,
-  definition, origin, var.flavor, 0);
+  definition, origin, var.flavor, 0, NULL);
   free (definition);
   free (n);
   return (v);
@@ -1568,12 +1574,14 @@ do_define (char *name, enum variable_origin origin, 
struct ebuffer *ebuf)
1 if following text should be ignored.  */
 
 static int
-conditional_line (char *line, int len, const gmk_floc *flocp)
+conditional_line (char *line, int len, const gmk_floc *flocp, struct 
parent_record **parents)
 {
   const char *cmdname;
   enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, c_else, c_endif } cmdtype;
   unsigned int i;
   unsigned int o;
+  struct variable *current_parent = NULL;
+  struct parent_record *temp_pr;
 
   /* Compare a word, both length and contents. */
 #define word1eq(s)  (len == CSTRLEN (s) && strneq (s, line, CSTRLEN (s)))
@@ -1653,7 +1661,7 @@ conditional_line (char *line, int len, const gmk_floc 
*flocp)
 
   /* If it's 'else' or 'endif' or an illegal conditional, fail.  */
   if (word1eq ("else") || word1eq ("endif")
-  || conditional_line (line, len, flocp) < 0)
+  || conditional_line (line, len, flocp, parents) < 0)
 EXTRATEXT ();
   else
 {
@@ -1721,12 +1729,32 @@ conditional_line (char *line, int len, const gmk_floc 
*flocp)
   conditionals->ignoring[o] =
 ((v != 0 && *v->value != '\0') == (cmdtype == c_ifndef));
 
+  /* deal with defined parent of variables  */
+  current_parent = v;
+  /* if v is defined  */
+  if ((current_parent != NULL) && (parents != NULL))
+{
+  /* the first parent */
+  if (*parents == NULL)
+*parents = alloc_parent_record (current_parent);
+  else
+{
+  /* check the last parent updated  */
+  temp_pr = (*parents);
+  while (temp_pr->next != NULL)
+  temp_pr

[PATCH 2/6] * variable.h: Add support of struct value_records and parent_records

2014-08-14 Thread Macpaul Lin
(struct parent_record): add struct parent_record,
for constructing variables dependencies.
(struct value_record): add struct value_record for record
each value is assigned to a variable.
(variable_name_extract): add support to extract variable name
with [$()] prefix.
(alloc_parent_record): a function allocate memory for a parent_record
(do_variable_definition): add a paremeter of parent_records which will keep
related parent_variable occured in conditional_line.
(try_variable_definition): add a paremeter of parent_records to make
parent_record be associaited when the variable is defined.

Signed-off-by: Macpaul Lin 
---
 variable.h | 27 +--
 1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/variable.h b/variable.h
index 3e2328a..03ba18b 100644
--- a/variable.h
+++ b/variable.h
@@ -47,6 +47,23 @@ enum variable_flavor
 #define EXP_COUNT_BITS  15  /* This gets all the bitfields into 32 bits */
 #define EXP_COUNT_MAX   ((1<https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH 5/6] * load.c: add support of parent_records

2014-08-14 Thread Macpaul Lin
(do_variable_definition): fix API consistency for supporting parent_records.

Signed-off-by: Macpaul Lin 
---
 load.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/load.c b/load.c
index b937c9f..78b800f 100644
--- a/load.c
+++ b/load.c
@@ -214,7 +214,8 @@ load_file (const gmk_floc *flocp, const char **ldname, int 
noerror)
 
   /* If it succeeded, add the load file to the loaded variable.  */
   if (r > 0)
-do_variable_definition (flocp, ".LOADED", *ldname, o_default, f_append, 0);
+do_variable_definition (flocp, ".LOADED", *ldname, o_default, f_append, 0,
+NULL);
 
   return r;
 }
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH v2 3/6] * variable.c: Add support for constructing value_records and parent_records

2014-08-18 Thread Macpaul Lin
(define_variable_in_set): assign NULL as initial value of a pointer to
value_record.
(free_parent_record): free all parent_records which were assigned.
(free_variable_record): free all value_records and related parent_records
belongs to a variable.
(free_variable_name_and_value): add free_variable_record to when variable
is going to be destoryed.
(initialize_file_variables): parameters change when do_variable_definition
is called.
(alloc_parent_record): allocate memory for a parent_record.
(do_assign_parent_record): assign a parent_record to its value_record.
(do_assign_value_record): assign a value_record to related variable.
(do_variable_definition): add parent_record related processing to construct
information for a variable.
(assign_variable_definition): add parent_record as a parameter of this wrapper.
(try_variable_definition): add parent_record as a parameter of
do_variable_definition
(print_variable): dump value_record and parent_record for a variable
(print_variable_dep_set): dump dependency of value_record, parent_record of a
variable from a set.
(dup_parent_records): a function for distinquish variables in the same
conditional line's depth but may have different parents sets.
(print_value_records): a function to dump all value_records, parent_records,
and other parents_records in depths belongs to this variable.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - simplify (free_parent_record).
  - simplify (free_variable_record).
  - add (dup_parent_records).
  - add depth support to (dup_parent_records).
  - add (print_value_records).
  - simplify (print_variable).

 variable.c | 258 +++--
 1 file changed, 253 insertions(+), 5 deletions(-)

diff --git a/variable.c b/variable.c
index 3f57e7d..5ac2139 100644
--- a/variable.c
+++ b/variable.c
@@ -254,6 +254,7 @@ define_variable_in_set (const char *name, unsigned int 
length,
   v->append = 0;
   v->private_var = 0;
   v->export = v_default;
+  v->v_records = NULL;
 
   v->exportable = 1;
   if (*name != '_' && (*name < 'A' || *name > 'Z')
@@ -278,12 +279,42 @@ define_variable_in_set (const char *name, unsigned int 
length,
does not need to be null-terminated. ORIGIN specifies the origin of the
variable (makefile, command line or environment). */
 
+void
+free_parent_record (struct parent_record *pr)
+{
+  if (pr != NULL)
+{
+  if (pr->next != NULL)
+ free_parent_record (pr->next);
+  free (pr);
+}
+}
+
+static void
+free_variable_record (struct value_record *vr)
+{
+  if (vr != NULL)
+{
+  if (vr->next != NULL)
+ free_variable_record (vr->next);
+
+  if (vr->p_records != NULL)
+ free_parent_record (vr->p_records);
+
+  free (vr->value);
+  free (vr);
+}
+}
+
 static void
 free_variable_name_and_value (const void *item)
 {
   struct variable *v = (struct variable *) item;
   free (v->name);
   free (v->value);
+
+  if (v->v_records)
+free_variable_record(v->v_records);
 }
 
 void
@@ -608,7 +639,7 @@ initialize_file_variables (struct file *file, int reading)
   v = do_variable_definition (
 &p->variable.fileinfo, p->variable.name,
 p->variable.value, p->variable.origin,
-p->variable.flavor, 1);
+p->variable.flavor, 1, NULL);
 }
 
   /* Also mark it as a per-target and copy export status. */
@@ -1125,17 +1156,92 @@ shell_result (const char *p)
   return result;
 }
 
+/* Given a destination pointer to a parent records, we duplicate the linking
+   list of source parent records to the destination pointer. */
+struct parent_record *
+dup_parent_records (struct parent_record **dst_pr, struct parent_record 
*src_pr)
+{
+  /* Duplicate new parent_record and assign to this variable  */
+  struct parent_record *new_pr = NULL;
+
+  if (src_pr != NULL)
+{
+   *dst_pr = alloc_parent_record (src_pr->parent, src_pr->depth);
+   (*dst_pr)->next = NULL;
+
+   if (src_pr->next != NULL)
+ {
+   dup_parent_records (&new_pr, src_pr->next);
+   (*dst_pr)->next = new_pr;
+ }
+}
+
+  return *dst_pr;
+}
+/* Given a variable as a "parent variable" which defines a value for another
+   variable.
+   This function will allocate a struct of parent_record to link these 
parents. */
+struct parent_record *
+alloc_parent_record (struct variable *parent, unsigned int depth)
+{
+  struct parent_record *pr;
+
+  pr = xmalloc(sizeof(struct parent_record));
+  pr->parent = parent;
+  pr->depth = depth;
+  pr->next = NULL;
+
+  return pr;
+}
+/* Given a defined value_record, and a parent_record, link the parents to
+   this value_record. */
+void
+do_assign_parent_record (struct value_record *vr, struct parent_record 
*pa

[PATCH v2 2/6] * variable.h: Add support of struct value_records and parent_records

2014-08-18 Thread Macpaul Lin
(struct parent_record): add struct parent_record,
for constructing variables dependencies.
(struct value_record): add struct value_record for record
each value is assigned to a variable.
(variable_name_extract): add support to extract variable name
with [$()] prefix.
(alloc_parent_record): a function allocate memory for a parent_record
(do_variable_definition): add a paremeter of parent_records which will keep
related parent_variable occured in conditional_line.
(try_variable_definition): add a paremeter of parent_records to make
parent_record be associaited when the variable is defined.
(dup_parent_record): a function for distinquish variables in the same
conditional line's depth but may have different parents sets.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - add depth to struct parent_record.
  - add (dup_parent_record).
  - add depth support for (alloc_parent_record).

 variable.h | 32 ++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/variable.h b/variable.h
index 3e2328a..0dae4a4 100644
--- a/variable.h
+++ b/variable.h
@@ -47,6 +47,25 @@ enum variable_flavor
 #define EXP_COUNT_BITS  15  /* This gets all the bitfields into 32 bits */
 #define EXP_COUNT_MAX   ((1<https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH v2 1/6] * expand.c (variable_name_extract): extract variable name and strip prefix.

2014-08-18 Thread Macpaul Lin
Variables used in conditional lines usually has '$',
'(', and ')' prefix, and etc.
We can use vairable_name_extract() to extract pure variable
name without these prefix.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - no changes.

 expand.c | 72 
 1 file changed, 72 insertions(+)

diff --git a/expand.c b/expand.c
index e4b08f1..0ef5c0e 100644
--- a/expand.c
+++ b/expand.c
@@ -181,6 +181,78 @@ reference_variable (char *o, const char *name, unsigned 
int length)
   return o;
 }
 
+/* Parse P (a null-terminated string) to get the variable name.
+
+   Get rid of $(..) related symbols to get variable name as an
+   a-zA-Z0-9 string. */
+char *
+variable_name_extract (char *p, char **ps)
+{
+  char *p2 = NULL;
+  char *p3 = NULL;
+
+  while (1)
+{
+  int c = *p++;
+
+  if (!STOP_SET (c, MAP_VARIABLE))
+return (char *)p2;
+
+  if (c == '$')
+{
+  /* This begins a variable expansion reference.  Make sure we don't
+ treat chars inside the reference as assignment tokens.  */
+  char closeparen;
+  int count;
+  c = *p++;
+  if (c == '(')
+{
+  closeparen = ')';
+  p2 = p;
+}
+  else if (c == '{')
+{
+  closeparen = '}';
+}
+  else
+/* '$$' or '$X'.  Either way, nothing special to do here.  */
+continue;
+
+  /* P now points past the opening paren or brace.
+ Count parens or braces until it is matched.  */
+  count = 0;
+  for (; *p != '\0'; ++p)
+{
+  if (*p == c)
+{
+  ++count;
+  p2 = p+1;
+}
+  else if (*p == closeparen)
+{
+  --count;
+  if (count < 0)
+{
+  if (!p3)
+p3 = p;
+*ps = p3;
+}
+  else
+{
+  if (!p3)
+  p3 = p;
+}
+  ++p;
+  break;
+}
+}
+  continue;
+}
+}
+
+  return (char *)p2;
+}
+
 /* Scan STRING for variable references and expansion-function calls.  Only
LENGTH bytes of STRING are actually scanned.  If LENGTH is -1, scan until
a null byte is found.
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH v2 6/6] * main.c: add --dep parameter for print variable dependency

2014-08-18 Thread Macpaul Lin
(print_dependency): print each value_record and parent_record of a variable.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - no changes.

 main.c | 33 -
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/main.c b/main.c
index 0508ae1..abbcb28 100644
--- a/main.c
+++ b/main.c
@@ -53,6 +53,7 @@ void remote_setup (void);
 void remote_cleanup (void);
 RETSIGTYPE fatal_error_signal (int sig);
 
+void print_variable_dependency (void);
 void print_variable_data_base (void);
 void print_dir_data_base (void);
 void print_rule_data_base (void);
@@ -180,6 +181,11 @@ int ignore_errors_flag = 0;
 
 int print_data_base_flag = 0;
 
+/* Nonzero means don't remake anything, just print the dependency
+   of variables reading from the makefile (-dep).  */
+
+int print_dependency_flag = 0;
+
 /* Nonzero means don't remake anything; just return a nonzero status
if the specified targets are not up to date (-q).  */
 
@@ -321,6 +327,8 @@ static const char *const usage[] =
 N_("\
   -d  Print lots of debugging information.\n"),
 N_("\
+  --depPrint dependency of variables extracted from 
Makefile.\n"),
+N_("\
   --debug[=FLAGS] Print various types of debugging 
information.\n"),
 N_("\
   -e, --environment-overrides\n\
@@ -407,6 +415,7 @@ static const struct command_switch switches[] =
 { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 },
 { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" },
 { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" },
+{ 'P', flag, &print_dependency_flag, 1, 1, 0, 0, 0, "print-dependency" },
 { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" },
 { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" },
 { 'R', flag, &no_builtin_variables_flag, 1, 1, 0, 0, 0,
@@ -462,6 +471,7 @@ static struct option long_option_aliases[] =
 { "dry-run",no_argument,0, 'n' },
 { "recon",  no_argument,0, 'n' },
 { "makefile",   required_argument,  0, 'f' },
+{ "dep",no_argument,0, 'P' },
   };
 
 /* List of goal targets.  */
@@ -2610,7 +2620,7 @@ handle_non_switch_argument (const char *arg, int env)
 /* Ignore plain '-' for compatibility.  */
 return;
 
-  v = try_variable_definition (0, arg, o_command, 0);
+  v = try_variable_definition (0, arg, o_command, 0, NULL);
   if (v != 0)
 {
   /* It is indeed a variable definition.  If we don't already have this
@@ -3275,6 +3285,24 @@ print_version (void)
   fflush (stdout);
 }
 
+/* Print a bunch of information about dependency between variables.  */
+
+static void
+print_dependency ()
+{
+  time_t when = time ((time_t *) 0);
+
+  print_version ();
+
+  printf (_("\n# Make dependency from data base, printed on %s"), ctime 
(&when));
+
+  print_variable_dependency ();
+  strcache_print_stats ("#");
+
+  when = time ((time_t *) 0);
+  printf (_("\n# Finished Make dependency from data base on %s\n"), ctime 
(&when));
+}
+
 /* Print a bunch of information about this and that.  */
 
 static void
@@ -3403,6 +3431,9 @@ die (int status)
   if (print_data_base_flag)
 print_data_base ();
 
+  if (print_dependency_flag)
+print_dependency ();
+
   if (verify_flag)
 verify_file_data_base ();
 
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH v2 5/6] * load.c: add support of parent_records

2014-08-18 Thread Macpaul Lin
(do_variable_definition): fix API consistency for supporting parent_records.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - no changes.

 load.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/load.c b/load.c
index b937c9f..78b800f 100644
--- a/load.c
+++ b/load.c
@@ -214,7 +214,8 @@ load_file (const gmk_floc *flocp, const char **ldname, int 
noerror)
 
   /* If it succeeded, add the load file to the loaded variable.  */
   if (r > 0)
-do_variable_definition (flocp, ".LOADED", *ldname, o_default, f_append, 0);
+do_variable_definition (flocp, ".LOADED", *ldname, o_default, f_append, 0,
+NULL);
 
   return r;
 }
-- 
1.9.1


___
Bug-make mailing list
Bug-make@gnu.org
https://lists.gnu.org/mailman/listinfo/bug-make


[PATCH v2 4/6] * read.c: Construct the dependency chain between parent and target variable

2014-08-18 Thread Macpaul Lin
(eval_makefile): deal with new parent_records paremeter for API consistancy,
(eval): assign related parent_records to target variable, and construct
tempoaray parent_records when ifdef/ifeq conditional_line is parsed.
(conditional_line): when ifdef/ifeq conditional_line is encountered,
construct tempoaray parent_records for later dependency chain assignment for
the target variable.

Signed-off-by: Macpaul Lin 
---
Changes for v2:
  - (eval): fix the problem of mapping the same parent_records set to multiple
variable in the same ifdef/ifeq depth.
  - (conditional_line): add if_cmds->depth support.

 read.c | 109 +++--
 1 file changed, 99 insertions(+), 10 deletions(-)

diff --git a/read.c b/read.c
index 6ac66f4..4311195 100644
--- a/read.c
+++ b/read.c
@@ -142,7 +142,11 @@ static void do_undefine (char *name, enum variable_origin 
origin,
  struct ebuffer *ebuf);
 static struct variable *do_define (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
-static int conditional_line (char *line, int len, const gmk_floc *flocp);
+struct parent_record *dup_parent_records (struct parent_record **dst_pr,
+  struct parent_record *src_pr);
+void free_parent_record (struct parent_record *pr);
+static int conditional_line (char *line, int len, const gmk_floc *flocp,
+ struct parent_record **parents);
 static void record_files (struct nameseq *filenames, const char *pattern,
   const char *pattern_percent, char *depstr,
   unsigned int cmds_started, char *commands,
@@ -432,7 +436,7 @@ eval_makefile (const char *filename, int flags)
 
   /* Add this makefile to the list. */
   do_variable_definition (&ebuf.floc, "MAKEFILE_LIST", filename, o_file,
-  f_append, 0);
+  f_append, 0, NULL);
 
   /* Evaluate the makefile */
 
@@ -591,6 +595,8 @@ eval (struct ebuffer *ebuf, int set_default)
   const char *pattern_percent;
   gmk_floc *fstart;
   gmk_floc fi;
+  struct parent_record *parents = NULL;
+  struct parent_record *new_parents = NULL;
 
 #define record_waiting_files()\
   do  \
@@ -749,7 +755,14 @@ eval (struct ebuffer *ebuf, int set_default)
   else if (vmod.define_v)
 v = do_define (p, origin, ebuf);
   else
-v = try_variable_definition (fstart, p, origin, 0);
+{
+  /* duplicate parent_records to avoid wrong link caused by sharing
+ the same parent_records between variables in the same ifeq
+ depth  */
+  dup_parent_records(&new_parents, parents);
+
+  v = try_variable_definition (fstart, p, origin, 0, new_parents);
+}
 
   assert (v != NULL);
 
@@ -782,7 +795,7 @@ eval (struct ebuffer *ebuf, int set_default)
 
   /* Check for conditional state changes.  */
   {
-int i = conditional_line (p, wlen, fstart);
+int i = conditional_line (p, wlen, fstart, &parents);
 if (i != -2)
   {
 if (i == -1)
@@ -1549,7 +1562,7 @@ do_define (char *name, enum variable_origin origin, 
struct ebuffer *ebuf)
 definition[idx - 1] = '\0';
 
   v = do_variable_definition (&defstart, name,
-  definition, origin, var.flavor, 0);
+  definition, origin, var.flavor, 0, NULL);
   free (definition);
   free (n);
   return (v);
@@ -1568,12 +1581,14 @@ do_define (char *name, enum variable_origin origin, 
struct ebuffer *ebuf)
1 if following text should be ignored.  */
 
 static int
-conditional_line (char *line, int len, const gmk_floc *flocp)
+conditional_line (char *line, int len, const gmk_floc *flocp, struct 
parent_record **parents)
 {
   const char *cmdname;
   enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, c_else, c_endif } cmdtype;
   unsigned int i;
   unsigned int o;
+  struct variable *current_parent = NULL;
+  struct parent_record *temp_pr;
 
   /* Compare a word, both length and contents. */
 #define word1eq(s)  (len == CSTRLEN (s) && strneq (s, line, CSTRLEN (s)))
@@ -1604,6 +1619,33 @@ conditional_line (char *line, int len, const gmk_floc 
*flocp)
   if (!conditionals->if_cmds)
 EXTRACMD ();
 
+  /* Remove temp parent_records belongs to this depth  */
+  temp_pr = (*parents);
+  if (temp_pr != NULL)
+{
+  /* Root depth */
+  if (temp_pr->depth == conditionals->if_cmds)
+{
+  free_parent_record (temp_pr);
+  *parents = NULL;
+}
+  else
+{
+  while (temp_pr->next != NULL)
+  

Re: [PATCH v2 1/6] * expand.c (variable_name_extract): extract variable name and strip prefix.

2014-08-21 Thread Macpaul Lin
Hi, Paul and other developers,

2014-08-18 22:35 GMT+08:00 Paul Smith :
> On Mon, 2014-08-18 at 21:27 +0800, Macpaul Lin wrote:
>> Variables used in conditional lines usually has '$',
>> '(', and ')' prefix, and etc.
>> We can use vairable_name_extract() to extract pure variable
>> name without these prefix.
>
> Hello.  Thanks for your work on GNU make!
>
> Can you provide some sort of summary of the feature you've created, what
> its goals are, examples, etc.?
>
> It can be helpful to contact me or someone on the development team
> before (or while) doing feature work for GNU make.  As a GNU project,
> for example, we'll need to get copyright assignment paperwork for any
> contribution of significant size and this takes some time.
>
> Also, we may have suggestions or alternative implementations or concerns
> that should be considered.  Of course these can always be addressed
> later, but it can save some effort to think about them up-front.
>
> And finally, note that fully-formed changes need to have at least a stab
> at changes to the manual (I usually rework these but it's helpful to
> have a starting point) and some additions to the regression test suite,
> if possible.
>
> Cheers!
>

It's very happy to receive your response!
Any kind of paperwork of copyright assigment is okay!
Sure, alternative implementations or any other concenrs need to be discussed.
GNU tools are widely delopyed and used in every single second.
I hope the patches could help people instead of bring them disasters.

About the paperwork, because I'm living oudside of U.S. If it can be done by
email or fax is good. If postmail is necessary will be okay, too. Just take
longer round trip time of these documentations.

The following is the description of the purpose of these patches.

* expand.c (variable_name_extract): extract variable name and strip prefix.
* variable.h: Add support of struct value_records and parent_records
* variable.c: Add support for constructing value_records and parent_records
* read.c: Construct the dependency chain between parent and target variable
* load.c: add support of parent_records
* main.c: add --dep parameter for print variable dependency

This set of patches were created to help developers to understand
the dependencies between compile options or any other variables defined
in makefiles.
The dependencies especially indicate the relationship between a variable
parent (assigner) and a variable itself as a child (assignee).
The relationship between variable parent and variable child usually defined
by conditional lines (ifeq/ifneq/ifdef/ifndef).

By recording the operation history of these conditional lines, we can keep
the operation history of a variable child and its variable parents.
These operation histories are stored in value_record and parent_records.
A value_record is a linking list to record each value was assigned to a
variable caused by a conditional line. And the parent_record will keep the
variables which made the value is assigned to this child value.

Developers can simply dump all these informations by simply use command line
`make --dep` to dump the dependency chain stored in makefile for a software
project.

Software projects is growing bigger and bigger nowadays. By adding this
--dep features may also help developers not only to understand the relationship
between definitions in makefiles and also test if their makefile has problem
(loop) in conditional checking for variables.

Here comes the examples:

Makefile:
  A = AA
  B = BB

  ifeq ($(A),AA)
  C = CC
  endif

  ifeq ($(A),AA)
  D = DD
  ifeq ($(B),BB)
  C += CCC
  endif
  endif

  ifeq ($(D),DD)
  ifeq ($(B),BB)
  E = EE
  endif
  endif

Output of `make --dep`
A = AA
B = BB
C = CC CCC
value: CC, parent: A, value: AA;
value: CCC, parent: A, value: AA; parent: B, value: BB;
D = DD
value: DD, parent: A, value: AA;
E = EE
value: EE, parent: D ,value DD; parent: B, value: BB;
parent name: D, value: DD, parent: A, value AA;


The following are some thought and futhur extension of current implementations.
1. Since the make variable evaluation were stateless and no records stored.
This implementation will use much more memory and linear search for linking list
to value_records and parent records.
I think we can add something conditional checking if the "--dep" option has been
enabled. There is no need to maintain these records if "--dep" option was not
enabled.

2. Loop detection and blacklists support.
Actually, I've found some makefile will wrote like this.

  A = AA
  ifeq ($(A),)
  A =
  endif

This kind of codes will lead a loop for a variable link a parents to itself.
When dump all parents will cause a infinite loop.
Some project may really need this kind of code for build.
I think add a blacklist to avoid make to assign this kind of variable
as parent coul