Merge "Stop supporting wrapping the build with `make`"
am: d69e849c9b

Change-Id: If6e369f82348d9d7aebe37104072a6878f7281ea
diff --git a/core/config.mk b/core/config.mk
index 15dea31..58461df 100644
--- a/core/config.mk
+++ b/core/config.mk
@@ -484,7 +484,6 @@
 prebuilt_sdk_tools := prebuilts/sdk/tools
 prebuilt_sdk_tools_bin := $(prebuilt_sdk_tools)/$(HOST_OS)/bin
 
-# Always use prebuilts for ckati and makeparallel
 prebuilt_build_tools := prebuilts/build-tools
 prebuilt_build_tools_wrappers := prebuilts/build-tools/common/bin
 prebuilt_build_tools_jars := prebuilts/build-tools/common/framework
@@ -542,7 +541,6 @@
 FILESLIST := $(SOONG_HOST_OUT_EXECUTABLES)/fileslist
 FILESLIST_UTIL :=$= build/make/tools/fileslist_util.py
 HOST_INIT_VERIFIER := $(HOST_OUT_EXECUTABLES)/host_init_verifier
-MAKEPARALLEL := $(prebuilt_build_tools_bin)/makeparallel
 SOONG_JAVAC_WRAPPER := $(SOONG_HOST_OUT_EXECUTABLES)/soong_javac_wrapper
 SOONG_ZIP := $(SOONG_HOST_OUT_EXECUTABLES)/soong_zip
 MERGE_ZIPS := $(SOONG_HOST_OUT_EXECUTABLES)/merge_zips
diff --git a/core/main.mk b/core/main.mk
index ecdbcbd..4e16c4a 100644
--- a/core/main.mk
+++ b/core/main.mk
@@ -10,22 +10,11 @@
 endif
 
 ifndef KATI
-
-host_prebuilts := linux-x86
-ifeq ($(shell uname),Darwin)
-host_prebuilts := darwin-x86
+$(warning Calling make directly is no longer supported.)
+$(warning Either use 'envsetup.sh; m' or 'build/soong/soong_ui.bash --make-mode')
+$(error done)
 endif
 
-.PHONY: run_soong_ui
-run_soong_ui:
-	+@prebuilts/build-tools/$(host_prebuilts)/bin/makeparallel --ninja build/soong/soong_ui.bash --make-mode $(MAKECMDGOALS)
-
-.PHONY: $(MAKECMDGOALS)
-$(sort $(MAKECMDGOALS)) : run_soong_ui
-	@#empty
-
-else # KATI
-
 $(info [1/1] initializing build system ...)
 
 # Absolute path of the present working direcotry.
@@ -1895,5 +1884,3 @@
 $(call dist-write-file,$(KATI_PACKAGE_MK_DIR)/dist.mk)
 
 $(info [$(call inc_and_print,subdir_makefiles_inc)/$(subdir_makefiles_total)] writing build rules ...)
