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

Referenced by load_rules().

1488 {
1489  DEBUG_open << "Reading rule for target " << first << "... ";
1490  if (false)
1491  {
1492  error:
1493  DEBUG_close << "failed\n";
1494  std::cerr << "Failed to load rules: syntax error" << std::endl;
1495  exit(EXIT_FAILURE);
1496  }
1497  rule_t rule;
1498 
1499  // Read targets and check genericity.
1500  string_list targets;
1501  if (!read_words(in, targets)) goto error;
1502  if (!first.empty()) targets.push_front(first);
1503  else if (targets.empty()) goto error;
1504  else DEBUG << "actual target: " << targets.front() << std::endl;
1505  bool generic = false;
1506  normalize_list(targets);
1507  for (string_list::const_iterator i = targets.begin(),
1508  i_end = targets.end(); i != i_end; ++i)
1509  {
1510  if (i->empty()) goto error;
1511  if ((i->find('%') != std::string::npos) != generic)
1512  {
1513  if (i == targets.begin()) generic = true;
1514  else goto error;
1515  }
1516  }
1517  std::swap(rule.targets, targets);
1518  skip_spaces(in);
1519  if (in.get() != ':') goto error;
1520 
1521  bool assignment = false;
1522 
1523  // Read dependencies.
1524  if (expect_token(in, Word))
1525  {
1526  std::string d = read_word(in);
1527  if (int tok = expect_token(in, Equal | Plusequal))
1528  {
1529  rule.vars.push_back(assign_t());
1530  string_list v;
1531  if (!read_words(in, v)) goto error;
1532  assign_t &a = rule.vars.back();
1533  a.name = d;
1534  a.append = tok == Plusequal;
1535  a.value.swap(v);
1536  assignment = true;
1537  }
1538  else
1539  {
1540  string_list v;
1541  if (!read_words(in, v)) goto error;
1542  v.push_front(d);
1543  normalize_list(v);
1544  rule.deps.swap(v);
1545  }
1546  }
1547  else
1548  {
1549  string_list v;
1550  if (!read_words(in, v)) goto error;
1551  normalize_list(v);
1552  rule.deps.swap(v);
1553  }
1554  skip_spaces(in);
1555  if (!skip_eol(in, true)) goto error;
1556 
1557  // Read script.
1558  std::ostringstream buf;
1559  while (true)
1560  {
1561  char c = in.get();
1562  if (!in.good()) break;
1563  if (c == '\t' || c == ' ')
1564  {
1565  in.get(*buf.rdbuf());
1566  if (in.fail() && !in.eof()) in.clear();
1567  }
1568  else if (c == '\r' || c == '\n')
1569  buf << c;
1570  else
1571  {
1572  in.putback(c);
1573  break;
1574  }
1575  }
1576  rule.script = buf.str();
1577 
1578  // Add generic rules to the correct set.
1579  if (generic)
1580  {
1581  if (assignment) goto error;
1582  generic_rules.push_back(rule);
1583  return;
1584  }
1585 
1586  if (!rule.script.empty())
1587  {
1588  if (assignment) goto error;
1589  register_scripted_rule(rule);
1590  }
1591  else
1592  {
1593  // Swap away the targets to avoid costly copies when registering.
1594  string_list targets;
1595  std::swap(rule.targets, targets);
1596  register_transparent_rule(rule, targets);
1597  std::swap(rule.targets, targets);
1598  }
1599 
1600  // If there is no default target yet, mark it as such.
1601  if (first_target.empty())
1602  first_target = rule.targets.front();
1603 }
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 1610 of file remake.cpp.

Referenced by server_mode().

1611 {
1612  DEBUG_open << "Loading rules... ";
1613  if (false)
1614  {
1615  error:
1616  std::cerr << "Failed to load rules: syntax error" << std::endl;
1617  exit(EXIT_FAILURE);
1618  }
1619  std::ifstream in(remakefile.c_str());
1620  if (!in.good())
1621  {
1622  std::cerr << "Failed to load rules: no Remakefile found" << std::endl;
1623  exit(EXIT_FAILURE);
1624  }
1625  skip_empty(in);
1626 
1627  // Read rules
1628  while (in.good())
1629  {
1630  char c = in.peek();
1631  if (c == '#')
1632  {
1633  while (in.get() != '\n') {}
1634  skip_empty(in);
1635  continue;
1636  }
1637  if (c == ' ' || c == '\t') goto error;
1638  if (expect_token(in, Word))
1639  {
1640  std::string name = read_word(in);
1641  if (name.empty()) goto error;
1642  if (int tok = expect_token(in, Equal | Plusequal))
1643  {
1644  DEBUG << "Assignment to variable " << name << std::endl;
1645  string_list value;
1646  if (!read_words(in, value)) goto error;
1647  string_list &dest = variables[name];
1648  if (tok == Equal) dest.swap(value);
1649  else dest.splice(dest.end(), value);
1650  if (!skip_eol(in, true)) goto error;
1651  }
1652  else load_rule(in, name);
1653  }
1654  else load_rule(in, std::string());
1655  }
1656 }
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 1457 of file remake.cpp.

Referenced by load_rule().

1458 {
1459  ref_ptr<rule_t> r(rule);
1460  for (string_list::const_iterator i = rule.targets.begin(),
1461  i_end = rule.targets.end(); i != i_end; ++i)
1462  {
1463  std::pair<rule_map::iterator, bool> j =
1464  specific_rules.insert(std::make_pair(*i, r));
1465  if (j.second) continue;
1466  std::cerr << "Failed to load rules: " << *i
1467  << " cannot be the target of several rules" << std::endl;
1468  exit(EXIT_FAILURE);
1469  }
1470 
1472  dep->targets = rule.targets;
1473  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1474  for (string_list::const_iterator i = rule.targets.begin(),
1475  i_end = rule.targets.end(); i != i_end; ++i)
1476  {
1478  dep->deps.insert(d->deps.begin(), d->deps.end());
1479  d = dep;
1480  }
1481 }
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 1413 of file remake.cpp.

Referenced by load_rule().

1414 {
1415  assert(rule.script.empty());
1416  for (string_list::const_iterator i = targets.begin(),
1417  i_end = targets.end(); i != i_end; ++i)
1418  {
1419  std::pair<rule_map::iterator, bool> j =
1420  specific_rules.insert(std::make_pair(*i, ref_ptr<rule_t>()));
1421  ref_ptr<rule_t> &r = j.first->second;
1422  if (j.second)
1423  {
1424  r = ref_ptr<rule_t>(rule);
1425  r->targets = string_list(1, *i);
1426  continue;
1427  }
1428  if (!r->script.empty())
1429  {
1430  std::cerr << "Failed to load rules: " << *i
1431  << " cannot be the target of several rules" << std::endl;
1432  exit(EXIT_FAILURE);
1433  }
1434  assert(r->targets.size() == 1 && r->targets.front() == *i);
1435  r->deps.insert(r->deps.end(), rule.deps.begin(), rule.deps.end());
1436  r->vars.insert(r->vars.end(), rule.vars.begin(), rule.vars.end());
1437  }
1438 
1439  for (string_list::const_iterator i = targets.begin(),
1440  i_end = targets.end(); i != i_end; ++i)
1441  {
1443  if (dep->targets.empty()) dep->targets.push_back(*i);
1444  dep->deps.insert(rule.deps.begin(), rule.deps.end());
1445  }
1446 }