* Add new jobserver feature.

* Small updates to the manual
* E.Zaretskii fix for new DJGPP version.
This commit is contained in:
Paul Smith 1999-04-25 04:30:55 +00:00
parent 7f3ffd4019
commit fc0fe4103a
14 changed files with 574 additions and 149 deletions

View File

@ -1,3 +1,68 @@
1999-04-25 Paul D. Smith <psmith@gnu.org>
* make.texinfo: Updates to @dircategory and @direntry suggested by
Karl Berry <karl@cs.umb.edu>.
1999-04-18 Eli Zaretskii <eliz@is.elta.co.il>
* configh.dos.template: Update to recognize that version 2.02 of
DJGPP contains sys_siglist stuff.
1999-04-14 Paul D. Smith <psmith@gnu.org>
* make.texinfo (Options/Recursion): Document the job server.
(Parallel): Tweaks.
1999-04-13 Paul D. Smith <psmith@gnu.org>
Implement a new "job server" feature; the implementation was
suggested by Howard Chu <hyc@highlandsun.com>.
* configure.in (job-server): New disable option for job server
support--it's enabled by default.
* NEWS: Summarize the new feature.
* acconfig.h: New definition MAKE_JOBSERVER if job server support
is enabled.
* config.h-vms.template: Undef MAKE_JOBSERVER for this port.
* config.h.W32.template: Ditto.
* config.ami.template: Ditto.
* main.c (struct command_switch): Add a new type: int_string.
(switches[]) Use int_string for -j if MAKE_JOBSERVER.
(init_switches): Initialize the new int_string switch type.
(print_usage): New function, extracted from decode_switches().
(decode_switches): Call it. Decode the new int_string switch type.
(define_makeflags): Add new int_string switch data to MAKEFLAGS.
(job_fds[]) Array to contain the pipe file descriptors.
(main): Parse the job_slots_str option results. If necessary,
create the pipe and seed it with tokens. Set the non-blocking bit
for the read fd. Enable the signal handler for SIGCHLD even if we
have a non-hanging wait; it's needed to interrupt the select() in
job.c:start_waiting_job().
* make.h: Declare job_fds[].
* job.h (struct child): Add job_token field to store the token for
this job (if any).
* job.c (reap_children): When a child is fully reaped, release the
token back into the pipe.
(free_child): If the child to be freed still has a token, put it
back.
(new_job): Initialize the job_token member.
(start_waiting_job): For local jobs, if we're using the pipe, get
a token before we check the load, etc. We do this by performing a
non-blocking read in a loop. If the read fails, no token is
available. Do a select on the fd to wait for a token. We need to
re-enable the signal handler for SIGCHLD even if we have a
non-hanging waitpid() or wait3(), so that the signal will
interrupt the select() and we can wake up to reap children.
(child_handler): Re-enable the signal handler. The count is still
kept although it's not needed or used unless you don't have
waitpid() or wait3().
1999-04-03 Paul D. Smith <psmith@gnu.org>
* remake.c (f_mtime): If: a) we found a file and b) we didn't

11
NEWS
View File

@ -1,6 +1,6 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
31 Mar 1999
13 Apr 1999
Copyright (C) 1992,93,94,95,96,97,98,1999 Free Software Foundation, Inc.
See the end for copying conditions.
@ -23,6 +23,15 @@ Version 3.78
* Make allows CRLF sequences as well as traditional LF, for
compatibility with makefiles created on other operating systems.
* A "job server" feature, proposed by Howard Chu <hyc@highlandsun.com>.
On systems that support POSIX pipe(2) semantics, GNU make can now pass
-jN options to submakes rather than forcing them all to use -j1. The
top make and all its sub-make processes use a pipe to communicate with
each other to ensure that no more than N jobs are started across all
makes. To get the old behavior of -j back, you can configure make
with the --disable-job-server option.
Version 3.77

View File

@ -10,6 +10,9 @@
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
#undef SCCS_GET_MINUS_G
/* Define this to enable job server support in GNU make. */
#undef MAKE_JOBSERVER
/* Define to be the nanoseconds member of struct stat's st_mtim,
if it exists. */
#undef ST_MTIM_NSEC
@ -26,3 +29,14 @@
/* Define to `unsigned long' or `unsigned long long'
if <inttypes.h> doesn't define. */
#undef uintmax_t
/* These are for AC_FUNC_SELECT */
/* Define if the system doesn't provide fd_set. */
#undef fd_set
/* Define the type of the first arg to select(). */
#undef fd_set_size_t
/* Define this if select() args need to be cast away from fd_set (HP-UX). */
#undef SELECT_FD_SET_CAST

