Remake
Functions
Server

Functions

static void complete_job (int job_id, bool success, bool started=true)
 
static std::string prepare_script (job_t const &job)
 
static status_e run_script (int job_id, job_t const &job)
 
static status_e start (std::string const &target, client_list::iterator &current)
 
static void complete_request (client_t &client, bool success)
 
static bool has_free_slots ()
 
static bool handle_clients ()
 
static void create_server ()
 
static void accept_client ()
 
static void finalize_job (pid_t pid, bool res)
 
static void server_loop ()
 
static void server_mode (std::string const &remakefile, string_list const &targets)
 

Detailed Description

Function Documentation

◆ accept_client()

static void accept_client ( )
static

Accept a connection from a client, get the job it spawned from, get the targets, and mark them as dependencies of the job targets.

Definition at line 2691 of file remake.cpp.

2692 {
2693  DEBUG_open << "Handling client request... ";
2694 
2695  // Accept connection.
2696 #ifdef WINDOWS
2697  socket_t fd = accept(socket_fd, NULL, NULL);
2698  if (fd == INVALID_SOCKET) return;
2699  if (!SetHandleInformation((HANDLE)fd, HANDLE_FLAG_INHERIT, 0))
2700  {
2701  error2:
2702  std::cerr << "Unexpected failure while setting connection with client" << std::endl;
2703  closesocket(fd);
2704  return;
2705  }
2706  // WSAEventSelect puts sockets into nonblocking mode, so disable it here.
2707  u_long nbio = 0;
2708  if (ioctlsocket(fd, FIONBIO, &nbio)) goto error2;
2709 #elif defined(LINUX)
2710  int fd = accept4(socket_fd, NULL, NULL, SOCK_CLOEXEC);
2711  if (fd < 0) return;
2712 #else
2713  int fd = accept(socket_fd, NULL, NULL);
2714  if (fd < 0) return;
2715  if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) return;
2716 #endif
2717  clients.push_front(client_t());
2718  client_list::iterator proc = clients.begin();
2719 
2720  if (false)
2721  {
2722  error:
2723  DEBUG_close << "failed\n";
2724  std::cerr << "Received an ill-formed client message" << std::endl;
2725  #ifdef WINDOWS
2726  closesocket(fd);
2727  #else
2728  close(fd);
2729  #endif
2730  clients.erase(proc);
2731  return;
2732  }
2733 
2734  // Receive message. Stop when encountering two nuls in a row.
2735  std::vector<char> buf;
2736  size_t len = 0;
2737  while (len < sizeof(int) + 2 || buf[len - 1] || buf[len - 2])
2738  {
2739  buf.resize(len + 1024);
2740  ssize_t l = recv(fd, &buf[0] + len, 1024, 0);
2741  if (l <= 0) goto error;
2742  len += l;
2743  }
2744 
2745  // Parse job that spawned the client.
2746  int job_id;
2747  memcpy(&job_id, &buf[0], sizeof(int));
2748  proc->socket = fd;
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;
2753  if (propagate_vars) proc->vars = i->second.vars;
2754 
2755  // Parse the targets and the variable assignments.
2756  // Mark the targets as dependencies of the job targets.
2757  dependency_t &dep = *dependencies[i->second.rule.targets.front()];
2758  string_list *last_var = NULL;
2759  char const *p = &buf[0] + sizeof(int);
2760  while (true)
2761  {
2762  len = strlen(p);
2763  if (len == 0)
2764  {
2765  ++waiting_jobs;
2766  break;
2767  }
2768  switch (*p)
2769  {
2770  case 'T':
2771  {
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);
2777  break;
2778  }
2779  case 'V':
2780  {
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];
2785  last_var->clear();
2786  break;
2787  }
2788  case 'W':
2789  {
2790  if (!last_var) goto error;
2791  last_var->push_back(std::string(p + 1, p + len));
2792  break;
2793  }
2794  default:
2795  goto error;
2796  }
2797  p += len + 1;
2798  }
2799 
2800  if (!propagate_vars && !proc->vars.empty())
2801  {
2802  std::cerr << "Assignments are ignored unless 'variable-propagation' is enabled" << std::endl;
2803  proc->vars.clear();
2804  }
2805 }

