406 #define WIN32_LEAN_AND_MEAN 426 #include <sys/stat.h> 427 #include <sys/types.h> 440 #include <winsock2.h> 444 #include <sys/socket.h> 446 #include <sys/wait.h> 452 #if defined(WINDOWS) || defined(MACOSX) 453 enum { MSG_NOSIGNAL = 0 };
482 if (ptr == p.
ptr)
return *
this;
483 if (ptr && --ptr->
cnt == 0)
delete ptr;
556 typedef std::map<std::string, ref_ptr<rule_t> >
rule_map;
716 static time_t
now = time(NULL);
763 log(): active(false), open(false), depth(0)
768 if (open) std::cerr << std::endl;
770 std::cerr << std::string(depth * 2,
' ');
776 if (o && open) std::cerr << std::endl;
779 if (o || !open) std::cerr << std::string(depth * 2,
' ');
796 if (debug.
active && still_open)
debug(
false) <<
"done\n";
800 #define DEBUG if (debug.active) debug() 801 #define DEBUG_open log_auto_close auto_close; if (debug.active) debug(true) 802 #define DEBUG_close if ((auto_close.still_open = false), debug.active) debug(false) 821 std::string
const &s = se.
input;
822 char const *quoted_char =
",: '";
823 char const *escaped_char =
"\"\\$!";
824 bool need_quotes =
false;
826 size_t len = s.length(), last = 0, j = 0;
827 for (
size_t i = 0; i < len; ++i)
829 if (strchr(escaped_char, s[i]))
832 if (!buf) buf =
new char[len * 2];
833 memcpy(&buf[j], &s[last], i - last);
839 if (!need_quotes && strchr(quoted_char, s[i]))
842 if (!need_quotes)
return out << s;
844 if (!buf)
return out << s <<
'"';
846 out.write(&s[last], len - last);
863 char *res = getcwd(buf,
sizeof(buf));
866 perror(
"Failed to get working directory");
871 for (
size_t i = 0, l =
working_dir.size(); i != l; ++i)
887 if (stat((
prefix_dir +
"/Remakefile").c_str(), &s) == 0)
892 perror(
"Failed to change working directory");
897 std::cout <<
"remake: Entering directory `" <<
prefix_dir <<
'\'' << std::endl;
902 if (pos == std::string::npos)
904 std::cerr <<
"Failed to locate Remakefile in the current directory or one of its parents" << std::endl;
916 static std::string
normalize_abs(std::string
const &s, std::string
const &p)
918 size_t l = p.length();
919 if (s.compare(0, l, p))
return s;
920 size_t ll = s.length();
921 if (ll == l)
return ".";
924 size_t pos = s.rfind(
'/', l);
925 assert(pos != std::string::npos);
926 return s.substr(pos + 1);
928 if (ll == l + 1)
return ".";
929 return s.substr(l + 1);
938 static std::string
normalize(std::string
const &s, std::string
const &w, std::string
const &p)
941 char const *delim =
"/\\";
945 size_t pos = s.find_first_of(delim);
946 if (pos == std::string::npos && w == p)
return s;
947 bool absolute = pos == 0;
948 if (!absolute && w != p && !w.empty())
950 size_t prev = 0, len = s.length();
956 std::string n = s.substr(prev, pos - prev);
959 if (!l.empty()) l.pop_back();
960 else if (!absolute && !w.empty())
967 if (pos >= len)
break;
969 pos = s.find_first_of(delim, prev);
970 if (pos == std::string::npos) pos = len;
972 string_list::const_iterator i = l.begin(), i_end = l.end();
973 if (i == i_end)
return absolute ?
"/" :
".";
975 if (absolute) n.push_back(
'/');
977 for (++i; i != i_end; ++i)
991 for (string_list::iterator i = l.begin(),
992 i_end = l.end(); i != i_end; ++i)
1012 while (strchr(
" \t", (c = in.get()))) {}
1013 if (in.good()) in.putback(c);
1022 while (strchr(
"\r\n", (c = in.get()))) {}
1023 if (in.good()) in.putback(c);
1030 static bool skip_eol(std::istream &in,
bool multi =
false)
1033 if (c ==
'\r') c = in.get();
1034 if (c !=
'\n' && in.good()) in.putback(c);
1035 if (c !=
'\n' && !in.eof())
return false;
1071 case ':': tok =
Colon;
break;
1072 case ',': tok =
Comma;
break;
1073 case '=': tok =
Equal;
break;
1075 case '|': tok =
Pipe;
break;
1105 static std::string
read_word(std::istream &in,
bool detect_equal =
true)
1109 if (!in.good())
return res;
1110 char const *separators =
" \t\r\n$(),:";
1111 bool quoted = c ==
'"';
1112 if (quoted) in.ignore(1);
1117 if (!in.good())
return res;
1129 if (detect_equal && c ==
'=')
1131 if (plus) in.putback(
'+');
1139 if (strchr(separators, c))
return res;
1141 if (detect_equal && c ==
'+') plus =
true;
1179 string_list::const_iterator vcur,
vend;
1187 if (local_variables)
1189 variable_map::const_iterator i = local_variables->find(
name);
1190 if (i != local_variables->end())
1192 vcur = i->second.begin();
1193 vend = i->second.end();
1199 vcur = i->second.begin();
1200 vend = i->second.end();
1224 : in(i), nested(NULL), local_variables(lv), earliest_exit(e), done(false) {}
1242 if (done)
return Eof;
1243 if (earliest_exit) done =
true;
1275 res.push_back(std::string());
1304 : gen(top.in, top.local_variables)
1360 :
gen(top.in, top.local_variables)
1406 if (!g || ok)
return g;
1427 std::cerr <<
"Failed to load database" << std::endl;
1435 if (in.eof())
return;
1436 if (targets.empty())
goto error;
1437 DEBUG <<
"reading dependencies of target " << targets.front() << std::endl;
1438 if (in.get() !=
':')
goto error;
1443 dep->
deps.insert(deps.begin(), deps.end());
1444 for (string_list::const_iterator i = targets.begin(),
1445 i_end = targets.end(); i != i_end; ++i)
1459 std::ifstream in(
".remake");
1475 std::ofstream db(
".remake");
1479 for (string_list::const_iterator i = dep->
targets.begin(),
1480 i_end = dep->
targets.end(); i != i_end; ++i)
1486 for (string_set::const_iterator i = dep->
deps.begin(),
1487 i_end = dep->
deps.end(); i != i_end; ++i)
1515 assert(rule.
script.empty());
1516 for (string_list::const_iterator i = targets.begin(),
1517 i_end = targets.end(); i != i_end; ++i)
1519 std::pair<rule_map::iterator, bool> j =
1530 std::cerr <<
"Failed to load rules: " << *i
1531 <<
" cannot be the target of several rules" << std::endl;
1538 for (string_list::const_iterator i = targets.begin(),
1539 i_end = targets.end(); i != i_end; ++i)
1559 for (string_list::const_iterator i = rule.
targets.begin(),
1560 i_end = rule.
targets.end(); i != i_end; ++i)
1562 std::pair<rule_map::iterator, bool> j =
1564 if (j.second)
continue;
1565 std::cerr <<
"Failed to load rules: " << *i
1566 <<
" cannot be the target of several rules" << std::endl;
1573 for (string_list::const_iterator i = rule.
targets.begin(),
1574 i_end = rule.
targets.end(); i != i_end; ++i)
1586 static void load_rule(std::istream &in, std::string
const &first)
1588 DEBUG_open <<
"Reading rule for target " << first <<
"... ";
1593 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
1601 if (!first.empty()) targets.push_front(first);
1602 else if (targets.empty())
goto error;
1603 else DEBUG <<
"actual target: " << targets.front() << std::endl;
1604 bool generic =
false;
1606 for (string_list::const_iterator i = targets.begin(),
1607 i_end = targets.end(); i != i_end; ++i)
1609 if (i->empty())
goto error;
1610 if ((i->find(
'%') != std::string::npos) !=
generic)
1612 if (i == targets.begin())
generic =
true;
1616 std::swap(rule.
targets, targets);
1618 if (in.get() !=
':')
goto error;
1620 bool assignment =
false;
1654 if (!
skip_eol(in,
true))
goto error;
1657 std::ostringstream buf;
1661 if (!in.good())
break;
1662 if (c ==
'\t' || c ==
' ')
1664 in.get(*buf.rdbuf());
1665 if (in.fail() && !in.eof()) in.clear();
1667 else if (c ==
'\r' || c ==
'\n')
1678 if (rule.
targets.front() ==
".PHONY")
1680 for (string_list::const_iterator i = rule.
deps.begin(),
1681 i_end = rule.
deps.end(); i != i_end; ++i)
1691 if (assignment)
goto error;
1696 if (!rule.
script.empty())
1698 if (assignment)
goto error;
1705 std::swap(rule.
targets, targets);
1707 std::swap(rule.
targets, targets);
1726 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
1729 std::ifstream in(remakefile.c_str());
1732 std::cerr <<
"Failed to load rules: no Remakefile found" << std::endl;
1745 while (in.get() !=
'\n') {}
1749 if (c ==
' ' || c ==
'\t')
goto error;
1753 if (name.empty())
goto error;
1756 DEBUG <<
"Assignment to variable " << name << std::endl;
1760 *(name ==
".OPTIONS" ? &options : &
variables[name]);
1761 if (tok ==
Equal) dest.swap(value);
1762 else dest.splice(dest.end(), value);
1763 if (!
skip_eol(in,
true))
goto error;
1771 for (string_list::const_iterator i = options.begin(),
1772 i_end = options.end(); i != i_end; ++i)
1777 std::cerr <<
"Failed to load rules: unrecognized option" << std::endl;
1795 for (assign_map::const_iterator i = src.
assigns.begin(),
1796 i_end = src.
assigns.end(); i != i_end; ++i)
1798 if (!i->second.append)
1801 dest.
assigns[i->first] = i->second;
1804 assign_map::iterator j = dest.
assigns.find(i->first);
1805 if (j == dest.
assigns.end())
goto new_assign;
1806 j->second.value.insert(j->second.value.end(),
1807 i->second.value.begin(), i->second.value.end());
1816 for (string_list::const_iterator i = src.begin(),
1817 i_end = src.end(); i != i_end; ++i)
1819 size_t pos = i->find(
'%');
1820 if (pos == std::string::npos) dst.push_back(*i);
1821 else dst.push_back(i->substr(0, pos) + pat + i->substr(pos + 1));
1832 size_t tlen = target.length(), plen = tlen + 1;
1836 for (string_list::const_iterator j = i->targets.begin(),
1837 j_end = i->targets.end(); j != j_end; ++j)
1839 size_t len = j->length();
1840 if (tlen < len)
continue;
1841 if (plen <= tlen - (len - 1))
continue;
1842 size_t pos = j->find(
'%');
1843 if (pos == std::string::npos)
continue;
1844 size_t len2 = len - (pos + 1);
1845 if (j->compare(0, pos, target, 0, pos) ||
1846 j->compare(pos + 1, len2, target, tlen - len2, len2))
1848 plen = tlen - (len - 1);
1849 job.
stem = target.substr(pos, plen);
1870 if (i != i_end && !i->second->script.empty())
1872 job.
rule = *i->second;
1881 job.
rule = *i->second;
1888 if (i == i_end)
return;
1894 for (string_list::const_iterator j = job.
rule.
targets.begin(),
1898 if (i == i_end)
continue;
1899 if (!i->second->script.empty())
return;
1924 std::pair<status_map::iterator,bool> i =
1927 if (!i.second)
return ts;
1928 DEBUG_open <<
"Checking status of " << target <<
"... ";
1929 dependency_map::const_iterator j =
dependencies.find(target);
1933 if (stat(target.c_str(), &s) != 0)
1942 ts.
last = s.st_mtime;
1955 for (string_list::const_iterator k = dep.
targets.begin(),
1956 k_end = dep.
targets.end(); k != k_end; ++k)
1959 if (stat(k->c_str(), &s) != 0)
1965 status[*k].last = s.st_mtime;
1966 if (s.st_mtime > latest) latest = s.st_mtime;
1969 for (string_set::const_iterator k = dep.
deps.begin(),
1970 k_end = dep.
deps.end(); k != k_end; ++k)
1973 if (latest < ts_.
last)
1981 DEBUG <<
"obsolete dependency " << *k << std::endl;
1987 for (string_list::const_iterator k = dep.
targets.begin(),
1988 k_end = dep.
targets.end(); k != k_end; ++k)
2001 DEBUG_open <<
"Rechecking status of " << target <<
"... ";
2002 status_map::iterator i =
status.find(target);
2003 assert(i !=
status.end());
2012 if (stat(target.c_str(), &s) != 0)
2017 else if (s.st_mtime != ts.last)
2020 ts.last = s.st_mtime;
2034 status_map::const_iterator i =
status.find(target);
2035 assert(i !=
status.end());
2037 DEBUG_open <<
"Rechecking obsoleteness of " << target <<
"... ";
2038 dependency_map::const_iterator j =
dependencies.find(target);
2041 for (string_set::const_iterator k = dep.deps.begin(),
2042 k_end = dep.deps.end(); k != k_end; ++k)
2046 for (string_list::const_iterator k = dep.targets.begin(),
2047 k_end = dep.targets.end(); k != k_end; ++k)
2068 DEBUG <<
"Completing job " << job_id <<
'\n';
2069 job_map::iterator i =
jobs.find(job_id);
2070 assert(i !=
jobs.end());
2071 string_list const &targets = i->second.rule.targets;
2075 if (show) std::cout <<
"Finished";
2076 for (string_list::const_iterator j = targets.begin(),
2077 j_end = targets.end(); j != j_end; ++j)
2080 if (show) std::cout <<
' ' << *j;
2082 if (show) std::cout << std::endl;
2086 std::cerr <<
"Failed to build";
2087 for (string_list::const_iterator j = targets.begin(),
2088 j_end = targets.end(); j != j_end; ++j)
2090 std::cerr <<
' ' << *j;
2095 DEBUG <<
"Removing " << *j <<
'\n';
2100 std::cerr << std::endl;
2111 std::istringstream in(s);
2112 std::ostringstream out;
2113 size_t len = s.size();
2117 size_t pos = in.tellg(), p = s.find(
'$', pos);
2118 if (p == std::string::npos || p == len - 1) p = len;
2119 out.write(&s[pos], p - pos);
2120 if (p == len)
break;
2136 for (string_list::const_iterator i = job.
rule.
deps.begin(),
2137 i_end = job.
rule.
deps.end(); i != i_end; ++i)
2139 if (first) first =
false;
2169 if (s ==
Eof)
break;
2170 if (first) first =
false;
2197 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2207 std::ostringstream job_id_buf;
2208 job_id_buf << job_id;
2209 std::string job_id_ = job_id_buf.str();
2211 DEBUG_open <<
"Starting script for job " << job_id <<
"... ";
2232 CloseHandle(pfd[0]);
2233 CloseHandle(pfd[1]);
2236 if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2238 if (!SetHandleInformation(pfd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
2241 ZeroMemory(&si,
sizeof(STARTUPINFO));
2242 si.cb =
sizeof(STARTUPINFO);
2243 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2244 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2245 si.hStdInput = pfd[0];
2246 si.dwFlags |= STARTF_USESTDHANDLES;
2247 PROCESS_INFORMATION pi;
2248 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
2249 if (!SetEnvironmentVariable(
"REMAKE_JOB_ID", job_id_.c_str()))
2251 char const *argv =
echo_scripts ?
"SH.EXE -e -s -v" :
"SH.EXE -e -s";
2252 if (!CreateProcess(NULL, (
char *)argv, NULL, NULL,
2253 true, 0, NULL, NULL, &si, &pi))
2257 CloseHandle(pi.hThread);
2258 DWORD len = script.length(), wlen;
2259 if (!WriteFile(pfd[1], script.c_str(), len, &wlen, NULL) || wlen < len)
2260 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2261 CloseHandle(pfd[0]);
2262 CloseHandle(pfd[1]);
2275 if (pipe(pfd) == -1)
2277 if (setenv(
"REMAKE_JOB_ID", job_id_.c_str(), 1))
2279 if (pid_t pid = vfork())
2281 if (pid == -1)
goto error2;
2282 ssize_t len = script.length();
2283 if (write(pfd[1], script.c_str(), len) < len)
2284 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2292 char const *argv[5] = {
"sh",
"-e",
"-s", NULL, NULL };
2300 execve(
"/bin/sh", (
char **)argv,
environ);
2301 _exit(EXIT_FAILURE);
2312 static status_e start(std::string
const &target, client_list::iterator ¤t)
2315 DEBUG_open <<
"Starting job " << job_id <<
" for " << target <<
"... ";
2322 std::cerr <<
"No rule for building " << target << std::endl;
2329 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2335 for (assign_map::const_iterator i = job.
rule.
assigns.begin(),
2338 std::pair<variable_map::iterator, bool> k =
2341 if (i->second.append)
2345 variable_map::const_iterator j =
variables.find(i->first);
2346 if (j !=
variables.end()) v = j->second;
2349 else if (!k.second) v.clear();
2350 v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2355 current->job_id = job_id;
2357 current->pending.insert(current->pending.end(),
2360 current->delayed =
true;
2372 DEBUG_open <<
"Completing request from client of job " << client.
job_id <<
"... ";
2378 job_map::const_iterator i =
jobs.find(client.
job_id);
2379 assert(i !=
jobs.end());
2388 char res = success ? 1 : 0;
2389 send(client.
socket, &res, 1, MSG_NOSIGNAL);
2391 closesocket(client.
socket);
2429 DEBUG_open <<
"Handling client requests... ";
2431 bool need_restart =
false;
2433 for (client_list::iterator i =
clients.begin(), i_next = i,
2437 DEBUG_open <<
"Handling client from job " << i->job_id <<
"... ";
2440 for (string_set::iterator j = i->running.begin(), j_next = j,
2441 j_end = i->running.end(); j != j_end; j = j_next)
2444 status_map::const_iterator k =
status.find(*j);
2445 assert(k !=
status.end());
2446 switch (k->second.status)
2457 i->running.erase(j);
2466 while (!i->pending.empty())
2468 std::string target = i->pending.front();
2469 i->pending.pop_front();
2474 i->running.insert(target);
2486 client_list::iterator j = i;
2487 switch (
start(target, i))
2490 goto pending_failed;
2493 j->running.insert(target);
2498 j->running.insert(target);
2503 need_restart =
true;
2513 if (i->running.empty() || i->failed)
2517 DEBUG_close << (i->failed ?
"failed\n" :
"finished\n");
2519 need_restart =
true;
2525 if (need_restart)
goto restart;
2530 std::cerr <<
"Circular dependency detected" << std::endl;
2531 client_list::iterator i =
clients.begin();
2547 perror(
"Failed to create server");
2557 struct sockaddr_in socket_addr;
2558 socket_addr.sin_family = AF_INET;
2559 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2560 socket_addr.sin_port = 0;
2563 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2565 if (!SetHandleInformation((HANDLE)
socket_fd, HANDLE_FLAG_INHERIT, 0))
2567 if (bind(socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2569 int len =
sizeof(sockaddr_in);
2570 if (getsockname(socket_fd, (
struct sockaddr *)&socket_addr, &len))
2572 std::ostringstream buf;
2573 buf << socket_addr.sin_port;
2574 if (!SetEnvironmentVariable(
"REMAKE_SOCKET", buf.str().c_str()))
2576 if (listen(socket_fd, 1000))
goto error;
2581 sigemptyset(&sigmask);
2582 sigaddset(&sigmask, SIGCHLD);
2583 if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1)
goto error;
2584 struct sigaction sa;
2586 sigemptyset(&sa.sa_mask);
2588 if (sigaction(SIGCHLD, &sa, NULL) == -1)
goto error;
2590 if (sigaction(SIGINT, &sa, NULL) == -1)
goto error;
2595 struct sockaddr_un socket_addr;
2597 if (len >=
sizeof(socket_addr.sun_path) - 1)
goto error2;
2598 socket_addr.sun_family = AF_UNIX;
2600 len +=
sizeof(socket_addr.sun_family);
2601 if (setenv(
"REMAKE_SOCKET",
socket_name, 1))
goto error;
2605 socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2608 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2610 if (fcntl(socket_fd, F_SETFD, FD_CLOEXEC) < 0)
goto error;
2612 if (bind(socket_fd, (
struct sockaddr *)&socket_addr, len))
2614 if (listen(socket_fd, 1000))
goto error;
2630 if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
2633 std::cerr <<
"Unexpected failure while setting connection with client" << std::endl;
2639 if (ioctlsocket(fd, FIONBIO, &nbio))
goto error2;
2640 #elif defined(LINUX) 2641 int fd = accept4(
socket_fd, NULL, NULL, SOCK_CLOEXEC);
2646 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
return;
2649 client_list::iterator proc =
clients.begin();
2655 std::cerr <<
"Received an ill-formed client message" << std::endl;
2666 std::vector<char> buf;
2668 while (len <
sizeof(
int) + 2 || buf[len - 1] || buf[len - 2])
2670 buf.resize(len + 1024);
2671 ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2672 if (l <= 0)
goto error;
2678 memcpy(&job_id, &buf[0],
sizeof(
int));
2680 proc->job_id = job_id;
2681 job_map::const_iterator i =
jobs.find(job_id);
2682 if (i ==
jobs.end())
goto error;
2683 DEBUG <<
"receiving request from job " << job_id << std::endl;
2690 char const *p = &buf[0] +
sizeof(int);
2703 if (len == 1)
goto error;
2704 std::string target(p + 1, p + len);
2705 DEBUG <<
"adding dependency " << target <<
" to job\n";
2706 proc->pending.push_back(target);
2707 dep.
deps.insert(target);
2712 if (len == 1)
goto error;
2713 std::string var(p + 1, p + len);
2714 DEBUG <<
"adding variable " << var <<
" to job\n";
2715 last_var = &proc->vars[var];
2721 if (!last_var)
goto error;
2722 last_var->push_back(std::string(p + 1, p + len));
2733 std::cerr <<
"Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2743 pid_job_map::iterator i =
job_pids.find(pid);
2745 int job_id = i->second;
2765 for (pid_job_map::const_iterator i =
job_pids.begin(),
2766 i_end =
job_pids.end(); i != i_end; ++i, ++num)
2770 WSAEVENT aev = WSACreateEvent();
2772 WSAEventSelect(
socket_fd, aev, FD_ACCEPT);
2773 DWORD w = WaitForMultipleObjects(len, h,
false, INFINITE);
2785 bool res = GetExitCodeProcess(pid, &s) && s == 0;
2790 sigemptyset(&emptymask);
2794 int ret = pselect(
socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2800 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2802 bool res = WIFEXITED(status) && WEXITSTATUS(status) == 0;
2825 clients.back().pending.push_back(remakefile);
2835 if (!targets.empty())
clients.back().pending = targets;
2848 std::cout <<
"remake: Leaving directory `" <<
prefix_dir <<
'\'' << std::endl;
2870 perror(
"Failed to send targets to server");
2873 if (targets.empty()) exit(EXIT_SUCCESS);
2878 struct sockaddr_in socket_addr;
2879 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2881 socket_addr.sin_family = AF_INET;
2882 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2883 socket_addr.sin_port = atoi(socket_name);
2884 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2887 struct sockaddr_un socket_addr;
2888 size_t len = strlen(socket_name);
2889 if (len >=
sizeof(socket_addr.sun_path) - 1) exit(EXIT_FAILURE);
2890 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2892 socket_addr.sun_family = AF_UNIX;
2893 strcpy(socket_addr.sun_path, socket_name);
2894 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(socket_addr.sun_family) + len))
2898 if (setsockopt(
socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &set_option,
sizeof(set_option)))
2904 char *
id = getenv(
"REMAKE_JOB_ID");
2905 int job_id =
id ? atoi(
id) : -1;
2906 if (send(
socket_fd, (
char *)&job_id,
sizeof(job_id), MSG_NOSIGNAL) !=
sizeof(job_id))
2910 for (string_list::const_iterator i = targets.begin(),
2911 i_end = targets.end(); i != i_end; ++i)
2913 DEBUG_open <<
"Sending target " << *i <<
"... ";
2914 std::string s =
'T' + *i;
2915 ssize_t len = s.length() + 1;
2916 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2921 for (variable_map::const_iterator i =
variables.begin(),
2922 i_end =
variables.end(); i != i_end; ++i)
2924 DEBUG_open <<
"Sending variable " << i->first <<
"... ";
2925 std::string s =
'V' + i->first;
2926 ssize_t len = s.length() + 1;
2927 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2929 for (string_list::const_iterator j = i->second.begin(),
2930 j_end = i->second.end(); j != j_end; ++j)
2932 std::string s =
'W' + *j;
2933 len = s.length() + 1;
2934 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2941 if (send(
socket_fd, &result, 1, MSG_NOSIGNAL) != 1)
goto error;
2942 if (recv(
socket_fd, &result, 1, 0) != 1) exit(EXIT_FAILURE);
2943 exit(result ? EXIT_SUCCESS : EXIT_FAILURE);
2959 std::cerr <<
"Usage: remake [options] [target] ...\n" 2961 " -B, --always-make Unconditionally make all targets.\n" 2962 " -d Echo script commands.\n" 2963 " -d -d Print lots of debugging information.\n" 2964 " -f FILE Read FILE as Remakefile.\n" 2965 " -h, --help Print this message and exit.\n" 2966 " -j[N], --jobs=[N] Allow N jobs at once; infinite jobs with no arg.\n" 2967 " -k, --keep-going Keep going when some targets cannot be made.\n" 2968 " -r Look up targets from the dependencies on stdin.\n" 2969 " -s, --silent, --quiet Do not echo targets.\n";
2986 std::string remakefile;
2988 bool literal_targets =
false;
2989 bool indirect_targets =
false;
2992 for (
int i = 1; i < argc; ++i)
2994 std::string arg = argv[i];
2995 if (arg.empty())
usage(EXIT_FAILURE);
2996 if (literal_targets)
goto new_target;
2997 if (arg ==
"-h" || arg ==
"--help")
usage(EXIT_SUCCESS);
3001 else if (arg ==
"-k" || arg ==
"--keep-going")
3003 else if (arg ==
"-s" || arg ==
"--silent" || arg ==
"--quiet")
3005 else if (arg ==
"-r")
3006 indirect_targets =
true;
3007 else if (arg ==
"-B" || arg ==
"--always-make")
3009 else if (arg ==
"-f")
3011 if (++i == argc)
usage(EXIT_FAILURE);
3012 remakefile = argv[i];
3014 else if (arg ==
"--")
3015 literal_targets =
true;
3016 else if (arg.compare(0, 2,
"-j") == 0)
3018 else if (arg.compare(0, 7,
"--jobs=") == 0)
3022 if (arg[0] ==
'-')
usage(EXIT_FAILURE);
3023 if (arg.find(
'=') != std::string::npos)
3025 std::istringstream in(arg);
3032 targets.push_back(arg);
3033 DEBUG <<
"New target: " << arg <<
'\n';
3040 if (indirect_targets)
3047 l.push_back(
dependencies.begin()->second->targets.front());
3049 for (string_list::const_iterator i = l.begin(),
3050 i_end = l.end(); i != i_end; ++i)
3052 dependency_map::const_iterator j =
dependencies.find(*i);
3055 for (string_set::const_iterator k = dep.
deps.begin(),
3056 k_end = dep.
deps.end(); k != k_end; ++k)
3066 if (WSAStartup(MAKEWORD(2,2), &wsaData))
3068 std::cerr <<
"Unexpected failure while initializing Windows Socket" << std::endl;
3074 if (
char *sn = getenv(
"REMAKE_SOCKET"))
client_mode(sn, targets);
3077 if (remakefile.empty())
3079 remakefile =
"Remakefile";
std::map< int, job_t > job_map
static void create_server()
std::string const & input
static bool still_need_rebuild(std::string const &target)
input_status next(std::string &)
int job_id
Job for which the built script called remake and spawned the client (negative for original clients)...
static status_e run_script(int job_id, job_t const &job)
ref_ptr & operator=(ref_ptr const &p)
static void complete_request(client_t &client, bool success)
static std::string normalize(std::string const &s, std::string const &w, std::string const &p)
static generator * get_function(input_generator const &, std::string const &)
std::map< std::string, status_t > status_map
static void find_rule(job_t &job, std::string const &target)
static void save_dependencies()
static void server_mode(std::string const &remakefile, string_list const &targets)
static void init_prefix_dir()
static char * socket_name
static bool propagate_vars
std::ostream & operator()(bool o)
static variable_map variables
std::list< std::string > string_list
variable_map vars
Variables set on request.
addprefix_generator(input_generator const &, bool &)
static int max_active_jobs
escape_string(std::string const &s)
bool delayed
Whether it is a dependency client and a script has to be started on request completion.
input_status next(std::string &)
std::set< std::string > string_set
static rule_map specific_rules
string_list wdeps
Like deps, except that they are not registered as dependencies.
ref_ptr(ref_ptr const &p)
static status_t const & get_status(std::string const &target)
std::map< std::string, string_list > variable_map
static void load_rule(std::istream &in, std::string const &first)
static std::string first_target
std::list< rule_t > rule_list
static void server_loop()
static bool build_failure
static client_list clients
static std::string read_word(std::istream &in, bool detect_equal=true)
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
string_list::const_iterator sufi
static bool skip_eol(std::istream &in, bool multi=false)
static bool read_words(input_generator &in, string_list &res)
static void register_scripted_rule(rule_t const &rule)
static void init_working_dir()
static std::ostream & operator<<(std::ostream &out, escape_string const &se)
static pid_job_map job_pids
static std::string normalize_abs(std::string const &s, std::string const &p)
assign_map assigns
Assignment of variables.
string_list::const_iterator vend
static std::string working_dir
static std::string prefix_dir
static bool obsolete_targets
std::ostream & operator()()
static void sigint_handler(int)
std::map< std::string, ref_ptr< dependency_t > > dependency_map
variable_map vars
Values of local variables.
static volatile sig_atomic_t got_SIGCHLD
static void update_status(std::string const &target)
variable_generator(std::string const &, variable_map const *)
Target is missing or obsolete.
std::string stem
Pattern used to instantiate the generic rule, if any.
string_list::const_iterator prei
static bool handle_clients()
static void accept_client()
string_list::const_iterator vcur
addsuffix_generator(input_generator const &, bool &)
static void merge_rule(rule_t &dest, rule_t const &src)
string_list targets
Files produced by this rule.
static bool has_free_slots()
Target has an obsolete dependency.
std::string script
Shell script for building the targets.
Target was successfully rebuilt.
static bool changed_prefix_dir
static void skip_spaces(std::istream &in)
input_status next(std::string &)
string_set running
Targets being built.
static void normalize_list(string_list &l, std::string const &w, std::string const &p)
std::map< std::string, ref_ptr< rule_t > > rule_map
static void skip_empty(std::istream &in)
static void find_generic_rule(job_t &job, std::string const &target)
socket_t socket
Socket used to reply to the client (invalid for pseudo clients).
static void substitute_pattern(std::string const &pat, string_list const &src, string_list &dst)
static socket_t socket_fd
rule_t rule
Original rule.
static int expect_token(std::istream &in, int mask)
string_list pending
Targets not yet started.
static void complete_job(int job_id, bool success, bool started=true)
static void usage(int exit_status)
static void client_mode(char *socket_name, string_list const &targets)
static void finalize_job(pid_t pid, bool res)
std::list< client_t > client_list
std::map< pid_t, int > pid_job_map
std::map< std::string, assign_t > assign_map
bool failed
Whether some targets failed in mode -k.
static status_e start(std::string const &target, client_list::iterator ¤t)
static void load_dependencies(std::istream &in)
static void load_rules(std::string const &remakefile)
static void register_transparent_rule(rule_t const &rule, string_list const &targets)
time_t last
Last-modified date.
input_status next(std::string &)
status_e status
Actual status.
static rule_list generic_rules
int main(int argc, char *argv[])
static dependency_map dependencies
static std::string prepare_script(job_t const &job)
Static prerequisites are being rebuilt.
static void sigchld_handler(int)