Remake
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

§ load_rule()

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 1586 of file remake.cpp.

Referenced by load_rules().

1587 {
1588  DEBUG_open << "Reading rule for target " << first << "... ";
1589  if (false)
1590  {
1591  error:
1592  DEBUG_close << "failed\n";
1593  std::cerr << "Failed to load rules: syntax error" << std::endl;
1594  exit(EXIT_FAILURE);
1595  }
1596  rule_t rule;
1597 
1598  // Read targets and check genericity.
1599  string_list targets;
1600  if (!read_words(in, targets)) goto error;
1601  if (!first.empty()) targets.push_front(first);
1602  else if (targets.empty()) goto error;
1603  else DEBUG << "actual target: " << targets.front() << std::endl;
1604  bool generic = false;
1605  normalize_list(targets, "", "");
1606  for (string_list::const_iterator i = targets.begin(),
1607  i_end = targets.end(); i != i_end; ++i)
1608  {
1609  if (i->empty()) goto error;
1610  if ((i->find('%') != std::string::npos) != generic)
1611  {
1612  if (i == targets.begin()) generic = true;
1613  else goto error;
1614  }
1615  }
1616  std::swap(rule.targets, targets);
1617  skip_spaces(in);
1618  if (in.get() != ':') goto error;
1619 
1620  bool assignment = false;
1621 
1622  // Read dependencies.
1623  {
1624  string_list v;
1625  if (expect_token(in, Word))
1626  {
1627  std::string d = read_word(in);
1628  if (int tok = expect_token(in, Equal | Plusequal))
1629  {
1630  if (!read_words(in, v)) goto error;
1631  assign_t &a = rule.assigns[d];
1632  a.append = tok == Plusequal;
1633  a.value.swap(v);
1634  assignment = true;
1635  goto end_line;
1636  }
1637  v.push_back(d);
1638  }
1639 
1640  if (!read_words(in, v)) goto error;
1641  normalize_list(v, "", "");
1642  rule.deps.swap(v);
1643 
1644  if (expect_token(in, Pipe))
1645  {
1646  if (!read_words(in, v)) goto error;
1647  normalize_list(v, "", "");
1648  rule.wdeps.swap(v);
1649  }
1650  }
1651 
1652  end_line:
1653  skip_spaces(in);
1654  if (!skip_eol(in, true)) goto error;
1655 
1656  // Read script.
1657  std::ostringstream buf;
1658  while (true)
1659  {
1660  char c = in.get();
1661  if (!in.good()) break;
1662  if (c == '\t' || c == ' ')
1663  {
1664  in.get(*buf.rdbuf());
1665  if (in.fail() && !in.eof()) in.clear();
1666  }
1667  else if (c == '\r' || c == '\n')
1668  buf << c;
1669  else
1670  {
1671  in.putback(c);
1672  break;
1673  }
1674  }
1675  rule.script = buf.str();
1676 
1677  // Register phony targets.
1678  if (rule.targets.front() == ".PHONY")
1679  {
1680  for (string_list::const_iterator i = rule.deps.begin(),
1681  i_end = rule.deps.end(); i != i_end; ++i)
1682  {
1683  status[*i].status = Todo;
1684  }
1685  return;
1686  }
1687 
1688  // Add generic rules to the correct set.
1689  if (generic)
1690  {
1691  if (assignment) goto error;
1692  generic_rules.push_back(rule);
1693  return;
1694  }
1695 
1696  if (!rule.script.empty())
1697  {
1698  if (assignment) goto error;
1699  register_scripted_rule(rule);
1700  }
1701  else
1702  {
1703  // Swap away the targets to avoid costly copies when registering.
1704  string_list targets;
1705  std::swap(rule.targets, targets);
1706  register_transparent_rule(rule, targets);
1707  std::swap(rule.targets, targets);
1708  }
1709 
1710  // If there is no default target yet, mark it as such.
1711  if (first_target.empty())
1712  first_target = rule.targets.front();
1713 }
#define DEBUG_open
Definition: remake.cpp:801
std::list< std::string > string_list
Definition: remake.cpp:456
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition: remake.cpp:549
static std::string first_target
Definition: remake.cpp:701
static std::string read_word(std::istream &in, bool detect_equal=true)
Definition: remake.cpp:1105
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition: remake.cpp:548
bool append
Definition: remake.cpp:536
static bool skip_eol(std::istream &in, bool multi=false)
Definition: remake.cpp:1030
static bool read_words(input_generator &in, string_list &res)
Definition: remake.cpp:1271
static void register_scripted_rule(rule_t const &rule)
Definition: remake.cpp:1556
assign_map assigns
Assignment of variables.
Definition: remake.cpp:550
static status_map status
Definition: remake.cpp:614
Target is missing or obsolete.
Definition: remake.cpp:512
string_list targets
Files produced by this rule.
Definition: remake.cpp:547
#define DEBUG
Definition: remake.cpp:800
std::string script
Shell script for building the targets.
Definition: remake.cpp:551
static void skip_spaces(std::istream &in)
Definition: remake.cpp:1009
#define DEBUG_close
Definition: remake.cpp:802
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
Definition: remake.cpp:989
string_list value
Definition: remake.cpp:537
static int expect_token(std::istream &in, int mask)
Definition: remake.cpp:1059
static void register_transparent_rule(rule_t const &rule, string_list const &targets)
Definition: remake.cpp:1513
static rule_list generic_rules
Definition: remake.cpp:619

§ load_rules()

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 1720 of file remake.cpp.

Referenced by server_mode().

