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

1629 {
1630  DEBUG_open << "Reading rule for target " << first << "... ";
1631  if (false)
1632  {
1633  error:
1634  DEBUG_close << "failed\n";
1635  std::cerr << "Failed to load rules: syntax error" << std::endl;
1636  exit(EXIT_FAILURE);
1637  }
1638 
1639  // Read targets and check genericity.
1640  string_list targets;
1641  if (!read_words(in, targets)) goto error;
1642  if (!first.empty()) targets.push_front(first);
1643  else if (targets.empty()) goto error;
1644  else DEBUG << "actual target: " << targets.front() << std::endl;
1645  bool generic = false;
1646  normalize_list(targets, "", "");
1647  for (string_list::const_iterator i = targets.begin(),
1648  i_end = targets.end(); i != i_end; ++i)
1649  {
1650  if (i->empty()) goto error;
1651  if ((i->find('%') != std::string::npos) != generic)
1652  {
1653  if (i == targets.begin()) generic = true;
1654  else goto error;
1655  }
1656  }
1657  skip_spaces(in);
1658  if (in.get() != ':') goto error;
1659 
1660  bool assignment = false, static_pattern = false;
1661 
1662  rule_t rule;
1663  rule.targets.swap(targets);
1664 
1665  // Read dependencies.
1666  {
1667  string_list v;
1668  if (expect_token(in, Word))
1669  {
1670  std::string d = read_word(in);
1671  if (int tok = expect_token(in, Equal | Plusequal))
1672  {
1673  if (!read_words(in, v)) goto error;
1674  assign_t &a = rule.assigns[d];
1675  a.append = tok == Plusequal;
1676  a.value.swap(v);
1677  assignment = true;
1678  goto end_line;
1679  }
1680  v.push_back(d);
1681  }
1682 
1683  if (!read_words(in, v)) goto error;
1684  normalize_list(v, "", "");
1685  rule.deps.swap(v);
1686 
1687  if (expect_token(in, Colon))
1688  {
1689  if (!read_words(in, v)) goto error;
1690  normalize_list(v, "", "");
1691  targets.swap(rule.targets);
1692  rule.targets.swap(rule.deps);
1693  rule.deps.swap(v);
1694  if (rule.targets.empty()) goto error;
1695  for (string_list::const_iterator i = rule.targets.begin(),
1696  i_end = rule.targets.end(); i != i_end; ++i)
1697  {
1698  if (i->find('%') == std::string::npos) goto error;
1699  }
1700  generic = false;
1701  static_pattern = true;
1702  }
1703 
1704  if (expect_token(in, Pipe))
1705  {
1706  if (!read_words(in, v)) goto error;
1707  normalize_list(v, "", "");
1708  rule.wdeps.swap(v);
1709  }
1710  }
1711 
1712  end_line:
1713  skip_spaces(in);
1714  if (!skip_eol(in, true)) goto error;
1715 
1716  // Read script.
1717  std::ostringstream buf;
1718  while (true)
1719  {
1720  char c = in.get();
1721  if (!in.good()) break;
1722  if (c == '\t' || c == ' ')
1723  {
1724  in.get(*buf.rdbuf());
1725  if (in.fail() && !in.eof()) in.clear();
1726  }
1727  else if (c == '\r' || c == '\n')
1728  buf << c;
1729  else
1730  {
1731  in.putback(c);
1732  break;
1733  }
1734  }
1735  rule.script = buf.str();
1736 
1737  // Register phony targets.
1738  if (rule.targets.front() == ".PHONY")
1739  {
1740  for (string_list::const_iterator i = rule.deps.begin(),
1741  i_end = rule.deps.end(); i != i_end; ++i)
1742  {
1743  status[*i].status = Todo;
1744  }
1745  return;
1746  }
1747 
1748  // Add generic rules to the correct set.
1749  if (generic)
1750  {
1751  if (assignment) goto error;
1752  generic_rules.push_back(rule);
1753  return;
1754  }
1755 
1756  if (!static_pattern)
1757  {
1758  if (!rule.script.empty() && assignment) goto error;
1759  register_rule(rule);
1760  return;
1761  }
1762 
1763  for (string_list::const_iterator i = targets.begin(),
1764  i_end = targets.end(); i != i_end; ++i)
1765  {
1766  rule_t r;
1767  instantiate_rule(*i, rule, r);
1768  if (!r.stem.empty()) register_rule(r);
1769  }
1770 }

