mirror of
https://github.com/mirror/make.git
synced 2025-02-04 08:40:27 +08:00
* Fixups to the make man page
* Minor syntax cleanups in the manual * In non-maintainer mode set NDEBUG to disable assert() * Performance improvements in strcache: Build Info 1000 2000 4000 3.82 -g 2.61s 8.85s 33.52s 3.82 -O2 1.90s 7.62s 27.82s New -g (with asserts) 1.03s 2.31s 5.79s New -O2 (no asserts) 0.65s 1.50s 3.52s
This commit is contained in:
parent
ae2ab76fac
commit
1454a04f81
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
||||
2011-02-21 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* strcache.c (various): Increase performance based on comments
|
||||
from Ralf Wildenhues <Ralf.Wildenhues@gmx.de>. Stop looking for
|
||||
a buffer when we find the first one that fits, not the best fit.
|
||||
If there is not enough free space in a buffer move it to a
|
||||
separate list so we don't have to walk it again.
|
||||
* make.h (NDEBUG): Turn off asserts unless maintainer mode is set.
|
||||
(strcache_add_len, strcache_setbufsize): Use unsigned length/size.
|
||||
* maintMakefile (AM_CPPFLAGS): Enable MAKE_MAINTAINER_MODE.
|
||||
|
||||
* remake.c (complain): Move translation lookups closer to use.
|
||||
|
||||
2011-02-13 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* doc/make.texi: Clean up references to "static" variables and
|
||||
semicolon errors. Patch from Michael Witten <mfwitten@gmail.com>.
|
||||
|
||||
2010-12-27 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* make.1: Update the header/footer info in the man page.
|
||||
|
||||
2010-11-28 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* read.c (record_target_var): Don't reset v if it's the same as
|
||||
|
@ -1487,11 +1487,11 @@ first (unescaped) variable reference to @var{ONEVAR} is expanded,
|
||||
while the second (escaped) variable reference is simply unescaped,
|
||||
without being recognized as a variable reference. Now during the
|
||||
secondary expansion the first word is expanded again but since it
|
||||
contains no variable or function references it remains the static
|
||||
value @file{onefile}, while the second word is now a normal reference
|
||||
to the variable @var{TWOVAR}, which is expanded to the value
|
||||
@file{twofile}. The final result is that there are two prerequisites,
|
||||
@file{onefile} and @file{twofile}.
|
||||
contains no variable or function references it remains the value
|
||||
@file{onefile}, while the second word is now a normal reference to the
|
||||
variable @var{TWOVAR}, which is expanded to the value @file{twofile}.
|
||||
The final result is that there are two prerequisites, @file{onefile}
|
||||
and @file{twofile}.
|
||||
|
||||
Obviously, this is not a very interesting case since the same result
|
||||
could more easily have been achieved simply by having both variables
|
||||
@ -5846,13 +5846,13 @@ Multiple @var{target} values create a target-specific variable value for
|
||||
each member of the target list individually.
|
||||
|
||||
The @var{variable-assignment} can be any valid form of assignment;
|
||||
recursive (@samp{=}), static (@samp{:=}), appending (@samp{+=}), or
|
||||
recursive (@samp{=}), simple (@samp{:=}), appending (@samp{+=}), or
|
||||
conditional (@samp{?=}). All variables that appear within the
|
||||
@var{variable-assignment} are evaluated within the context of the
|
||||
target: thus, any previously-defined target-specific variable values
|
||||
will be in effect. Note that this variable is actually distinct from
|
||||
any ``global'' value: the two variables do not have to have the same
|
||||
flavor (recursive vs.@: static).
|
||||
flavor (recursive vs.@: simple).
|
||||
|
||||
Target-specific variables have the same priority as any other makefile
|
||||
variable. Variables provided on the command line (and in the
|
||||
@ -6512,7 +6512,9 @@ be substituted.
|
||||
@cindex arguments of functions
|
||||
@cindex functions, syntax of
|
||||
|
||||
A function call resembles a variable reference. It looks like this:
|
||||
A function call resembles a variable reference. It can appear
|
||||
anywhere a variable reference can appear, and it is expanded using the
|
||||
same rules as variable references. A function call looks like this:
|
||||
|
||||
@example
|
||||
$(@var{function} @var{arguments})
|
||||
@ -7344,7 +7346,7 @@ The syntax of the @code{value} function is:
|
||||
$(value @var{variable})
|
||||
@end example
|
||||
|
||||
Note that @var{variable} is the @emph{name} of a variable; not a
|
||||
Note that @var{variable} is the @emph{name} of a variable, not a
|
||||
@emph{reference} to that variable. Therefore you would not normally
|
||||
use a @samp{$} or parentheses when writing it. (You can, however, use
|
||||
a variable reference in the name if you want the name not to be a
|
||||
@ -7455,7 +7457,7 @@ The syntax of the @code{origin} function is:
|
||||
$(origin @var{variable})
|
||||
@end example
|
||||
|
||||
Note that @var{variable} is the @emph{name} of a variable to inquire about;
|
||||
Note that @var{variable} is the @emph{name} of a variable to inquire about,
|
||||
not a @emph{reference} to that variable. Therefore you would not normally
|
||||
use a @samp{$} or parentheses when writing it. (You can, however, use a
|
||||
variable reference in the name if you want the name not to be a constant.)
|
||||
@ -7566,7 +7568,7 @@ The syntax of the @code{flavor} function is:
|
||||
$(flavor @var{variable})
|
||||
@end example
|
||||
|
||||
Note that @var{variable} is the @emph{name} of a variable to inquire about;
|
||||
Note that @var{variable} is the @emph{name} of a variable to inquire about,
|
||||
not a @emph{reference} to that variable. Therefore you would not normally
|
||||
use a @samp{$} or parentheses when writing it. (You can, however, use a
|
||||
variable reference in the name if you want the name not to be a constant.)
|
||||
|
@ -5,6 +5,9 @@
|
||||
# We like mondo-warnings!
|
||||
AM_CFLAGS += -Wall -Wextra -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wbad-function-cast
|
||||
|
||||
MAKE_MAINTAINER_MODE := -DMAKE_MAINTAINER_MODE
|
||||
AM_CPPFLAGS += $(MAKE_MAINTAINER_MODE)
|
||||
|
||||
# I want this one but I have to wait for the const cleanup!
|
||||
# -Wwrite-strings
|
||||
|
||||
|
168
make.1
168
make.1
@ -1,49 +1,35 @@
|
||||
.TH MAKE 1 "22 August 1989" "GNU" "LOCAL USER COMMANDS"
|
||||
.TH MAKE 1 "27 December 2010" "GNU" "User Commands"
|
||||
.SH NAME
|
||||
make \- GNU make utility to maintain groups of programs
|
||||
.SH SYNOPSIS
|
||||
.B "make "
|
||||
[
|
||||
.B \-f
|
||||
.I makefile
|
||||
] [ options ] ... [ targets ] ...
|
||||
.SH WARNING
|
||||
This man page is an extract of the documentation of GNU
|
||||
.IR make .
|
||||
It is updated only occasionally, because the GNU project does not use nroff.
|
||||
For complete, current documentation, refer to the Info file
|
||||
.B make.info
|
||||
which is made from the Texinfo source file
|
||||
.BR make.texi .
|
||||
.B make
|
||||
[\fIOPTION\fR]... [\fITARGET\fR]...
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
The purpose of the
|
||||
The
|
||||
.I make
|
||||
utility is to determine automatically which
|
||||
pieces of a large program need to be recompiled, and issue the commands to
|
||||
recompile them.
|
||||
The manual describes the GNU implementation of
|
||||
.IR make ,
|
||||
which was written by Richard Stallman and Roland McGrath, and is
|
||||
currently maintained by Paul Smith.
|
||||
Our examples show C programs, since they are most common, but you can use
|
||||
.I make
|
||||
with any programming language whose compiler can be run with a
|
||||
shell command.
|
||||
utility will determine automatically which pieces of a large program need to
|
||||
be recompiled, and issue the commands to recompile them. The manual describes
|
||||
the GNU implementation of
|
||||
.BR make ,
|
||||
which was written by Richard Stallman and Roland McGrath, and is currently
|
||||
maintained by Paul Smith. Our examples show C programs, since they are very
|
||||
common, but you can use
|
||||
.B make
|
||||
with any programming language whose compiler can be run with a shell command.
|
||||
In fact,
|
||||
.I make
|
||||
is not limited to programs.
|
||||
You can use it to describe any task where some files must be
|
||||
updated automatically from others whenever the others change.
|
||||
.B make
|
||||
is not limited to programs. You can use it to describe any task where some
|
||||
files must be updated automatically from others whenever the others change.
|
||||
.LP
|
||||
To prepare to use
|
||||
.IR make ,
|
||||
.BR make ,
|
||||
you must write a file called the
|
||||
.I makefile
|
||||
that describes the relationships among files in your program, and the
|
||||
states the commands for updating each file.
|
||||
In a program, typically the executable file is updated from object
|
||||
files, which are in turn made by compiling source files.
|
||||
that describes the relationships among files in your program, and the states
|
||||
the commands for updating each file. In a program, typically the executable
|
||||
file is updated from object files, which are in turn made by compiling source
|
||||
files.
|
||||
.LP
|
||||
Once a suitable makefile exists, each time you change some source files,
|
||||
this simple shell command:
|
||||
@ -54,16 +40,15 @@ this simple shell command:
|
||||
.sp 1
|
||||
suffices to perform all necessary recompilations.
|
||||
The
|
||||
.I make
|
||||
program uses the makefile data base and the last-modification times
|
||||
of the files to decide which of the files need to be updated.
|
||||
For each of those files, it issues the commands recorded in the data base.
|
||||
.B make
|
||||
program uses the makefile description and the last-modification times of the
|
||||
files to decide which of the files need to be updated. For each of those
|
||||
files, it issues the commands recorded in the makefile.
|
||||
.LP
|
||||
.I make
|
||||
.B make
|
||||
executes commands in the
|
||||
.I makefile
|
||||
to update
|
||||
one or more target
|
||||
to update one or more target
|
||||
.IR names ,
|
||||
where
|
||||
.I name
|
||||
@ -71,7 +56,7 @@ is typically a program.
|
||||
If no
|
||||
.B \-f
|
||||
option is present,
|
||||
.I make
|
||||
.B make
|
||||
will look for the makefiles
|
||||
.IR GNUmakefile ,
|
||||
.IR makefile ,
|
||||
@ -90,27 +75,27 @@ listing, right near other important files such as
|
||||
.IR README .)
|
||||
The first name checked,
|
||||
.IR GNUmakefile ,
|
||||
is not recommended for most makefiles.
|
||||
You should use this name if you have a makefile that is specific to GNU
|
||||
.IR make ,
|
||||
is not recommended for most makefiles. You should use this name if you have a
|
||||
makefile that is specific to GNU
|
||||
.BR make ,
|
||||
and will not be understood by other versions of
|
||||
.IR make .
|
||||
.BR make .
|
||||
If
|
||||
.I makefile
|
||||
is `\-', the standard input is read.
|
||||
.LP
|
||||
.I make
|
||||
.B make
|
||||
updates a target if it depends on prerequisite files
|
||||
that have been modified since the target was last modified,
|
||||
or if the target does not exist.
|
||||
.SH OPTIONS
|
||||
.sp 1
|
||||
.TP 0.5i
|
||||
.BR \-b , " \-m"
|
||||
\fB\-b\fR, \fB\-m\fR
|
||||
These options are ignored for compatibility with other versions of
|
||||
.IR make .
|
||||
.BR make .
|
||||
.TP 0.5i
|
||||
.BR \-B , " \-\-always\-make"
|
||||
\fB\-B\fR, \fB\-\-always\-make\fR
|
||||
Unconditionally make all targets.
|
||||
.TP 0.5i
|
||||
\fB\-C\fR \fIdir\fR, \fB\-\-directory\fR=\fIdir\fR
|
||||
@ -126,7 +111,7 @@ previous one:
|
||||
is equivalent to
|
||||
.BR "\-C " /etc.
|
||||
This is typically used with recursive invocations of
|
||||
.IR make .
|
||||
.BR make .
|
||||
.TP 0.5i
|
||||
.B \-d
|
||||
Print debugging information in addition to normal processing.
|
||||
@ -134,7 +119,7 @@ The debugging information says which files are being considered for
|
||||
remaking, which file-times are being compared and with what results,
|
||||
which files actually need to be remade, which implicit rules are
|
||||
considered and which are applied---everything interesting about how
|
||||
.I make
|
||||
.B make
|
||||
decides what to do.
|
||||
.TP 0.5i
|
||||
.BI \-\-debug "[=FLAGS]"
|
||||
@ -160,7 +145,7 @@ for details on invocation of commands, and
|
||||
.I m
|
||||
for debugging while remaking makefiles.
|
||||
.TP 0.5i
|
||||
.BR \-e , " \-\-environment\-overrides"
|
||||
\fB\-e\fR, \fB\-\-environment\-overrides\fR
|
||||
Give variables taken from the environment precedence
|
||||
over variables from makefiles.
|
||||
.TP 0.5i
|
||||
@ -169,7 +154,7 @@ Use
|
||||
.I file
|
||||
as a makefile.
|
||||
.TP 0.5i
|
||||
.BR \-i , " \-\-ignore\-errors"
|
||||
\fB\-i\fR, \fB\-\-ignore\-errors\fR
|
||||
Ignore all errors in commands executed to remake files.
|
||||
.TP 0.5i
|
||||
\fB\-I\fR \fIdir\fR, \fB\-\-include\-dir\fR=\fIdir\fR
|
||||
@ -181,13 +166,14 @@ If several
|
||||
options are used to specify several directories, the directories are
|
||||
searched in the order specified.
|
||||
Unlike the arguments to other flags of
|
||||
.IR make ,
|
||||
.BR make ,
|
||||
directories given with
|
||||
.B \-I
|
||||
flags may come directly after the flag:
|
||||
.BI \-I dir
|
||||
is allowed, as well as
|
||||
.BI "\-I " dir.
|
||||
.B \-I
|
||||
.IR dir .
|
||||
This syntax is allowed for compatibility with the C
|
||||
preprocessor's
|
||||
.B \-I
|
||||
@ -203,10 +189,10 @@ option, the last one is effective.
|
||||
If the
|
||||
.B \-j
|
||||
option is given without an argument,
|
||||
.IR make
|
||||
.BR make
|
||||
will not limit the number of jobs that can run simultaneously.
|
||||
.TP 0.5i
|
||||
.BR \-k , " \-\-keep\-going"
|
||||
\fB\-k\fR, \fB\-\-keep\-going\fR
|
||||
Continue as much as possible after an error.
|
||||
While the target that failed, and those that depend on it, cannot
|
||||
be remade, the other dependencies of these targets can be processed
|
||||
@ -219,10 +205,10 @@ others jobs running and the load average is at least
|
||||
(a floating-point number).
|
||||
With no argument, removes a previous load limit.
|
||||
.TP 0.5i
|
||||
.BR \-L , " \-\-check\-symlink\-times"
|
||||
\fB\-L\fR, \fB\-\-check\-symlink\-times\fR
|
||||
Use the latest mtime between symlinks and target.
|
||||
.TP 0.5i
|
||||
.BR \-n , " \-\-just\-print" , " \-\-dry\-run" , " \-\-recon"
|
||||
\fB\-n\fR, \fB\-\-just\-print\fR, \fB\-\-dry\-run\fR, \fB\-\-recon\fR
|
||||
Print the commands that would be executed, but do not execute them (except in
|
||||
certain circumstances).
|
||||
.TP 0.5i
|
||||
@ -234,7 +220,7 @@ on account of changes in
|
||||
.IR file .
|
||||
Essentially the file is treated as very old and its rules are ignored.
|
||||
.TP 0.5i
|
||||
.BR \-p , " \-\-print\-data\-base"
|
||||
\fB\-p\fR, \fB\-\-print\-data\-base\fR
|
||||
Print the data base (rules and variable values) that results from
|
||||
reading the makefiles; then execute as usual or as otherwise
|
||||
specified.
|
||||
@ -242,63 +228,61 @@ This also prints the version information given by the
|
||||
.B \-v
|
||||
switch (see below).
|
||||
To print the data base without trying to remake any files, use
|
||||
.B make
|
||||
.B \-p
|
||||
.BI \-f /dev/null.
|
||||
.IR "make \-p \-f/dev/null" .
|
||||
.TP 0.5i
|
||||
.BR \-q , " \-\-question"
|
||||
\fB\-q\fR, \fB\-\-question\fR
|
||||
``Question mode''.
|
||||
Do not run any commands, or print anything; just return an exit status
|
||||
that is zero if the specified targets are already up to date, nonzero
|
||||
otherwise.
|
||||
.TP 0.5i
|
||||
.BR \-r , " \-\-no\-builtin\-rules"
|
||||
\fB\-r\fR, \fB\-\-no\-builtin\-rules\fR
|
||||
Eliminate use of the built\-in implicit rules.
|
||||
Also clear out the default list of suffixes for suffix rules.
|
||||
.TP 0.5i
|
||||
.BR \-R , " \-\-no\-builtin\-variables"
|
||||
\fB\-R\fR, \fB\-\-no\-builtin\-variables\fR
|
||||
Don't define any built\-in variables.
|
||||
.TP 0.5i
|
||||
.BR \-s , " \-\-silent" , " \-\-quiet"
|
||||
\fB\-s\fR, \fB\-\-silent\fR, \fB\-\-quiet\fR
|
||||
Silent operation; do not print the commands as they are executed.
|
||||
.TP 0.5i
|
||||
.BR \-S , " \-\-no\-keep\-going" , " \-\-stop"
|
||||
\fB\-S\fR, \fB\-\-no\-keep\-going\fR, \fB\-\-stop\fR
|
||||
Cancel the effect of the
|
||||
.B \-k
|
||||
option.
|
||||
This is never necessary except in a recursive
|
||||
.I make
|
||||
.B make
|
||||
where
|
||||
.B \-k
|
||||
might be inherited from the top-level
|
||||
.I make
|
||||
.B make
|
||||
via MAKEFLAGS or if you set
|
||||
.B \-k
|
||||
in MAKEFLAGS in your environment.
|
||||
.TP 0.5i
|
||||
.BR \-t , " \-\-touch"
|
||||
\fB\-t\fR, \fB\-\-touch\fR
|
||||
Touch files (mark them up to date without really changing them)
|
||||
instead of running their commands.
|
||||
This is used to pretend that the commands were done, in order to fool
|
||||
future invocations of
|
||||
.IR make .
|
||||
.BR make .
|
||||
.TP 0.5i
|
||||
.B \-\-trace
|
||||
Print information about the commands invoked by
|
||||
.IR make.
|
||||
.BR make.
|
||||
.TP 0.5i
|
||||
.BR \-v , " \-\-version"
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Print the version of the
|
||||
.I make
|
||||
.B make
|
||||
program plus a copyright, a list of authors and a notice that there
|
||||
is no warranty.
|
||||
.TP 0.5i
|
||||
.BR \-w , " \-\-print\-directory"
|
||||
\fB\-w\fR, \fB\-\-print\-directory\fR
|
||||
Print a message containing the working directory
|
||||
before and after other processing.
|
||||
This may be useful for tracking down errors from complicated nests of
|
||||
recursive
|
||||
.I make
|
||||
.B make
|
||||
commands.
|
||||
.TP 0.5i
|
||||
.B \-\-no\-print\-directory
|
||||
@ -318,25 +302,35 @@ Without
|
||||
it is almost the same as running a
|
||||
.I touch
|
||||
command on the given file before running
|
||||
.IR make ,
|
||||
.BR make ,
|
||||
except that the modification time is changed only in the imagination of
|
||||
.IR make .
|
||||
.BR make .
|
||||
.TP 0.5i
|
||||
.B \-\-warn\-undefined\-variables
|
||||
Warn when an undefined variable is referenced.
|
||||
.SH "EXIT STATUS"
|
||||
GNU
|
||||
.I make
|
||||
.B make
|
||||
exits with a status of zero if all makefiles were successfully parsed
|
||||
and no targets that were built failed. A status of one will be returned
|
||||
if the
|
||||
.B \-q
|
||||
flag was used and
|
||||
.I make
|
||||
.B make
|
||||
determines that a target needs to be rebuilt. A status of two will be
|
||||
returned if any errors were encountered.
|
||||
.SH "SEE ALSO"
|
||||
.I "The GNU Make Manual"
|
||||
The full documentation for
|
||||
.B make
|
||||
is maintained as a Texinfo manual. If the
|
||||
.B info
|
||||
and
|
||||
.B make
|
||||
programs are properly installed at your site, the command
|
||||
.IP
|
||||
.B info make
|
||||
.PP
|
||||
should give you access to the complete manual.
|
||||
.SH BUGS
|
||||
See the chapter `Problems and Bugs' in
|
||||
.IR "The GNU Make Manual" .
|
||||
@ -345,9 +339,9 @@ This manual page contributed by Dennis Morse of Stanford University.
|
||||
Further updates contributed by Mike Frysinger. It has been reworked by Roland
|
||||
McGrath. Maintained by Paul Smith.
|
||||
.SH "COPYRIGHT"
|
||||
Copyright (C) 1992, 1993, 1996, 1999, 2007, 2010 Free Software Foundation, Inc.
|
||||
This file is part of GNU
|
||||
.IR make .
|
||||
Copyright \(co 1992, 1993, 1996, 1999, 2007, 2010 Free Software Foundation, Inc.
|
||||
This file is part of
|
||||
.IR "GNU make" .
|
||||
.LP
|
||||
GNU Make is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
|
15
make.h
15
make.h
@ -43,6 +43,12 @@ char *alloca ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Disable assert() unless we're a maintainer.
|
||||
Some asserts are compute-intensive. */
|
||||
#ifndef MAKE_MAINTAINER_MODE
|
||||
# define NDEBUG 1
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CRAY
|
||||
/* This must happen before #include <signal.h> so
|
||||
@ -60,13 +66,12 @@ char *alloca ();
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef HAVE_SYS_TIMEB_H
|
||||
/* SCO 3.2 "devsys 4.2" has a prototype for `ftime' in <time.h> that bombs
|
||||
unless <sys/timeb.h> has been included first. Does every system have a
|
||||
<sys/timeb.h>? If any does not, configure should check for it. */
|
||||
unless <sys/timeb.h> has been included first. */
|
||||
# include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
@ -456,8 +461,8 @@ void strcache_init (void);
|
||||
void strcache_print_stats (const char *prefix);
|
||||
int strcache_iscached (const char *str);
|
||||
const char *strcache_add (const char *str);
|
||||
const char *strcache_add_len (const char *str, int len);
|
||||
int strcache_setbufsize (int size);
|
||||
const char *strcache_add_len (const char *str, unsigned int len);
|
||||
int strcache_setbufsize (unsigned int size);
|
||||
|
||||
#ifdef HAVE_VFORK_H
|
||||
# include <vfork.h>
|
||||
|
10
remake.c
10
remake.c
@ -355,11 +355,6 @@ update_file (struct file *file, unsigned int depth)
|
||||
static void
|
||||
complain (struct file *file)
|
||||
{
|
||||
const char *msg_noparent
|
||||
= _("%sNo rule to make target `%s'%s");
|
||||
const char *msg_parent
|
||||
= _("%sNo rule to make target `%s', needed by `%s'%s");
|
||||
|
||||
/* If this file has no_diag set then it means we tried to update it
|
||||
before in the dontcare mode and failed. The target that actually
|
||||
failed is not necessarily this file but could be one of its direct
|
||||
@ -379,6 +374,11 @@ complain (struct file *file)
|
||||
|
||||
if (d == 0)
|
||||
{
|
||||
const char *msg_noparent
|
||||
= _("%sNo rule to make target `%s'%s");
|
||||
const char *msg_parent
|
||||
= _("%sNo rule to make target `%s', needed by `%s'%s");
|
||||
|
||||
/* Didn't find any dependencies to complain about. */
|
||||
if (!keep_going_flag)
|
||||
{
|
||||
|
201
strcache.c
201
strcache.c
@ -16,29 +16,40 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "make.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
/* The size (in bytes) of each cache buffer.
|
||||
Try to pick something that will map well into the heap. */
|
||||
#define CACHE_BUFFER_SIZE (8192 - 16)
|
||||
|
||||
|
||||
/* A string cached here will never be freed, so we don't need to worry about
|
||||
reference counting. We just store the string, and then remember it in a
|
||||
hash so it can be looked up again. */
|
||||
|
||||
typedef unsigned short int sc_buflen_t;
|
||||
|
||||
struct strcache {
|
||||
struct strcache *next; /* The next block of strings. */
|
||||
char *end; /* Pointer to the beginning of the free space. */
|
||||
int count; /* # of strings in this buffer (for stats). */
|
||||
int bytesfree; /* The amount of the buffer that is free. */
|
||||
struct strcache *next; /* The next block of strings. Must be first! */
|
||||
sc_buflen_t end; /* Offset to the beginning of free space. */
|
||||
sc_buflen_t bytesfree; /* Free space left in this buffer. */
|
||||
sc_buflen_t count; /* # of strings in this buffer (for stats). */
|
||||
char buffer[1]; /* The buffer comes after this. */
|
||||
};
|
||||
|
||||
static int bufsize = CACHE_BUFFER_SIZE;
|
||||
/* The size (in bytes) of each cache buffer.
|
||||
Try to pick something that will map well into the heap.
|
||||
This must be able to be represented by a short int (<=65535). */
|
||||
#define CACHE_BUFFER_BASE (8192)
|
||||
#define CACHE_BUFFER_ALLOC(_s) ((_s) - (2 * sizeof (size_t)))
|
||||
#define CACHE_BUFFER_OFFSET (offsetof (struct strcache, buffer))
|
||||
#define CACHE_BUFFER_SIZE(_s) (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET)
|
||||
|
||||
static sc_buflen_t bufsize = CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE);
|
||||
static struct strcache *strcache = NULL;
|
||||
static struct strcache *fullcache = NULL;
|
||||
|
||||
static unsigned long total_buffers = 0;
|
||||
static unsigned long total_strings = 0;
|
||||
static unsigned long total_size = 0;
|
||||
|
||||
/* Add a new buffer to the cache. Add it at the front to reduce search time.
|
||||
This can also increase the overhead, since it's less likely that older
|
||||
@ -49,50 +60,65 @@ static struct strcache *
|
||||
new_cache()
|
||||
{
|
||||
struct strcache *new;
|
||||
new = xmalloc (sizeof (*new) + bufsize);
|
||||
new->end = new->buffer;
|
||||
new = xmalloc (bufsize + CACHE_BUFFER_OFFSET);
|
||||
new->end = 0;
|
||||
new->count = 0;
|
||||
new->bytesfree = bufsize;
|
||||
|
||||
new->next = strcache;
|
||||
strcache = new;
|
||||
|
||||
++total_buffers;
|
||||
return new;
|
||||
}
|
||||
|
||||
static const char *
|
||||
add_string(const char *str, int len)
|
||||
add_string (const char *str, unsigned int len)
|
||||
{
|
||||
struct strcache *best = NULL;
|
||||
char *res;
|
||||
struct strcache *sp;
|
||||
const char *res;
|
||||
struct strcache **spp = &strcache;
|
||||
/* We need space for the nul char. */
|
||||
unsigned int sz = len + 1;
|
||||
|
||||
/* If the string we want is too large to fit into a single buffer, then
|
||||
we're screwed; nothing will ever fit! Change the maximum size of the
|
||||
cache to be big enough. */
|
||||
if (len > bufsize)
|
||||
bufsize = len * 2;
|
||||
|
||||
/* First, find a cache with enough free space. We always look through all
|
||||
the blocks and choose the one with the best fit (the one that leaves the
|
||||
least amount of space free). */
|
||||
for (sp = strcache; sp != NULL; sp = sp->next)
|
||||
if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree))
|
||||
best = sp;
|
||||
no existing cache is large enough. Change the maximum size. */
|
||||
if (sz > bufsize)
|
||||
bufsize = CACHE_BUFFER_SIZE ((((sz + 1) / CACHE_BUFFER_BASE) + 1)
|
||||
* CACHE_BUFFER_BASE);
|
||||
else
|
||||
/* Find the first cache with enough free space. */
|
||||
for (; *spp != NULL; spp = &(*spp)->next)
|
||||
if ((*spp)->bytesfree > sz)
|
||||
break;
|
||||
|
||||
/* If nothing is big enough, make a new cache. */
|
||||
if (!best)
|
||||
best = new_cache();
|
||||
sp = *spp;
|
||||
if (sp == NULL)
|
||||
{
|
||||
sp = new_cache ();
|
||||
spp = &sp;
|
||||
}
|
||||
|
||||
assert (best->bytesfree > len);
|
||||
/* Add the string to this cache. */
|
||||
res = &sp->buffer[sp->end];
|
||||
memmove (res, str, len);
|
||||
res[len] = '\0';
|
||||
sp->end += sz;
|
||||
sp->bytesfree -= sz;
|
||||
++sp->count;
|
||||
|
||||
/* Add the string to the best cache. */
|
||||
res = best->end;
|
||||
memcpy (best->end, str, len);
|
||||
best->end += len;
|
||||
*(best->end++) = '\0';
|
||||
best->bytesfree -= len + 1;
|
||||
++best->count;
|
||||
/* If the amount free in this cache is less than the average string size,
|
||||
consider it full and move it to the full list. */
|
||||
++total_strings;
|
||||
total_size += sz;
|
||||
|
||||
if (sp->bytesfree < (total_size / total_strings) + 1)
|
||||
{
|
||||
*spp = (*spp)->next;
|
||||
sp->next = fullcache;
|
||||
fullcache = sp;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -128,7 +154,7 @@ add_hash (const char *str, int len)
|
||||
char *const *slot = (char *const *) hash_find_slot (&strings, str);
|
||||
const char *key = *slot;
|
||||
|
||||
/* Count the total number of adds we performed. */
|
||||
/* Count the total number of add operations we performed. */
|
||||
++total_adds;
|
||||
|
||||
if (!HASH_VACANT (key))
|
||||
@ -147,7 +173,10 @@ strcache_iscached (const char *str)
|
||||
struct strcache *sp;
|
||||
|
||||
for (sp = strcache; sp != 0; sp = sp->next)
|
||||
if (str >= sp->buffer && str < sp->end)
|
||||
if (str >= sp->buffer && str < sp->buffer + sp->end)
|
||||
return 1;
|
||||
for (sp = fullcache; sp != 0; sp = sp->next)
|
||||
if (str >= sp->buffer && str < sp->buffer + sp->end)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@ -163,7 +192,7 @@ strcache_add (const char *str)
|
||||
}
|
||||
|
||||
const char *
|
||||
strcache_add_len (const char *str, int len)
|
||||
strcache_add_len (const char *str, unsigned int len)
|
||||
{
|
||||
/* If we're not given a nul-terminated string we have to create one, because
|
||||
the hashing functions expect it. */
|
||||
@ -179,7 +208,7 @@ strcache_add_len (const char *str, int len)
|
||||
}
|
||||
|
||||
int
|
||||
strcache_setbufsize(int size)
|
||||
strcache_setbufsize(unsigned int size)
|
||||
{
|
||||
if (size > bufsize)
|
||||
bufsize = size;
|
||||
@ -198,49 +227,65 @@ strcache_init (void)
|
||||
void
|
||||
strcache_print_stats (const char *prefix)
|
||||
{
|
||||
int numbuffs = 0, numstrs = 0;
|
||||
int totsize = 0, avgsize, maxsize = 0, minsize = bufsize;
|
||||
int totfree = 0, avgfree, maxfree = 0, minfree = bufsize;
|
||||
int lastused = 0, lastfree = 0;
|
||||
const struct strcache *sp;
|
||||
unsigned long numbuffs = 0, fullbuffs = 0;
|
||||
unsigned long totfree = 0, maxfree = 0, minfree = bufsize;
|
||||
|
||||
if (strcache)
|
||||
if (! strcache)
|
||||
{
|
||||
const struct strcache *sp;
|
||||
|
||||
/* Count the first buffer separately since it's not full. */
|
||||
lastused = strcache->end - strcache->buffer;
|
||||
lastfree = strcache->bytesfree;
|
||||
|
||||
for (sp = strcache->next; sp != NULL; sp = sp->next)
|
||||
{
|
||||
int bf = sp->bytesfree;
|
||||
int sz = sp->end - sp->buffer;
|
||||
|
||||
++numbuffs;
|
||||
numstrs += sp->count;
|
||||
|
||||
totsize += sz;
|
||||
maxsize = (sz > maxsize ? sz : maxsize);
|
||||
minsize = (sz < minsize ? sz : minsize);
|
||||
|
||||
totfree += bf;
|
||||
maxfree = (bf > maxfree ? bf : maxfree);
|
||||
minfree = (bf < minfree ? bf : minfree);
|
||||
}
|
||||
printf(_("\n%s No strcache buffers\n"), prefix);
|
||||
return;
|
||||
}
|
||||
|
||||
avgsize = numbuffs ? (int)(totsize / numbuffs) : 0;
|
||||
avgfree = numbuffs ? (int)(totfree / numbuffs) : 0;
|
||||
/* Count the first buffer separately since it's not full. */
|
||||
for (sp = strcache->next; sp != NULL; sp = sp->next)
|
||||
{
|
||||
sc_buflen_t bf = sp->bytesfree;
|
||||
|
||||
printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"),
|
||||
prefix, numstrs, total_adds, (total_adds - numstrs));
|
||||
printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"),
|
||||
prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize));
|
||||
printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
|
||||
prefix, totsize, lastused, maxsize, minsize, avgsize);
|
||||
printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
|
||||
prefix, totfree, lastfree, maxfree, minfree, avgfree);
|
||||
totfree += bf;
|
||||
maxfree = (bf > maxfree ? bf : maxfree);
|
||||
minfree = (bf < minfree ? bf : minfree);
|
||||
|
||||
fputs (_("\n# strcache hash-table stats:\n# "), stdout);
|
||||
++numbuffs;
|
||||
}
|
||||
for (sp = fullcache; sp != NULL; sp = sp->next)
|
||||
{
|
||||
sc_buflen_t bf = sp->bytesfree;
|
||||
|
||||
totfree += bf;
|
||||
maxfree = (bf > maxfree ? bf : maxfree);
|
||||
minfree = (bf < minfree ? bf : minfree);
|
||||
|
||||
++numbuffs;
|
||||
++fullbuffs;
|
||||
}
|
||||
|
||||
/* Make sure we didn't lose any buffers. */
|
||||
assert (total_buffers == numbuffs + 1);
|
||||
|
||||
printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"),
|
||||
prefix, numbuffs + 1, fullbuffs, total_strings, total_size,
|
||||
(total_size / total_strings));
|
||||
|
||||
printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"),
|
||||
prefix, bufsize, strcache->end, strcache->count,
|
||||
(strcache->end / strcache->count));
|
||||
|
||||
if (numbuffs)
|
||||
{
|
||||
unsigned long sz = total_size - bufsize;
|
||||
unsigned long cnt = total_strings - strcache->count;
|
||||
sc_buflen_t avgfree = totfree / numbuffs;
|
||||
|
||||
printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"),
|
||||
prefix, sz, cnt, sz / cnt);
|
||||
|
||||
printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"),
|
||||
prefix, totfree, maxfree, minfree, avgfree);
|
||||
}
|
||||
|
||||
printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"),
|
||||
prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds));
|
||||
fputs (_("# hash-table stats:\n# "), stdout);
|
||||
hash_print_stats (&strings, stdout);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user