Remake
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Functions
Rule parser

Functions

static void register_transparent_rule (rule_t const &rule, string_list const &targets)
 
static void register_scripted_rule (rule_t const &rule)
 
static void load_rule (std::istream &in, std::string const &first)
 
static void load_rules (std::string const &remakefile)
 

Detailed Description

Function Documentation

static void load_rule ( std::istream &  in,
std::string const &  first 
)
static

Read a rule starting with target first, if nonempty. Store into generic_rules or specific_rules depending on its genericity.

Definition at line 1579 of file remake.cpp.

Referenced by load_rules().

1580 {
1581  DEBUG_open << "Reading rule for target " << first << "... ";
1582  if (false)
1583  {
1584  error:
1585  DEBUG_close << "failed\n";
1586  std::cerr << "Failed to load rules: syntax error" << std::endl;
1587  exit(EXIT_FAILURE);
1588  }
1589  rule_t rule;
1590 
1591  // Read targets and check genericity.
1592  string_list targets;
1593  if (!read_words(in, targets)) goto error;
1594  if (!first.empty()) targets.push_front(first);
1595  else if (targets.empty()) goto error;
1596  else DEBUG << "actual target: " << targets.front() << std::endl;
1597  bool generic = false;
1598  normalize_list(targets, "", "");
1599  for (string_list::const_iterator i = targets.begin(),
1600  i_end = targets.end(); i != i_end; ++i)
1601  {
1602  if (i->empty()) goto error;
1603  if ((i->find('%') != std::string::npos) != generic)
1604  {
1605  if (i == targets.begin()) generic = true;
1606  else goto error;
1607  }
1608  }
1609  std::swap(rule.targets, targets);
1610  skip_spaces(in);
1611  if (in.get() != ':') goto error;
1612 
1613  bool assignment = false;
1614 
1615  // Read dependencies.
1616  {
1617  string_list v;
1618  if (expect_token(in, Word))
1619  {
1620  std::string d = read_word(in);
1621  if (int tok = expect_token(in, Equal | Plusequal))
1622  {
1623  if (!read_words(in, v)) goto error;
1624  assign_t &a = rule.assigns[d];
1625  a.append = tok == Plusequal;
1626  a.value.swap(v);
1627  assignment = true;
1628  goto end_line;
1629  }
1630  v.push_back(d);
1631  }
1632 
1633  if (!read_words(in, v)) goto error;
1634  normalize_list(v, "", "");
1635  rule.deps.swap(v);
1636 
1637  if (expect_token(in, Pipe))
1638  {
1639  if (!read_words(in, v)) goto error;
1640  normalize_list(v, "", "");
1641  rule.wdeps.swap(v);
1642  }
1643  }
1644 
1645  end_line:
1646  skip_spaces(in);
1647  if (!skip_eol(in, true)) goto error;
1648 
1649  // Read script.
1650  std::ostringstream buf;
1651  while (true)
1652  {
1653  char c = in.get();
1654  if (!in.good()) break;
1655  if (c == '\t' || c == ' ')
1656  {
1657  in.get(*buf.rdbuf());
1658  if (in.fail() && !in.eof()) in.clear();
1659  }
1660  else if (c == '\r' || c == '\n')
1661  buf << c;
1662  else
1663  {
1664  in.putback(c);
1665  break;
1666  }
1667  }
1668  rule.script = buf.str();
1669 
1670  // Register phony targets.
1671  if (rule.targets.front() == ".PHONY")
1672  {
1673  for (string_list::const_iterator i = rule.deps.begin(),
1674  i_end = rule.deps.end(); i != i_end; ++i)
1675  {
1676  status[*i].status = Todo;
1677  }
1678  return;
1679  }
1680 
1681  // Add generic rules to the correct set.
1682  if (generic)
1683  {
1684  if (assignment) goto error;
1685  generic_rules.push_back(rule);
1686  return;
1687  }
1688 
1689  if (!rule.script.empty())
1690  {
1691  if (assignment) goto error;
1692  register_scripted_rule(rule);
1693  }
1694  else
1695  {
1696  // Swap away the targets to avoid costly copies when registering.
1697  string_list targets;
1698  std::swap(rule.targets, targets);
1699  register_transparent_rule(rule, targets);
1700  std::swap(rule.targets, targets);
1701  }
1702 
1703  // If there is no default target yet, mark it as such.
1704  if (first_target.empty())
1705  first_target = rule.targets.front();
1706 }
static void load_rules ( std::string const &  remakefile)
static

Load rules from remakefile. If some rules have dependencies and non-generic targets, add these dependencies to the targets.

Definition at line 1713 of file remake.cpp.

Referenced by server_mode().