Referenced by load_rules().

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

1778 {
1779  DEBUG_open << "Loading rules... ";
1780  if (false)
1781  {
1782  error:
1783  std::cerr << "Failed to load rules: syntax error" << std::endl;
1784  exit(EXIT_FAILURE);
1785  }
1786  std::ifstream in(remakefile.c_str());
1787  if (!in.good())
1788  {
1789  std::cerr << "Failed to load rules: no Remakefile found" << std::endl;
1790  exit(EXIT_FAILURE);
1791  }
1792  skip_empty(in);
1793 
1794  string_list options;
1795 
1796  // Read rules
1797  while (in.good())
1798  {
1799  char c = in.peek();
1800  if (c == '#')
1801  {
1802  while (in.get() != '\n') {}
1803  skip_empty(in);
1804  continue;
1805  }
1806  if (c == ' ' || c == '\t') goto error;
1807  if (expect_token(in, Word))
1808  {
1809  std::string name = read_word(in);
1810  if (name.empty()) goto error;
1811  if (int tok = expect_token(in, Equal | Plusequal))
1812  {
1813  DEBUG << "Assignment to variable " << name << std::endl;
1814  string_list value;
1815  if (!read_words(in, value)) goto error;
1816  string_list &dest =
1817  *(name == ".OPTIONS" ? &options : &variables[name]);
1818  if (tok == Equal) dest.swap(value);
1819  else dest.splice(dest.end(), value);
1820  if (!skip_eol(in, true)) goto error;
1821  }
1822  else load_rule(in, name);
1823  }
1824  else load_rule(in, std::string());
1825  }
1826 
1827  // Set actual options.
1828  for (string_list::const_iterator i = options.begin(),
1829  i_end = options.end(); i != i_end; ++i)
1830  {
1831  if (*i == "variable-propagation") propagate_vars = true;
1832  else
1833  {
1834  std::cerr << "Failed to load rules: unrecognized option" << std::endl;
1835  exit(EXIT_FAILURE);
1836  }
1837  }
1838 }

Referenced by server_mode().

◆ register_rule()

static void register_rule ( rule_t const &  rule)
static

Register a specific rule.

Definition at line 1603 of file remake.cpp.

1604 {
1605  if (!rule.script.empty())
1606  {
1607  register_scripted_rule(rule);
1608  }
1609  else
1610  {
1611  // Swap away the targets to avoid costly copies when registering.
1612  rule_t &r = const_cast<rule_t &>(rule);
1613  string_list targets;
1614  targets.swap(r.targets);
1615  register_transparent_rule(r, targets);
1616  targets.swap(r.targets);
1617  }
1618 
1619  // If there is no default target yet, mark it as such.
1620  if (first_target.empty())
1621  first_target = rule.targets.front();
1622 }

Referenced by load_rule().

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

1575 {
1576  ref_ptr<rule_t> r(rule);
1577  for (string_list::const_iterator i = rule.targets.begin(),
1578  i_end = rule.targets.end(); i != i_end; ++i)
1579  {
1580  std::pair<rule_map::iterator, bool> j =
1581  specific_rules.insert(std::make_pair(*i, r));
1582  if (j.second) continue;
1583  std::cerr << "Failed to load rules: " << *i
1584  << " cannot be the target of several rules" << std::endl;
1585  exit(EXIT_FAILURE);
1586  }
1587 
1589  dep->targets = rule.targets;
1590  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1591  for (string_list::const_iterator i = rule.targets.begin(),
1592  i_end = rule.targets.end(); i != i_end; ++i)
1593  {
1595  dep->deps.insert(d->deps.begin(), d->deps.end());
1596  d = dep;
1597  }
1598 }

Referenced by register_rule().

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

