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

Referenced by load_rules().

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

Referenced by server_mode().

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

Referenced by load_rule().

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

Referenced by load_rule().

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