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, ¶llel, &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);
-}