1532 {
1533  assert(rule.script.empty());
1534  for (string_list::const_iterator i = targets.begin(),
1535  i_end = targets.end(); i != i_end; ++i)
1536  {
1537  std::pair<rule_map::iterator, bool> j =
1538  specific_rules.insert(std::make_pair(*i, ref_ptr<rule_t>()));
1539  ref_ptr<rule_t> &r = j.first->second;
1540  if (j.second)
1541  {
1542  r = ref_ptr<rule_t>(rule);
1543  r->targets = string_list(1, *i);
1544  continue;
1545  }
1546  if (!r->script.empty())
1547  {
1548  std::cerr << "Failed to load rules: " << *i
1549  << " cannot be the target of several rules" << std::endl;
1550  exit(EXIT_FAILURE);
1551  }
1552  assert(r->targets.size() == 1 && r->targets.front() == *i);
1553  merge_rule(*r, rule);
1554  }
1555 
1556  for (string_list::const_iterator i = targets.begin(),
1557  i_end = targets.end(); i != i_end; ++i)
1558  {
1560  if (dep->targets.empty()) dep->targets.push_back(*i);
1561  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1562  }
1563 }

Referenced by register_rule().

first_target
static std::string first_target
Definition: remake.cpp:716
string_list
std::list< std::string > string_list
Definition: remake.cpp:471
propagate_vars
static bool propagate_vars
Definition: remake.cpp:751
load_rule
static void load_rule(std::istream &in, std::string const &first)
Definition: remake.cpp:1628
DEBUG
#define DEBUG
Definition: remake.cpp:817
skip_eol
static bool skip_eol(std::istream &in, bool multi=false)
Definition: remake.cpp:1047
DEBUG_close
#define DEBUG_close
Definition: remake.cpp:819
dependencies
static dependency_map dependencies
Definition: remake.cpp:624
rule_t::targets
string_list targets
Files produced by this rule.
Definition: remake.cpp:562
status
static status_map status
Definition: remake.cpp:629
register_transparent_rule
static void register_transparent_rule(rule_t const &rule, string_list const &targets)
Definition: remake.cpp:1531
read_words
static bool read_words(input_generator &in, string_list &res)
Definition: remake.cpp:1288
Plusequal
@ Plusequal
Definition: remake.cpp:1066
rule_t::script
std::string script
Shell script for building the targets.
Definition: remake.cpp:567
register_rule
static void register_rule(rule_t const &rule)
Definition: remake.cpp:1603
Colon
@ Colon
Definition: remake.cpp:1061
Todo
@ Todo
Target is missing or obsolete.
Definition: remake.cpp:527
read_word
static std::string read_word(std::istream &in, bool detect_equal=true)
Definition: remake.cpp:1122
rule_t
Definition: remake.cpp:561
generic_rules
static rule_list generic_rules
Definition: remake.cpp:634
dependency_t::targets
string_list targets
Definition: remake.cpp:513
Equal
@ Equal
Definition: remake.cpp:1062
specific_rules
static rule_map specific_rules
Definition: remake.cpp:639
dependency_t::deps
string_set deps
Definition: remake.cpp:514
assign_t::value
string_list value
Definition: remake.cpp:552
merge_rule
static void merge_rule(rule_t &dest, rule_t const &src)
Definition: remake.cpp:1848
DEBUG_open
#define DEBUG_open
Definition: remake.cpp:818
Pipe
@ Pipe
Definition: remake.cpp:1067
instantiate_rule
static void instantiate_rule(std::string const &target, rule_t const &src, rule_t &dst)
Definition: remake.cpp:1887
rule_t::assigns
assign_map assigns
Assignment of variables.
Definition: remake.cpp:565
normalize_list
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
Definition: remake.cpp:1006
variables
static variable_map variables
Definition: remake.cpp:619
skip_empty
static void skip_empty(std::istream &in)
Definition: remake.cpp:1036
Word
@ Word
Definition: remake.cpp:1060
register_scripted_rule
static void register_scripted_rule(rule_t const &rule)
Definition: remake.cpp:1574
rule_t::deps
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition: remake.cpp:563
rule_t::stem
std::string stem
Stem used to instantiate the rule, if any.
Definition: remake.cpp:566
assign_t
Definition: remake.cpp:550
expect_token
static int expect_token(std::istream &in, int mask)
Definition: remake.cpp:1076
assign_t::append
bool append
Definition: remake.cpp:551
skip_spaces
static void skip_spaces(std::istream &in)
Definition: remake.cpp:1026
rule_t::wdeps
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition: remake.cpp:564
ref_ptr
Definition: remake.cpp:482