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 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;
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}
static bool skip_eol(std::istream &in, bool multi=false)
Definition remake.cpp:1047
static int expect_token(std::istream &in, int mask)
Definition remake.cpp:1076
static std::string read_word(std::istream &in, bool detect_equal=true)
Definition remake.cpp:1122
static void skip_spaces(std::istream &in)
Definition remake.cpp:1026
@ Plusequal
Definition remake.cpp:1066
@ Word
Definition remake.cpp:1060
@ Equal
Definition remake.cpp:1062
@ Colon
Definition remake.cpp:1061
@ Pipe
Definition remake.cpp:1067
static void register_rule(rule_t const &rule)
Definition remake.cpp:1603
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
Definition remake.cpp:1006
static void instantiate_rule(std::string const &target, rule_t const &src, rule_t &dst)
Definition remake.cpp:1887
static bool read_words(input_generator &in, string_list &res)
Definition remake.cpp:1288
static rule_list generic_rules
Definition remake.cpp:634
std::list< std::string > string_list
Definition remake.cpp:471
static status_map status
Definition remake.cpp:629
#define DEBUG_close
Definition remake.cpp:819
@ Todo
Target is missing or obsolete.
Definition remake.cpp:527
#define DEBUG_open
Definition remake.cpp:818
#define DEBUG
Definition remake.cpp:817
assign_map assigns
Assignment of variables.
Definition remake.cpp:565
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition remake.cpp:564
std::string script
Shell script for building the targets.
Definition remake.cpp:567
string_list targets
Files produced by this rule.
Definition remake.cpp:562
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition remake.cpp:563

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;
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;
1791 }
1792 skip_empty(in);
1793
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;
1836 }
1837 }
1838}
static void skip_empty(std::istream &in)
Definition remake.cpp:1036
static void load_rule(std::istream &in, std::string const &first)
Definition remake.cpp:1628
static variable_map variables
Definition remake.cpp:619
static bool propagate_vars
Definition remake.cpp:751

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 {
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}
static void register_transparent_rule(rule_t const &rule, string_list const &targets)
Definition remake.cpp:1531
static void register_scripted_rule(rule_t const &rule)
Definition remake.cpp:1574
static std::string first_target
Definition remake.cpp:716

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;
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}
static dependency_map dependencies
Definition remake.cpp:624
static rule_map specific_rules
Definition remake.cpp:639

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;
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}
static void merge_rule(rule_t &dest, rule_t const &src)
Definition remake.cpp:1848

Referenced by register_rule().