405 #define WIN32_LEAN_AND_MEAN
425 #include <sys/stat.h>
426 #include <sys/types.h>
439 #include <winsock2.h>
443 #include <sys/socket.h>
445 #include <sys/wait.h>
451 #if defined(WINDOWS) || defined(MACOSX)
452 enum { MSG_NOSIGNAL = 0 };
481 if (
ptr == p.
ptr)
return *
this;
554 typedef std::map<std::string, ref_ptr<rule_t> >
rule_map;
714 static time_t
now = time(NULL);
761 if (
open) std::cerr << std::endl;
763 std::cerr << std::string(
depth * 2,
' ');
769 if (o &&
open) std::cerr << std::endl;
772 if (o || !
open) std::cerr << std::string(
depth * 2,
' ');
793 #define DEBUG if (debug.active) debug()
794 #define DEBUG_open log_auto_close auto_close; if (debug.active) debug(true)
795 #define DEBUG_close if ((auto_close.still_open = false), debug.active) debug(false)
814 std::string
const &s = se.
input;
815 char const *quoted_char =
",: '";
816 char const *escaped_char =
"\"\\$!";
817 bool need_quotes =
false;
819 size_t len = s.length(), last = 0, j = 0;
820 for (
size_t i = 0; i < len; ++i)
822 if (strchr(escaped_char, s[i]))
825 if (!buf) buf =
new char[len * 2];
826 memcpy(&buf[j], &s[last], i - last);
832 if (!need_quotes && strchr(quoted_char, s[i]))
835 if (!need_quotes)
return out << s;
837 if (!buf)
return out << s <<
'"';
839 out.write(&s[last], len - last);
856 char *res = getcwd(buf,
sizeof(buf));
859 perror(
"Failed to get working directory");
864 for (
size_t i = 0, l =
working_dir.size(); i != l; ++i)
880 if (stat((
prefix_dir +
"/Remakefile").c_str(), &s) == 0)
885 perror(
"Failed to change working directory");
890 std::cout <<
"remake: Entering directory `" <<
prefix_dir <<
'\'' << std::endl;
895 if (pos == std::string::npos)
897 std::cerr <<
"Failed to locate Remakefile in the current directory or one of its parents" << std::endl;
909 static std::string
normalize_abs(std::string
const &s, std::string
const &p)
911 size_t l = p.length();
912 if (s.compare(0, l, p))
return s;
913 size_t ll = s.length();
914 if (ll == l)
return ".";
917 size_t pos = s.rfind(
'/', l);
918 assert(pos != std::string::npos);
919 return s.substr(pos + 1);
921 if (ll == l + 1)
return ".";
922 return s.substr(l + 1);
931 static std::string
normalize(std::string
const &s, std::string
const &w, std::string
const &p)
934 char const *delim =
"/\\";
938 size_t pos = s.find_first_of(delim);
939 if (pos == std::string::npos && w == p)
return s;
940 bool absolute = pos == 0;
941 if (!absolute && w != p && !w.empty())
943 size_t prev = 0, len = s.length();
949 std::string n = s.substr(prev, pos - prev);
952 if (!l.empty()) l.pop_back();
953 else if (!absolute && !w.empty())
960 if (pos >= len)
break;
962 pos = s.find_first_of(delim, prev);
963 if (pos == std::string::npos) pos = len;
965 string_list::const_iterator i = l.begin(), i_end = l.end();
966 if (i == i_end)
return absolute ?
"/" :
".";
968 if (absolute) n.push_back(
'/');
970 for (++i; i != i_end; ++i)
984 for (string_list::iterator i = l.begin(),
985 i_end = l.end(); i != i_end; ++i)
1005 while (strchr(
" \t", (c = in.get()))) {}
1006 if (in.good()) in.putback(c);
1015 while (strchr(
"\r\n", (c = in.get()))) {}
1016 if (in.good()) in.putback(c);
1023 static bool skip_eol(std::istream &in,
bool multi =
false)
1026 if (c ==
'\r') c = in.get();
1027 if (c !=
'\n' && in.good()) in.putback(c);
1028 if (c !=
'\n' && !in.eof())
return false;
1064 case ':': tok =
Colon;
break;
1065 case ',': tok =
Comma;
break;
1066 case '=': tok =
Equal;
break;
1068 case '|': tok =
Pipe;
break;
1098 static std::string
read_word(std::istream &in,
bool detect_equal =
true)
1102 if (!in.good())
return res;
1103 char const *separators =
" \t\r\n$(),:";
1104 bool quoted = c ==
'"';
1105 if (quoted) in.ignore(1);
1110 if (!in.good())
return res;
1122 if (detect_equal && c ==
'=')
1124 if (plus) in.putback(
'+');
1132 if (strchr(separators, c))
return res;
1134 if (detect_equal && c ==
'+') plus =
true;
1180 if (local_variables)
1182 variable_map::const_iterator i = local_variables->find(
name);
1183 if (i != local_variables->end())
1185 vcur = i->second.begin();
1186 vend = i->second.end();
1192 vcur = i->second.begin();
1193 vend = i->second.end();
1268 res.push_back(std::string());
1297 : gen(top.in, top.local_variables)
1353 : gen(top.in, top.local_variables)
1399 if (!g || ok)
return g;
1420 std::cerr <<
"Failed to load database" << std::endl;
1428 if (in.eof())
return;
1429 if (targets.empty())
goto error;
1430 DEBUG <<
"reading dependencies of target " << targets.front() << std::endl;
1431 if (in.get() !=
':')
goto error;
1436 dep->
deps.insert(deps.begin(), deps.end());
1437 for (string_list::const_iterator i = targets.begin(),
1438 i_end = targets.end(); i != i_end; ++i)
1452 std::ifstream in(
".remake");
1468 std::ofstream db(
".remake");
1472 for (string_list::const_iterator i = dep->
targets.begin(),
1473 i_end = dep->
targets.end(); i != i_end; ++i)
1479 for (string_set::const_iterator i = dep->
deps.begin(),
1480 i_end = dep->
deps.end(); i != i_end; ++i)
1508 assert(rule.
script.empty());
1509 for (string_list::const_iterator i = targets.begin(),
1510 i_end = targets.end(); i != i_end; ++i)
1512 std::pair<rule_map::iterator, bool> j =
1523 std::cerr <<
"Failed to load rules: " << *i
1524 <<
" cannot be the target of several rules" << std::endl;
1531 for (string_list::const_iterator i = targets.begin(),
1532 i_end = targets.end(); i != i_end; ++i)
1552 for (string_list::const_iterator i = rule.
targets.begin(),
1553 i_end = rule.
targets.end(); i != i_end; ++i)
1555 std::pair<rule_map::iterator, bool> j =
1557 if (j.second)
continue;
1558 std::cerr <<
"Failed to load rules: " << *i
1559 <<
" cannot be the target of several rules" << std::endl;
1566 for (string_list::const_iterator i = rule.
targets.begin(),
1567 i_end = rule.
targets.end(); i != i_end; ++i)
1579 static void load_rule(std::istream &in, std::string
const &first)
1581 DEBUG_open <<
"Reading rule for target " << first <<
"... ";
1586 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
1594 if (!first.empty()) targets.push_front(first);
1595 else if (targets.empty())
goto error;
1596 else DEBUG <<
"actual target: " << targets.front() << std::endl;
1597 bool generic =
false;
1599 for (string_list::const_iterator i = targets.begin(),
1600 i_end = targets.end(); i != i_end; ++i)
1602 if (i->empty())
goto error;
1603 if ((i->find(
'%') != std::string::npos) !=
generic)
1605 if (i == targets.begin())
generic =
true;
1609 std::swap(rule.
targets, targets);
1611 if (in.get() !=
':')
goto error;
1613 bool assignment =
false;
1647 if (!
skip_eol(in,
true))
goto error;
1650 std::ostringstream buf;
1654 if (!in.good())
break;
1655 if (c ==
'\t' || c ==
' ')
1657 in.get(*buf.rdbuf());
1658 if (in.fail() && !in.eof()) in.clear();
1660 else if (c ==
'\r' || c ==
'\n')
1671 if (rule.
targets.front() ==
".PHONY")
1673 for (string_list::const_iterator i = rule.
deps.begin(),
1674 i_end = rule.
deps.end(); i != i_end; ++i)
1684 if (assignment)
goto error;
1689 if (!rule.
script.empty())
1691 if (assignment)
goto error;
1698 std::swap(rule.
targets, targets);
1700 std::swap(rule.
targets, targets);
1719 std::cerr <<
"Failed to load rules: syntax error" << std::endl;
1722 std::ifstream in(remakefile.c_str());
1725 std::cerr <<
"Failed to load rules: no Remakefile found" << std::endl;
1738 while (in.get() !=
'\n') {}
1742 if (c ==
' ' || c ==
'\t')
goto error;
1746 if (name.empty())
goto error;
1749 DEBUG <<
"Assignment to variable " << name << std::endl;
1753 *(name ==
".OPTIONS" ? &options : &
variables[name]);
1754 if (tok ==
Equal) dest.swap(value);
1755 else dest.splice(dest.end(), value);
1756 if (!
skip_eol(in,
true))
goto error;
1764 for (string_list::const_iterator i = options.begin(),
1765 i_end = options.end(); i != i_end; ++i)
1770 std::cerr <<
"Failed to load rules: unrecognized option" << std::endl;
1788 for (assign_map::const_iterator i = src.
assigns.begin(),
1789 i_end = src.
assigns.end(); i != i_end; ++i)
1791 if (!i->second.append)
1794 dest.
assigns[i->first] = i->second;
1797 assign_map::iterator j = dest.
assigns.find(i->first);
1798 if (j == dest.
assigns.end())
goto new_assign;
1799 j->second.value.insert(j->second.value.end(),
1800 i->second.value.begin(), i->second.value.end());
1809 for (string_list::const_iterator i = src.begin(),
1810 i_end = src.end(); i != i_end; ++i)
1812 size_t pos = i->find(
'%');
1813 if (pos == std::string::npos) dst.push_back(*i);
1814 else dst.push_back(i->substr(0, pos) + pat + i->substr(pos + 1));
1825 size_t tlen = target.length(), plen = tlen + 1;
1829 for (string_list::const_iterator j = i->targets.begin(),
1830 j_end = i->targets.end(); j != j_end; ++j)
1832 size_t len = j->length();
1833 if (tlen < len)
continue;
1834 if (plen <= tlen - (len - 1))
continue;
1835 size_t pos = j->find(
'%');
1836 if (pos == std::string::npos)
continue;
1837 size_t len2 = len - (pos + 1);
1838 if (j->compare(0, pos, target, 0, pos) ||
1839 j->compare(pos + 1, len2, target, tlen - len2, len2))
1841 plen = tlen - (len - 1);
1842 job.
stem = target.substr(pos, plen);
1863 if (i != i_end && !i->second->script.empty())
1865 job.
rule = *i->second;
1874 job.
rule = *i->second;
1881 if (i == i_end)
return;
1887 for (string_list::const_iterator j = job.
rule.
targets.begin(),
1891 if (i == i_end)
continue;
1892 if (!i->second->script.empty())
return;
1917 std::pair<status_map::iterator,bool> i =
1920 if (!i.second)
return ts;
1921 DEBUG_open <<
"Checking status of " << target <<
"... ";
1922 dependency_map::const_iterator j =
dependencies.find(target);
1926 if (stat(target.c_str(), &s) != 0)
1935 ts.
last = s.st_mtime;
1941 for (string_list::const_iterator k = dep.
targets.begin(),
1942 k_end = dep.
targets.end(); k != k_end; ++k)
1945 if (stat(k->c_str(), &s) != 0)
1951 status[*k].last = s.st_mtime;
1952 if (s.st_mtime > latest) latest = s.st_mtime;
1955 for (string_set::const_iterator k = dep.
deps.begin(),
1956 k_end = dep.
deps.end(); k != k_end; ++k)
1959 if (latest < ts_.
last)
1967 DEBUG <<
"obsolete dependency " << *k << std::endl;
1973 for (string_list::const_iterator k = dep.
targets.begin(),
1974 k_end = dep.
targets.end(); k != k_end; ++k)
1987 DEBUG_open <<
"Rechecking status of " << target <<
"... ";
1988 status_map::iterator i =
status.find(target);
1989 assert(i !=
status.end());
1998 if (stat(target.c_str(), &s) != 0)
2003 else if (s.st_mtime != ts.last)
2006 ts.last = s.st_mtime;
2020 DEBUG_open <<
"Rechecking obsoleteness of " << target <<
"... ";
2021 status_map::const_iterator i =
status.find(target);
2022 assert(i !=
status.end());
2023 if (i->second.status !=
Recheck)
return true;
2024 dependency_map::const_iterator j =
dependencies.find(target);
2027 for (string_set::const_iterator k = dep.deps.begin(),
2028 k_end = dep.deps.end(); k != k_end; ++k)
2032 for (string_list::const_iterator k = dep.targets.begin(),
2033 k_end = dep.targets.end(); k != k_end; ++k)
2054 DEBUG <<
"Completing job " << job_id <<
'\n';
2055 job_map::iterator i =
jobs.find(job_id);
2056 assert(i !=
jobs.end());
2057 string_list const &targets = i->second.rule.targets;
2061 for (string_list::const_iterator j = targets.begin(),
2062 j_end = targets.end(); j != j_end; ++j)
2071 std::cerr <<
"Failed to build";
2072 for (string_list::const_iterator j = targets.begin(),
2073 j_end = targets.end(); j != j_end; ++j)
2076 std::cerr <<
' ' << *j;
2079 std::cerr << std::endl;
2090 std::istringstream in(s);
2091 std::ostringstream out;
2092 size_t len = s.size();
2096 size_t pos = in.tellg(), p = s.find(
'$', pos);
2097 if (p == std::string::npos || p == len - 1) p = len;
2098 out.write(&s[pos], p - pos);
2099 if (p == len)
break;
2115 for (string_list::const_iterator i = job.
rule.
deps.begin(),
2116 i_end = job.
rule.
deps.end(); i != i_end; ++i)
2118 if (first) first =
false;
2148 if (s ==
Eof)
break;
2149 if (first) first =
false;
2176 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2186 std::ostringstream job_id_buf;
2187 job_id_buf << job_id;
2188 std::string job_id_ = job_id_buf.str();
2190 DEBUG_open <<
"Starting script for job " << job_id <<
"... ";
2211 CloseHandle(pfd[0]);
2212 CloseHandle(pfd[1]);
2215 if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2217 if (!SetHandleInformation(pfd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
2220 ZeroMemory(&si,
sizeof(STARTUPINFO));
2221 si.cb =
sizeof(STARTUPINFO);
2222 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
2223 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2224 si.hStdInput = pfd[0];
2225 si.dwFlags |= STARTF_USESTDHANDLES;
2226 PROCESS_INFORMATION pi;
2227 ZeroMemory(&pi,
sizeof(PROCESS_INFORMATION));
2228 if (!SetEnvironmentVariable(
"REMAKE_JOB_ID", job_id_.c_str()))
2230 char const *argv =
echo_scripts ?
"SH.EXE -e -s -v" :
"SH.EXE -e -s";
2231 if (!CreateProcess(NULL, (
char *)argv, NULL, NULL,
2232 true, 0, NULL, NULL, &si, &pi))
2236 CloseHandle(pi.hThread);
2237 DWORD len = script.length(), wlen;
2238 if (!WriteFile(pfd[1], script.c_str(), len, &wlen, NULL) || wlen < len)
2239 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2240 CloseHandle(pfd[0]);
2241 CloseHandle(pfd[1]);
2254 if (pipe(pfd) == -1)
2256 if (setenv(
"REMAKE_JOB_ID", job_id_.c_str(), 1))
2258 if (pid_t pid = vfork())
2260 if (pid == -1)
goto error2;
2261 ssize_t len = script.length();
2262 if (write(pfd[1], script.c_str(), len) < len)
2263 std::cerr <<
"Unexpected failure while sending script to shell" << std::endl;
2271 char const *argv[5] = {
"sh",
"-e",
"-s", NULL, NULL };
2279 execve(
"/bin/sh", (
char **)argv,
environ);
2280 _exit(EXIT_FAILURE);
2291 static status_e start(std::string
const &target, client_list::iterator ¤t)
2294 DEBUG_open <<
"Starting job " << job_id <<
" for " << target <<
"... ";
2301 std::cerr <<
"No rule for building " << target << std::endl;
2304 for (string_list::const_iterator i = job.
rule.
targets.begin(),
2310 for (assign_map::const_iterator i = job.
rule.
assigns.begin(),
2313 std::pair<variable_map::iterator, bool> k =
2316 if (i->second.append)
2320 variable_map::const_iterator j =
variables.find(i->first);
2321 if (j !=
variables.end()) v = j->second;
2324 else if (!k.second) v.clear();
2325 v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2330 current->job_id = job_id;
2332 current->pending.insert(current->pending.end(),
2335 current->delayed =
true;
2347 DEBUG_open <<
"Completing request from client of job " << client.
job_id <<
"... ";
2353 job_map::const_iterator i =
jobs.find(client.
job_id);
2354 assert(i !=
jobs.end());
2363 char res = success ? 1 : 0;
2364 send(client.
socket, &res, 1, MSG_NOSIGNAL);
2366 closesocket(client.
socket);
2404 DEBUG_open <<
"Handling client requests... ";
2406 bool need_restart =
false;
2408 for (client_list::iterator i =
clients.begin(), i_next = i,
2412 DEBUG_open <<
"Handling client from job " << i->job_id <<
"... ";
2415 for (string_set::iterator j = i->running.begin(), j_next = j,
2416 j_end = i->running.end(); j != j_end; j = j_next)
2419 status_map::const_iterator k =
status.find(*j);
2420 assert(k !=
status.end());
2421 switch (k->second.status)
2431 i->running.erase(j);
2440 while (!i->pending.empty())
2442 std::string target = i->pending.front();
2443 i->pending.pop_front();
2447 i->running.insert(target);
2459 client_list::iterator j = i;
2460 switch (
start(target, i))
2463 goto pending_failed;
2466 j->running.insert(target);
2471 j->running.insert(target);
2476 need_restart =
true;
2486 if (i->running.empty() || i->failed)
2490 DEBUG_close << (i->failed ?
"failed\n" :
"finished\n");
2492 need_restart =
true;
2498 if (need_restart)
goto restart;
2503 std::cerr <<
"Circular dependency detected" << std::endl;
2504 client_list::iterator i =
clients.begin();
2520 perror(
"Failed to create server");
2530 struct sockaddr_in socket_addr;
2531 socket_addr.sin_family = AF_INET;
2532 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2533 socket_addr.sin_port = 0;
2536 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2538 if (!SetHandleInformation((HANDLE)
socket_fd, HANDLE_FLAG_INHERIT, 0))
2540 if (bind(socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2542 int len =
sizeof(sockaddr_in);
2543 if (getsockname(socket_fd, (
struct sockaddr *)&socket_addr, &len))
2545 std::ostringstream buf;
2546 buf << socket_addr.sin_port;
2547 if (!SetEnvironmentVariable(
"REMAKE_SOCKET", buf.str().c_str()))
2549 if (listen(socket_fd, 1000))
goto error;
2554 sigemptyset(&sigmask);
2555 sigaddset(&sigmask, SIGCHLD);
2556 if (sigprocmask(SIG_BLOCK, &sigmask, NULL) == -1)
goto error;
2557 struct sigaction sa;
2559 sigemptyset(&sa.sa_mask);
2561 if (sigaction(SIGCHLD, &sa, NULL) == -1)
goto error;
2563 if (sigaction(SIGINT, &sa, NULL) == -1)
goto error;
2568 struct sockaddr_un socket_addr;
2570 if (len >=
sizeof(socket_addr.sun_path) - 1)
goto error2;
2571 socket_addr.sun_family = AF_UNIX;
2573 len +=
sizeof(socket_addr.sun_family);
2574 if (setenv(
"REMAKE_SOCKET",
socket_name, 1))
goto error;
2578 socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2581 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2583 if (fcntl(socket_fd, F_SETFD, FD_CLOEXEC) < 0)
goto error;
2585 if (bind(socket_fd, (
struct sockaddr *)&socket_addr, len))
2587 if (listen(socket_fd, 1000))
goto error;
2603 if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
2606 std::cerr <<
"Unexpected failure while setting connection with client" << std::endl;
2612 if (ioctlsocket(fd, FIONBIO, &nbio))
goto error2;
2613 #elif defined(LINUX)
2614 int fd = accept4(
socket_fd, NULL, NULL, SOCK_CLOEXEC);
2619 if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
return;
2622 client_list::iterator proc =
clients.begin();
2628 std::cerr <<
"Received an ill-formed client message" << std::endl;
2639 std::vector<char> buf;
2641 while (len <
sizeof(
int) + 2 || buf[len - 1] || buf[len - 2])
2643 buf.resize(len + 1024);
2644 ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2645 if (l <= 0)
goto error;
2651 memcpy(&job_id, &buf[0],
sizeof(
int));
2653 proc->job_id = job_id;
2654 job_map::const_iterator i =
jobs.find(job_id);
2655 if (i ==
jobs.end())
goto error;
2656 DEBUG <<
"receiving request from job " << job_id << std::endl;
2663 char const *p = &buf[0] +
sizeof(int);
2676 if (len == 1)
goto error;
2677 std::string target(p + 1, p + len);
2678 DEBUG <<
"adding dependency " << target <<
" to job\n";
2679 proc->pending.push_back(target);
2680 dep.
deps.insert(target);
2685 if (len == 1)
goto error;
2686 std::string var(p + 1, p + len);
2687 DEBUG <<
"adding variable " << var <<
" to job\n";
2688 last_var = &proc->vars[var];
2694 if (!last_var)
goto error;
2695 last_var->push_back(std::string(p + 1, p + len));
2706 std::cerr <<
"Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2716 pid_job_map::iterator i =
job_pids.find(pid);
2718 int job_id = i->second;
2738 for (pid_job_map::const_iterator i =
job_pids.begin(),
2739 i_end =
job_pids.end(); i != i_end; ++i, ++num)
2743 WSAEVENT aev = WSACreateEvent();
2745 WSAEventSelect(
socket_fd, aev, FD_ACCEPT);
2746 DWORD w = WaitForMultipleObjects(len, h,
false, INFINITE);
2758 bool res = GetExitCodeProcess(pid, &s) && s == 0;
2763 sigemptyset(&emptymask);
2767 int ret = pselect(
socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2773 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2775 bool res = WIFEXITED(status) && WEXITSTATUS(status) == 0;
2798 clients.back().pending.push_back(remakefile);
2808 if (!targets.empty())
clients.back().pending = targets;
2821 std::cout <<
"remake: Leaving directory `" <<
prefix_dir <<
'\'' << std::endl;
2843 perror(
"Failed to send targets to server");
2846 if (targets.empty()) exit(EXIT_SUCCESS);
2851 struct sockaddr_in socket_addr;
2852 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2854 socket_addr.sin_family = AF_INET;
2855 socket_addr.sin_addr.s_addr = inet_addr(
"127.0.0.1");
2856 socket_addr.sin_port = atoi(socket_name);
2857 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(sockaddr_in)))
2860 struct sockaddr_un socket_addr;
2861 size_t len = strlen(socket_name);
2862 if (len >=
sizeof(socket_addr.sun_path) - 1) exit(EXIT_FAILURE);
2863 socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2865 socket_addr.sun_family = AF_UNIX;
2866 strcpy(socket_addr.sun_path, socket_name);
2867 if (connect(
socket_fd, (
struct sockaddr *)&socket_addr,
sizeof(socket_addr.sun_family) + len))
2871 if (setsockopt(
socket_fd, SOL_SOCKET, SO_NOSIGPIPE, &set_option,
sizeof(set_option)))
2877 char *
id = getenv(
"REMAKE_JOB_ID");
2878 int job_id =
id ? atoi(
id) : -1;
2879 if (send(
socket_fd, (
char *)&job_id,
sizeof(job_id), MSG_NOSIGNAL) !=
sizeof(job_id))
2883 for (string_list::const_iterator i = targets.begin(),
2884 i_end = targets.end(); i != i_end; ++i)
2886 DEBUG_open <<
"Sending target " << *i <<
"... ";
2887 std::string s =
'T' + *i;
2888 ssize_t len = s.length() + 1;
2889 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2894 for (variable_map::const_iterator i =
variables.begin(),
2895 i_end =
variables.end(); i != i_end; ++i)
2897 DEBUG_open <<
"Sending variable " << i->first <<
"... ";
2898 std::string s =
'V' + i->first;
2899 ssize_t len = s.length() + 1;
2900 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2902 for (string_list::const_iterator j = i->second.begin(),
2903 j_end = i->second.end(); j != j_end; ++j)
2905 std::string s =
'W' + *j;
2906 len = s.length() + 1;
2907 if (send(
socket_fd, s.c_str(), len, MSG_NOSIGNAL) != len)
2914 if (send(
socket_fd, &result, 1, MSG_NOSIGNAL) != 1)
goto error;
2915 if (recv(
socket_fd, &result, 1, 0) != 1) exit(EXIT_FAILURE);
2916 exit(result ? EXIT_SUCCESS : EXIT_FAILURE);
2932 std::cerr <<
"Usage: remake [options] [target] ...\n"
2934 " -d Echo script commands.\n"
2935 " -d -d Print lots of debugging information.\n"
2936 " -f FILE Read FILE as Remakefile.\n"
2937 " -h, --help Print this message and exit.\n"
2938 " -j[N], --jobs=[N] Allow N jobs at once; infinite jobs with no arg.\n"
2939 " -k Keep going when some targets cannot be made.\n"
2940 " -r Look up targets from the dependencies on stdin.\n"
2941 " -s, --silent, --quiet Do not echo targets.\n";
2958 std::string remakefile;
2960 bool literal_targets =
false;
2961 bool indirect_targets =
false;
2964 for (
int i = 1; i < argc; ++i)
2966 std::string arg = argv[i];
2967 if (arg.empty())
usage(EXIT_FAILURE);
2968 if (literal_targets)
goto new_target;
2969 if (arg ==
"-h" || arg ==
"--help")
usage(EXIT_SUCCESS);
2973 else if (arg ==
"-k" || arg ==
"--keep-going")
2975 else if (arg ==
"-s" || arg ==
"--silent" || arg ==
"--quiet")
2977 else if (arg ==
"-r")
2978 indirect_targets =
true;
2979 else if (arg ==
"-f")
2981 if (++i == argc)
usage(EXIT_FAILURE);
2982 remakefile = argv[i];
2984 else if (arg ==
"--")
2985 literal_targets =
true;
2986 else if (arg.compare(0, 2,
"-j") == 0)
2988 else if (arg.compare(0, 7,
"--jobs=") == 0)
2992 if (arg[0] ==
'-')
usage(EXIT_FAILURE);
2993 if (arg.find(
'=') != std::string::npos)
2995 std::istringstream in(arg);
3002 targets.push_back(arg);
3003 DEBUG <<
"New target: " << arg <<
'\n';
3010 if (indirect_targets)
3017 l.push_back(
dependencies.begin()->second->targets.front());
3019 for (string_list::const_iterator i = l.begin(),
3020 i_end = l.end(); i != i_end; ++i)
3022 dependency_map::const_iterator j =
dependencies.find(*i);
3025 for (string_set::const_iterator k = dep.
deps.begin(),
3026 k_end = dep.
deps.end(); k != k_end; ++k)
3036 if (WSAStartup(MAKEWORD(2,2), &wsaData))
3038 std::cerr <<
"Unexpected failure while initializing Windows Socket" << std::endl;
3044 if (
char *sn = getenv(
"REMAKE_SOCKET"))
client_mode(sn, targets);
3047 if (remakefile.empty())
3049 remakefile =
"Remakefile";