1714 {
1715  DEBUG_open << "Loading rules... ";
1716  if (false)
1717  {
1718  error:
1719  std::cerr << "Failed to load rules: syntax error" << std::endl;
1720  exit(EXIT_FAILURE);
1721  }
1722  std::ifstream in(remakefile.c_str());
1723  if (!in.good())
1724  {
1725  std::cerr << "Failed to load rules: no Remakefile found" << std::endl;
1726  exit(EXIT_FAILURE);
1727  }
1728  skip_empty(in);
1729 
1730  string_list options;
1731 
1732  // Read rules
1733  while (in.good())
1734  {
1735  char c = in.peek();
1736  if (c == '#')
1737  {
1738  while (in.get() != '\n') {}
1739  skip_empty(in);
1740  continue;
1741  }
1742  if (c == ' ' || c == '\t') goto error;
1743  if (expect_token(in, Word))
1744  {
1745  std::string name = read_word(in);
1746  if (name.empty()) goto error;
1747  if (int tok = expect_token(in, Equal | Plusequal))
1748  {
1749  DEBUG << "Assignment to variable " << name << std::endl;
1750  string_list value;
1751  if (!read_words(in, value)) goto error;
1752  string_list &dest =
1753  *(name == ".OPTIONS" ? &options : &variables[name]);
1754  if (tok == Equal) dest.swap(value);
1755  else dest.splice(dest.end(), value);
1756  if (!skip_eol(in, true)) goto error;
1757  }
1758  else load_rule(in, name);
1759  }
1760  else load_rule(in, std::string());
1761  }
1762 
1763  // Set actual options.
1764  for (string_list::const_iterator i = options.begin(),
1765  i_end = options.end(); i != i_end; ++i)
1766  {
1767  if (*i == "variable-propagation") propagate_vars = true;
1768  else
1769  {
1770  std::cerr << "Failed to load rules: unrecognized option" << std::endl;
1771  exit(EXIT_FAILURE);
1772  }
1773  }
1774 }
static void register_scripted_rule ( rule_t const &  rule)
static

Register a specific rule with a nonempty script:

  • Check that none of the targets already has an associated rule.
  • Create a single shared rule and associate it to all the targets.
  • Merge the prerequisites of all the targets into a single set and add the prerequisites of the rule to it. (The preexisting prerequisites, if any, come from a previous run.)

Definition at line 1549 of file remake.cpp.

Referenced by load_rule().

1550 {
1551  ref_ptr<rule_t> r(rule);
1552  for (string_list::const_iterator i = rule.targets.begin(),
1553  i_end = rule.targets.end(); i != i_end; ++i)
1554  {
1555  std::pair<rule_map::iterator, bool> j =
1556  specific_rules.insert(std::make_pair(*i, r));
1557  if (j.second) continue;
1558  std::cerr << "Failed to load rules: " << *i
1559  << " cannot be the target of several rules" << std::endl;
1560  exit(EXIT_FAILURE);
1561  }
1562 
1564  dep->targets = rule.targets;
1565  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1566  for (string_list::const_iterator i = rule.targets.begin(),
1567  i_end = rule.targets.end(); i != i_end; ++i)
1568  {
1570  dep->deps.insert(d->deps.begin(), d->deps.end());
1571  d = dep;
1572  }
1573 }
static void register_transparent_rule ( rule_t const &  rule,
string_list const &  targets 
)
static

Register a specific rule with an empty script:

  • Check that none of the targets already has an associated rule with a nonempty script.
  • Create a new rule with a single target for each target, if needed.
  • Add the prerequisites of rule to all these associated rules.

Definition at line 1506 of file remake.cpp.

Referenced by load_rule().

1507 {
1508  assert(rule.script.empty());
1509  for (string_list::const_iterator i = targets.begin(),
1510  i_end = targets.end(); i != i_end; ++i)
1511  {
1512  std::pair<rule_map::iterator, bool> j =
1513  specific_rules.insert(std::make_pair(*i, ref_ptr<rule_t>()));
1514  ref_ptr<rule_t> &r = j.first->second;
1515  if (j.second)
1516  {
1517  r = ref_ptr<rule_t>(rule);
1518  r->targets = string_list(1, *i);
1519  continue;
1520  }
1521  if (!r->script.empty())
1522  {
1523  std::cerr << "Failed to load rules: " << *i
1524  << " cannot be the target of several rules" << std::endl;
1525  exit(EXIT_FAILURE);
1526  }
1527  assert(r->targets.size() == 1 && r->targets.front() == *i);
1528  merge_rule(*r, rule);
1529  }
1530 
1531  for (string_list::const_iterator i = targets.begin(),
1532  i_end = targets.end(); i != i_end; ++i)
1533  {
1535  if (dep->targets.empty()) dep->targets.push_back(*i);
1536  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1537  }
1538 }