1721 {
1722  DEBUG_open << "Loading rules... ";
1723  if (false)
1724  {
1725  error:
1726  std::cerr << "Failed to load rules: syntax error" << std::endl;
1727  exit(EXIT_FAILURE);
1728  }
1729  std::ifstream in(remakefile.c_str());
1730  if (!in.good())
1731  {
1732  std::cerr << "Failed to load rules: no Remakefile found" << std::endl;
1733  exit(EXIT_FAILURE);
1734  }
1735  skip_empty(in);
1736 
1737  string_list options;
1738 
1739  // Read rules
1740  while (in.good())
1741  {
1742  char c = in.peek();
1743  if (c == '#')
1744  {
1745  while (in.get() != '\n') {}
1746  skip_empty(in);
1747  continue;
1748  }
1749  if (c == ' ' || c == '\t') goto error;
1750  if (expect_token(in, Word))
1751  {
1752  std::string name = read_word(in);
1753  if (name.empty()) goto error;
1754  if (int tok = expect_token(in, Equal | Plusequal))
1755  {
1756  DEBUG << "Assignment to variable " << name << std::endl;
1757  string_list value;
1758  if (!read_words(in, value)) goto error;
1759  string_list &dest =
1760  *(name == ".OPTIONS" ? &options : &variables[name]);
1761  if (tok == Equal) dest.swap(value);
1762  else dest.splice(dest.end(), value);
1763  if (!skip_eol(in, true)) goto error;
1764  }
1765  else load_rule(in, name);
1766  }
1767  else load_rule(in, std::string());
1768  }
1769 
1770  // Set actual options.
1771  for (string_list::const_iterator i = options.begin(),
1772  i_end = options.end(); i != i_end; ++i)
1773  {
1774  if (*i == "variable-propagation") propagate_vars = true;
1775  else
1776  {
1777  std::cerr << "Failed to load rules: unrecognized option" << std::endl;
1778  exit(EXIT_FAILURE);
1779  }
1780  }
1781 }
#define DEBUG_open
Definition: remake.cpp:801
static bool propagate_vars
Definition: remake.cpp:736
static variable_map variables
Definition: remake.cpp:604
std::list< std::string > string_list
Definition: remake.cpp:456
static void load_rule(std::istream &in, std::string const &first)
Definition: remake.cpp:1586
static std::string read_word(std::istream &in, bool detect_equal=true)
Definition: remake.cpp:1105
static bool skip_eol(std::istream &in, bool multi=false)
Definition: remake.cpp:1030
static bool read_words(input_generator &in, string_list &res)
Definition: remake.cpp:1271
#define DEBUG
Definition: remake.cpp:800
static void skip_empty(std::istream &in)
Definition: remake.cpp:1019
static int expect_token(std::istream &in, int mask)
Definition: remake.cpp:1059

§ register_scripted_rule()

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 1556 of file remake.cpp.

Referenced by load_rule().

1557 {
1558  ref_ptr<rule_t> r(rule);
1559  for (string_list::const_iterator i = rule.targets.begin(),
1560  i_end = rule.targets.end(); i != i_end; ++i)
1561  {
1562  std::pair<rule_map::iterator, bool> j =
1563  specific_rules.insert(std::make_pair(*i, r));
1564  if (j.second) continue;
1565  std::cerr << "Failed to load rules: " << *i
1566  << " cannot be the target of several rules" << std::endl;
1567  exit(EXIT_FAILURE);
1568  }
1569 
1571  dep->targets = rule.targets;
1572  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1573  for (string_list::const_iterator i = rule.targets.begin(),
1574  i_end = rule.targets.end(); i != i_end; ++i)
1575  {
1577  dep->deps.insert(d->deps.begin(), d->deps.end());
1578  d = dep;
1579  }
1580 }
string_list targets
Definition: remake.cpp:498
static rule_map specific_rules
Definition: remake.cpp:624
string_set deps
Definition: remake.cpp:499
static dependency_map dependencies
Definition: remake.cpp:609

§ register_transparent_rule()

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 1513 of file remake.cpp.

Referenced by load_rule().

1514 {
1515  assert(rule.script.empty());
1516  for (string_list::const_iterator i = targets.begin(),
1517  i_end = targets.end(); i != i_end; ++i)
1518  {
1519  std::pair<rule_map::iterator, bool> j =
1520  specific_rules.insert(std::make_pair(*i, ref_ptr<rule_t>()));
1521  ref_ptr<rule_t> &r = j.first->second;
1522  if (j.second)
1523  {
1524  r = ref_ptr<rule_t>(rule);
1525  r->targets = string_list(1, *i);
1526  continue;
1527  }
1528  if (!r->script.empty())
1529  {
1530  std::cerr << "Failed to load rules: " << *i
1531  << " cannot be the target of several rules" << std::endl;
1532  exit(EXIT_FAILURE);
1533  }
1534  assert(r->targets.size() == 1 && r->targets.front() == *i);
1535  merge_rule(*r, rule);
1536  }
1537 
1538  for (string_list::const_iterator i = targets.begin(),
1539  i_end = targets.end(); i != i_end; ++i)
1540  {
1542  if (dep->targets.empty()) dep->targets.push_back(*i);
1543  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1544  }
1545 }
std::list< std::string > string_list
Definition: remake.cpp:456
string_list targets
Definition: remake.cpp:498
static rule_map specific_rules
Definition: remake.cpp:624
string_set deps
Definition: remake.cpp:499
static void merge_rule(rule_t &dest, rule_t const &src)
Definition: remake.cpp:1791
string_list targets
Files produced by this rule.
Definition: remake.cpp:547
std::string script
Shell script for building the targets.
Definition: remake.cpp:551
static dependency_map dependencies
Definition: remake.cpp:609