Remake
Loading...
Searching...
No Matches
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 1626 of file remake.cpp.

1627{
1628 DEBUG_open << "Reading rule for target " << first << "... ";
1629 if (false)
1630 {
1631 error:
1632 DEBUG_close << "failed\n";
1633 std::cerr << "Failed to load rules: syntax error" << std::endl;
1635 }
1636
1637 // Read targets and check genericity.
1638 string_list targets;
1639 if (!read_words(in, targets)) goto error;
1640 if (!first.empty()) targets.push_front(first);
1641 else if (targets.empty()) goto error;
1642 else DEBUG << "actual target: " << targets.front() << std::endl;
1643 bool generic = false;
1644 normalize_list(targets, "", "");
1645 for (string_list::const_iterator i = targets.begin(),
1646 i_end = targets.end(); i != i_end; ++i)
1647 {
1648 if (i->empty()) goto error;
1649 if ((i->find('%') != std::string::npos) != generic)
1650 {
1651 if (i == targets.begin()) generic = true;
1652 else goto error;
1653 }
1654 }
1655 skip_spaces(in);
1656 if (in.get() != ':') goto error;
1657
1658 bool assignment = false, static_pattern = false;
1659
1660 rule_t rule;
1661 rule.targets.swap(targets);
1662
1663 // Read dependencies.
1664 {
1665 string_list v;
1666 if (expect_token(in, Word))
1667 {
1668 std::string d = read_word(in);
1669 if (int tok = expect_token(in, Equal | Plusequal))
1670 {
1671 if (!read_words(in, v)) goto error;
1672 assign_t &a = rule.assigns[d];
1673 a.append = tok == Plusequal;
1674 a.value.swap(v);
1675 assignment = true;
1676 goto end_line;
1677 }
1678 v.push_back(d);
1679 }
1680
1681 if (!read_words(in, v)) goto error;
1682 normalize_list(v, "", "");
1683 rule.deps.swap(v);
1684
1685 if (expect_token(in, Colon))
1686 {
1687 if (!read_words(in, v)) goto error;
1688 normalize_list(v, "", "");
1689 targets.swap(rule.targets);
1690 rule.targets.swap(rule.deps);
1691 rule.deps.swap(v);
1692 if (rule.targets.empty()) goto error;
1693 for (string_list::const_iterator i = rule.targets.begin(),
1694 i_end = rule.targets.end(); i != i_end; ++i)
1695 {
1696 if (i->find('%') == std::string::npos) goto error;
1697 }
1698 generic = false;
1699 static_pattern = true;
1700 }
1701
1702 if (expect_token(in, Pipe))
1703 {
1704 if (!read_words(in, v)) goto error;
1705 normalize_list(v, "", "");
1706 rule.wdeps.swap(v);
1707 }
1708 }
1709
1710 end_line:
1711 skip_spaces(in);
1712 if (!skip_eol(in, true)) goto error;
1713
1714 // Read script.
1715 std::ostringstream buf;
1716 while (true)
1717 {
1718 char c = in.get();
1719 if (!in.good()) break;
1720 if (c == '\t' || c == ' ')
1721 {
1722 in.get(*buf.rdbuf());
1723 if (in.fail() && !in.eof()) in.clear();
1724 }
1725 else if (c == '\r' || c == '\n')
1726 buf << c;
1727 else
1728 {
1729 in.putback(c);
1730 break;
1731 }
1732 }
1733 rule.script = buf.str();
1734
1735 // Register phony targets.
1736 if (rule.targets.front() == ".PHONY")
1737 {
1738 for (string_list::const_iterator i = rule.deps.begin(),
1739 i_end = rule.deps.end(); i != i_end; ++i)
1740 {
1741 status[*i].status = Todo;
1742 }
1743 return;
1744 }
1745
1746 // Add generic rules to the correct set.
1747 if (generic)
1748 {
1749 if (assignment) goto error;
1750 generic_rules.push_back(rule);
1751 return;
1752 }
1753
1754 if (!static_pattern)
1755 {
1756 if (!rule.script.empty() && assignment) goto error;
1757 register_rule(rule);
1758 return;
1759 }
1760
1761 for (string_list::const_iterator i = targets.begin(),
1762 i_end = targets.end(); i != i_end; ++i)
1763 {
1764 rule_t r;
1765 instantiate_rule(*i, rule, r);
1766 if (!r.stem.empty()) register_rule(r);
1767 }
1768}
static bool skip_eol(std::istream &in, bool multi=false)
Definition remake.cpp:1045
static int expect_token(std::istream &in, int mask)
Definition remake.cpp:1074
static std::string read_word(std::istream &in, bool detect_equal=true)
Definition remake.cpp:1120
static void skip_spaces(std::istream &in)
Definition remake.cpp:1024
@ Plusequal
Definition remake.cpp:1064
@ Word
Definition remake.cpp:1058
@ Equal
Definition remake.cpp:1060
@ Colon
Definition remake.cpp:1059
@ Pipe
Definition remake.cpp:1065
static void register_rule(rule_t const &rule)
Definition remake.cpp:1601
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
Definition remake.cpp:1004
static void instantiate_rule(std::string const &target, rule_t const &src, rule_t &dst)
Definition remake.cpp:1885
static bool read_words(input_generator &in, string_list &res)
Definition remake.cpp:1286
static rule_list generic_rules
Definition remake.cpp:632
std::list< std::string > string_list
Definition remake.cpp:469
static status_map status
Definition remake.cpp:627
#define DEBUG_close
Definition remake.cpp:817
@ Todo
Target is missing or obsolete.
Definition remake.cpp:525
#define DEBUG_open
Definition remake.cpp:816
#define DEBUG
Definition remake.cpp:815
assign_map assigns
Assignment of variables.
Definition remake.cpp:563
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition remake.cpp:562
std::string script
Shell script for building the targets.
Definition remake.cpp:565
string_list targets
Files produced by this rule.
Definition remake.cpp:560
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition remake.cpp:561

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

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