Referenced by server_loop().

◆ complete_job()

static void complete_job ( int  job_id,
bool  success,
bool  started = true 
)
static

Handle job completion.

Definition at line 2133 of file remake.cpp.

2134 {
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;
2139  if (success)
2140  {
2141  bool show = show_targets && started;
2142  if (show) std::cout << "Finished";
2143  for (string_list::const_iterator j = targets.begin(),
2144  j_end = targets.end(); j != j_end; ++j)
2145  {
2146  update_status(*j);
2147  if (show) std::cout << ' ' << *j;
2148  }
2149  if (show) std::cout << std::endl;
2150  }
2151  else
2152  {
2153  std::cerr << "Failed to build";
2154  for (string_list::const_iterator j = targets.begin(),
2155  j_end = targets.end(); j != j_end; ++j)
2156  {
2157  std::cerr << ' ' << *j;
2158  update_status(*j);
2159  status_e &s = status[*j].status;
2160  if (s != Uptodate)
2161  {
2162  DEBUG << "Removing " << *j << '\n';
2163  remove(j->c_str());
2164  }
2165  s = Failed;
2166  }
2167  std::cerr << std::endl;
2168  }
2169  jobs.erase(i);
2170 }

Referenced by complete_request(), finalize_job(), and run_script().

◆ complete_request()

static void complete_request ( client_t client,
bool  success 
)
static

Send a reply to a client then remove it. If the client was a dependency client, start the actual script.

Definition at line 2438 of file remake.cpp.

2439 {
2440  DEBUG_open << "Completing request from client of job " << client.job_id << "... ";
2441  if (client.delayed)
2442  {
2443  assert(client.socket == INVALID_SOCKET);
2444  if (success)
2445  {
2446  job_map::const_iterator i = jobs.find(client.job_id);
2447  assert(i != jobs.end());
2448  if (still_need_rebuild(i->second.rule.targets.front()))
2449  run_script(client.job_id, i->second);
2450  else complete_job(client.job_id, true, false);
2451  }
2452  else complete_job(client.job_id, false);
2453  }
2454  else if (client.socket != INVALID_SOCKET)
2455  {
2456  char res = success ? 1 : 0;
2457  send(client.socket, &res, 1, MSG_NOSIGNAL);
2458  #ifdef WINDOWS
2459  closesocket(client.socket);
2460  #else
2461  close(client.socket);
2462  #endif
2463  --waiting_jobs;
2464  }
2465 
2466  if (client.job_id < 0 && !success) build_failure = true;
2467 }

Referenced by handle_clients().

◆ create_server()

static void create_server ( )
static

Create a named unix socket that listens for build requests. Also set the REMAKE_SOCKET environment variable that will be inherited by all the job scripts.

Definition at line 2611 of file remake.cpp.

2612 {
2613  if (false)
2614  {
2615  error:
2616  perror("Failed to create server");
2617 #ifndef WINDOWS
2618  error2:
2619 #endif
2620  exit(EXIT_FAILURE);
2621  }
2622  DEBUG_open << "Creating server... ";
2623 
2624 #ifdef WINDOWS
2625  // Prepare a windows socket.
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;
2630 
2631  // Create and listen to the socket.
2632  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
2633  if (socket_fd == INVALID_SOCKET) goto error;
2634  if (!SetHandleInformation((HANDLE)socket_fd, HANDLE_FLAG_INHERIT, 0))
2635  goto error;
2636  if (bind(socket_fd, (struct sockaddr *)&socket_addr, sizeof(sockaddr_in)))
2637  goto error;
2638  int len = sizeof(sockaddr_in);
2639  if (getsockname(socket_fd, (struct sockaddr *)&socket_addr, &len))
2640  goto error;
2641  std::ostringstream buf;
2642  buf << socket_addr.sin_port;
2643  if (!SetEnvironmentVariable("REMAKE_SOCKET", buf.str().c_str()))
2644  goto error;
2645  if (listen(socket_fd, 1000)) goto error;
2646 #else
2647  // Set signal handlers for SIGCHLD and SIGINT.
2648  // Block SIGCHLD (unblocked during select).
2649  sigset_t sigmask;
2650  sigemptyset(&sigmask);
2651  sigaddset(&sigmask, SIGCHLD);
2652  if (sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask) == -1) goto error;
2653  struct sigaction sa;
2654  sa.sa_flags = 0;
2655  sigemptyset(&sa.sa_mask);
2656  sa.sa_handler = &sigchld_handler;
2657  if (sigaction(SIGCHLD, &sa, NULL) == -1) goto error;
2658  sa.sa_handler = &sigint_handler;
2659  if (sigaction(SIGINT, &sa, NULL) == -1) goto error;
2660 
2661  // Prepare a named unix socket in temporary directory.
2662  socket_name = tempnam(NULL, "rmk-");
2663  if (!socket_name) goto error2;
2664  struct sockaddr_un socket_addr;
2665  size_t len = strlen(socket_name);
2666  if (len >= sizeof(socket_addr.sun_path) - 1) goto error2;
2667  socket_addr.sun_family = AF_UNIX;
2668  strcpy(socket_addr.sun_path, socket_name);
2669  len += sizeof(socket_addr.sun_family);
2670  if (setenv("REMAKE_SOCKET", socket_name, 1)) goto error;
2671 
2672  // Create and listen to the socket.
2673 #ifdef LINUX
2674  socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
2675  if (socket_fd == INVALID_SOCKET) goto error;
2676 #else
2677  socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
2678  if (socket_fd == INVALID_SOCKET) goto error;
2679  if (fcntl(socket_fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
2680 #endif
2681  if (bind(socket_fd, (struct sockaddr *)&socket_addr, len))
2682  goto error;
2683  if (listen(socket_fd, 1000)) goto error;
2684 #endif
2685 }

Referenced by server_mode().

◆ finalize_job()

static void finalize_job ( pid_t  pid,
bool  res 
)
static

Handle child process exit status.

Definition at line 2810 of file remake.cpp.

2811 {
2812  pid_job_map::iterator i = job_pids.find(pid);
2813  assert(i != job_pids.end());
2814  int job_id = i->second;
2815  job_pids.erase(i);
2816  --running_jobs;
2817  complete_job(job_id, res);
2818 }

Referenced by server_loop().

◆ handle_clients()

static bool handle_clients ( )
static

Handle client requests:

  • check for running targets that have finished,
  • start as many pending targets as allowed,
  • complete the request if there are neither running nor pending targets left or if any of them failed.
Returns
true if some child processes are still running.
Postcondition
If there are pending requests, at least one child process is running.
Invariant
New free slots cannot appear during a run, since the only way to decrease running_jobs is finalize_job and the only way to increase waiting_jobs is accept_client. None of these functions are called during a run. So breaking out as soon as there are no free slots left is fine.

Definition at line 2495 of file remake.cpp.

2496 {
2497  DEBUG_open << "Handling client requests... ";
2498  restart:
2499  bool need_restart = false;
2500 
2501  for (client_list::iterator i = clients.begin(), i_next = i,
2502  i_end = clients.end(); i != i_end; i = i_next)
2503  {
2504  if (!has_free_slots()) break;
2505  ++i_next;
2506  DEBUG_open << "Handling client from job " << i->job_id << "... ";
2507 
2508  // Remove running targets that have finished.
2509  for (string_set::iterator j = i->running.begin(), j_next = j,
2510  j_end = i->running.end(); j != j_end; j = j_next)
2511  {
2512  ++j_next;
2513  status_map::const_iterator k = status.find(*j);
2514  assert(k != status.end());
2515  switch (k->second.status)
2516  {
2517  case Running:
2518  case RunningRecheck:
2519  break;
2520  case Failed:
2521  i->failed = true;
2522  if (!keep_going) goto complete;
2523  // fallthrough
2524  case Uptodate:
2525  case Remade:
2526  i->running.erase(j);
2527  break;
2528  case Recheck:
2529  case Todo:
2530  assert(false);
2531  }
2532  }
2533 
2534  // Start pending targets.
2535  while (!i->pending.empty())
2536  {
2537  std::string target = i->pending.front();
2538  i->pending.pop_front();
2539  switch (get_status(target).status)
2540  {
2541  case Running:
2542  case RunningRecheck:
2543  i->running.insert(target);
2544  break;
2545  case Failed:
2546  pending_failed:
2547  i->failed = true;
2548  if (!keep_going) goto complete;
2549  // fallthrough
2550  case Uptodate:
2551  case Remade:
2552  break;
2553  case Recheck:
2554  case Todo:
2555  client_list::iterator j = i;
2556  switch (start(target, i))
2557  {
2558  case Failed:
2559  goto pending_failed;
2560  case Running:
2561  // A shell was started, check for free slots.
2562  j->running.insert(target);
2563  if (!has_free_slots()) return true;
2564  break;
2565  case RunningRecheck:
2566  // Switch to the dependency client that was inserted.
2567  j->running.insert(target);
2568  i_next = j;
2569  break;
2570  case Remade:
2571  // Nothing to run.
2572  need_restart = true;
2573  break;
2574  default:
2575  assert(false);
2576  }
2577  }
2578  }
2579 
2580  // Try to complete the request.
2581  // (This might start a new job if it was a dependency client.)
2582  if (i->running.empty() || i->failed)
2583  {
2584  complete:
2585  complete_request(*i, !i->failed);
2586  DEBUG_close << (i->failed ? "failed\n" : "finished\n");
2587  clients.erase(i);
2588  need_restart = true;
2589  }
2590  }
2591 
2592  if (running_jobs != waiting_jobs) return true;
2593  if (running_jobs == 0 && clients.empty()) return false;
2594  if (need_restart) goto restart;
2595 
2596  // There is a circular dependency.
2597  // Try to break it by completing one of the requests.
2598  assert(!clients.empty());
2599  std::cerr << "Circular dependency detected" << std::endl;
2600  client_list::iterator i = clients.begin();
2601  complete_request(*i, false);
2602  clients.erase(i);
2603  goto restart;
2604 }

Referenced by server_loop().

◆ has_free_slots()

static bool has_free_slots ( )
static

Return whether there are slots for starting new jobs.

Definition at line 2472 of file remake.cpp.

2473 {
2474  if (max_active_jobs <= 0) return true;
2476 }

Referenced by handle_clients().

◆ prepare_script()

static std::string prepare_script ( job_t const &  job)
static

Return the script obtained by substituting variables.

Definition at line 2175 of file remake.cpp.

2176 {
2177  std::string const &s = job.rule.script;
2178  std::istringstream in(s);
2179  std::ostringstream out;
2180  size_t len = s.size();
2181 
2182  while (!in.eof())
2183  {
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;
2188  ++p;
2189  switch (s[p])
2190  {
2191  case '$':
2192  out << '$';
2193  in.seekg(p + 1);
2194  break;
2195  case '<':
2196  if (!job.rule.deps.empty())
2197  out << job.rule.deps.front();
2198  in.seekg(p + 1);
2199  break;
2200  case '^':
2201  {
2202  bool first = true;
2203  for (string_list::const_iterator i = job.rule.deps.begin(),
2204  i_end = job.rule.deps.end(); i != i_end; ++i)
2205  {
2206  if (first) first = false;
2207  else out << ' ';
2208  out << *i;
2209  }
2210  in.seekg(p + 1);
2211  break;
2212  }
2213  case '@':
2214  assert(!job.rule.targets.empty());
2215  out << job.rule.targets.front();
2216  in.seekg(p + 1);
2217  break;
2218  case '*':
2219  out << job.rule.stem;
2220  in.seekg(p + 1);
2221  break;
2222  case '(':
2223  {
2224  in.seekg(p - 1);
2225  bool first = true;
2226  input_generator gen(in, &job.vars, true);
2227  while (true)
2228  {
2229  std::string w;
2230  input_status s = gen.next(w);
2231  if (s == SyntaxError)
2232  {
2233  // TODO
2234  return "false";
2235  }
2236  if (s == Eof) break;
2237  if (first) first = false;
2238  else out << ' ';
2239  out << w;
2240  }
2241  break;
2242  }
2243  default:
2244  // Let dollars followed by an unrecognized character
2245  // go through. This differs from Make, which would
2246  // use a one-letter variable.
2247  out << '$';
2248  in.seekg(p);
2249  }
2250  }
2251 
2252  return out.str();
2253 }

Referenced by run_script().

◆ run_script()

static status_e run_script ( int  job_id,
job_t const &  job 
)
static

Execute the script from rule.

Definition at line 2258 of file remake.cpp.

2259 {
2261  dep->targets = job.rule.targets;
2262  dep->deps.insert(job.rule.deps.begin(), job.rule.deps.end());
2263  if (show_targets) std::cout << "Building";
2264  for (string_list::const_iterator i = job.rule.targets.begin(),
2265  i_end = job.rule.targets.end(); i != i_end; ++i)
2266  {
2267  dependencies[*i] = dep;
2268  if (show_targets) std::cout << ' ' << *i;
2269  }
2270  if (show_targets) std::cout << std::endl;
2271 
2272  std::string script = prepare_script(job);
2273 
2274  std::ostringstream job_id_buf;
2275  job_id_buf << job_id;
2276  std::string job_id_ = job_id_buf.str();
2277 
2278  DEBUG_open << "Starting script for job " << job_id << "... ";
2279  if (script.empty())
2280  {
2281  DEBUG_close << "no script\n";
2282  complete_job(job_id, true);
2283  return Remade;
2284  }
2285 
2286  if (false)
2287  {
2288  error:
2289  DEBUG_close << "failed\n";
2290  complete_job(job_id, false);
2291  return Failed;
2292  }
2293 
2294 #ifdef WINDOWS
2295  HANDLE pfd[2];
2296  if (false)
2297  {
2298  error2:
2299  CloseHandle(pfd[0]);
2300  CloseHandle(pfd[1]);
2301  goto error;
2302  }
2303  if (!CreatePipe(&pfd[0], &pfd[1], NULL, 0))
2304  goto error;
2305  if (!SetHandleInformation(pfd[0], HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
2306  goto error2;
2307  STARTUPINFO si;
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()))
2317  goto error2;
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))
2321  {
2322  goto error2;
2323  }
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]);
2330  ++running_jobs;
2331  job_pids[pi.hProcess] = job_id;
2332  return Running;
2333 #else
2334  int pfd[2];
2335  if (false)
2336  {
2337  error2:
2338  close(pfd[0]);
2339  close(pfd[1]);
2340  goto error;
2341  }
2342  if (pipe(pfd) == -1)
2343  goto error;
2344  if (setenv("REMAKE_JOB_ID", job_id_.c_str(), 1))
2345  goto error2;
2346  if (pid_t pid = vfork())
2347  {
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;
2352  close(pfd[0]);
2353  close(pfd[1]);
2354  ++running_jobs;
2355  job_pids[pid] = job_id;
2356  return Running;
2357  }
2358  // Child process starts here. Notice the use of vfork above.
2359  char const *argv[5] = { "sh", "-e", "-s", NULL, NULL };
2360  if (echo_scripts) argv[3] = "-v";
2361  close(pfd[1]);
2362  if (pfd[0] != 0)
2363  {
2364  dup2(pfd[0], 0);
2365  close(pfd[0]);
2366  }
2367  sigprocmask(SIG_SETMASK, &old_sigmask, NULL);
2368  execve("/bin/sh", (char **)argv, environ);
2369  _exit(EXIT_FAILURE);
2370 #endif
2371 }

