Make improvements

- You can now run `make -j8 toolchain` on Windows
- You can now run `make -j` on MacOS ARM64 and BSD OSes
- You can now use our Emacs dev environment on MacOS/Windows
- Fix bug where the x16 register was being corrupted by --ftrace
- The programs under build/bootstrap/ are updated as fat binaries
- The Makefile now explains how to download cosmocc-0.0.12 toolchain
- The build scripts under bin/ now support "cosmo" branded toolchains
- stat() now goes faster on Windows (shaves 100ms off `make` latency)
- Code cleanup and added review on the Windows signal checking code
- posix_spawnattr_setrlimit() now works around MacOS ARM64 bugs
- Landlock Make now favors posix_spawn() on non-Linux/OpenBSD
- posix_spawn() now has better --strace logging on Windows
- fstatat() can now avoid EACCES in more cases on Windows
- fchmod() can now change the readonly bit on Windows
This commit is contained in:
Justine Tunney 2023-10-14 20:57:15 -07:00
parent 06c6baaf50
commit c9fecf3a55
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
109 changed files with 1188 additions and 454 deletions

195
third_party/make/job.c vendored
View file

@ -47,6 +47,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/macros.internal.h"
#include "libc/math.h"
#include "libc/nexgen32e/kcpuids.h"
#include "libc/proc/posix_spawn.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
@ -63,10 +64,14 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "libc/x/x.h"
#include "third_party/make/commands.h"
#include "third_party/make/dep.h"
#include "third_party/make/findprog.h"
#include "third_party/make/os.h"
#include "third_party/make/variable.h"
// clang-format off
#define USE_POSIX_SPAWN (!IsLinux() && !IsOpenbsd())
#define HAVE_POSIX_SPAWNATTR_SETSIGMASK
#ifdef WINDOWS32
const char *default_shell = "sh.exe";
int no_default_sh_exe = 1;
@ -1891,6 +1896,153 @@ child_execute_job (struct childbase *child,
fderr = child->output.err;
}
if (USE_POSIX_SPAWN) {
char *cmd;
posix_spawnattr_t attr;
posix_spawn_file_actions_t fa;
short flags = 0;
if ((r = posix_spawnattr_init (&attr)) != 0)
goto done;
if ((r = posix_spawn_file_actions_init (&fa)) != 0)
{
posix_spawnattr_destroy (&attr);
goto done;
}
// [jart] use setrlimit on posix_spawn
// TODO(jart): support landlock make rlimit variables
if (stack_limit.rlim_cur && RLIMIT_STACK < RLIM_NLIMITS)
{
posix_spawnattr_setrlimit (&attr, RLIMIT_STACK, &stack_limit);
flags |= POSIX_SPAWN_SETRLIMIT;
}
/* Unblock all signals. */
#ifdef HAVE_POSIX_SPAWNATTR_SETSIGMASK
{
sigset_t mask;
sigemptyset (&mask);
r = posix_spawnattr_setsigmask (&attr, &mask);
if (r != 0)
goto cleanup;
flags |= POSIX_SPAWN_SETSIGMASK;
}
#endif /* have posix_spawnattr_setsigmask() */
/* USEVFORK can give significant speedup on systems where it's available. */
#ifdef POSIX_SPAWN_USEVFORK
flags |= POSIX_SPAWN_USEVFORK;
#endif
/* For any redirected FD, dup2() it to the standard FD.
They are all marked close-on-exec already. */
if (fdin >= 0 && fdin != FD_STDIN)
if ((r = posix_spawn_file_actions_adddup2 (&fa, fdin, FD_STDIN)) != 0)
goto cleanup;
if (fdout != FD_STDOUT)
if ((r = posix_spawn_file_actions_adddup2 (&fa, fdout, FD_STDOUT)) != 0)
goto cleanup;
if (fderr != FD_STDERR)
if ((r = posix_spawn_file_actions_adddup2 (&fa, fderr, FD_STDERR)) != 0)
goto cleanup;
/* We can't use the POSIX_SPAWN_RESETIDS flag: when make is invoked under
restrictive environments like unshare it will fail with EINVAL. */
/* Apply the spawn flags. */
if ((r = posix_spawnattr_setflags (&attr, flags)) != 0)
goto cleanup;
/* Look up the program on the child's PATH, if needed. */
{
const char *p = NULL;
char **pp;
for (pp = child->environment; *pp != NULL; ++pp)
if ((*pp)[0] == 'P' && (*pp)[1] == 'A' && (*pp)[2] == 'T'
&& (*pp)[3] == 'H' &&(*pp)[4] == '=')
{
p = (*pp) + 5;
break;
}
/* execvp() will use a default PATH if none is set; emulate that. */
if (p == NULL)
{
size_t l = confstr (_CS_PATH, NULL, 0);
if (l)
{
char *dp = alloca (l);
confstr (_CS_PATH, dp, l);
p = dp;
}
}
cmd = (char *)find_in_given_path (argv[0], p, NULL, 0);
}
if (!cmd)
{
r = errno;
goto cleanup;
}
/* Start the program. */
while ((r = posix_spawn (&pid, cmd, &fa, &attr, argv,
child->environment)) == EINTR)
;
/* posix_spawn() doesn't provide sh fallback like exec() does; implement
it here. POSIX doesn't specify the path to sh so use the default. */
if (r == ENOEXEC)
{
char **nargv;
char **pp;
size_t l = 0;
for (pp = argv; *pp != NULL; ++pp)
++l;
nargv = xmalloc (sizeof (char *) * (l + 3));
nargv[0] = (char *)default_shell;
nargv[1] = cmd;
memcpy (&nargv[2], &argv[1], sizeof (char *) * l);
while ((r = posix_spawn (&pid, nargv[0], &fa, &attr, nargv,
child->environment)) == EINTR)
;
free (nargv);
}
if (r == 0)
{
/* Spawn succeeded but may fail later: remember the command. */
free (child->cmd_name);
if (cmd != argv[0])
child->cmd_name = cmd;
else
child->cmd_name = xstrdup(cmd);
}
cleanup:
posix_spawn_file_actions_destroy (&fa);
posix_spawnattr_destroy (&attr);
done:
if (r != 0)
pid = -1;
if (pid < 0)
OSS (error, NILF, "%s: %s", argv[0], strerror (r));
return pid;
} // USE_POSIX_SPAWN
pid = fork();
if (pid != 0)
return pid;
@ -2446,17 +2598,23 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
shell = default_shell;
/* [jart] remove code that forces slow path if not using /bin/sh */
/* else if (strcmp (shell, default_shell)) */
/* goto slow; */
if (ifs)
for (cap = ifs; *cap != '\0'; ++cap)
if (*cap != ' ' && *cap != '\t' && *cap != '\n')
if (*cap != ' ' && *cap != '\t' && *cap != '\n') {
// kprintf("slow because whitespace\n");
goto slow;
}
if (shellflags)
if (shellflags[0] != '-'
|| ((shellflags[1] != 'c' || shellflags[2] != '\0')
&& (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0')))
&& (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0'))) {
// kprintf("slow because shell flags\n");
goto slow;
}
i = strlen (line) + 1;
@ -2515,18 +2673,21 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
If we see any of those, punt.
But on MSDOS, if we use COMMAND.COM, double and single
quotes have the same effect. */
else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell)
else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell) {
// kprintf("slow because backslash\n");
goto slow;
else
} else
*ap++ = *p;
}
else if (strchr (sh_chars, *p) != 0)
else if (strchr (sh_chars, *p) != 0) {
/* Not inside a string, but it's a special char. */
// kprintf("slow because %#c found in %#s\n", *p, line);
goto slow;
else if (one_shell && *p == '\n')
} else if (one_shell && *p == '\n') {
/* In .ONESHELL mode \n is a separator like ; or && */
// kprintf("slow because oneshell thing\n");
goto slow;
else
} else
/* Not a special char. */
switch (*p)
{
@ -2535,8 +2696,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
first word with no equals sign in it. This is not the case
with sh -k, but we never get here when using nonstandard
shell flags. */
if (! seen_nonequals && unixy_shell)
if (! seen_nonequals && unixy_shell) {
// kprintf("slow because nonequals\n");
goto slow;
}
word_has_equals = 1;
*ap++ = '=';
break;
@ -2590,10 +2753,12 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
/* Update SEEN_NONEQUALS, which tells us if every word
heretofore has contained an '='. */
seen_nonequals |= ! word_has_equals;
if (word_has_equals && ! seen_nonequals)
if (word_has_equals && ! seen_nonequals) {
/* An '=' in a word before the first
word without one is magical. */
// kprintf("slow because word equals\n");
goto slow;
}
word_has_equals = 0; /* Prepare for the next word. */
/* If this argument is the command name,
@ -2604,8 +2769,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
int j;
for (j = 0; sh_cmds[j] != 0; ++j)
{
if (streq (sh_cmds[j], new_argv[0]))
if (streq (sh_cmds[j], new_argv[0])) {
// kprintf("slow because builtin shell commands\n");
goto slow;
}
}
}
@ -2621,9 +2788,11 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
}
end_of_line:
if (instring)
if (instring) {
/* Let the shell deal with an unterminated quote. */
// kprintf("slow because unterminated quote\n");
goto slow;
}
/* Terminate the last argument and the argument list. */
@ -2636,8 +2805,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
{
int j;
for (j = 0; sh_cmds[j] != 0; ++j)
if (streq (sh_cmds[j], new_argv[0]))
if (streq (sh_cmds[j], new_argv[0])) {
// kprintf("slow because sh_cmds\n");
goto slow;
}
}
if (new_argv[0] == 0)