421#define WIN32_LEAN_AND_MEAN
442#include <sys/types.h>
459#include <sys/socket.h>
467#if defined(WINDOWS) || defined(MACOSX)
468enum { MSG_NOSIGNAL = 0 };
497 if (
ptr == p.
ptr)
return *
this;
572typedef std::map<std::string, ref_ptr<rule_t> >
rule_map;
731static time_t
now = time(NULL);
785 if (
open) std::cerr << std::endl;
787 std::cerr << std::string(
depth * 2,
' ');
793 if (o &&
open) std::cerr << std::endl;
796 if (o || !
open) std::cerr << std::string(
depth * 2,
' ');
817#define DEBUG if (debug.active) debug()
818#define DEBUG_open log_auto_close auto_close; if (debug.active) debug(true)
819#define DEBUG_close if ((auto_close.still_open = false), debug.active) debug(false)
838 std::string
const &s = se.
input;
839 char const *quoted_char =
",: '";
840 char const *escaped_char =
"\"\\$!";
841 bool need_quotes =
false;
843 size_t len = s.length(), last = 0, j = 0;
844 for (
size_t i = 0; i < len; ++i)
846 if (strchr(escaped_char, s[i]))
849 if (!buf) buf =
new char[len * 2];
850 memcpy(&buf[j], &s[last], i - last);
856 if (!need_quotes && strchr(quoted_char, s[i]))
859 if (!need_quotes)
return out << s;
861 if (!buf)
return out << s <<
'"';
863 out.write(&s[last], len - last);
880 char *res = getcwd(buf,
sizeof(buf));
883 perror(
"Failed to get working directory");
888 for (
size_t i = 0, l =
working_dir.size(); i != l; ++i)
904 if (stat((
prefix_dir +
"/Remakefile").c_str(), &s) == 0)
909 perror(
"Failed to change working directory");
914 std::cout <<
"remake: Entering directory `" <<
prefix_dir <<
'\'' << std::endl;
919 if (pos == std::string::npos)
921 std::cerr <<
"Failed to locate Remakefile in the current directory or one of its parents" << std::endl;
935 size_t l = p.length();
936 if (s.compare(0, l, p))
return s;
937 size_t ll = s.length();
938 if (ll == l)
return ".";
941 size_t pos = s.rfind(
'/', l);
942 assert(pos != std::string::npos);
943 return s.substr(pos + 1);
945 if (ll == l + 1)
return ".";
946 return s.substr(l + 1);
955static std::string
normalize(std::string
const &s, std::string
const &w, std::string
const &p)
958 char const *delim =
"/\\";
962 size_t pos = s.find_first_of(delim);
963 if (pos == std::string::npos && w == p)
return s;
964 bool absolute = pos == 0;
965 if (!absolute && w != p && !w.empty())
967 size_t prev = 0, len = s.length();
973 std::string n = s.substr(prev, pos - prev);
976 if (!l.empty()) l.pop_back();
977 else if (!absolute && !w.empty())
984 if (pos >= len)
break;
986 pos = s.find_first_of(delim, prev);
987 if (pos == std::string::npos) pos = len;
989 string_list::const_iterator i = l.begin(), i_end = l.end();
990 if (i == i_end)
return absolute ?
"/" :
".";
992 if (absolute) n.push_back(
'/');
994 for (++i; i != i_end; ++i)
1008 for (string_list::iterator i = l.begin(),
1009 i_end = l.end(); i != i_end; ++i)
1029 while (strchr(
" \t", (c = in.get()))) {}
1030 if (in.good()) in.putback(c);
1039 while (strchr(
"\r\n", (c = in.get()))) {}
1040 if (in.good()) in.putback(c);
1047static bool skip_eol(std::istream &in,
bool multi =
false)
1050 if (c ==
'\r') c = in.get();
1051 if (c !=
'\n' && in.good()) in.putback(c);
1052 if (c !=
'\n' && !in.eof())
return false;
1088 case ':': tok =
Colon;
break;
1089 case ',': tok =
Comma;
break;
1090 case '=': tok =
Equal;
break;
1092 case '|': tok =
Pipe;
break;
1122static std::string
read_word(std::istream &in,
bool detect_equal =
true)
1126 if (!in.good())
return res;
1127 char const *separators =
" \t\r\n$(),:";
1128 bool quoted = c ==
'"';
1129 if (quoted) in.ignore(1);
1134 if (!in.good())
return res;
1146 if (detect_equal && c ==
'=')
1148 if (plus) in.putback(
'+');
1156 if (strchr(separators, c))
return res;
1158 if (detect_equal && c ==
'+') plus =
true;
1204 if (local_variables)
1206 variable_map::const_iterator i = local_variables->find(
name);
1207 if (i != local_variables->end())
1209 vcur = i->second.begin();
1210 vend = i->second.end();
1216 vcur = i->second.begin();
1217 vend = i->second.end();
1292 res.push_back(std::string());
1321 : gen(top.in, top.local_variables)
1377 : gen(top.in, top.local_variables)
1423 if (!g || ok)
return g;
1444 std::cerr <<
"Failed to load database" << std::endl;
1452 if (in.eof())
return;
1453 if (targets.empty())
goto error;
1454 DEBUG <<
"reading dependencies of target " << targets.front() << std::endl;
1455 if (in.get() !=
':')
goto error;
1457 dep->targets = targets;
1460 dep->deps.insert(deps.begin(), deps.end());
1461 for (string_list::const_iterator i = targets.begin(),
1462 i_end = targets.end(); i != i_end; ++i)
1476 std::ifstream in(
".remake");
1492 std::ofstream db(
".remake");
1496 for (string_list::const_iterator i = dep->targets.begin(),
1497 i_end = dep->targets.end(); i != i_end; ++i)
1503 for (string_set::const_iterator i = dep->deps.begin(),
1504 i_end = dep->deps.end(); i != i_end; ++i)
1533 assert(rule.
script.empty());
1534 for (string_list::const_iterator i = targets.begin(),
1535 i_end = targets.end(); i != i_end; ++i)
1537 std::pair<rule_map::iterator, bool> j =
1546 if (!r->script.empty())
1548 std::cerr <<
"Failed to load rules: " << *i
1549 <<
" cannot be the target of several rules" << std::endl;
1552 assert(r->targets.size() == 1 && r->targets.front() == *i);
1556 for (string_list::const_iterator i = targets.begin(),
1557 i_end = targets.end(); i != i_end; ++i)
1560 if (dep->targets.empty()) dep->targets.push_back(*i);
1561 dep->deps.insert(rule.
deps.begin(), rule.
deps.end());
1577 for (string_list::const_iterator i = rule.
targets.begin(),
1578 i_end = rule.
targets.end(); i != i_end; ++i)
1580 std::pair<rule_map::iterator, bool> j =
1582 if (j.second)
continue;
1583 std::cerr <<
"Failed to load rules: " << *i
1584 <<
" cannot be the target of several rules" << std::endl;
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)
1595 dep->deps.insert(d->deps.begin(), d->deps.end());
1605 if (!rule.
script.empty())
1628static void load_rule(std::istream &in, std::string
const &first)
1630 DEBUG_open <<
"Reading rule for target " << first <<
"... ";
1635 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
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;
1647 for (string_list::const_iterator i = targets.begin(),
1648 i_end = targets.end(); i != i_end; ++i)
1650 if (i->empty())
goto error;
1651 if ((i->find(
'%') != std::string::npos) != generic)
1653 if (i == targets.begin())
generic =
true;
1658 if (in.get() !=
':')
goto error;
1660 bool assignment =
false, static_pattern =
false;
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)
1698 if (i->find(
'%') == std::string::npos)
goto error;
1701 static_pattern =
true;
1714 if (!
skip_eol(in,
true))
goto error;
1717 std::ostringstream buf;
1721 if (!in.good())
break;
1722 if (c ==
'\t' || c ==
' ')
1724 in.get(*buf.rdbuf());
1725 if (in.fail() && !in.eof()) in.clear();
1727 else if (c ==
'\r' || c ==
'\n')
1738 if (rule.
targets.front() ==
".PHONY")
1740 for (string_list::const_iterator i = rule.
deps.begin(),
1741 i_end = rule.
deps.end(); i != i_end; ++i)
1751 if (assignment)
goto error;
1756 if (!static_pattern)
1758 if (!rule.
script.empty() && assignment)
goto error;
1763 for (string_list::const_iterator i = targets.begin(),
1764 i_end = targets.end(); i != i_end; ++i)
1783 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
1786 std::ifstream in(remakefile.c_str());
1789 std::cerr <<
"Failed to load rules: no Remakefile found" << std::endl;
1802 while (in.get() !=
'\n') {}
1806 if (c ==
' ' || c ==
'\t')
goto error;
1810 if (name.empty())
goto error;
1813 DEBUG <<
"Assignment to variable " << name << std::endl;
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;
1828 for (string_list::const_iterator i = options.begin(),
1829 i_end = options.end(); i != i_end; ++i)
1834 std::cerr <<
"Failed to load rules: unrecognized option" << std::endl;
1852 for (assign_map::const_iterator i = src.
assigns.begin(),
1853 i_end = src.
assigns.end(); i != i_end; ++i)
1855 if (!i->second.append)
1858 dest.
assigns[i->first] = i->second;
1861 assign_map::iterator j = dest.
assigns.find(i->first);
1862 if (j == dest.
assigns.end())
goto new_assign;
1863 j->second.value.insert(j->second.value.end(),
1864 i->second.value.begin(), i->second.value.end());
1873 for (string_list::const_iterator i = src.begin(),
1874 i_end = src.end(); i != i_end; ++i)
1876 size_t pos = i->find(
'%');
1877 if (pos == std::string::npos) dst.push_back(*i);
1878 else dst.push_back(i->substr(0, pos) + pat + i->substr(pos + 1));
1889 size_t tlen = target.length(), plen = dst.
stem.length();
1890 for (string_list::const_iterator j = src.
targets.begin(),
1891 j_end = src.
targets.end(); j != j_end; ++j)
1893 size_t len = j->length();
1894 if (tlen < len)
continue;
1895 if (plen && plen <= tlen - (len - 1))
continue;
1896 size_t pos = j->find(
'%');
1897 if (pos == std::string::npos)
continue;
1898 size_t len2 = len - (pos + 1);
1899 if (j->compare(0, pos, target, 0, pos) ||
1900 j->compare(pos + 1, len2, target, tlen - len2, len2))
1902 plen = tlen - (len - 1);
1904 dst.stem = target.substr(pos, plen);
1937 if (i != i_end && !i->second->script.empty())
1939 job.
rule = *i->second;
1948 job.
rule = *i->second;
1955 if (i == i_end)
return;
1961 for (string_list::const_iterator j = job.
rule.
targets.begin(),
1965 if (i == i_end)
continue;
1966 if (!i->second->script.empty())
return;
1991 std::pair<status_map::iterator,bool> i =
1994 if (!i.second)
return ts;
1995 DEBUG_open <<
"Checking status of " << target <<
"... ";
1996 dependency_map::const_iterator j =
dependencies.find(target);
2000 if (stat(target.c_str(), &s) != 0)
2009 ts.
last = s.st_mtime;
2022 for (string_list::const_iterator k = dep.
targets.begin(),
2023 k_end = dep.
targets.end(); k != k_end; ++k)
2026 if (stat(k->c_str(), &s) != 0)
2032 status[*k].last = s.st_mtime;
2033 if (s.st_mtime > latest) latest = s.st_mtime;
2036 for (string_set::const_iterator k = dep.
deps.begin(),
2037 k_end = dep.
deps.end(); k != k_end; ++k)
2040 if (latest < ts_.
last)
2048 DEBUG <<
"obsolete dependency " << *k << std::endl;
2054 for (string_list::const_iterator k = dep.
targets.begin(),
2055 k_end = dep.
targets.end(); k != k_end; ++k)
2068 DEBUG_open <<
"Rechecking status of " << target <<
"... ";
2069 status_map::iterator i =
status.find(target);
2070 assert(i !=
status.end());
2079 if (stat(target.c_str(), &s) != 0)
2084 else if (s.st_mtime != ts.
last)
2087 ts.
last = s.st_mtime;
2101 status_map::const_iterator i =
status.find(target);
2102 assert(i !=
status.end());
2104 DEBUG_open <<
"Rechecking obsoleteness of " << target <<
"... ";
2105 dependency_map::const_iterator j =
dependencies.find(target);
2108 for (string_set::const_iterator k = dep.
deps.begin(),
2109 k_end = dep.
deps.end(); k != k_end; ++k)
2113 for (string_list::const_iterator k = dep.
targets.begin(),
2114 k_end = dep.
targets.end(); k != k_end; ++k)
2135 DEBUG <<
"Completing job " << job_id <<
'\n';
2136 job_map::iterator i =
jobs.find(job_id);
2137 assert(i !=
jobs.end());
2138 string_list const &targets = i->second.rule.targets;
2142 if (show) std::cout <<
"Finished";
2143 for (string_list::const_iterator j = targets.begin(),
2144 j_end = targets.end(); j != j_end; ++j)
2147 if (show) std::cout <<
' ' << *j;
2149 if (show) std::cout << std::endl;
2153 std::cerr <<
"Failed to build";
2154 for (string_list::const_iterator j = targets.begin(),
2155 j_end = targets.end(); j != j_end; ++j)
2157 std::cerr <<
' ' << *j;
2162 DEBUG <<
"Removing " << *j <<
'\n';
2167 std::cerr << std::endl;
2178 std::istringstream in(s);
2179 std::ostringstream out;
2180 size_t len = s.size();
2184 size_t pos = in.tellg(), p = s.find(
'$', pos);
2185 if (p == std::string::npos || p == len - 1) p = len;
2186 out.write(&s[pos], p - pos);
2187 if (p == len)
break;
2203 for (string_list::const_iterator i = job.
rule.
deps.begin(),
2204 i_end = job.
rule.
deps.end(); i != i_end; ++i)
2206 if (first) first =
false;
2236 if (s ==
Eof)
break;
2237 if (first) first =
false;
2264 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2274 std::ostringstream job_id_buf;
2275 job_id_buf << job_id;
2276 std::string job_id_ = job_id_buf.str();
2278 DEBUG_open <<
"Starting script for job " << job_id <<
"... ";
2299 CloseHandle(pfd[0]);
2300 CloseHandle(pfd[1]);
2303 if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2305 if (!SetHandleInformation(pfd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
2308 ZeroMemory(&si,
sizeof(STARTUPINFO));
2309 si.cb =
sizeof(STARTUPINFO);
2310 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2311 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2312 si.hStdInput = pfd[0];
2313 si.dwFlags |= STARTF_USESTDHANDLES;
2314 PROCESS_INFORMATION pi;
2315 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
2316 if (!SetEnvironmentVariable(
"REMAKE_JOB_ID", job_id_.c_str()))
2318 char const *argv =
echo_scripts ?
"SH.EXE -e -s -v" :
"SH.EXE -e -s";
2319 if (!CreateProcess(NULL, (
char *)argv, NULL, NULL,
2320 true, 0, NULL, NULL, &si, &pi))
2324 CloseHandle(pi.hThread);
2325 DWORD len = script.length(), wlen;
2326 if (!WriteFile(pfd[1], script.c_str(), len, &wlen, NULL) || wlen < len)
2327 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2328 CloseHandle(pfd[0]);
2329 CloseHandle(pfd[1]);
2342 if (pipe(pfd) == -1)
2344 if (setenv(
"REMAKE_JOB_ID", job_id_.c_str(), 1))
2346 if (pid_t pid = vfork())
2348 if (pid == -1)
goto error2;
2349 ssize_t len = script.length();
2350 if (write(pfd[1], script.c_str(), len) < len)
2351 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2359 char const *argv[5] = {
"sh",
"-e",
"-s", NULL, NULL };
2368 execve(
"/bin/sh", (
char **)argv,
environ);
2369 _exit(EXIT_FAILURE);
2383 DEBUG_open <<
"Starting job " << job_id <<
" for " << target <<
"... ";
2390 std::cerr <<
"No rule for building " << target << std::endl;
2397 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2403 for (assign_map::const_iterator i = job.
rule.
assigns.begin(),
2406 std::pair<variable_map::iterator, bool> k =
2409 if (i->second.append)
2413 variable_map::const_iterator j =
variables.find(i->first);
2414 if (j !=
variables.end()) v = j->second;
2417 else if (!k.second) v.clear();
2418 v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2423 current->job_id = job_id;
2425 current->pending.insert(current->pending.end(),
2428 current->delayed =
true;
2440 DEBUG_open <<
"Completing request from client of job " << client.
job_id <<
"... ";
2446 job_map::const_iterator i =
jobs.find(client.
job_id);
2447 assert(i !=
jobs.end());
2456 char res = success ? 1 : 0;
2457 send(client.
socket, &res, 1, MSG_NOSIGNAL);
2459 closesocket(client.
socket);
2497 DEBUG_open <<
"Handling client requests... ";
2499 bool need_restart =
false;
2501 for (client_list::iterator i =
clients.begin(), i_next = i,
2502 i_end =
clients.end(); i != i_end; i = i_next)
2506 DEBUG_open <<
"Handling client from job " << i->job_id <<
"... ";
2509 for (string_set::iterator j = i->running.begin(), j_next = j,
2510 j_end = i->running.end(); j != j_end; j = j_next)
2513 status_map::const_iterator k =
status.find(*j);
2514 assert(k !=
status.end());
2515 switch (k->second.status)
2526 i->running.erase(j);
2535 while (!i->pending.empty())
2537 std::string target = i->pending.front();
2538 i->pending.pop_front();
2543 i->running.insert(target);
2555 client_list::iterator j = i;
2556 switch (
start(target, i))
2559 goto pending_failed;
2562 j->running.insert(target);
2567 j->running.insert(target);
2572 need_restart =
true;
2582 if (i->running.empty() || i->failed)
2586 DEBUG_close << (i->failed ?
"failed\n" :
"finished\n");
2588 need_restart =
true;
2594 if (need_restart)
goto restart;
2599 std::cerr <<
"Circular dependency detected" << std::endl;
2600 client_list::iterator i =
clients.begin();
2616 perror(
"Failed to create server");
2626 struct sockaddr_in socket_addr;
2627 socket_addr.sin_family = AF_INET;
2628 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2629 socket_addr.sin_port = 0;
2632 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2634 if (!SetHandleInformation((HANDLE)
socket_fd, HANDLE_FLAG_INHERIT, 0))
2636 if (bind(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2638 int len =
sizeof(sockaddr_in);
2639 if (getsockname(
socket_fd, (
struct sockaddr *)&socket_addr, &len))
2641 std::ostringstream buf;
2642 buf << socket_addr.sin_port;
2643 if (!SetEnvironmentVariable(
"REMAKE_SOCKET", buf.str().c_str()))
2645 if (listen(
socket_fd, 1000))
goto error;
2650 sigemptyset(&sigmask);
2651 sigaddset(&sigmask, SIGCHLD);
2652 if (sigprocmask(SIG_BLOCK, &sigmask, &
old_sigmask) == -1)
goto error;
2653 struct sigaction sa;
2655 sigemptyset(&sa.sa_mask);
2657 if (sigaction(SIGCHLD, &sa, NULL) == -1)
goto error;
2659 if (sigaction(SIGINT, &sa, NULL) == -1)
goto error;
2664 struct sockaddr_un socket_addr;
2666 if (len >=
sizeof(socket_addr.sun_path) - 1)
goto error2;
2667 socket_addr.sun_family = AF_UNIX;
2669 len +=
sizeof(socket_addr.sun_family);
2670 if (setenv(
"REMAKE_SOCKET",
socket_name, 1))
goto error;
2674 socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2677 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2679 if (fcntl(
socket_fd, F_SETFD, FD_CLOEXEC) < 0)
goto error;
2681 if (bind(
socket_fd, (
struct sockaddr *)&socket_addr, len))
2683 if (listen(
socket_fd, 1000))
goto error;
2699 if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
2702 std::cerr <<
"Unexpected failure while setting connection with client" << std::endl;
2708 if (ioctlsocket(fd, FIONBIO, &nbio))
goto error2;
2710 int fd = accept4(
socket_fd, NULL, NULL, SOCK_CLOEXEC);
2715 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
return;
2718 client_list::iterator proc =
clients.begin();
2724 std::cerr <<
"Received an ill-formed client message" << std::endl;
2735 std::vector<char> buf;
2737 while (len <
sizeof(
int) + 2 || buf[len - 1] || buf[len - 2])
2739 buf.resize(len + 1024);
2740 ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2741 if (l <= 0)
goto error;
2747 memcpy(&job_id, &buf[0],
sizeof(
int));
2749 proc->job_id = job_id;
2750 job_map::const_iterator i =
jobs.find(job_id);
2751 if (i ==
jobs.end())
goto error;
2752 DEBUG <<
"receiving request from job " << job_id << std::endl;
2759 char const *p = &buf[0] +
sizeof(int);
2772 if (len == 1)
goto error;
2773 std::string target(p + 1, p + len);
2774 DEBUG <<
"adding dependency " << target <<
" to job\n";
2775 proc->pending.push_back(target);
2776 dep.
deps.insert(target);
2781 if (len == 1)
goto error;
2782 std::string var(p + 1, p + len);
2783 DEBUG <<
"adding variable " << var <<
" to job\n";
2784 last_var = &proc->vars[var];
2790 if (!last_var)
goto error;
2791 last_var->push_back(std::string(p + 1, p + len));
2802 std::cerr <<
"Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2812 pid_job_map::iterator i =
job_pids.find(pid);
2814 int job_id = i->second;
2834 for (pid_job_map::const_iterator i =
job_pids.begin(),
2835 i_end =
job_pids.end(); i != i_end; ++i, ++num)
2839 WSAEVENT aev = WSACreateEvent();
2841 WSAEventSelect(
socket_fd, aev, FD_ACCEPT);
2842 DWORD w = WaitForMultipleObjects(len, h,
false, INFINITE);
2854 bool res = GetExitCodeProcess(pid, &s) && s == 0;
2859 sigemptyset(&emptymask);
2863 int ret = pselect(
socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2869 while ((pid = waitpid(-1, &
status, WNOHANG)) > 0)
2871 bool res = WIFEXITED(
status) && WEXITSTATUS(
status) == 0;
2894 clients.back().pending.push_back(remakefile);
2904 if (!targets.empty())
clients.back().pending = targets;
2917 std::cout <<
"remake: Leaving directory `" <<
prefix_dir <<
'\'' << std::endl;
2939 perror(
"Failed to send targets to server");
2942 if (targets.empty()) exit(EXIT_SUCCESS);
2947 struct sockaddr_in socket_addr;
2948 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2950 socket_addr.sin_family = AF_INET;
2951 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2953 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2956 struct sockaddr_un socket_addr;
2958 if (len >=
sizeof(socket_addr.sun_path) - 1) exit(EXIT_FAILURE);
2959 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2961 socket_addr.sun_family = AF_UNIX;
2963 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(socket_addr.sun_family) + len))
2967 if (setsockopt(
socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &set_option,
sizeof(set_option)))
2973 char *
id = getenv(
"REMAKE_JOB_ID");
2974 int job_id =
id ? atoi(
id) : -1;
2975 if (send(
socket_fd, (
char *)&job_id,
sizeof(job_id), MSG_NOSIGNAL) !=
sizeof(job_id))
2979 for (string_list::const_iterator i = targets.begin(),
2980 i_end = targets.end(); i != i_end; ++i)
2982 DEBUG_open <<
"Sending target " << *i <<
"... ";
2983 std::string s =
'T' + *i;
2984 ssize_t len = s.length() + 1;
2985 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2990 for (variable_map::const_iterator i =
variables.begin(),
2991 i_end =
variables.end(); i != i_end; ++i)
2993 DEBUG_open <<
"Sending variable " << i->first <<
"... ";
2994 std::string s =
'V' + i->first;
2995 ssize_t len = s.length() + 1;
2996 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2998 for (string_list::const_iterator j = i->second.begin(),
2999 j_end = i->second.end(); j != j_end; ++j)
3001 std::string s =
'W' + *j;
3002 len = s.length() + 1;
3003 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
3010 if (send(
socket_fd, &result, 1, MSG_NOSIGNAL) != 1)
goto error;
3011 if (recv(
socket_fd, &result, 1, 0) != 1) exit(EXIT_FAILURE);
3012 exit(result ? EXIT_SUCCESS : EXIT_FAILURE);
3028 std::cerr <<
"Usage: remake [options] [target] ...\n"
3030 " -B, --always-make Unconditionally make all targets.\n"
3031 " -d Echo script commands.\n"
3032 " -d -d Print lots of debugging information.\n"
3033 " -f FILE Read FILE as Remakefile.\n"
3034 " -h, --help Print this message and exit.\n"
3035 " -j[N], --jobs=[N] Allow N jobs at once; infinite jobs with no arg.\n"
3036 " -k, --keep-going Keep going when some targets cannot be made.\n"
3037 " -r Look up targets from the dependencies on stdin.\n"
3038 " -s, --silent, --quiet Do not echo targets.\n";
3055 std::string remakefile;
3057 bool literal_targets =
false;
3058 bool indirect_targets =
false;
3061 for (
int i = 1; i < argc; ++i)
3063 std::string arg = argv[i];
3064 if (arg.empty())
usage(EXIT_FAILURE);
3065 if (literal_targets)
goto new_target;
3066 if (arg ==
"-h" || arg ==
"--help")
usage(EXIT_SUCCESS);
3070 else if (arg ==
"-k" || arg ==
"--keep-going")
3072 else if (arg ==
"-s" || arg ==
"--silent" || arg ==
"--quiet")
3074 else if (arg ==
"-r")
3075 indirect_targets =
true;
3076 else if (arg ==
"-B" || arg ==
"--always-make")
3078 else if (arg ==
"-f")
3080 if (++i == argc)
usage(EXIT_FAILURE);
3081 remakefile = argv[i];
3083 else if (arg ==
"--")
3084 literal_targets =
true;
3085 else if (arg.compare(0, 2,
"-j") == 0)
3087 else if (arg.compare(0, 7,
"--jobs=") == 0)
3091 if (arg[0] ==
'-')
usage(EXIT_FAILURE);
3092 if (arg.find(
'=') != std::string::npos)
3094 std::istringstream in(arg);
3101 targets.push_back(arg);
3102 DEBUG <<
"New target: " << arg <<
'\n';
3109 if (indirect_targets)
3116 l.push_back(
dependencies.begin()->second->targets.front());
3118 for (string_list::const_iterator i = l.begin(),
3119 i_end = l.end(); i != i_end; ++i)
3121 dependency_map::const_iterator j =
dependencies.find(*i);
3124 for (string_set::const_iterator k = dep.
deps.begin(),
3125 k_end = dep.
deps.end(); k != k_end; ++k)
3135 if (WSAStartup(MAKEWORD(2,2), &wsaData))
3137 std::cerr <<
"Unexpected failure while initializing Windows Socket" << std::endl;
3143 if (
char *sn = getenv(
"REMAKE_SOCKET"))
client_mode(sn, targets);
3146 if (remakefile.empty())
3148 remakefile =
"Remakefile";
static void client_mode(char *socket_name, string_list const &targets)
static void save_dependencies()
static void load_dependencies()
static bool skip_eol(std::istream &in, bool multi=false)
static int expect_token(std::istream &in, int mask)
static void skip_empty(std::istream &in)
static std::string read_word(std::istream &in, bool detect_equal=true)
static void skip_spaces(std::istream &in)
static void load_rules(std::string const &remakefile)
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 std::string normalize_abs(std::string const &s, std::string const &p)
static std::string normalize(std::string const &s, std::string const &w, std::string const &p)
static void init_working_dir()
static void init_prefix_dir()
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
static void substitute_pattern(std::string const &pat, string_list const &src, string_list &dst)
static void instantiate_rule(std::string const &target, rule_t const &src, rule_t &dst)
static void find_generic_rule(job_t &job, std::string const &target)
static void merge_rule(rule_t &dest, rule_t const &src)
static void find_rule(job_t &job, std::string const &target)
static void complete_request(client_t &client, bool success)
static void accept_client()
static bool handle_clients()
static void create_server()
static void finalize_job(pid_t pid, bool res)
static std::string prepare_script(job_t const &job)
static status_e start(std::string const &target, client_list::iterator ¤t)
static status_e run_script(int job_id, job_t const &job)
static bool has_free_slots()
static void complete_job(int job_id, bool success, bool started=true)
static void server_loop()
static void server_mode(std::string const &remakefile, string_list const &targets)
static bool still_need_rebuild(std::string const &target)
static void update_status(std::string const &target)
static status_t const & get_status(std::string const &target)
input_status next(std::string &)
addprefix_generator(input_generator const &, bool &)
variable_generator(std::string const &, variable_map const *)
static bool read_words(input_generator &in, string_list &res)
input_status next(std::string &)
input_status next(std::string &)
addsuffix_generator(input_generator const &, bool &)
static generator * get_function(input_generator const &, std::string const &)
input_status next(std::string &)
int main(int argc, char *argv[])
static void usage(int exit_status)
static int max_active_jobs
static bool build_failure
static void sigchld_handler(int)
std::map< int, job_t > job_map
std::map< std::string, status_t > status_map
std::map< std::string, ref_ptr< rule_t > > rule_map
static client_list clients
static std::string first_target
static rule_list generic_rules
std::list< std::string > string_list
static std::string working_dir
std::list< rule_t > rule_list
@ Failed
Build failed for target.
@ Todo
Target is missing or obsolete.
@ Running
Target is being rebuilt.
@ Recheck
Target has an obsolete dependency.
@ Remade
Target was successfully rebuilt.
@ Uptodate
Target is up-to-date.
@ RunningRecheck
Static prerequisites are being rebuilt.
static dependency_map dependencies
static std::ostream & operator<<(std::ostream &out, escape_string const &se)
static variable_map variables
std::set< std::string > string_set
static bool obsolete_targets
static bool changed_prefix_dir
std::map< pid_t, int > pid_job_map
static char * socket_name
static pid_job_map job_pids
std::map< std::string, ref_ptr< dependency_t > > dependency_map
std::map< std::string, assign_t > assign_map
static sigset_t old_sigmask
std::map< std::string, string_list > variable_map
static rule_map specific_rules
static socket_t socket_fd
static std::string prefix_dir
static bool propagate_vars
static void sigint_handler(int)
static volatile sig_atomic_t got_SIGCHLD
std::list< client_t > client_list
string_list::const_iterator prei
string_list::const_iterator sufi
string_list pending
Targets not yet started.
socket_t socket
Socket used to reply to the client (invalid for pseudo clients).
bool delayed
Whether it is a dependency client and a script has to be started on request completion.
bool failed
Whether some targets failed in mode -k.
int job_id
Job for which the built script called remake and spawned the client (negative for original clients).
string_set running
Targets being built.
variable_map vars
Variables set on request.
escape_string(std::string const &s)
std::string const & input
virtual input_status next(std::string &)=0
variable_map vars
Values of local variables.
rule_t rule
Original rule.
std::ostream & operator()(bool o)
std::ostream & operator()()
ref_ptr(ref_ptr const &p)
ref_ptr & operator=(ref_ptr const &p)
assign_map assigns
Assignment of variables.
string_list wdeps
Like deps, except that they are not registered as dependencies.
std::string script
Shell script for building the targets.
string_list targets
Files produced by this rule.
std::string stem
Stem used to instantiate the rule, if any.
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
status_e status
Actual status.
time_t last
Last-modified date.
string_list::const_iterator vend
string_list::const_iterator vcur