Referenced by complete_request(), and start().

◆ server_loop()

static void server_loop ( )
static

Loop until all the jobs have finished.

Postcondition
There are no client requests left, not even virtual ones.

Definition at line 2825 of file remake.cpp.

2826 {
2827  while (handle_clients())
2828  {
2829  DEBUG_open << "Handling events... ";
2830  #ifdef WINDOWS
2831  size_t len = job_pids.size() + 1;
2832  HANDLE h[len];
2833  int num = 0;
2834  for (pid_job_map::const_iterator i = job_pids.begin(),
2835  i_end = job_pids.end(); i != i_end; ++i, ++num)
2836  {
2837  h[num] = i->first;
2838  }
2839  WSAEVENT aev = WSACreateEvent();
2840  h[num] = aev;
2841  WSAEventSelect(socket_fd, aev, FD_ACCEPT);
2842  DWORD w = WaitForMultipleObjects(len, h, false, INFINITE);
2843  WSAEventSelect(socket_fd, aev, 0);
2844  WSACloseEvent(aev);
2845  if (len <= w)
2846  continue;
2847  if (w == len - 1)
2848  {
2849  accept_client();
2850  continue;
2851  }
2852  pid_t pid = h[w];
2853  DWORD s = 0;
2854  bool res = GetExitCodeProcess(pid, &s) && s == 0;
2855  CloseHandle(pid);
2856  finalize_job(pid, res);
2857  #else
2858  sigset_t emptymask;
2859  sigemptyset(&emptymask);
2860  fd_set fdset;
2861  FD_ZERO(&fdset);
2862  FD_SET(socket_fd, &fdset);
2863  int ret = pselect(socket_fd + 1, &fdset, NULL, NULL, NULL, &emptymask);
2864  if (ret > 0 /* && FD_ISSET(socket_fd, &fdset)*/) accept_client();
2865  if (!got_SIGCHLD) continue;
2866  got_SIGCHLD = 0;
2867  pid_t pid;
2868  int status;
2869  while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
2870  {
2871  bool res = WIFEXITED(status) && WEXITSTATUS(status) == 0;
2872  finalize_job(pid, res);
2873  }
2874  #endif
2875  }
2876 
2877  assert(clients.empty());
2878 }

Referenced by server_mode().

◆ server_mode()

static void server_mode ( std::string const &  remakefile,
string_list const &  targets 
)
static

Load dependencies and rules, listen to client requests, and loop until all the requests have completed. If Remakefile is obsolete, perform a first run with it only, then reload the rules, and perform a second with the original clients.

Definition at line 2886 of file remake.cpp.

2887 {
2889  load_rules(remakefile);
2890  create_server();
2891  if (get_status(remakefile).status != Uptodate)
2892  {
2893  clients.push_back(client_t());
2894  clients.back().pending.push_back(remakefile);
2895  server_loop();
2896  if (build_failure) goto early_exit;
2897  variables.clear();
2898  specific_rules.clear();
2899  generic_rules.clear();
2900  first_target.clear();
2901  load_rules(remakefile);
2902  }
2903  clients.push_back(client_t());
2904  if (!targets.empty()) clients.back().pending = targets;
2905  else if (!first_target.empty())
2906  clients.back().pending.push_back(first_target);
2907  server_loop();
2908  early_exit:
2909  close(socket_fd);
2910 #ifndef WINDOWS
2911  remove(socket_name);
2912  free(socket_name);
2913 #endif
2916  {
2917  std::cout << "remake: Leaving directory `" << prefix_dir << '\'' << std::endl;
2918  }
2919  exit(build_failure ? EXIT_FAILURE : EXIT_SUCCESS);
2920 }