-
-endif # KATI
diff --git a/core/ninja_config.mk b/core/ninja_config.mk
index e33ebf5..b1f4b03 100644
--- a/core/ninja_config.mk
+++ b/core/ninja_config.mk
@@ -55,7 +55,7 @@
 include $(wildcard vendor/*/build/ninja_config.mk)
 
 # Any Android goals that need to be built.
-ANDROID_GOALS := $(filter-out $(KATI_OUTPUT_PATTERNS) $(CKATI) $(MAKEPARALLEL),\
+ANDROID_GOALS := $(filter-out $(KATI_OUTPUT_PATTERNS),\
     $(sort $(ORIGINAL_MAKECMDGOALS) $(MAKECMDGOALS)))
 # Goals we need to pass to Ninja.
 NINJA_GOALS := $(filter-out $(NINJA_EXCLUDE_GOALS), $(ANDROID_GOALS))
diff --git a/tools/makeparallel/.gitignore b/tools/makeparallel/.gitignore
deleted file mode 100644
index a7d6181..0000000
--- a/tools/makeparallel/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-makeparallel
-*.o
-*.d
-test.out
diff --git a/tools/makeparallel/Android.bp b/tools/makeparallel/Android.bp
deleted file mode 100644
index 898db68..0000000
--- a/tools/makeparallel/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_binary_host {
-    name: "makeparallel",
-    srcs: [
-        "makeparallel.cpp",
-    ],
-    cflags: ["-Wall", "-Werror"],
-}
diff --git a/tools/makeparallel/Makefile b/tools/makeparallel/Makefile
deleted file mode 100644
index 82a4abf..0000000
--- a/tools/makeparallel/Makefile
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright 2015 Google Inc. All rights reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Find source file location from path to this Makefile
-MAKEPARALLEL_SRC_PATH := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
-ifndef MAKEPARALLEL_SRC_PATH
-  MAKEPARALLEL_SRC_PATH := .
-endif
-
-# Set defaults if they weren't set by the including Makefile
-MAKEPARALLEL_CXX ?= $(CXX)
-MAKEPARALLEL_LD ?= $(CXX)
-MAKEPARALLEL_INTERMEDIATES_PATH ?= .
-MAKEPARALLEL_BIN_PATH ?= .
-
-MAKEPARALLEL_CXX_SRCS := \
-	makeparallel.cpp
-
-MAKEPARALLEL_CXXFLAGS := -Wall -Werror -MMD -MP
-
-MAKEPARALLEL_CXX_SRCS := $(addprefix $(MAKEPARALLEL_SRC_PATH)/,\
-	$(MAKEPARALLEL_CXX_SRCS))
-
-MAKEPARALLEL_CXX_OBJS := $(patsubst $(MAKEPARALLEL_SRC_PATH)/%.cpp,$(MAKEPARALLEL_INTERMEDIATES_PATH)/%.o,$(MAKEPARALLEL_CXX_SRCS))
-
-MAKEPARALLEL := $(MAKEPARALLEL_BIN_PATH)/makeparallel
-
-ifeq ($(shell uname),Linux)
-MAKEPARALLEL_LIBS := -lrt -lpthread
-endif
-
-# Rule to build makeparallel into MAKEPARALLEL_BIN_PATH
-$(MAKEPARALLEL): $(MAKEPARALLEL_CXX_OBJS)
-	@mkdir -p $(dir $@)
-	$(MAKEPARALLEL_LD) -std=c++11 $(MAKEPARALLEL_CXXFLAGS) -o $@ $^ $(MAKEPARALLEL_LIBS)
-
-# Rule to build source files into object files in MAKEPARALLEL_INTERMEDIATES_PATH
-$(MAKEPARALLEL_CXX_OBJS): $(MAKEPARALLEL_INTERMEDIATES_PATH)/%.o: $(MAKEPARALLEL_SRC_PATH)/%.cpp
-	@mkdir -p $(dir $@)
-	$(MAKEPARALLEL_CXX) -c -std=c++11 $(MAKEPARALLEL_CXXFLAGS) -o $@ $<
-
-makeparallel_clean:
-	rm -rf $(MAKEPARALLEL)
-	rm -rf $(MAKEPARALLEL_INTERMEDIATES_PATH)/*.o
-	rm -rf $(MAKEPARALLEL_INTERMEDIATES_PATH)/*.d
-
-.PHONY: makeparallel_clean
-
--include $(MAKEPARALLEL_INTERMEDIATES_PATH)/*.d
-
-.PHONY: makeparallel_test
-MAKEPARALLEL_TEST := MAKEFLAGS= MAKELEVEL= MAKEPARALLEL=$(MAKEPARALLEL) $(MAKE) -f Makefile.test test
-MAKEPARALLEL_NINJA_TEST := MAKEFLAGS= MAKELEVEL= MAKEPARALLEL="$(MAKEPARALLEL) --ninja" $(MAKE) -f Makefile.test test
-makeparallel_test: $(MAKEPARALLEL)
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) -j1234
-	@EXPECTED="-j123"  $(MAKEPARALLEL_TEST) -j123
-	@EXPECTED=""       $(MAKEPARALLEL_TEST) -j1
-	@EXPECTED="-j$$(($$(nproc) + 2))"   $(MAKEPARALLEL_TEST) -j
-	@EXPECTED=""       $(MAKEPARALLEL_TEST)
-
-	@EXPECTED="-j1234" $(MAKEPARALLEL_NINJA_TEST) -j1234
-	@EXPECTED="-j123"  $(MAKEPARALLEL_NINJA_TEST) -j123
-	@EXPECTED="-j1"    $(MAKEPARALLEL_NINJA_TEST) -j1
-	@EXPECTED="-j1"    $(MAKEPARALLEL_NINJA_TEST)
-	@EXPECTED=""       $(MAKEPARALLEL_NINJA_TEST) -j
-	@EXPECTED=""       $(MAKEPARALLEL_NINJA_TEST) -j -l
-
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) --no-print-directory -j1234
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) --no-print-directory -k -j1234
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) -k -j1234
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) -j1234 -k
-	@EXPECTED="-j1234" $(MAKEPARALLEL_TEST) -kt -j1234
-
-	@EXPECTED="-j1234"     $(MAKEPARALLEL_NINJA_TEST) --no-print-directory -j1234
-	@EXPECTED="-j1234 -k0" $(MAKEPARALLEL_NINJA_TEST) --no-print-directory -k -j1234
-	@EXPECTED="-j1234 -k0" $(MAKEPARALLEL_NINJA_TEST) -k -j1234
-	@EXPECTED="-j1234 -k0" $(MAKEPARALLEL_NINJA_TEST) -j1234 -k
-	@EXPECTED="-j1234 -k0" $(MAKEPARALLEL_NINJA_TEST) -kt -j1234
-
-	@EXPECTED=""       $(MAKEPARALLEL_TEST) A=-j1234
-
-	@EXPECTED="-j1234 args" ARGS="args" $(MAKEPARALLEL_TEST) -j1234
diff --git a/tools/makeparallel/Makefile.test b/tools/makeparallel/Makefile.test
deleted file mode 100644
index cf53684..0000000
--- a/tools/makeparallel/Makefile.test
+++ /dev/null
@@ -1,12 +0,0 @@
-MAKEPARALLEL ?= ./makeparallel
-
-.PHONY: test
-test:
-	@+echo MAKEFLAGS=$${MAKEFLAGS};              \
-	result=$$($(MAKEPARALLEL) echo $(ARGS));     \
-	echo result: $${result};                     \
-	if [ "$${result}" = "$(EXPECTED)" ]; then    \
-	  echo SUCCESS && echo;                      \
-	else                                         \
-	  echo FAILED expected $(EXPECTED) && false; \
-	fi
diff --git a/tools/makeparallel/README.md b/tools/makeparallel/README.md
deleted file mode 100644
index 2e5fbf9..0000000
--- a/tools/makeparallel/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-<!---
-Copyright (C) 2015 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-makeparallel
-============
-makeparallel communicates with the [GNU make jobserver](http://make.mad-scientist.net/papers/jobserver-implementation/)
-in order claim all available jobs, and then passes the number of jobs
-claimed to a subprocess with `-j<jobs>`.
-
-The number of available jobs is determined by reading tokens from the jobserver
-until a read would block.  If the makeparallel rule is the only one running the
-number of jobs will be the total size of the jobserver pool, i.e. the value
-passed to make with `-j`.  Any jobs running in parallel with with the
-makeparellel rule will reduce the measured value, and thus reduce the
-parallelism available to the subprocess.
-
-To run a multi-thread or multi-process binary inside GNU make using
-makeparallel, add
-```Makefile
-	+makeparallel subprocess arguments
-```
-to a rule.  For example, to wrap ninja in make, use something like:
-```Makefile
-	+makeparallel ninja -f build.ninja
-```
-
-To determine the size of the jobserver pool, add
-```Makefile
-	+makeparallel echo > make.jobs
-```
-to a rule that is guarantee to run alone (i.e. all other rules are either
-dependencies of the makeparallel rule, or the depend on the makeparallel
-rule.  The output file will contain the `-j<num>` flag passed to the parent
-make process, or `-j1` if no flag was found.  Since GNU make will run
-makeparallel during the execution phase, after all variables have been
-set and evaluated, it is not possible to get the output of makeparallel
-into a make variable.  Instead, use a shell substitution to read the output
-file directly in a recipe.  For example:
-```Makefile
-	echo Make was started with $$(cat make.jobs)
-```
diff --git a/tools/makeparallel/makeparallel.cpp b/tools/makeparallel/makeparallel.cpp
deleted file mode 100644
index 66babdf..0000000
--- a/tools/makeparallel/makeparallel.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (C) 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// makeparallel communicates with the GNU make jobserver
-// (http://make.mad-scientist.net/papers/jobserver-implementation/)
-// in order claim all available jobs, and then passes the number of jobs
-// claimed to a subprocess with -j<jobs>.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <string>
-#include <vector>
-
-#ifdef __linux__
-#include <error.h>
-#endif
-
-#ifdef __APPLE__
-#include <err.h>
-#define error(code, eval, fmt, ...) errc(eval, code, fmt, ##__VA_ARGS__)
-// Darwin does not interrupt syscalls by default.
-#define TEMP_FAILURE_RETRY(exp) (exp)
-#endif
-
-// Throw an error if fd is not valid.
-static void CheckFd(int fd) {
-  int ret = fcntl(fd, F_GETFD);
-  if (ret < 0) {
-    if (errno == EBADF) {
-      error(errno, 0, "no jobserver pipe, prefix recipe command with '+'");
-    } else {
-      error(errno, errno, "fnctl failed");
-    }
-  }
-}
-
-// Extract flags from MAKEFLAGS that need to be propagated to subproccess
-static std::vector<std::string> ReadMakeflags() {
-  std::vector<std::string> args;
-
-  const char* makeflags_env = getenv("MAKEFLAGS");
-  if (makeflags_env == nullptr) {
-    return args;
-  }
-
-  // The MAKEFLAGS format is pretty useless.  The first argument might be empty
-  // (starts with a leading space), or it might be a set of one-character flags
-  // merged together with no leading space, or it might be a variable
-  // definition.
-
-  std::string makeflags = makeflags_env;
-
-  // Split makeflags into individual args on spaces.  Multiple spaces are
-  // elided, but an initial space will result in a blank arg.
-  size_t base = 0;
-  size_t found;
-  do {
-    found = makeflags.find_first_of(" ", base);
-    args.push_back(makeflags.substr(base, found - base));
-    base = found + 1;
-  } while (found != makeflags.npos);
-
-  // Drop the first argument if it is empty
-  while (args.size() > 0 && args[0].size() == 0) {
-	  args.erase(args.begin());
-  }
-
-  // Prepend a - to the first argument if it does not have one and is not a
-  // variable definition
-  if (args.size() > 0 && args[0][0] != '-') {
-    if (args[0].find('=') == makeflags.npos) {
-      args[0] = '-' + args[0];
-    }
-  }
-
-  return args;
-}
-
-static bool ParseMakeflags(std::vector<std::string>& args,
-    int* in_fd, int* out_fd, bool* parallel, bool* keep_going) {
-
-  std::vector<char*> getopt_argv;
-  // getopt starts reading at argv[1]
-  getopt_argv.reserve(args.size() + 1);
-  getopt_argv.push_back(strdup(""));
-  for (std::string& v : args) {
-    getopt_argv.push_back(strdup(v.c_str()));
-  }
-
-  opterr = 0;
-  optind = 1;
-  while (1) {
-    const static option longopts[] = {
-        {"jobserver-fds", required_argument, 0, 0},
-        {0, 0, 0, 0},
-    };
-    int longopt_index = 0;
-
-    int c = getopt_long(getopt_argv.size(), getopt_argv.data(), "kj",
-        longopts, &longopt_index);
-
-    if (c == -1) {
-      break;
-    }
-
-    switch (c) {
-    case 0:
-      switch (longopt_index) {
-      case 0:
-      {
-        // jobserver-fds
-        if (sscanf(optarg, "%d,%d", in_fd, out_fd) != 2) {
-          error(EXIT_FAILURE, 0, "incorrect format for --jobserver-fds: %s", optarg);
-        }
-        // TODO: propagate in_fd, out_fd
-        break;
-      }
-      default:
-        abort();
-      }
-      break;
-    case 'j':
-      *parallel = true;
-      break;
-    case 'k':
-      *keep_going = true;
-      break;
-    case '?':
-      // ignore unknown arguments
-      break;
-    default:
-      abort();
-    }
-  }
-
-  for (char *v : getopt_argv) {
-    free(v);
-  }
-
-  return true;
-}
-
-// Read a single byte from fd, with timeout in milliseconds.  Returns true if
-// a byte was read, false on timeout.  Throws away the read value.
-// Non-reentrant, uses timer and signal handler global state, plus static
-// variable to communicate with signal handler.
-//
-// Uses a SIGALRM timer to fire a signal after timeout_ms that will interrupt
-// the read syscall if it hasn't yet completed.  If the timer fires before the
-// read the read could block forever, so read from a dup'd fd and close it from
-// the signal handler, which will cause the read to return EBADF if it occurs
-// after the signal.
-// The dup/read/close combo is very similar to the system described to avoid
-// a deadlock between SIGCHLD and read at
-// http://make.mad-scientist.net/papers/jobserver-implementation/
-static bool ReadByteTimeout(int fd, int timeout_ms) {
-  // global variable to communicate with the signal handler
-  static int dup_fd = -1;
-
-  // dup the fd so the signal handler can close it without losing the real one
-  dup_fd = dup(fd);
-  if (dup_fd < 0) {
-    error(errno, errno, "dup failed");
-  }
-
-  // set up a signal handler that closes dup_fd on SIGALRM
-  struct sigaction action = {};
-  action.sa_flags = SA_SIGINFO,
-  action.sa_sigaction = [](int, siginfo_t*, void*) {
-    close(dup_fd);
-  };
-  struct sigaction oldaction = {};
-  int ret = sigaction(SIGALRM, &action, &oldaction);
-  if (ret < 0) {
-    error(errno, errno, "sigaction failed");
-  }
-
-  // queue a SIGALRM after timeout_ms
-  const struct itimerval timeout = {{}, {0, timeout_ms * 1000}};
-  ret = setitimer(ITIMER_REAL, &timeout, NULL);
-  if (ret < 0) {
-    error(errno, errno, "setitimer failed");
-  }
-
-  // start the blocking read
-  char buf;
-  int read_ret = read(dup_fd, &buf, 1);
-  int read_errno = errno;
-
-  // cancel the alarm in case it hasn't fired yet
-  const struct itimerval cancel = {};
-  ret = setitimer(ITIMER_REAL, &cancel, NULL);
-  if (ret < 0) {
-    error(errno, errno, "reset setitimer failed");
-  }
-
-  // remove the signal handler
-  ret = sigaction(SIGALRM, &oldaction, NULL);
-  if (ret < 0) {
-    error(errno, errno, "reset sigaction failed");
-  }
-
-  // clean up the dup'd fd in case the signal never fired
-  close(dup_fd);
-  dup_fd = -1;
-
-  if (read_ret == 0) {
-    error(EXIT_FAILURE, 0, "EOF on jobserver pipe");
-  } else if (read_ret > 0) {
-    return true;
-  } else if (read_errno == EINTR || read_errno == EBADF) {
-    return false;
-  } else {
-    error(read_errno, read_errno, "read failed");
-  }
-  abort();
-}
-
-// Measure the size of the jobserver pool by reading from in_fd until it blocks
-static int GetJobserverTokens(int in_fd) {
-  int tokens = 0;
-  pollfd pollfds[] = {{in_fd, POLLIN, 0}};
-  int ret;
-  while ((ret = TEMP_FAILURE_RETRY(poll(pollfds, 1, 0))) != 0) {
-    if (ret < 0) {
-      error(errno, errno, "poll failed");
-    } else if (pollfds[0].revents != POLLIN) {
-      error(EXIT_FAILURE, 0, "unexpected event %d\n", pollfds[0].revents);
-    }
-
-    // There is probably a job token in the jobserver pipe.  There is a chance
-    // another process reads it first, which would cause a blocking read to
-    // block forever (or until another process put a token back in the pipe).
-    // The file descriptor can't be set to O_NONBLOCK as that would affect
-    // all users of the pipe, including the parent make process.
-    // ReadByteTimeout emulates a non-blocking read on a !O_NONBLOCK socket
-    // using a SIGALRM that fires after a short timeout.
-    bool got_token = ReadByteTimeout(in_fd, 10);
-    if (!got_token) {
-      // No more tokens
-      break;
-    } else {
-      tokens++;
-    }
-  }
-
-  // This process implicitly gets a token, so pool size is measured size + 1
-  return tokens;
-}
-
-// Return tokens to the jobserver pool.
-static void PutJobserverTokens(int out_fd, int tokens) {
-  // Return all the tokens to the pipe
-  char buf = '+';
-  for (int i = 0; i < tokens; i++) {
-    int ret = TEMP_FAILURE_RETRY(write(out_fd, &buf, 1));
-    if (ret < 0) {
-      error(errno, errno, "write failed");
-    } else if (ret == 0) {
-      error(EXIT_FAILURE, 0, "EOF on jobserver pipe");
-    }
-  }
-}
-
-int main(int argc, char* argv[]) {
-  int in_fd = -1;
-  int out_fd = -1;
-  bool parallel = false;
-  bool keep_going = false;
-  bool ninja = false;
-  int tokens = 0;
-
-  if (argc > 1 && strcmp(argv[1], "--ninja") == 0) {
-    ninja = true;
-    argv++;
-    argc--;
-  }
-
-  if (argc < 2) {
-    error(EXIT_FAILURE, 0, "expected command to run");
-  }
-
-  const char* path = argv[1];
-  std::vector<char*> args({argv[1]});
-
-  std::vector<std::string> makeflags = ReadMakeflags();
-  if (ParseMakeflags(makeflags, &in_fd, &out_fd, &parallel, &keep_going)) {
-    if (in_fd >= 0 && out_fd >= 0) {
-      CheckFd(in_fd);
-      CheckFd(out_fd);
-      fcntl(in_fd, F_SETFD, FD_CLOEXEC);
-      fcntl(out_fd, F_SETFD, FD_CLOEXEC);
-      tokens = GetJobserverTokens(in_fd);
-    }
-  }
-
-  std::string jarg;
-  if (parallel) {
-    if (tokens == 0) {
-      if (ninja) {
-        // ninja is parallel by default
-        jarg = "";
-      } else {
-        // make -j with no argument, guess a reasonable parallelism like ninja does
-        jarg = "-j" + std::to_string(sysconf(_SC_NPROCESSORS_ONLN) + 2);
-      }
-    } else {
-      jarg = "-j" + std::to_string(tokens + 1);
-    }
-  }
-
-
-  if (ninja) {
-    if (!parallel) {
-      // ninja is parallel by default, pass -j1 to disable parallelism if make wasn't parallel
-      args.push_back(strdup("-j1"));
-    } else {
-      if (jarg != "") {
-        args.push_back(strdup(jarg.c_str()));
-      }
-    }
-    if (keep_going) {
-      args.push_back(strdup("-k0"));
-    }
-  } else {
-    if (jarg != "") {
-      args.push_back(strdup(jarg.c_str()));
-    }
-  }
-
-  args.insert(args.end(), &argv[2], &argv[argc]);
-
-  args.push_back(nullptr);
-
-  static pid_t pid;
-
-  // Set up signal handlers to forward SIGTERM to child.
-  // Assume that all other signals are sent to the entire process group,
-  // and that we'll wait for our child to exit instead of handling them.
-  struct sigaction action = {};
-  action.sa_flags = SA_RESTART;
-  action.sa_handler = [](int signal) {
-    if (signal == SIGTERM && pid > 0) {
-      kill(pid, signal);
-    }
-  };
-
-  int ret = 0;
-  if (!ret) ret = sigaction(SIGHUP, &action, NULL);
-  if (!ret) ret = sigaction(SIGINT, &action, NULL);
-  if (!ret) ret = sigaction(SIGQUIT, &action, NULL);
-  if (!ret) ret = sigaction(SIGTERM, &action, NULL);
-  if (!ret) ret = sigaction(SIGALRM, &action, NULL);
-  if (ret < 0) {
-    error(errno, errno, "sigaction failed");
-  }
-
-  pid = fork();
-  if (pid < 0) {
-    error(errno, errno, "fork failed");
-  } else if (pid == 0) {
-    // child
-    unsetenv("MAKEFLAGS");
-    unsetenv("MAKELEVEL");
-
-    // make 3.81 sets the stack ulimit to unlimited, which may cause problems
-    // for child processes
-    struct rlimit rlim{};
-    if (getrlimit(RLIMIT_STACK, &rlim) == 0 && rlim.rlim_cur == RLIM_INFINITY) {
-      rlim.rlim_cur = 8*1024*1024;
-      setrlimit(RLIMIT_STACK, &rlim);
-    }
-
-    int ret = execvp(path, args.data());
-    if (ret < 0) {
-      error(errno, errno, "exec %s failed", path);
-    }
-    abort();
-  }
-
-  // parent
-
-  siginfo_t status = {};
-  int exit_status = 0;
-  ret = waitid(P_PID, pid, &status, WEXITED);
-  if (ret < 0) {
-    error(errno, errno, "waitpid failed");
-  } else if (status.si_code == CLD_EXITED) {
-    exit_status = status.si_status;
-  } else {
-    exit_status = -(status.si_status);
-  }
-
-  if (tokens > 0) {
-    PutJobserverTokens(out_fd, tokens);
-  }
-  exit(exit_status);
-}