Referenced by server_mode().

◆ register_rule()

static void register_rule ( rule_t const & rule)
static

Register a specific rule.

Definition at line 1601 of file remake.cpp.

1602{
1603 if (!rule.script.empty())
1604 {
1606 }
1607 else
1608 {
1609 // Swap away the targets to avoid costly copies when registering.
1610 rule_t &r = const_cast<rule_t &>(rule);
1611 string_list targets;
1612 targets.swap(r.targets);
1613 register_transparent_rule(r, targets);
1614 targets.swap(r.targets);
1615 }
1616
1617 // If there is no default target yet, mark it as such.
1618 if (first_target.empty())
1619 first_target = rule.targets.front();
1620}
static void register_transparent_rule(rule_t const &rule, string_list const &targets)
Definition remake.cpp:1529
static void register_scripted_rule(rule_t const &rule)
Definition remake.cpp:1572
static std::string first_target
Definition remake.cpp:714

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

1573{
1574 ref_ptr<rule_t> r(rule);
1575 for (string_list::const_iterator i = rule.targets.begin(),
1576 i_end = rule.targets.end(); i != i_end; ++i)
1577 {
1578 std::pair<rule_map::iterator, bool> j =
1579 specific_rules.insert(std::make_pair(*i, r));
1580 if (j.second) continue;
1581 std::cerr << "Failed to load rules: " << *i
1582 << " cannot be the target of several rules" << std::endl;
1584 }
1585
1587 dep->targets = rule.targets;
1588 dep->deps.insert(rule.deps.begin(), rule.deps.end());
1589 for (string_list::const_iterator i = rule.targets.begin(),
1590 i_end = rule.targets.end(); i != i_end; ++i)
1591 {
1593 dep->deps.insert(d->deps.begin(), d->deps.end());
1594 d = dep;
1595 }
1596}
static dependency_map dependencies
Definition remake.cpp:622
static rule_map specific_rules
Definition remake.cpp:637

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

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

Referenced by register_rule().