Referenced by main().

◆ start()

static status_e start ( std::string const &  target,
client_list::iterator &  current 
)
static

Create a job for target according to the loaded rules. Mark all the targets from the rule as running and reset their dependencies. Inherit variables from current, if enabled. If the rule has dependencies, create a new client to build them just before current, and change current so that it points to it.

Definition at line 2380 of file remake.cpp.

2381 {
2382  int job_id = job_counter++;
2383  DEBUG_open << "Starting job " << job_id << " for " << target << "... ";
2384  job_t &job = jobs[job_id];
2385  find_rule(job, target);
2386  if (job.rule.targets.empty())
2387  {
2388  status[target].status = Failed;
2389  DEBUG_close << "failed\n";
2390  std::cerr << "No rule for building " << target << std::endl;
2391  return Failed;
2392  }
2393  bool has_deps = !job.rule.deps.empty() || !job.rule.wdeps.empty();
2394  status_e st = Running;
2395  if (has_deps && status[target].status == Recheck)
2396  st = RunningRecheck;
2397  for (string_list::const_iterator i = job.rule.targets.begin(),
2398  i_end = job.rule.targets.end(); i != i_end; ++i)
2399  {
2400  status[*i].status = st;
2401  }
2402  if (propagate_vars) job.vars = current->vars;
2403  for (assign_map::const_iterator i = job.rule.assigns.begin(),
2404  i_end = job.rule.assigns.end(); i != i_end; ++i)
2405  {
2406  std::pair<variable_map::iterator, bool> k =
2407  job.vars.insert(std::make_pair(i->first, string_list()));
2408  string_list &v = k.first->second;
2409  if (i->second.append)
2410  {
2411  if (k.second)
2412  {
2413  variable_map::const_iterator j = variables.find(i->first);
2414  if (j != variables.end()) v = j->second;
2415  }
2416  }
2417  else if (!k.second) v.clear();
2418  v.insert(v.end(), i->second.value.begin(), i->second.value.end());
2419  }
2420  if (has_deps)
2421  {
2422  current = clients.insert(current, client_t());
2423  current->job_id = job_id;
2424  current->pending = job.rule.deps;
2425  current->pending.insert(current->pending.end(),
2426  job.rule.wdeps.begin(), job.rule.wdeps.end());
2427  if (propagate_vars) current->vars = job.vars;
2428  current->delayed = true;
2429  return RunningRecheck;
2430  }
2431  return run_script(job_id, job);
2432 }

Referenced by handle_clients().

first_target
static std::string first_target
Definition: remake.cpp:716
clients
static client_list clients
Definition: remake.cpp:655
client_t::socket
socket_t socket
Socket used to reply to the client (invalid for pseudo clients).
Definition: remake.cpp:603
save_dependencies
static void save_dependencies()
Definition: remake.cpp:1489
job_t
Definition: remake.cpp:579
string_list
std::list< std::string > string_list
Definition: remake.cpp:471
Recheck
@ Recheck
Target has an obsolete dependency.
Definition: remake.cpp:528
propagate_vars
static bool propagate_vars
Definition: remake.cpp:751
DEBUG
#define DEBUG
Definition: remake.cpp:817
job_t::vars
variable_map vars
Values of local variables.
Definition: remake.cpp:581
Uptodate
@ Uptodate
Target is up-to-date.
Definition: remake.cpp:526
input_status
input_status
Definition: remake.cpp:1175
build_failure
static bool build_failure
Definition: remake.cpp:704
job_pids
static pid_job_map job_pids
Definition: remake.cpp:649
DEBUG_close
#define DEBUG_close
Definition: remake.cpp:819
dependencies
static dependency_map dependencies
Definition: remake.cpp:624
rule_t::targets
string_list targets
Files produced by this rule.
Definition: remake.cpp:562
status
static status_map status
Definition: remake.cpp:629
input_generator
Definition: remake.cpp:1235
running_jobs
static int running_jobs
Definition: remake.cpp:680
Remade
@ Remade
Target was successfully rebuilt.
Definition: remake.cpp:531
load_rules
static void load_rules(std::string const &remakefile)
Definition: remake.cpp:1777
find_rule
static void find_rule(job_t &job, std::string const &target)
Definition: remake.cpp:1932
max_active_jobs
static int max_active_jobs
Definition: remake.cpp:661
changed_prefix_dir
static bool changed_prefix_dir
Definition: remake.cpp:746
handle_clients
static bool handle_clients()
Definition: remake.cpp:2495
run_script
static status_e run_script(int job_id, job_t const &job)
Definition: remake.cpp:2258
socket_fd
static socket_t socket_fd
Definition: remake.cpp:699
accept_client
static void accept_client()
Definition: remake.cpp:2691
get_status
static status_t const & get_status(std::string const &target)
Definition: remake.cpp:1989
Todo
@ Todo
Target is missing or obsolete.
Definition: remake.cpp:527
got_SIGCHLD
static volatile sig_atomic_t got_SIGCHLD
Definition: remake.cpp:761
finalize_job
static void finalize_job(pid_t pid, bool res)
Definition: remake.cpp:2810
Failed
@ Failed
Build failed for target.
Definition: remake.cpp:532
environ
char ** environ
generic_rules
static rule_list generic_rules
Definition: remake.cpp:634
client_t::delayed
bool delayed
Whether it is a dependency client and a script has to be started on request completion.
Definition: remake.cpp:609
INVALID_SOCKET
@ INVALID_SOCKET
Definition: remake.cpp:463
dependency_t::targets
string_list targets
Definition: remake.cpp:513
update_status
static void update_status(std::string const &target)
Definition: remake.cpp:2066
specific_rules
static rule_map specific_rules
Definition: remake.cpp:639
client_t::job_id
int job_id
Job for which the built script called remake and spawned the client (negative for original clients).
Definition: remake.cpp:604
complete_job
static void complete_job(int job_id, bool success, bool started=true)
Definition: remake.cpp:2133
prefix_dir
static std::string prefix_dir
Definition: remake.cpp:741
job_counter
static int job_counter
Definition: remake.cpp:694
Running
@ Running
Target is being rebuilt.
Definition: remake.cpp:529
dependency_t::deps
string_set deps
Definition: remake.cpp:514
prepare_script
static std::string prepare_script(job_t const &job)
Definition: remake.cpp:2175
DEBUG_open
#define DEBUG_open
Definition: remake.cpp:818
create_server
static void create_server()
Definition: remake.cpp:2611
still_need_rebuild
static bool still_need_rebuild(std::string const &target)
Definition: remake.cpp:2099
jobs
static job_map jobs
Definition: remake.cpp:644
rule_t::assigns
assign_map assigns
Assignment of variables.
Definition: remake.cpp:565
variables
static variable_map variables
Definition: remake.cpp:619
dependency_t
Definition: remake.cpp:512
status_e
status_e
Definition: remake.cpp:525
SyntaxError
@ SyntaxError
Definition: remake.cpp:1177
keep_going
static bool keep_going
Definition: remake.cpp:667
show_targets
static bool show_targets
Definition: remake.cpp:721
sigint_handler
static void sigint_handler(int)
Definition: remake.cpp:768
Eof
@ Eof
Definition: remake.cpp:1178
start
static status_e start(std::string const &target, client_list::iterator &current)
Definition: remake.cpp:2380
rule_t::deps
string_list deps
Dependencies used for an implicit call to remake at the start of the script.
Definition: remake.cpp:563
old_sigmask
static sigset_t old_sigmask
Definition: remake.cpp:759
sigchld_handler
static void sigchld_handler(int)
Definition: remake.cpp:763
load_dependencies
static void load_dependencies(std::istream &in)
Definition: remake.cpp:1439
client_t
Definition: remake.cpp:602
socket_t
int socket_t
Definition: remake.cpp:462
echo_scripts
static bool echo_scripts
Definition: remake.cpp:726
RunningRecheck
@ RunningRecheck
Static prerequisites are being rebuilt.
Definition: remake.cpp:530
rule_t::wdeps
string_list wdeps
Like deps, except that they are not registered as dependencies.
Definition: remake.cpp:564
complete_request
static void complete_request(client_t &client, bool success)
Definition: remake.cpp:2438
has_free_slots
static bool has_free_slots()
Definition: remake.cpp:2472
job_t::rule
rule_t rule
Original rule.
Definition: remake.cpp:580
socket_name
static char * socket_name
Definition: remake.cpp:710
ref_ptr
Definition: remake.cpp:482
waiting_jobs
static int waiting_jobs
Definition: remake.cpp:688
server_loop
static void server_loop()
Definition: remake.cpp:2825