View File

@ -208,3 +208,84 @@ AC_DEFUN(jm_AC_TYPE_UINTMAX_T,
fi
fi
])
dnl ---------------------------------------------------------------------------
dnl From Steve Robbins <steve@nyongwa.montreal.qc.ca>
dnl From a proposed change made on the autoconf list on 2 Feb 1999
dnl http://sourceware.cygnus.com/ml/autoconf/1999-02/msg00001.html
AC_DEFUN(AC_FUNC_SELECT,
[AC_CHECK_FUNCS(select)
if test "$ac_cv_func_select" = yes; then
AC_CHECK_HEADERS(unistd.h sys/types.h sys/time.h sys/select.h sys/socket.h)
AC_MSG_CHECKING([argument types of select()])
AC_CACHE_VAL(ac_cv_type_fd_set_size_t,dnl
[AC_CACHE_VAL(ac_cv_type_fd_set,dnl
[for ac_cv_type_fd_set in 'fd_set' 'int'; do
for ac_cv_type_fd_set_size_t in 'int' 'size_t' 'unsigned long' 'unsigned'; do
for ac_type_timeval in 'struct timeval' 'const struct timeval'; do
AC_TRY_COMPILE(dnl
[#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif],
[extern select ($ac_cv_type_fd_set_size_t,
$ac_cv_type_fd_set *, $ac_cv_type_fd_set *, $ac_cv_type_fd_set *,
$ac_type_timeval *);],
[ac_found=yes ; break 3],ac_found=no)
done
done
done
])dnl AC_CACHE_VAL
])dnl AC_CACHE_VAL
if test "$ac_found" = no; then
AC_MSG_ERROR([can't determine argument types])
fi
AC_MSG_RESULT([select($ac_cv_type_fd_set_size_t,$ac_cv_type_fd_set *,...)])
AC_DEFINE_UNQUOTED(fd_set_size_t, $ac_cv_type_fd_set_size_t)
ac_cast=
if test "$ac_cv_type_fd_set" != fd_set; then
# Arguments 2-4 are not fd_set. Some weirdo systems use fd_set type for
# FD_SET macros, but insist that you cast the argument to select. I don't
# understand why that might be, but it means we cannot define fd_set.
AC_EGREP_CPP(dnl
changequote(<<,>>)dnl
<<(^|[^a-zA-Z_0-9])fd_set[^a-zA-Z_0-9]>>dnl
changequote([,]),dnl
[#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif],dnl
# We found fd_set type in a header, need special cast
ac_cast="($ac_cv_type_fd_set *)",dnl
# No fd_set type; it is safe to define it
AC_DEFINE_UNQUOTED(fd_set,$ac_cv_type_fd_set))
fi
AC_DEFINE_UNQUOTED(SELECT_FD_SET_CAST,$ac_cast)
fi
])

View File

@ -176,6 +176,13 @@
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
/* #undef SCCS_GET_MINUS_G */
/* Define this to enable job server support in GNU make. */
/* #undef MAKE_JOBSERVER */
/* Define to be the nanoseconds member of struct stat's st_mtim,
if it exists. */
/* #undef ST_MTIM_NSEC */
/* Define this if the C library defines the variable `sys_siglist'. */
/* #undef HAVE_SYS_SIGLIST */

View File

@ -180,6 +180,13 @@
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
/* #undef SCCS_GET_MINUS_G */
/* Define this to enable job server support in GNU make. */
/* #undef MAKE_JOBSERVER */
/* Define to be the nanoseconds member of struct stat's st_mtim,
if it exists. */
/* #undef ST_MTIM_NSEC */
/* Define this if the C library defines the variable `sys_siglist'. */
/* #undefine HAVE_SYS_SIGLIST */

View File

@ -191,6 +191,13 @@
/* Define this if the SCCS `get' command understands the `-G<file>' option. */
/* #undef SCCS_GET_MINUS_G */
/* Define this to enable job server support in GNU make. */
/* #undef MAKE_JOBSERVER */
/* Define to be the nanoseconds member of struct stat's st_mtim,
if it exists. */
/* #undef ST_MTIM_NSEC */
/* Define this if the C library defines the variable `sys_siglist'. */
/* #undef HAVE_SYS_SIGLIST */

View File

@ -1,4 +1,3 @@
/* Generated automatically from configure.in by autoheader. DO NOT EDIT! */
/* Many things are defined already by a system header. */
#include <sys/config.h>
@ -9,8 +8,20 @@
/* Version of this package (needed by automake) */
#define VERSION "%VERSION%"
#if __DJGPP__ > 2 || __DJGPP_MINOR__ > 1
/* Define if `sys_siglist' is declared by <signal.h>. */
# define SYS_SIGLIST_DECLARED 1
/* Define this if the C library defines the variable `_sys_siglist'. */
# define HAVE_SYS_SIGLIST 1
#else
/* Define NSIG. */
#define NSIG SIGMAX
# define NSIG SIGMAX
#endif
/* Define if you have sigsetmask. */
#define HAVE_SIGSETMASK 1

View File

@ -3,7 +3,7 @@ AC_REVISION([$Id$])
AC_PREREQ(2.13)dnl dnl Minimum Autoconf version required.
AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir.
AM_INIT_AUTOMAKE(make, 3.77.90)
AM_INIT_AUTOMAKE(make, 3.77.xx)
AM_CONFIG_HEADER(config.h)
dnl Regular configure stuff
@ -57,7 +57,7 @@ AC_CHECK_LIB(posix4, clock_gettime)
AC_CHECK_FUNCS(memmove strdup psignal mktemp pstat_getdynamic \
clock_gettime dup2 getcwd sigsetmask getgroups setlinebuf \
seteuid setegid setreuid setregid strerror strsignal)
seteuid setegid setreuid setregid strerror strsignal pipe)
AC_CHECK_SYMBOL(sys_siglist)
AC_FUNC_ALLOCA
AC_FUNC_VFORK
@ -66,6 +66,7 @@ AC_FUNC_STRCOLL
AC_FUNC_CLOSEDIR_VOID
AC_FUNC_SETVBUF_REVERSED
AC_FUNC_GETLOADAVG
AC_FUNC_SELECT
AC_CHECK_LIB(kstat, kstat_open)
# Check out the wait reality.
@ -124,6 +125,18 @@ AC_ARG_WITH(customs,
;;
esac])
dnl See if we can handle the job server feature, and if the user wants it.
AC_ARG_ENABLE(job-server,
[ --disable-job-server Disallow recursive make communication during -jN],
[make_cv_job_server="$enableval"],
[make_cv_job_server="yes"])
case "$ac_cv_func_pipe $make_cv_job_server" in
"yes yes") AC_DEFINE(MAKE_JOBSERVER) ;;
esac
AC_CACHE_CHECK(for location of SCCS get command, make_cv_path_sccs_get, [
if test -f /usr/sccs/get; then
make_cv_path_sccs_get=/usr/sccs/get

134
job.c
View File

@ -1,5 +1,5 @@
/* Job execution and handling for GNU Make.
Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.
Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
@ -257,10 +257,10 @@ vmsWaitForChildren(int *status)
#endif
/* If we can't use waitpid() or wait3(), then we use a signal handler
to track the number of SIGCHLD's we got. This is less robust. */
#ifndef WAIT_NOHANG
/* Count the number of dead children we have. If we can use wait3() or
waitpid() then we'll never use this count: it's completely unnecessary.
But we need the handler installed to interrupt the select() call for
the jobs pipe, so we might as well keep it. */
static unsigned int dead_children = 0;
@ -273,10 +273,9 @@ child_handler (sig)
++dead_children;
if (debug_flag)
printf ("Got a SIGCHLD; %d unreaped children.\n", dead_children);
printf ("Got a SIGCHLD; %u unreaped children.\n", dead_children);
}
#endif /* WAIT_NOHANG */
extern int shell_function_pid, shell_function_completed;
@ -292,11 +291,15 @@ reap_children (block, err)
{
WAIT_T status;
#ifdef WAIT_NOHANG
int dead_children = 1; /* Initially, assume we have some. */
/* Initially, assume we have some. */
int reap_more = 1;
# define REAP_MORE reap_more
#else
# define REAP_MORE dead_children
#endif
while ((children != 0 || shell_function_pid != 0) &&
(block || dead_children))
(block || REAP_MORE))
{
int remote = 0;
register int pid;
@ -312,8 +315,12 @@ reap_children (block, err)
error (NILF, "*** Waiting for unfinished jobs....");
}
#ifndef WAIT_NOHANG
/* We have one less dead child to reap.
/* We have one less dead child to reap. As noted in
child_handler() above, this count is completely unimportant for
all modern, POSIX-y systems that support wait3() or waitpid().
The rest of this comment below applies only to early, broken
pre-POSIX systems. We keep the count only because... it's there...
The test and decrement are not atomic; if it is compiled into:
register = dead_children - 1;
dead_children = register;
@ -327,7 +334,6 @@ reap_children (block, err)
if (dead_children > 0)
--dead_children;
#endif
any_remote = 0;
any_local = shell_function_pid != 0;
@ -405,7 +411,7 @@ reap_children (block, err)
{
/* No local children are dead. */
#ifdef WAIT_NOHANG
dead_children = 0;
reap_more = 0;
#endif
if (block && any_remote)
{
@ -612,6 +618,22 @@ reap_children (block, err)
live and call reap_children again. */
block_sigs ();
#ifdef MAKE_JOBSERVER
/* If this job has a token out, return it. */
if (c->job_token)
{
assert(job_slots_used > 0);
write (job_fds[1], &c->job_token, 1);
if (debug_flag)
printf ("Released token `%c' for child 0x%08lx.\n",
c->job_token, (unsigned long int) c);
c->job_token = 0;
}
#endif
/* There is now another slot open. */
if (job_slots_used > 0)
--job_slots_used;
/* Remove the child from the chain and free it. */
if (lastc == 0)
children = c->next;
@ -620,10 +642,6 @@ reap_children (block, err)
if (! handling_fatal_signal) /* Don't bother if about to die. */
free_child (c);
/* There is now another slot open. */
if (job_slots_used > 0)
--job_slots_used;
unblock_sigs ();
/* If the job failed, and the -k flag was not given, die,
@ -662,6 +680,19 @@ free_child (child)
free ((char *) child->environment);
}
#ifdef MAKE_JOBSERVER
/* If this child has a token it hasn't relinquished, give it up now.
This can happen if the job completes immediately, mainly because
all the command lines evaluated to empty strings. */
if (child->job_token)
{
write (job_fds[1], &child->job_token, 1);
if (debug_flag)
printf ("Freed token `%c' for child 0x%08lx.\n",
child->job_token, (unsigned long int) child);
}
#endif
free ((char *) child);
}
@ -1083,28 +1114,77 @@ static int
start_waiting_job (c)
struct child *c;
{
struct file *f = c->file;
/* If we can start a job remotely, we always want to, and don't care about
the local load average. We record that the job should be started
remotely in C->remote for start_job_command to test. */
c->remote = start_remote_job_p (1);
/* If this job is to be started locally, and we are already running
some jobs, make this one wait if the load average is too high. */
if (!c->remote && job_slots_used > 0 && load_too_high ())
/* If not, start it locally. */
if (!c->remote)
{
#ifdef MAKE_JOBSERVER
/* If this is not a recurse command and we are controlling
multiple jobs, obtain a token before starting child. */
if (job_fds[0] >= 0 && !f->cmds->any_recurse)
{
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(job_fds[0], &rfds);
/* Read a token. We set the non-blocking bit on this earlier,
so if there's no token to be read we'll fall through to the
select. The select block until (a) there's data to read,
in which case we come back around and try to grab the token
before someone else does, or (b) a signal, such as SIGCHLD,
is caught (because we installed a handler for it). If the
latter, call reap_children() to try to free up some slots. */
while (read (job_fds[0], &c->job_token, 1) < 1)
{
int r = select (job_fds[0]+1, SELECT_FD_SET_CAST &rfds,
NULL, NULL, NULL);
if (r < 0)
{
#ifdef EINTR
if (errno != EINTR)
/* We should definitely handle this more gracefully!
What kinds of things can happen here? ^C closes the
pipe? Something else closes it? */
pfatal_with_name ("read jobs pipe");
#endif
/* We were interrupted; handle any dead children. */
reap_children (1, 0);
}
}
assert(c->job_token != 0);
if (debug_flag)
printf ("Obtained token `%c' for child 0x%08lx.\n",
c->job_token, (unsigned long int) c);
}
#endif
/* If we are running at least one job already and the load average
is too high, make this one wait. */
if (job_slots_used > 0 && load_too_high ())
{
/* Put this child on the chain of children waiting
for the load average to go down. */
set_command_state (c->file, cs_running);
set_command_state (f, cs_running);
c->next = waiting_jobs;
waiting_jobs = c;
return 0;
}
}
/* Start the first command; reap_children will run later command lines. */
start_job_command (c);
switch (c->file->command_state)
switch (f->command_state)
{
case cs_running:
c->next = children;
@ -1120,16 +1200,16 @@ start_waiting_job (c)
case cs_not_started:
/* All the command lines turned out to be empty. */
c->file->update_status = 0;
f->update_status = 0;
/* FALLTHROUGH */
case cs_finished:
notice_finished_file (c->file);
notice_finished_file (f);
free_child (c);
break;
default:
assert (c->file->command_state == cs_finished);
assert (f->command_state == cs_finished);
break;
}
@ -1157,8 +1237,9 @@ new_job (file)
/* Chop the commands up into lines if they aren't already. */
chop_commands (cmds);
/* Wait for a job slot to be freed up. If we allow an infinite number
don't bother; also job_slots will == 0 if we're using the job pipe. */
if (job_slots != 0)
/* Wait for a job slot to be freed up. */
while (job_slots_used == job_slots)
reap_children (1, 0);
@ -1273,6 +1354,7 @@ new_job (file)
c->command_ptr = 0;
c->environment = 0;
c->sh_batch_file = NULL;
c->job_token = 0;
/* Fetch the first command line to be run. */
if (job_next_command (c))

5
job.h
View File

@ -1,5 +1,5 @@
/* Definitions for managing subprocesses in GNU Make.
Copyright (C) 1992, 1993, 1996 Free Software Foundation, Inc.
Copyright (C) 1992, 1993, 1996, 1999 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
@ -39,13 +39,14 @@ struct child
int efn; /* Completion event flag number */
int cstatus; /* Completion status */
#endif
char *sh_batch_file; /* Script file for shell commands */
unsigned int remote:1; /* Nonzero if executing remotely. */
unsigned int noerror:1; /* Nonzero if commands contained a `-'. */
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
char *sh_batch_file; /* Script file for shell commands */
char job_token; /* The token read from the job pipe. */
};
extern struct child *children;

418
main.c
View File

@ -1,5 +1,5 @@
/* Argument parsing and main program of GNU Make.
Copyright (C) 1988,89,90,91,94,95,96,97,98 Free Software Foundation, Inc.
Copyright (C) 1988,89,90,91,94,95,96,97,98,99 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
@ -34,6 +34,9 @@ MA 02111-1307, USA. */
#include <windows.h>
#include "pathstuff.h"
#endif
#if defined(MAKE_JOBSERVER) && defined(HAVE_FCNTL_H)
# include <fcntl.h>
#endif
#ifdef _AMIGA
int __stack = 20000; /* Make sure we have 20K of stack space */
@ -83,6 +86,7 @@ struct command_switch
flag, /* Turn int flag on. */
flag_off, /* Turn int flag off. */
string, /* One string per switch. */
int_string, /* One string. */
positive_int, /* A positive integer. */
floating, /* A floating-point number (double). */
ignore /* Ignored. */
@ -190,9 +194,16 @@ static struct stringlist *makefiles = 0;
unsigned int job_slots = 1;
unsigned int default_job_slots = 1;
/* Value of job_slots that means no limit. */
static char *job_slots_str = "1";
#ifndef MAKE_JOBSERVER
/* Value of job_slots that means no limit. */
static unsigned int inf_jobs = 0;
#endif
/* File descriptors for the jobs pipe. */
int job_fds[2] = { -1, -1 };
/* Maximum load average at which multiple jobs will be run.
Negative values mean unlimited, while zero means limit to
@ -264,8 +275,13 @@ static const struct command_switch switches[] =
{ 'I', string, (char *) &include_directories, 1, 1, 0, 0, 0,
"include-dir", "DIRECTORY",
"Search DIRECTORY for included makefiles" },
{ 'j', positive_int, (char *) &job_slots, 1, 1, 0,
{ 'j',
#ifndef MAKE_JOBSERVER
positive_int, (char *) &job_slots, 1, 1, 0,
(char *) &inf_jobs, (char *) &default_job_slots,
#else
int_string, (char *)&job_slots_str, 1, 1, 0, "0", "1",
#endif
"jobs", "N",
"Allow N jobs at once; infinite jobs with no arg" },
{ 'k', flag, (char *) &keep_going_flag, 1, 1, 0,
@ -1144,13 +1160,19 @@ int main (int argc, char ** argv)
}
}
#ifndef HAVE_WAIT_NOHANG
#if defined(MAKE_JOBSERVER) || !defined(HAVE_WAIT_NOHANG)
/* If we don't have a hanging wait we have to fall back to old, broken
functionality here and rely on the signal handler and counting
children.
Also, if we're using the jobs pipe we need a signal handler so that
SIGCHLD is not ignored; we need it to interrupt select(2) in
job.c:start_waiting_job() if we're waiting on the pipe for a token. */
{
extern RETSIGTYPE child_handler PARAMS ((int sig));
/* Set up to handle children dying. This must be done before
reading in the makefiles so that `shell' function calls will work.
Note we only do this if we have to. */
reading in the makefiles so that `shell' function calls will work. */
# if defined SIGCHLD
(void) signal (SIGCHLD, child_handler);
# endif
@ -1236,6 +1258,59 @@ int main (int argc, char ** argv)
decode_env_switches ("MFLAGS", 6);
#endif
#ifdef MAKE_JOBSERVER
/* If extended jobs are available then the -j option can have one of 4
formats: (1) not specified: default is "1"; (2) specified with no
value: default is "0" (infinite); (3) specified with a single
value: this means the user wants N job slots; or (4) specified with
2 values separated by commas. The latter means we're a submake and
the two values are the read and write FDs, respectively, for the
pipe. Note this last form is undocumented for the user!
*/
sscanf(job_slots_str, "%d", &job_slots);
{
char *cp = index(job_slots_str, ',');
if (cp && sscanf(cp+1, "%d", &job_fds[1]) == 1)
{
job_fds[0] = job_slots;
job_slots = 0;
}
}
/* In case #3 above, set up the pipe and set up the submake options
properly. */
if (job_slots > 1)
{
char buf[(sizeof("1024")*2)+1];
char c = '0';
if (pipe(job_fds) < 0)
pfatal_with_name("creating jobs pipe");
/* Set the read FD to nonblocking; we'll use select() to wait
for it in job.c. */
fcntl (job_fds[0], F_SETFL, O_NONBLOCK);
for (; job_slots; --job_slots)
{
write(job_fds[1], &c, 1);
if (c == '9')
c = 'a';
else if (c == 'z')
c = 'A';
else if (c == 'Z')
c = '0'; /* Start over again!! */
else
++c;
}
sprintf(buf, "%d,%d", job_fds[0], job_fds[1]);
job_slots_str = xstrdup(buf);
}
#endif
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
define_makeflags (1, 0);
@ -1650,6 +1725,7 @@ init_switches ()
long_options[i].has_arg = no_argument;
break;
case int_string:
case string:
case positive_int:
case floating:
@ -1742,156 +1818,13 @@ handle_non_switch_argument (arg, env)
}
}
/* Decode switches from ARGC and ARGV.
They came from the environment if ENV is nonzero. */
/* Print a nice usage method. */
static void
decode_switches (argc, argv, env)
int argc;
char **argv;
int env;
print_usage (bad)
int bad;
{
int bad = 0;
register const struct command_switch *cs;
register struct stringlist *sl;
register int c;
/* getopt does most of the parsing for us.
First, get its vectors set up. */
init_switches ();
/* Let getopt produce error messages for the command line,
but not for options from the environment. */
opterr = !env;
/* Reset getopt's state. */
optind = 0;
while (optind < argc)
{
/* Parse the next argument. */
c = getopt_long (argc, argv, options, long_options, (int *) 0);
if (c == EOF)
/* End of arguments, or "--" marker seen. */
break;
else if (c == 1)
/* An argument not starting with a dash. */
handle_non_switch_argument (optarg, env);
else if (c == '?')
/* Bad option. We will print a usage message and die later.
But continue to parse the other options so the user can
see all he did wrong. */
bad = 1;
else
for (cs = switches; cs->c != '\0'; ++cs)
if (cs->c == c)
{
/* Whether or not we will actually do anything with
this switch. We test this individually inside the
switch below rather than just once outside it, so that
options which are to be ignored still consume args. */
int doit = !env || cs->env;
switch (cs->type)
{
default:
abort ();
case ignore:
break;
case flag:
case flag_off:
if (doit)
*(int *) cs->value_ptr = cs->type == flag;
break;
case string:
if (!doit)
break;
if (optarg == 0)
optarg = cs->noarg_value;
sl = *(struct stringlist **) cs->value_ptr;
if (sl == 0)
{
sl = (struct stringlist *)
xmalloc (sizeof (struct stringlist));
sl->max = 5;
sl->idx = 0;
sl->list = (char **) xmalloc (5 * sizeof (char *));
*(struct stringlist **) cs->value_ptr = sl;
}
else if (sl->idx == sl->max - 1)
{
sl->max += 5;
sl->list = (char **)
xrealloc ((char *) sl->list,
sl->max * sizeof (char *));
}
sl->list[sl->idx++] = optarg;
sl->list[sl->idx] = 0;
break;
case positive_int:
if (optarg == 0 && argc > optind
&& isdigit (argv[optind][0]))
optarg = argv[optind++];
if (!doit)
break;
if (optarg != 0)
{
int i = atoi (optarg);
if (i < 1)
{
if (doit)
error (NILF, "the `-%c' option requires a \
positive integral argument",
cs->c);
bad = 1;
}
else
*(unsigned int *) cs->value_ptr = i;
}
else
*(unsigned int *) cs->value_ptr
= *(unsigned int *) cs->noarg_value;
break;
#ifndef NO_FLOAT
case floating:
if (optarg == 0 && optind < argc
&& (isdigit (argv[optind][0]) || argv[optind][0] == '.'))
optarg = argv[optind++];
if (doit)
*(double *) cs->value_ptr
= (optarg != 0 ? atof (optarg)
: *(double *) cs->noarg_value);
break;
#endif
}
/* We've found the switch. Stop looking. */
break;
}
}
/* There are no more options according to getting getopt, but there may
be some arguments left. Since we have asked for non-option arguments
to be returned in order, this only happens when there is a "--"
argument to prevent later arguments from being options. */
while (optind < argc)
handle_non_switch_argument (argv[optind++], env);
if (!env && (bad || print_usage_flag))
{
/* Print a nice usage message. */
FILE *usageto;
if (print_version_flag)
@ -1980,7 +1913,172 @@ positive integral argument",
- DESCRIPTION_COLUMN,
buf, cs->description);
}
}
/* Decode switches from ARGC and ARGV.
They came from the environment if ENV is nonzero. */
static void
decode_switches (argc, argv, env)
int argc;
char **argv;
int env;
{
int bad = 0;
register const struct command_switch *cs;
register struct stringlist *sl;
register int c;
/* getopt does most of the parsing for us.
First, get its vectors set up. */
init_switches ();
/* Let getopt produce error messages for the command line,
but not for options from the environment. */
opterr = !env;
/* Reset getopt's state. */
optind = 0;
while (optind < argc)
{
/* Parse the next argument. */
c = getopt_long (argc, argv, options, long_options, (int *) 0);
if (c == EOF)
/* End of arguments, or "--" marker seen. */
break;
else if (c == 1)
/* An argument not starting with a dash. */
handle_non_switch_argument (optarg, env);
else if (c == '?')
/* Bad option. We will print a usage message and die later.
But continue to parse the other options so the user can
see all he did wrong. */
bad = 1;
else
for (cs = switches; cs->c != '\0'; ++cs)
if (cs->c == c)
{
/* Whether or not we will actually do anything with
this switch. We test this individually inside the
switch below rather than just once outside it, so that
options which are to be ignored still consume args. */
int doit = !env || cs->env;
switch (cs->type)
{
default:
abort ();
case ignore:
break;
case flag:
case flag_off:
if (doit)
*(int *) cs->value_ptr = cs->type == flag;
break;
case int_string:
if (optarg == 0 && argc > optind
&& isdigit (argv[optind][0]))
optarg = argv[optind++];
if (!doit)
break;
if (optarg == 0)
optarg = cs->noarg_value;
*(char **)cs->value_ptr = optarg;
break;
case string:
if (!doit)
break;
if (optarg == 0)
optarg = cs->noarg_value;
sl = *(struct stringlist **) cs->value_ptr;
if (sl == 0)
{
sl = (struct stringlist *)
xmalloc (sizeof (struct stringlist));
sl->max = 5;
sl->idx = 0;
sl->list = (char **) xmalloc (5 * sizeof (char *));
*(struct stringlist **) cs->value_ptr = sl;
}
else if (sl->idx == sl->max - 1)
{
sl->max += 5;
sl->list = (char **)
xrealloc ((char *) sl->list,
sl->max * sizeof (char *));
}
sl->list[sl->idx++] = optarg;
sl->list[sl->idx] = 0;
break;
case positive_int:
if (optarg == 0 && argc > optind
&& isdigit (argv[optind][0]))
optarg = argv[optind++];
if (!doit)
break;
if (optarg != 0)
{
int i = atoi (optarg);
if (i < 1)
{
if (doit)
error (NILF, "the `-%c' option requires a \
positive integral argument",
cs->c);
bad = 1;
}
else
*(unsigned int *) cs->value_ptr = i;
}
else
*(unsigned int *) cs->value_ptr
= *(unsigned int *) cs->noarg_value;
break;
#ifndef NO_FLOAT
case floating:
if (optarg == 0 && optind < argc
&& (isdigit (argv[optind][0]) || argv[optind][0] == '.'))
optarg = argv[optind++];
if (doit)
*(double *) cs->value_ptr
= (optarg != 0 ? atof (optarg)
: *(double *) cs->noarg_value);
break;
#endif
}
/* We've found the switch. Stop looking. */
break;
}
}
/* There are no more options according to getting getopt, but there may
be some arguments left. Since we have asked for non-option arguments
to be returned in order, this only happens when there is a "--"
argument to prevent later arguments from being options. */
while (optind < argc)
handle_non_switch_argument (argv[optind++], env);
if (!env && (bad || print_usage_flag))
{
print_usage(bad);
die (bad ? 2 : 0);
}
}
@ -2193,6 +2291,22 @@ define_makeflags (all, makefile)
break;
#endif
case int_string:
if (all)
{
char *vp = *(char **)cs->value_ptr;
if (cs->default_value != 0
&& streq(vp, cs->default_value))
break;
if (cs->noarg_value != 0
&& streq(vp, cs->noarg_value))
ADD_FLAG("", 0); /* Optional value omitted; see below. */
else
ADD_FLAG(vp, strlen(vp));
}
break;
case string:
if (all)
{

3
make.h
View File

@ -1,5 +1,5 @@
/* Miscellaneous global declarations and portability cruft for GNU Make.
Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.
Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
@ -458,6 +458,7 @@ extern int clock_skew_detected;
extern int batch_mode_shell;
extern unsigned int job_slots;
extern int job_fds[2];
#ifndef NO_FLOAT
extern double max_load_average;
#else

View File

@ -10,8 +10,8 @@
@set RCSID $Id$
@set EDITION 0.53
@set VERSION 3.78
@set UPDATED 22 March 1999
@set UPDATE-MONTH March 1999
@set UPDATED 14 April 1999
@set UPDATE-MONTH April 1999
@comment The ISBN number might need to change on next publication.
@set ISBN 1-882114-80-9 @c CHANGE THIS BEFORE PRINTING AGAIN! --psmith 16jul98
@ -24,12 +24,12 @@
@c Combine the program and concept indices:
@syncodeindex pg cp
@ifinfo
@dircategory The GNU make utility
@dircategory GNU Packages
@direntry
* Make: (make.info). The GNU make utility.
* Make: (make). Remake files automatically.
@end direntry
@ifinfo
This file documents the GNU Make utility, which determines
automatically which pieces of a large program need to be recompiled,
and issues the commands to recompile them.
@ -3032,8 +3032,8 @@ there is no limit on the number of job slots. The default number of job
slots is one, which means serial execution (one thing at a time).
One unpleasant consequence of running several commands simultaneously is
that output from all of the commands comes when the commands send it, so
messages from different commands may be interspersed.
that output generated by the commands appears whenever each command
sends it, so messages from different commands may be interspersed.
Another problem is that two processes cannot both take input from the
same device; so to make sure that only one command tries to take input
@ -3057,6 +3057,10 @@ standard input at all if you are using the parallel execution feature; but
if you are not using this feature, then standard input works normally in
all commands.
Finally, handling recursive @code{make} invocations raises issues. For
more information on this, see
@ref{Options/Recursion, ,Communicating Options to a Sub-@code{make}}.
If a command fails (is killed by a signal or exits with a nonzero
status), and errors are not ignored for that command
(@pxref{Errors, ,Errors in Commands}),
@ -3546,13 +3550,22 @@ into @code{MAKEFLAGS}; these options are not passed down.@refill
@cindex recursion, and @code{-j}
@cindex job slots, and recursion
The @samp{-j} option is a special case (@pxref{Parallel, ,Parallel Execution}).
If you set it to some numeric value, @samp{-j 1} is always put into
@code{MAKEFLAGS} instead of the value you specified. This is because if
the @w{@samp{-j}} option were passed down to sub-@code{make}s, you would
get many more jobs running in parallel than you asked for. If you give
@samp{-j} with no numeric argument, meaning to run as many jobs as
possible in parallel, this is passed down, since multiple infinities are
no more than one.@refill
If you set it to some numeric value @samp{N} and your operating system
supports it (most any UNIX system will; others typically won't), the
parent @code{make} and all the sub-@code{make}s will communicate to
ensure that there are only @samp{N} jobs running at the same time
between them all. Note that any job that is marked recursive
(@pxref{Instead of Execution, ,Instead of Executing the Commands})
doesn't count against the total jobs (otherwise we could get @samp{N}
sub-@code{make}s running and have no slots left over for any real work!)
If your operating system doesn't support the above communication, then
@samp{-j 1} is always put into @code{MAKEFLAGS} instead of the value you
specified. This is because if the @w{@samp{-j}} option were passed down
to sub-@code{make}s, you would get many more jobs running in parallel
than you asked for. If you give @samp{-j} with no numeric argument,
meaning to run as many jobs as possible in parallel, this is passed
down, since multiple infinities are no more than one.@refill
If you do not want to pass the other flags down, you must change the
value of @code{MAKEFLAGS}, like this: