Esempio n. 1
0
static int
dep_hash_cmp (const void *x, const void *y)
{
    const struct dep *dx = x;
    const struct dep *dy = y;
    return strcmp (dep_name (dx), dep_name (dy));
}
Esempio n. 2
0
static int
update_file_1 (struct file *file, unsigned int depth)
{
  FILE_TIMESTAMP this_mtime;
  int noexist, must_make, deps_changed;
  int dep_status = 0;
  struct file *ofile;
  struct dep *d, *ad;
  struct dep amake;
  int running = 0;

  DBF (DB_VERBOSE, _("Considering target file '%s'.\n"));

  if (file->updated)
    {
      if (file->update_status > 0)
	{
	  DBF (DB_VERBOSE,
               _("Recently tried and failed to update file '%s'.\n"));

          /* If the file we tried to make is marked no_diag then no message
             was printed about it when it failed during the makefile rebuild.
             If we're trying to build it again in the normal rebuild, print a
             message now.  */
          if (file->no_diag && !file->dontcare)
              complain (file);

	  return file->update_status;
	}

      DBF (DB_VERBOSE, _("File '%s' was considered already.\n"));
      return 0;
    }

  switch (file->command_state)
    {
    case cs_not_started:
    case cs_deps_running:
      break;
    case cs_running:
      DBF (DB_VERBOSE, _("Still updating file '%s'.\n"));
      return 0;
    case cs_finished:
      DBF (DB_VERBOSE, _("Finished updating file '%s'.\n"));
      return file->update_status;
    default:
      abort ();
    }

  /* Determine whether the diagnostics will be issued should this update
     fail. */
  file->no_diag = file->dontcare;

  ++depth;

  /* Notice recursive update of the same file.  */
  start_updating (file);

  /* We might change file if we find a different one via vpath;
     remember this one to turn off updating.  */
  ofile = file;

  /* Looking at the file's modtime beforehand allows the possibility
     that its name may be changed by a VPATH search, and thus it may
     not need an implicit rule.  If this were not done, the file
     might get implicit commands that apply to its initial name, only
     to have that name replaced with another found by VPATH search.  */

  this_mtime = file_mtime (file);
  check_renamed (file);
  noexist = this_mtime == NONEXISTENT_MTIME;
  if (noexist)
    DBF (DB_BASIC, _("File '%s' does not exist.\n"));
  else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX
	   && file->low_resolution_time)
    {
      /* Avoid spurious rebuilds due to low resolution time stamps.  */
      int ns = FILE_TIMESTAMP_NS (this_mtime);
      if (ns != 0)
	error (NILF, _("*** Warning: .LOW_RESOLUTION_TIME file '%s' has a high resolution time stamp"),
	       file->name);
      this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
    }

  must_make = noexist;

  /* If file was specified as a target with no commands,
     come up with some default commands.  */

  if (!file->phony && file->cmds == 0 && !file->tried_implicit)
    {
      if (try_implicit_rule (file, depth))
	DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
      else
	DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
      file->tried_implicit = 1;
    }
  if (file->cmds == 0 && !file->is_target
      && default_file != 0 && default_file->cmds != 0)
    {
      DBF (DB_IMPLICIT, _("Using default recipe for '%s'.\n"));
      file->cmds = default_file->cmds;
    }

  /* Update all non-intermediate files we depend on, if necessary, and see
     whether any of them is more recent than this file.  We need to walk our
     deps, AND the deps of any also_make targets to ensure everything happens
     in the correct order.  */

  amake.file = file;
  amake.next = file->also_make;
  ad = &amake;
  while (ad)
    {
      struct dep *lastd = 0;

      /* Find the deps we're scanning */
      d = ad->file->deps;
      ad = ad->next;

      while (d)
        {
          FILE_TIMESTAMP mtime;
          int maybe_make;
          int dontcare = 0;

          check_renamed (d->file);

          mtime = file_mtime (d->file);
          check_renamed (d->file);

          if (is_updating (d->file))
            {
              error (NILF, _("Circular %s <- %s dependency dropped."),
                     file->name, d->file->name);
              /* We cannot free D here because our the caller will still have
                 a reference to it when we were called recursively via
                 check_dep below.  */
              if (lastd == 0)
                file->deps = d->next;
              else
                lastd->next = d->next;
              d = d->next;
              continue;
            }

          d->file->parent = file;
          maybe_make = must_make;

          /* Inherit dontcare flag from our parent. */
          if (rebuilding_makefiles)
            {
              dontcare = d->file->dontcare;
              d->file->dontcare = file->dontcare;
            }

          dep_status |= check_dep (d->file, depth, this_mtime, &maybe_make);

          /* Restore original dontcare flag. */
          if (rebuilding_makefiles)
            d->file->dontcare = dontcare;

          if (! d->ignore_mtime)
            must_make = maybe_make;

          check_renamed (d->file);

          {
            register struct file *f = d->file;
            if (f->double_colon)
              f = f->double_colon;
            do
              {
                running |= (f->command_state == cs_running
                            || f->command_state == cs_deps_running);
                f = f->prev;
              }
            while (f != 0);
          }

          if (dep_status != 0 && !keep_going_flag)
            break;

          if (!running)
            /* The prereq is considered changed if the timestamp has changed while
               it was built, OR it doesn't exist.  */
            d->changed = ((file_mtime (d->file) != mtime)
                          || (mtime == NONEXISTENT_MTIME));

          lastd = d;
          d = d->next;
        }
    }

  /* Now we know whether this target needs updating.
     If it does, update all the intermediate files we depend on.  */

  if (must_make || always_make_flag)
    {
      for (d = file->deps; d != 0; d = d->next)
	if (d->file->intermediate)
	  {
            int dontcare = 0;

	    FILE_TIMESTAMP mtime = file_mtime (d->file);
	    check_renamed (d->file);
	    d->file->parent = file;

            /* Inherit dontcare flag from our parent. */
            if (rebuilding_makefiles)
              {
                dontcare = d->file->dontcare;
                d->file->dontcare = file->dontcare;
              }


	    dep_status |= update_file (d->file, depth);

            /* Restore original dontcare flag. */
            if (rebuilding_makefiles)
              d->file->dontcare = dontcare;

	    check_renamed (d->file);

	    {
	      register struct file *f = d->file;
	      if (f->double_colon)
		f = f->double_colon;
	      do
		{
		  running |= (f->command_state == cs_running
			      || f->command_state == cs_deps_running);
		  f = f->prev;
		}
	      while (f != 0);
	    }

	    if (dep_status != 0 && !keep_going_flag)
	      break;

	    if (!running)
	      d->changed = ((file->phony && file->cmds != 0)
			    || file_mtime (d->file) != mtime);
	  }
    }

  finish_updating (file);
  finish_updating (ofile);

  DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n"));

  if (running)
    {
      set_command_state (file, cs_deps_running);
      --depth;
      DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n"));
      return 0;
    }

  /* If any dependency failed, give up now.  */

  if (dep_status != 0)
    {
      file->update_status = dep_status;
      notice_finished_file (file);

      --depth;

      DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n"));

      if (depth == 0 && keep_going_flag
	  && !just_print_flag && !question_flag)
	error (NILF,
               _("Target '%s' not remade because of errors."), file->name);

      return dep_status;
    }

  if (file->command_state == cs_deps_running)
    /* The commands for some deps were running on the last iteration, but
       they have finished now.  Reset the command_state to not_started to
       simplify later bookkeeping.  It is important that we do this only
       when the prior state was cs_deps_running, because that prior state
       was definitely propagated to FILE's also_make's by set_command_state
       (called above), but in another state an also_make may have
       independently changed to finished state, and we would confuse that
       file's bookkeeping (updated, but not_started is bogus state).  */
    set_command_state (file, cs_not_started);

  /* Now record which prerequisites are more
     recent than this file, so we can define $?.  */

  deps_changed = 0;
  for (d = file->deps; d != 0; d = d->next)
    {
      FILE_TIMESTAMP d_mtime = file_mtime (d->file);
      check_renamed (d->file);

      if (! d->ignore_mtime)
        {
#if 1
          /* %%% In version 4, remove this code completely to
	   implement not remaking deps if their deps are newer
	   than their parents.  */
          if (d_mtime == NONEXISTENT_MTIME && !d->file->intermediate)
            /* We must remake if this dep does not
               exist and is not intermediate.  */
            must_make = 1;
#endif

          /* Set DEPS_CHANGED if this dep actually changed.  */
          deps_changed |= d->changed;
        }

      /* Set D->changed if either this dep actually changed,
	 or its dependent, FILE, is older or does not exist.  */
      d->changed |= noexist || d_mtime > this_mtime;

      if (!noexist && ISDB (DB_BASIC|DB_VERBOSE))
	{
          const char *fmt = 0;

          if (d->ignore_mtime)
            {
              if (ISDB (DB_VERBOSE))
                fmt = _("Prerequisite '%s' is order-only for target '%s'.\n");
            }
          else if (d_mtime == NONEXISTENT_MTIME)
            {
              if (ISDB (DB_BASIC))
                fmt = _("Prerequisite '%s' of target '%s' does not exist.\n");
            }
	  else if (d->changed)
            {
              if (ISDB (DB_BASIC))
                fmt = _("Prerequisite '%s' is newer than target '%s'.\n");
            }
          else if (ISDB (DB_VERBOSE))
            fmt = _("Prerequisite '%s' is older than target '%s'.\n");

          if (fmt)
            {
              print_spaces (depth);
              printf (fmt, dep_name (d), file->name);
              fflush (stdout);
            }
	}
    }

  /* Here depth returns to the value it had when we were called.  */
  depth--;

  if (file->double_colon && file->deps == 0)
    {
      must_make = 1;
      DBF (DB_BASIC,
           _("Target '%s' is double-colon and has no prerequisites.\n"));
    }
  else if (!noexist && file->is_target && !deps_changed && file->cmds == 0
           && !always_make_flag)
    {
      must_make = 0;
      DBF (DB_VERBOSE,
           _("No recipe for '%s' and no prerequisites actually changed.\n"));
    }
  else if (!must_make && file->cmds != 0 && always_make_flag)
    {
      must_make = 1;
      DBF (DB_VERBOSE, _("Making '%s' due to always-make flag.\n"));
    }

  if (!must_make)
    {
      if (ISDB (DB_VERBOSE))
        {
          print_spaces (depth);
          printf (_("No need to remake target '%s'"), file->name);
          if (!streq (file->name, file->hname))
              printf (_("; using VPATH name '%s'"), file->hname);
          puts (".");
          fflush (stdout);
        }

      notice_finished_file (file);

      /* Since we don't need to remake the file, convert it to use the
         VPATH filename if we found one.  hfile will be either the
         local name if no VPATH or the VPATH name if one was found.  */

      while (file)
        {
          file->name = file->hname;
          file = file->prev;
        }

      return 0;
    }

  DBF (DB_BASIC, _("Must remake target '%s'.\n"));

  /* It needs to be remade.  If it's VPATH and not reset via GPATH, toss the
     VPATH.  */
  if (!streq(file->name, file->hname))
    {
      DB (DB_BASIC, (_("  Ignoring VPATH name '%s'.\n"), file->hname));
      file->ignore_vpath = 1;
    }

  /* Now, take appropriate actions to remake the file.  */
  remake_file (file);

  if (file->command_state != cs_finished)
    {
      DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n"));
      return 0;
    }

  switch (file->update_status)
    {
    case 2:
      DBF (DB_BASIC, _("Failed to remake target file '%s'.\n"));
      break;
    case 0:
      DBF (DB_BASIC, _("Successfully remade target file '%s'.\n"));
      break;
    case 1:
      DBF (DB_BASIC, _("Target file '%s' needs remade under -q.\n"));
      break;
    default:
      assert (file->update_status >= 0 && file->update_status <= 2);
      break;
    }

  file->updated = 1;
  return file->update_status;
}
Esempio n. 3
0
void
set_file_variables (struct file *file)
{
    struct dep *d;
    const char *at, *percent, *star, *less;

#ifndef	NO_ARCHIVES
    /* If the target is an archive member `lib(member)',
       then $@ is `lib' and $% is `member'.  */

    if (ar_name (file->name))
    {
        unsigned int len;
        const char *cp;
        char *p;

        cp = strchr (file->name, '(');
        p = alloca (cp - file->name + 1);
        memcpy (p, file->name, cp - file->name);
        p[cp - file->name] = '\0';
        at = p;
        len = strlen (cp + 1);
        p = alloca (len);
        memcpy (p, cp + 1, len - 1);
        p[len - 1] = '\0';
        percent = p;
    }
    else
#endif	/* NO_ARCHIVES.  */
    {
        at = file->name;
        percent = "";
    }

    /* $* is the stem from an implicit or static pattern rule.  */
    if (file->stem == 0)
    {
        /* In Unix make, $* is set to the target name with
        any suffix in the .SUFFIXES list stripped off for
         explicit rules.  We store this in the `stem' member.  */
        const char *name;
        unsigned int len;

#ifndef	NO_ARCHIVES
        if (ar_name (file->name))
        {
            name = strchr (file->name, '(') + 1;
            len = strlen (name) - 1;
        }
        else
#endif
        {
            name = file->name;
            len = strlen (name);
        }

        for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
        {
            unsigned int slen = strlen (dep_name (d));
            if (len > slen && strneq (dep_name (d), name + (len - slen), slen))
            {
                file->stem = strcache_add_len (name, len - slen);
                break;
            }
        }
        if (d == 0)
            file->stem = "";
    }
    star = file->stem;

    /* $< is the first not order-only dependency.  */
    less = "";
    for (d = file->deps; d != 0; d = d->next)
        if (!d->ignore_mtime)
        {
            if (!d->need_2nd_expansion)
                less = dep_name (d);
            break;
        }

    if (file->cmds == default_file->cmds)
        /* This file got its commands from .DEFAULT.
           In this case $< is the same as $@.  */
        less = at;

#define	DEFINE_VARIABLE(name, len, value) \
  (void) define_variable_for_file (name,len,value,o_automatic,0,file)

    /* Define the variables.  */

    DEFINE_VARIABLE ("<", 1, less);
    DEFINE_VARIABLE ("*", 1, star);
    DEFINE_VARIABLE ("@", 1, at);
    DEFINE_VARIABLE ("%", 1, percent);

    /* Compute the values for $^, $+, $?, and $|.  */

    {
        static char *plus_value=0, *bar_value=0, *qmark_value=0;
        static unsigned int plus_max=0, bar_max=0, qmark_max=0;

        unsigned int qmark_len, plus_len, bar_len;
        char *cp;
        char *caret_value;
        char *qp;
        char *bp;
        unsigned int len;

        struct hash_table dep_hash;
        void **slot;

        /* Compute first the value for $+, which is supposed to contain
           duplicate dependencies as they were listed in the makefile.  */

        plus_len = 0;
        bar_len = 0;
        for (d = file->deps; d != 0; d = d->next)
        {
            if (!d->need_2nd_expansion)
            {
                if (d->ignore_mtime)
                    bar_len += strlen (dep_name (d)) + 1;
                else
                    plus_len += strlen (dep_name (d)) + 1;
            }
        }

        if (bar_len == 0)
            bar_len++;

        if (plus_len == 0)
            plus_len++;

        if (plus_len > plus_max)
            plus_value = xrealloc (plus_value, plus_max = plus_len);

        cp = plus_value;

        qmark_len = plus_len + 1;	/* Will be this or less.  */
        for (d = file->deps; d != 0; d = d->next)
            if (! d->ignore_mtime && ! d->need_2nd_expansion)
            {
                const char *c = dep_name (d);

#ifndef	NO_ARCHIVES
                if (ar_name (c))
                {
                    c = strchr (c, '(') + 1;
                    len = strlen (c) - 1;
                }
                else
#endif
                    len = strlen (c);

                memcpy (cp, c, len);
                cp += len;
                *cp++ = FILE_LIST_SEPARATOR;
                if (! (d->changed || always_make_flag))
                    qmark_len -= len + 1;	/* Don't space in $? for this one.  */
            }

        /* Kill the last space and define the variable.  */

        cp[cp > plus_value ? -1 : 0] = '\0';
        DEFINE_VARIABLE ("+", 1, plus_value);

        /* Compute the values for $^, $?, and $|.  */

        cp = caret_value = plus_value; /* Reuse the buffer; it's big enough.  */

        if (qmark_len > qmark_max)
            qmark_value = xrealloc (qmark_value, qmark_max = qmark_len);
        qp = qmark_value;

        if (bar_len > bar_max)
            bar_value = xrealloc (bar_value, bar_max = bar_len);
        bp = bar_value;

        /* Make sure that no dependencies are repeated in $^, $?, and $|.  It
           would be natural to combine the next two loops but we can't do it
           because of a situation where we have two dep entries, the first
           is order-only and the second is normal (see below).  */

        hash_init (&dep_hash, 500, dep_hash_1, dep_hash_2, dep_hash_cmp);

        for (d = file->deps; d != 0; d = d->next)
        {
            if (d->need_2nd_expansion)
                continue;

            slot = hash_find_slot (&dep_hash, d);
            if (HASH_VACANT (*slot))
                hash_insert_at (&dep_hash, d, slot);
            else
            {
                /* Check if the two prerequisites have different ignore_mtime.
                   If so then we need to "upgrade" one that is order-only.  */

                struct dep* hd = (struct dep*) *slot;

                if (d->ignore_mtime != hd->ignore_mtime)
                    d->ignore_mtime = hd->ignore_mtime = 0;
            }
        }

        for (d = file->deps; d != 0; d = d->next)
        {
            const char *c;

            if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d)
                continue;

            c = dep_name (d);
#ifndef	NO_ARCHIVES
            if (ar_name (c))
            {
                c = strchr (c, '(') + 1;
                len = strlen (c) - 1;
            }
            else
#endif
                len = strlen (c);

            if (d->ignore_mtime)
            {
                memcpy (bp, c, len);
                bp += len;
                *bp++ = FILE_LIST_SEPARATOR;
            }
            else
            {
                memcpy (cp, c, len);
                cp += len;
                *cp++ = FILE_LIST_SEPARATOR;
                if (d->changed || always_make_flag)
                {
                    memcpy (qp, c, len);
                    qp += len;
                    *qp++ = FILE_LIST_SEPARATOR;
                }
            }
        }

        hash_free (&dep_hash, 0);

        /* Kill the last spaces and define the variables.  */

        cp[cp > caret_value ? -1 : 0] = '\0';
        DEFINE_VARIABLE ("^", 1, caret_value);

        qp[qp > qmark_value ? -1 : 0] = '\0';
        DEFINE_VARIABLE ("?", 1, qmark_value);

        bp[bp > bar_value ? -1 : 0] = '\0';
        DEFINE_VARIABLE ("|", 1, bar_value);
    }

#undef	DEFINE_VARIABLE
}
Esempio n. 4
0
static unsigned long
dep_hash_2 (const void *key)
{
    const struct dep *d = key;
    return_STRING_HASH_2 (dep_name (d));
}
Esempio n. 5
0
void
count_implicit_rule_limits (void)
{
  char *name;
  int namelen;
  struct rule *rule, *lastrule;

  num_pattern_rules = max_pattern_targets = max_pattern_deps = 0;
  max_pattern_dep_length = 0;

  name = 0;
  namelen = 0;
  rule = pattern_rules;
  lastrule = 0;
  while (rule != 0)
    {
      unsigned int ndeps = 0;
      struct dep *dep;
      struct rule *next = rule->next;

      ++num_pattern_rules;

      if (rule->num > max_pattern_targets)
	max_pattern_targets = rule->num;

      for (dep = rule->deps; dep != 0; dep = dep->next)
	{
          const char *dname = dep_name (dep);
          unsigned int len = strlen (dname);

#ifdef VMS
          const char *p = strrchr (dname, ']');
          const char *p2;
          if (p == 0)
            p = strrchr (dname, ':');
          p2 = p != 0 ? strchr (dname, '%') : 0;
#else
          const char *p = strrchr (dname, '/');
          const char *p2 = p != 0 ? strchr (dname, '%') : 0;
#endif
          ndeps++;

	  if (len > max_pattern_dep_length)
	    max_pattern_dep_length = len;

	  if (p != 0 && p2 > p)
	    {
	      /* There is a slash before the % in the dep name.
		 Extract the directory name.  */
	      if (p == dname)
		++p;
	      if (p - dname > namelen)
		{
		  namelen = p - dname;
		  name = xrealloc (name, namelen + 1);
		}
	      memcpy (name, dname, p - dname);
	      name[p - dname] = '\0';

	      /* In the deps of an implicit rule the 'changed' flag
		 actually indicates that the dependency is in a
		 nonexistent subdirectory.  */

	      dep->changed = !dir_file_exists_p (name, "");
	    }
	  else
	    /* This dependency does not reside in a subdirectory.  */
	    dep->changed = 0;
	}

      if (ndeps > max_pattern_deps)
	max_pattern_deps = ndeps;

      lastrule = rule;
      rule = next;
    }

  if (name != 0)
    free (name);
}
Esempio n. 6
0
void
convert_to_pattern (void)
{
  struct dep *d, *d2;
  char *rulename;

  /* We will compute every potential suffix rule (.x.y) from the list of
     suffixes in the .SUFFIXES target's dependencies and see if it exists.
     First find the longest of the suffixes.  */

  maxsuffix = 0;
  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      unsigned int l = strlen (dep_name (d));
      if (l > maxsuffix)
	maxsuffix = l;
    }

  /* Space to construct the suffix rule target name.  */
  rulename = alloca ((maxsuffix * 2) + 1);

  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      unsigned int slen;

      /* Make a rule that is just the suffix, with no deps or commands.
	 This rule exists solely to disqualify match-anything rules.  */
      convert_suffix_rule (dep_name (d), 0, 0);

      if (d->file->cmds != 0)
	/* Record a pattern for this suffix's null-suffix rule.  */
	convert_suffix_rule ("", dep_name (d), d->file->cmds);

      /* Add every other suffix to this one and see if it exists as a
         two-suffix rule.  */
      slen = strlen (dep_name (d));
      memcpy (rulename, dep_name (d), slen);

      for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
	{
          struct file *f;
          unsigned int s2len;

	  s2len = strlen (dep_name (d2));

          /* Can't build something from itself.  */
	  if (slen == s2len && streq (dep_name (d), dep_name (d2)))
	    continue;

	  memcpy (rulename + slen, dep_name (d2), s2len + 1);
	  f = lookup_file (rulename);
	  if (f == 0 || f->cmds == 0)
	    continue;

	  if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
	    /* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'.
	       It also generates a normal '%.a: %.X' rule below.  */
	    convert_suffix_rule (NULL, /* Indicates '(%.o)'.  */
				 dep_name (d),
				 f->cmds);

	  /* The suffix rule '.X.Y:' is converted
	     to the pattern rule '%.Y: %.X'.  */
	  convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds);
	}
    }
}
Esempio n. 7
0
void
convert_to_pattern (void)
{
  register struct dep *d, *d2;
  register struct file *f;
  register char *rulename;
  register unsigned int slen, s2len;

  /* Compute maximum length of all the suffixes.  */

  maxsuffix = 0;
  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      register unsigned int namelen = strlen (dep_name (d));
      if (namelen > maxsuffix)
	maxsuffix = namelen;
    }

  rulename = (char *) alloca ((maxsuffix * 2) + 1);

  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      /* Make a rule that is just the suffix, with no deps or commands.
	 This rule exists solely to disqualify match-anything rules.  */
      convert_suffix_rule (dep_name (d), (char *) 0, (struct commands *) 0);

      f = d->file;
      if (f->cmds != 0)
	/* Record a pattern for this suffix's null-suffix rule.  */
	convert_suffix_rule ("", dep_name (d), f->cmds);

      /* Record a pattern for each of this suffix's two-suffix rules.  */
      slen = strlen (dep_name (d));
      bcopy (dep_name (d), rulename, slen);
      for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
	{
	  s2len = strlen (dep_name (d2));

	  if (slen == s2len && streq (dep_name (d), dep_name (d2)))
	    continue;

	  bcopy (dep_name (d2), rulename + slen, s2len + 1);
	  f = lookup_file (rulename);
	  if (f == 0 || f->cmds == 0)
	    continue;

	  if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
	    /* A suffix rule `.X.a:' generates the pattern rule `(%.o): %.X'.
	       It also generates a normal `%.a: %.X' rule below.  */
	    convert_suffix_rule ((char *) 0, /* Indicates `(%.o)'.  */
				 dep_name (d),
				 f->cmds);

	  /* The suffix rule `.X.Y:' is converted
	     to the pattern rule `%.Y: %.X'.  */
	  convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds);
	}
    }
}
Esempio n. 8
0
void
convert_to_pattern ()
{
  register struct dep *d, *d2, *newd;
  register struct file *f;
  register char *rulename;
  register unsigned int slen, s2len;
  register char *name, **names;

  /* Compute maximum length of all the suffixes.  */

  maxsuffix = 0;
  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      register unsigned int namelen = strlen (dep_name (d));
      if (namelen > maxsuffix)
	maxsuffix = namelen;
    }

  rulename = (char *) alloca ((maxsuffix * 2) + 1);

  for (d = suffix_file->deps; d != 0; d = d->next)
    {
      /* Make a rule that is just the suffix, with no deps or commands.
	 This rule exists solely to disqualify match-anything rules.  */
      slen = strlen (dep_name (d));
      name = (char *) xmalloc (1 + slen + 1);
      name[0] = '%';
      bcopy (dep_name (d), name + 1, slen + 1);
      names = (char **) xmalloc (2 * sizeof (char *));
      names[0] = name;
      names[1] = 0;
      create_pattern_rule (names, (char **) 0, 0, (struct dep *) 0,
			   (struct commands *) 0, 0);

      f = d->file;
      if (f->cmds != 0)
	{
	  /* Record a pattern for this suffix's null-suffix rule.  */
	  newd = (struct dep *) xmalloc (sizeof (struct dep));
	  /* Construct this again rather than using the contents
	     of NAME (above), since that may have been freed by
	     create_pattern_rule.  */
	  newd->name = (char *) xmalloc (1 + slen + 1);
	  newd->name[0] = '%';
	  bcopy (dep_name (d), newd->name + 1, slen + 1);
	  newd->next = 0;
	  names = (char **) xmalloc (2 * sizeof (char *));
	  names[0] = savestring ("%", 1);
	  names[1] = 0;
	  create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0);
	}

      /* Record a pattern for each of this suffix's two-suffix rules.  */
      bcopy (dep_name (d), rulename, slen);
      for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
	{
	  s2len = strlen (dep_name (d2));

	  if (slen == s2len && streq (dep_name (d), dep_name (d2)))
	    continue;

	  bcopy (dep_name (d2), rulename + slen, s2len + 1);
	  f = lookup_file (rulename);
	  if (f == 0 || f->cmds == 0)
	    continue;

	  if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
	    /* The suffix rule `.X.a:' is converted
	       to the pattern rule `(%.o): %.X'.  */
	    name = savestring ("(%.o)", 5);
	  else
	    {
	      /* The suffix rule `.X.Y:' is converted
		 to the pattern rule `%.Y: %.X'.  */
	      name = (char *) xmalloc (1 + s2len + 1);
	      name[0] = '%';
	      bcopy (dep_name (d2), name + 1, s2len + 1);
	    }
	  names = (char **) xmalloc (2 * sizeof (char *));
	  names[0] = name;
	  names[1] = 0;
	  newd = (struct dep *) xmalloc (sizeof (struct dep));
	  newd->next = 0;
	  /* Construct this again (see comment above).  */
	  newd->name = (char *) xmalloc (1 + slen + 1);
	  newd->name[0] = '%';
	  bcopy (dep_name (d), newd->name + 1, slen + 1);
	  create_pattern_rule (names, (char **) 0, 0, newd, f->cmds, 0);
	}
    }
}