Import GNU Make 4.4.1

Landlock Make hasn't been working well on AARCH64 systems. Let's do this
over the right way, using our new build tools.
This commit is contained in:
Justine Tunney 2023-11-30 20:50:10 -08:00
parent 9315ebbfd9
commit 14bf57180f
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
88 changed files with 13931 additions and 16191 deletions

View file

@ -98,7 +98,7 @@ errno_t ttyname_r(int fd, char *buf, size_t size) {
} }
} }
errno = e; errno = e;
STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)size, buf, STRACE("ttyname_r(%d, %#.*hhs) → %s", fd, (int)strnlen(buf, size), buf,
!res ? "0" : _strerrno(res)); !res ? "0" : _strerrno(res));
return res; return res;
} }

View file

@ -1,90 +0,0 @@
-----------------------------------
GNU make development up to version 3.75 by:
Roland McGrath <roland@gnu.org>
Development starting with GNU make 3.76 by:
Paul D. Smith <psmith@gnu.org>
Additional development starting with GNU make 3.81 by:
Boris Kolpackov <boris@kolpackov.net>
GNU Make User's Manual
Written by:
Richard M. Stallman <rms@gnu.org>
Edited by:
Roland McGrath <roland@gnu.org>
Bob Chassell <bob@gnu.org>
Melissa Weisshaus <melissa@gnu.org>
Paul D. Smith <psmith@gnu.org>
-----------------------------------
GNU make porting efforts:
Port to VMS by:
Klaus Kaempf <kkaempf@progis.de>
Hartmut Becker <Hartmut.Becker@hp.com>
Archive support/Bug fixes by:
John W. Eaton <jwe@bevo.che.wisc.edu>
Martin Zinser <zinser@decus.decus.de>
Port to Amiga by:
Aaron Digulla <digulla@fh-konstanz.de>
Port to MS-DOS (DJGPP), OS/2, and MS-Windows (native/MinGW) by:
DJ Delorie <dj@delorie.com>
Rob Tulloh <rob_tulloh@tivoli.com>
Eli Zaretskii <eliz@gnu.org>
Jonathan Grant <jg@jguk.org>
Andreas Beuning <andreas.buening@nexgo.de>
Earnie Boyd <earnie@uses.sf.net>
Troy Runkel <Troy.Runkel@mathworks.com>
-----------------------------------
Other contributors:
Janet Carson <janet_carson@tivoli.com>
Howard Chu <hyc@highlandsun.com>
Ludovic Courtès <ludo@gnu.org>
Paul Eggert <eggert@twinsun.com>
Ramon Garcia Fernandez <ramon.garcia.f@gmail.com>
Klaus Heinz <kamar@ease.rhein-main.de>
Michael Joosten
Jim Kelton <jim_kelton@tivoli.com>
David Lubbren <uhay@rz.uni-karlsruhe.de>
Tim Magill <tim.magill@telops.gte.com>
Markus Mauhart <qwe123@chello.at>
Greg McGary <greg@mcgary.org>
Thien-Thi Nguyen <ttn@gnuvola.org>
Thomas Riedl <thomas.riedl@siemens.com>
Han-Wen Nienhuys <hanwen@cs.uu.nl>
Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Carl Staelin (Princeton University)
Ian Stewartson (Data Logic Limited)
David A. Wheeler <dwheeler@dwheeler.com>
David Boyce <dsb@boyski.com>
Frank Heckenbach <f.heckenbach@fh-soft.de>
Kaz Kylheku <kaz@kylheku.com>
Christof Warlich <cwarlich@gmx.de>
With suggestions/comments/bug reports from a cast of ... well ...
hundreds, anyway :)
-------------------------------------------------------------------------------
Copyright (C) 1997-2020 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -14,67 +14,42 @@ THIRD_PARTY_MAKE_A = \
o/$(MODE)/third_party/make/make.a o/$(MODE)/third_party/make/make.a
THIRD_PARTY_MAKE_HDRS = \ THIRD_PARTY_MAKE_HDRS = \
third_party/make/filename.h \
third_party/make/dirname.h \
third_party/make/stddef.h \
third_party/make/error.h \
third_party/make/gnumake.h \
third_party/make/gettext.h \
third_party/make/stdlib.h \
third_party/make/xalloc.h \
third_party/make/xalloc-oversized.h \
third_party/make/os.h \
third_party/make/stdint.h \
third_party/make/fd-hook.h \
third_party/make/job.h \
third_party/make/unistd.h \
third_party/make/getprogname.h \
third_party/make/config.h \
third_party/make/concat-filename.h \ third_party/make/concat-filename.h \
third_party/make/findprog.h \ third_party/make/commands.h \
third_party/make/intprops.h \ third_party/make/glob.h \
third_party/make/exitfail.h \ third_party/make/config.h \
third_party/make/alloca.h \
third_party/make/hash.h \
third_party/make/rule.h \
third_party/make/filedef.h \
third_party/make/fcntl.h \
third_party/make/stdio.h \
third_party/make/variable.h \
third_party/make/debug.h \ third_party/make/debug.h \
third_party/make/output.h \
third_party/make/getopt.h \
third_party/make/dep.h \ third_party/make/dep.h \
third_party/make/commands.h third_party/make/findprog.h \
third_party/make/filedef.h \
third_party/make/filename.h \
third_party/make/getopt.h \
third_party/make/gettext.h \
third_party/make/gnumake.h \
third_party/make/hash.h \
third_party/make/job.h \
third_party/make/makeint.h \
third_party/make/mkconfig.h \
third_party/make/mkcustom.h \
third_party/make/os.h \
third_party/make/output.h \
third_party/make/rule.h \
third_party/make/shuffle.h \
third_party/make/variable.h
THIRD_PARTY_MAKE_INCS = \ THIRD_PARTY_MAKE_INCS = \
third_party/make/makeint.inc third_party/make/makeint.h
THIRD_PARTY_MAKE_CHECKS = \ THIRD_PARTY_MAKE_CHECKS = \
$(THIRD_PARTY_MAKE_A).pkg $(THIRD_PARTY_MAKE_A).pkg
# libgnu.a recipe THIRD_PARTY_MAKE_SRCS = \
THIRD_PARTY_MAKE_SRCS_LIB = \ third_party/make/glob.c \
third_party/make/basename-lgpl.c \
third_party/make/concat-filename.c \
third_party/make/dirname-lgpl.c \
third_party/make/error.c \
third_party/make/exitfail.c \
third_party/make/fcntl.c \
third_party/make/fd-hook.c \
third_party/make/findprog-in.c \
third_party/make/getprogname.c \
third_party/make/stripslash.c \
third_party/make/unistd.c \
third_party/make/xalloc-die.c \
third_party/make/xconcat-filename.c \
third_party/make/xmalloc.c
THIRD_PARTY_MAKE_SRCS_BASE = \
third_party/make/commands.c \ third_party/make/commands.c \
third_party/make/default.c \ third_party/make/default.c \
third_party/make/dir.c \ third_party/make/dir.c \
third_party/make/concat-filename.c \
third_party/make/findprog-in.c \
third_party/make/expand.c \ third_party/make/expand.c \
third_party/make/file.c \ third_party/make/file.c \
third_party/make/function.c \ third_party/make/function.c \
@ -97,12 +72,9 @@ THIRD_PARTY_MAKE_SRCS_BASE = \
third_party/make/strcache.c \ third_party/make/strcache.c \
third_party/make/variable.c \ third_party/make/variable.c \
third_party/make/version.c \ third_party/make/version.c \
third_party/make/shuffle.c \
third_party/make/vpath.c third_party/make/vpath.c
THIRD_PARTY_MAKE_SRCS = \
$(THIRD_PARTY_MAKE_SRCS_BASE) \
$(THIRD_PARTY_MAKE_SRCS_LIB)
THIRD_PARTY_MAKE_OBJS = \ THIRD_PARTY_MAKE_OBJS = \
$(THIRD_PARTY_MAKE_SRCS:%.c=o/$(MODE)/%.o) $(THIRD_PARTY_MAKE_SRCS:%.c=o/$(MODE)/%.o)
@ -170,12 +142,9 @@ o/$(MODE)/third_party/make/hash.o: private \
$(THIRD_PARTY_MAKE_OBJS): private \ $(THIRD_PARTY_MAKE_OBJS): private \
CFLAGS += \ CFLAGS += \
-fportcosmo \
-DNO_ARCHIVES \ -DNO_ARCHIVES \
-DHAVE_CONFIG_H \ -DHAVE_CONFIG_H
-DSTACK_FRAME_UNLIMITED \
-DINCLUDEDIR=\".\" \
-DLIBDIR=\".\" \
-DLOCALEDIR=\".\"
.PHONY: o/$(MODE)/third_party/make .PHONY: o/$(MODE)/third_party/make
o/$(MODE)/third_party/make: \ o/$(MODE)/third_party/make: \

View file

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View file

@ -5,8 +5,8 @@ DESCRIPTION
ORIGIN ORIGIN
GNU Make 4.3 GNU Make 4.4.1
http://ftp.gnu.org/gnu/make/make-4.3.tar.gz http://ftp.gnu.org/gnu/make/make-4.4.1.tar.gz
LICENSE LICENSE
@ -30,4 +30,3 @@ LOCAL CHANGES
- .MAXCORE variable to set upper limit on core dumps - .MAXCORE variable to set upper limit on core dumps
- Do automatic setup and teardown of TMPDIR per rule - Do automatic setup and teardown of TMPDIR per rule
- Remove code that forces slow path if not using /bin/sh - Remove code that forces slow path if not using /bin/sh
- Remove 200,000 lines of VAX/OS2/DOS/AMIGA/etc. code

View file

@ -1,68 +0,0 @@
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
/* Memory allocation on the stack.
Copyright (C) 1995, 1999, 2001-2004, 2006-2020 Free Software Foundation,
Inc.
This program 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 Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, see
<https://www.gnu.org/licenses/>.
*/
/* Avoid using the symbol _ALLOCA_H here, as Bison assumes _ALLOCA_H
means there is a real alloca function. */
#ifndef _GL_ALLOCA_H
#define _GL_ALLOCA_H
/* alloca (N) returns a pointer to N bytes of memory
allocated on the stack, which will last until the function returns.
Use of alloca should be avoided:
- inside arguments of function calls - undefined behaviour,
- in inline functions - the allocation may actually last until the
calling function returns,
- for huge N (say, N >= 65536) - you never know how large (or small)
the stack is, and when the stack cannot fulfill the memory allocation
request, the program just crashes.
*/
#ifndef alloca
# ifdef __GNUC__
/* Some version of mingw have an <alloca.h> that causes trouble when
included after 'alloca' gets defined as a macro. As a workaround, include
this <alloca.h> first and define 'alloca' as a macro afterwards. */
# if (defined _WIN32 && ! defined __CYGWIN__) && 1
# endif
# define alloca __builtin_alloca
# elif defined _AIX
# define alloca __alloca
# elif defined _MSC_VER
# define alloca _alloca
# elif defined __DECC && defined __VMS
# define alloca __ALLOCA
# elif defined __TANDEM && defined _TNS_E_TARGET
# ifdef __cplusplus
extern "C"
# endif
void *_alloca (unsigned short);
# pragma intrinsic (_alloca)
# define alloca _alloca
# elif defined __MVS__
# else
# ifdef __cplusplus
extern "C"
# endif
void *alloca (size_t);
# endif
#endif
#endif /* _GL_ALLOCA_H */

90
third_party/make/ar.c vendored
View file

@ -1,5 +1,5 @@
/* Interface to 'ar' archives for GNU Make. /* Interface to 'ar' archives for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
@ -13,13 +13,16 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc"
/**/ #include "makeint.h"
#include "libc/mem/alg.h"
#include "third_party/make/dep.h" #ifndef NO_ARCHIVES
#include "third_party/make/filedef.h"
#include "third_party/musl/fnmatch.h" #include "filedef.h"
#include "dep.h"
#include <fnmatch.h>
#include <intprops.h>
/* Return nonzero if NAME is an archive-member reference, zero if not. An /* Return nonzero if NAME is an archive-member reference, zero if not. An
archive-member reference is a name like 'lib(member)' where member is a archive-member reference is a name like 'lib(member)' where member is a
@ -33,7 +36,7 @@ ar_name (const char *name)
const char *p = strchr (name, '('); const char *p = strchr (name, '(');
const char *end; const char *end;
if (p == 0 || p == name) if (p == NULL || p == name)
return 0; return 0;
end = p + strlen (p) - 1; end = p + strlen (p) - 1;
@ -58,6 +61,9 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p)
*arname_p = xstrdup (name); *arname_p = xstrdup (name);
p = strchr (*arname_p, '('); p = strchr (*arname_p, '(');
/* This is never called unless ar_name() is true so p cannot be NULL. */
if (!p)
OS (fatal, NILF, "Internal: ar_parse_name: bad name '%s'", *arname_p);
*(p++) = '\0'; *(p++) = '\0';
p[strlen (p) - 1] = '\0'; p[strlen (p) - 1] = '\0';
*memname_p = p; *memname_p = p;
@ -67,10 +73,10 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p)
/* This function is called by 'ar_scan' to find which member to look at. */ /* This function is called by 'ar_scan' to find which member to look at. */
/* ARGSUSED */ /* ARGSUSED */
static long int static intmax_t
ar_member_date_1 (int desc UNUSED, const char *mem, int truncated, ar_member_date_1 (int desc UNUSED, const char *mem, int truncated,
long int hdrpos UNUSED, long int datapos UNUSED, long int hdrpos UNUSED, long int datapos UNUSED,
long int size UNUSED, long int date, long int size UNUSED, intmax_t date,
int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED, int uid UNUSED, int gid UNUSED, unsigned int mode UNUSED,
const void *name) const void *name)
{ {
@ -84,7 +90,7 @@ ar_member_date (const char *name)
{ {
char *arname; char *arname;
char *memname; char *memname;
long int val; intmax_t val;
ar_parse_name (name, &arname, &memname); ar_parse_name (name, &arname, &memname);
@ -109,11 +115,19 @@ ar_member_date (const char *name)
free (arname); free (arname);
return (val <= 0 ? (time_t) -1 : (time_t) val); return 0 < val && val <= TYPE_MAXIMUM (time_t) ? val : -1;
} }
/* Set the archive-member NAME's modtime to now. */ /* Set the archive-member NAME's modtime to now. */
#ifdef VMS
int
ar_touch (const char *name)
{
O (error, NILF, _("touch archive member is not available on VMS"));
return -1;
}
#else
int int
ar_touch (const char *name) ar_touch (const char *name)
{ {
@ -158,7 +172,7 @@ ar_touch (const char *name)
return val; return val;
} }
#endif /* !VMS */
/* State of an 'ar_glob' run, passed to 'ar_glob_match'. */ /* State of an 'ar_glob' run, passed to 'ar_glob_match'. */
@ -173,6 +187,9 @@ struct ar_glob_state
{ {
const char *arname; const char *arname;
const char *pattern; const char *pattern;
#ifdef VMS
char *suffix;
#endif
size_t size; size_t size;
struct nameseq *chain; struct nameseq *chain;
unsigned int n; unsigned int n;
@ -181,10 +198,10 @@ struct ar_glob_state
/* This function is called by 'ar_scan' to match one archive /* This function is called by 'ar_scan' to match one archive
element against the pattern in STATE. */ element against the pattern in STATE. */
static long int static intmax_t
ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED, ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
long int hdrpos UNUSED, long int datapos UNUSED, long int hdrpos UNUSED, long int datapos UNUSED,
long int size UNUSED, long int date UNUSED, int uid UNUSED, long int size UNUSED, intmax_t date UNUSED, int uid UNUSED,
int gid UNUSED, unsigned int mode UNUSED, const void *arg) int gid UNUSED, unsigned int mode UNUSED, const void *arg)
{ {
struct ar_glob_state *state = (struct ar_glob_state *)arg; struct ar_glob_state *state = (struct ar_glob_state *)arg;
@ -192,14 +209,20 @@ ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0)
{ {
/* We have a match. Add it to the chain. */ /* We have a match. Add it to the chain. */
struct nameseq *new = xcalloc (1, state->size); struct nameseq *new = xcalloc (state->size);
#ifdef VMS
if (state->suffix)
new->name = strcache_add(
concat(5, state->arname, "(", mem, state->suffix, ")"));
else
#endif
new->name = strcache_add(concat(4, state->arname, "(", mem, ")")); new->name = strcache_add(concat(4, state->arname, "(", mem, ")"));
new->next = state->chain; new->next = state->chain;
state->chain = new; state->chain = new;
++state->n; ++state->n;
} }
return 0L; return 0;
} }
/* Return nonzero if PATTERN contains any metacharacters. /* Return nonzero if PATTERN contains any metacharacters.
@ -245,7 +268,9 @@ ar_glob (const char *arname, const char *member_pattern, size_t size)
struct nameseq *n; struct nameseq *n;
const char **names; const char **names;
unsigned int i; unsigned int i;
#ifdef VMS
char *vms_member_pattern;
#endif
if (! ar_glob_pattern_p (member_pattern, 1)) if (! ar_glob_pattern_p (member_pattern, 1))
return 0; return 0;
@ -253,11 +278,36 @@ ar_glob (const char *arname, const char *member_pattern, size_t size)
ar_glob_match will accumulate them in STATE.chain. */ ar_glob_match will accumulate them in STATE.chain. */
state.arname = arname; state.arname = arname;
state.pattern = member_pattern; state.pattern = member_pattern;
#ifdef VMS
{
/* In a copy of the pattern, find the suffix, save it and remove it from
the pattern */
char *lastdot;
vms_member_pattern = xstrdup(member_pattern);
lastdot = strrchr(vms_member_pattern, '.');
state.suffix = lastdot;
if (lastdot)
{
state.suffix = xstrdup(lastdot);
*lastdot = 0;
}
state.pattern = vms_member_pattern;
}
#endif
state.size = size; state.size = size;
state.chain = 0; state.chain = 0;
state.n = 0; state.n = 0;
ar_scan (arname, ar_glob_match, &state); ar_scan (arname, ar_glob_match, &state);
#ifdef VMS
/* Deallocate any duplicated string */
free(vms_member_pattern);
if (state.suffix)
{
free(state.suffix);
}
#endif
if (state.chain == 0) if (state.chain == 0)
return 0; return 0;
@ -278,3 +328,5 @@ ar_glob (const char *arname, const char *member_pattern, size_t size)
return state.chain; return state.chain;
} }
#endif /* Not NO_ARCHIVES. */

View file

@ -1,5 +1,5 @@
/* Library function for scanning an archive file. /* Library function for scanning an archive file.
Copyright (C) 1987-2020 Free Software Foundation, Inc. Copyright (C) 1987-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,16 +12,290 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/sysv/consts/o.h" #include "makeint.h"
#include "third_party/make/makeint.inc"
#ifdef TEST #ifdef TEST
/* Hack, the real error() routine eventually pulls in die from main.c */ /* Hack, the real error() routine eventually pulls in die from main.c */
#define error(a, b, c, d) #define error(a, b, c, d)
#endif #endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#include <sys/file.h>
#endif
#ifndef NO_ARCHIVES
#ifdef VMS
#include <lbrdef.h>
#include <mhddef.h>
#include <credef.h>
#include <descrip.h>
#include <ctype.h>
#include <ssdef.h>
#include <stsdef.h>
#include <rmsdef.h>
/* This symbol should be present in lbrdef.h. */
#if !defined LBR$_HDRTRUNC
#pragma extern_model save
#pragma extern_model globalvalue
extern unsigned int LBR$_HDRTRUNC;
#pragma extern_model restore
#endif
#include <unixlib.h>
#include <lbr$routines.h>
const char *
vmsify (const char *name, int type);
/* Time conversion from VMS to Unix
Conversion from local time (stored in library) to GMT (needed for gmake)
Note: The tm_gmtoff element is a VMS extension to the ANSI standard. */
static time_t
vms_time_to_unix(void *vms_time)
{
struct tm *tmp;
time_t unix_time;
unix_time = decc$fix_time(vms_time);
tmp = localtime(&unix_time);
unix_time -= tmp->tm_gmtoff;
return unix_time;
}
/* VMS library routines need static variables for callback */
static void *VMS_lib_idx;
static const void *VMS_saved_arg;
static intmax_t (*VMS_function) ();
static intmax_t VMS_function_ret;
/* This is a callback procedure for lib$get_index */
static int
VMS_get_member_info(struct dsc$descriptor_s *module, unsigned long *rfa)
{
int status, i;
const int truncated = 0; /* Member name may be truncated */
time_t member_date; /* Member date */
char *filename;
unsigned int buffer_length; /* Actual buffer length */
/* Unused constants - Make does not actually use most of these */
const int file_desc = -1; /* archive file descriptor for reading the data */
const int header_position = 0; /* Header position */
const int data_position = 0; /* Data position in file */
const int data_size = 0; /* Data size */
const int uid = 0; /* member gid */
const int gid = 0; /* member gid */
const int mode = 0; /* member protection mode */
/* End of unused constants */
static struct dsc$descriptor_s bufdesc =
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
/* Only need the module definition */
struct mhddef *mhd;
/* If a previous callback is non-zero, just return that status */
if (VMS_function_ret)
{
return SS$_NORMAL;
}
/* lbr_set_module returns more than just the module header. So allocate
a buffer which is big enough: the maximum LBR$C_MAXHDRSIZ. That's at
least bigger than the size of struct mhddef.
If the request is too small, a buffer truncated warning is issued so
it can be reissued with a larger buffer.
We do not care if the buffer is truncated, so that is still a success. */
mhd = xmalloc(LBR$C_MAXHDRSIZ);
bufdesc.dsc$a_pointer = (char *) mhd;
bufdesc.dsc$w_length = LBR$C_MAXHDRSIZ;
status = lbr$set_module(&VMS_lib_idx, rfa, &bufdesc, &buffer_length, 0);
if ((status != LBR$_HDRTRUNC) && !$VMS_STATUS_SUCCESS(status))
{
ON(error, NILF,
_("lbr$set_module() failed to extract module info, status = %d"),
status);
lbr$close(&VMS_lib_idx);
return status;
}
#ifdef TEST
/* When testing this code, it is useful to know the length returned */
printf ("Input length = %d, actual = %u\n",
bufdesc.dsc$w_length, buffer_length);
#endif
/* Conversion from VMS time to C time.
VMS defectlet - mhddef is sub-optimal, for the time, it has a 32 bit
longword, mhd$l_datim, and a 32 bit fill instead of two longwords, or
equivalent. */
member_date = vms_time_to_unix(&mhd->mhd$l_datim);
free(mhd);
/* Here we have a problem. The module name on VMS does not have
a file type, but the filename pattern in the "VMS_saved_arg"
may have one.
But only the method being called knows how to interpret the
filename pattern.
There are currently two different formats being used.
This means that we need a VMS specific code in those methods
to handle it. */
filename = xmalloc(module->dsc$w_length + 1);
/* TODO: We may need an option to preserve the case of the module
For now force the module name to lower case */
for (i = 0; i < module->dsc$w_length; i++)
filename[i] = _tolower((unsigned char )module->dsc$a_pointer[i]);
filename[i] = '\0';
VMS_function_ret = (*VMS_function)(file_desc, filename, truncated,
header_position, data_position, data_size, member_date, uid, gid, mode,
VMS_saved_arg);
free(filename);
return SS$_NORMAL;
}
/* Takes three arguments ARCHIVE, FUNCTION and ARG.
Open the archive named ARCHIVE, find its members one by one,
and for each one call FUNCTION with the following arguments:
archive file descriptor for reading the data,
member name,
member name might be truncated flag,
member header position in file,
member data position in file,
member data size,
member date,
member uid,
member gid,
member protection mode,
ARG.
NOTE: on VMS systems, only name, date, and arg are meaningful!
The descriptor is poised to read the data of the member
when FUNCTION is called. It does not matter how much
data FUNCTION reads.
If FUNCTION returns nonzero, we immediately return
what FUNCTION returned.
Returns -1 if archive does not exist,
Returns -2 if archive has invalid format.
Returns 0 if have scanned successfully. */
intmax_t
ar_scan (const char *archive, ar_member_func_t function, const void *varg)
{
char *vms_archive;
static struct dsc$descriptor_s libdesc =
{ 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
const unsigned long func = LBR$C_READ;
const unsigned long type = LBR$C_TYP_UNK;
const unsigned long index = 1;
unsigned long lib_idx;
int status;
VMS_saved_arg = varg;
/* Null archive string can show up in test and cause an access violation */
if (archive == NULL)
{
/* Null filenames do not exist */
return -1;
}
/* archive path name must be in VMS format */
vms_archive = (char *) vmsify(archive, 0);
status = lbr$ini_control(&VMS_lib_idx, &func, &type, 0);
if (!$VMS_STATUS_SUCCESS(status))
{
ON(error, NILF, _("lbr$ini_control() failed with status = %d"), status);
return -2;
}
libdesc.dsc$a_pointer = vms_archive;
libdesc.dsc$w_length = strlen(vms_archive);
status = lbr$open(&VMS_lib_idx, &libdesc, 0, NULL, 0, NULL, 0);
if (!$VMS_STATUS_SUCCESS(status))
{
/* TODO: A library format failure could mean that this is a file
generated by the GNU AR utility and in that case, we need to
take the UNIX codepath. This will also take a change to the
GNV AR wrapper program. */
switch (status)
{
case RMS$_FNF:
/* Archive does not exist */
return -1;
default:
#ifndef TEST
OSN(error, NILF,
_("unable to open library '%s' to lookup member status %d"),
archive, status);
#endif
/* For library format errors, specification says to return -2 */
return -2;
}
}
VMS_function = function;
/* Clear the return status, as we are supposed to stop calling the
callback function if it becomes non-zero, and this is a static
variable. */
VMS_function_ret = 0;
status = lbr$get_index(&VMS_lib_idx, &index, VMS_get_member_info, NULL, 0);
lbr$close(&VMS_lib_idx);
/* Unless a failure occurred in the lbr$ routines, return the
the status from the 'function' routine. */
if ($VMS_STATUS_SUCCESS(status))
{
return VMS_function_ret;
}
/* This must be something wrong with the library and an error
message should already have been printed. */
return -2;
}
#else /* !VMS */
/* SCO Unix's compiler defines both of these. */
#ifdef M_UNIX
#undef M_XENIX
#endif
/* On the sun386i and in System V rel 3, ar.h defines two different archive /* On the sun386i and in System V rel 3, ar.h defines two different archive
formats depending upon whether you have defined PORTAR (normal) or PORT5AR formats depending upon whether you have defined PORTAR (normal) or PORT5AR
(System V Release 1). There is no default, one or the other must be defined (System V Release 1). There is no default, one or the other must be defined
@ -57,7 +331,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#endif #endif
#ifndef WINDOWS32 #ifndef WINDOWS32
# if 0 && !defined (__ANDROID__) && !defined (__BEOS__) # if !defined (__ANDROID__) && !defined (__BEOS__) && !defined(MK_OS_ZOS)
# include <ar.h>
# else # else
/* These platforms don't have <ar.h> but have archives in the same format /* These platforms don't have <ar.h> but have archives in the same format
* as many other Unices. This was taken from GNU binutils for BeOS. * as many other Unices. This was taken from GNU binutils for BeOS.
@ -80,6 +355,9 @@ struct ar_hdr
/* These should allow us to read Windows (VC++) libraries (according to Frank /* These should allow us to read Windows (VC++) libraries (according to Frank
* Libbrecht <frankl@abzx.belgium.hp.com>) * Libbrecht <frankl@abzx.belgium.hp.com>)
*/ */
# include <windows.h>
# include <windef.h>
# include <io.h>
# define ARMAG IMAGE_ARCHIVE_START # define ARMAG IMAGE_ARCHIVE_START
# define SARMAG IMAGE_ARCHIVE_START_SIZE # define SARMAG IMAGE_ARCHIVE_START_SIZE
# define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER # define ar_hdr _IMAGE_ARCHIVE_MEMBER_HEADER
@ -98,8 +376,41 @@ struct ar_hdr
# define AR_HDR_SIZE (sizeof (struct ar_hdr)) # define AR_HDR_SIZE (sizeof (struct ar_hdr))
#endif #endif
#include "third_party/make/output.h" #include "intprops.h"
#include "output.h"
static uintmax_t
parse_int (const char *ptr, const size_t len, const int base, uintmax_t max,
const char *type, const char *archive, const char *name)
{
const char *const ep = ptr + len;
const int maxchar = '0' + base - 1;
uintmax_t val = 0;
/* In all the versions I know of the spaces come last, but be safe. */
while (ptr < ep && *ptr == ' ')
++ptr;
while (ptr < ep && *ptr != ' ')
{
uintmax_t nv;
if (*ptr < '0' || *ptr > maxchar)
OSSS (fatal, NILF,
_("Invalid %s for archive %s member %s"), type, archive, name);
nv = (val * base) + (*ptr - '0');
if (nv < val || nv > max)
OSSS (fatal, NILF,
_("Invalid %s for archive %s member %s"), type, archive, name);
val = nv;
++ptr;
}
return val;
}
/* Takes three arguments ARCHIVE, FUNCTION and ARG. /* Takes three arguments ARCHIVE, FUNCTION and ARG.
Open the archive named ARCHIVE, find its members one by one, Open the archive named ARCHIVE, find its members one by one,
@ -127,7 +438,7 @@ struct ar_hdr
Returns -2 if archive has invalid format. Returns -2 if archive has invalid format.
Returns 0 if have scanned successfully. */ Returns 0 if have scanned successfully. */
long int intmax_t
ar_scan (const char *archive, ar_member_func_t function, const void *arg) ar_scan (const char *archive, ar_member_func_t function, const void *arg)
{ {
#ifdef AIAMAG #ifdef AIAMAG
@ -138,7 +449,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
# endif # endif
#endif #endif
char *namemap = 0; char *namemap = 0;
int namemap_size = 0; unsigned int namemap_size = 0;
int desc = open (archive, O_RDONLY, 0); int desc = open (archive, O_RDONLY, 0);
if (desc < 0) if (desc < 0)
return -1; return -1;
@ -238,7 +549,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
while (1) while (1)
{ {
int nread; ssize_t nread;
struct ar_hdr member_header; struct ar_hdr member_header;
#ifdef AIAMAGBIG #ifdef AIAMAGBIG
struct ar_hdr_big member_header_big; struct ar_hdr_big member_header_big;
@ -247,7 +558,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
# define ARNAME_MAX 255 # define ARNAME_MAX 255
char name[ARNAME_MAX + 1]; char name[ARNAME_MAX + 1];
int name_len; int name_len;
long int dateval; intmax_t dateval;
int uidval, gidval; int uidval, gidval;
long int data_offset; long int data_offset;
#else #else
@ -259,9 +570,13 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
#endif #endif
long int eltsize; long int eltsize;
unsigned int eltmode; unsigned int eltmode;
long int fnval; intmax_t eltdate;
int eltuid, eltgid;
intmax_t fnval;
off_t o; off_t o;
memset(&member_header, '\0', sizeof (member_header));
EINTRLOOP (o, lseek (desc, member_offset, 0)); EINTRLOOP (o, lseek (desc, member_offset, 0));
if (o < 0) if (o < 0)
goto invalid; goto invalid;
@ -288,7 +603,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
name[name_len] = '\0'; name[name_len] = '\0';
sscanf (member_header_big.ar_date, "%12ld", &dateval); sscanf (member_header_big.ar_date, "%12" SCNdMAX, &dateval);
sscanf (member_header_big.ar_uid, "%12d", &uidval); sscanf (member_header_big.ar_uid, "%12d", &uidval);
sscanf (member_header_big.ar_gid, "%12d", &gidval); sscanf (member_header_big.ar_gid, "%12d", &gidval);
sscanf (member_header_big.ar_mode, "%12o", &eltmode); sscanf (member_header_big.ar_mode, "%12o", &eltmode);
@ -316,7 +631,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
name[name_len] = '\0'; name[name_len] = '\0';
sscanf (member_header.ar_date, "%12ld", &dateval); sscanf (member_header.ar_date, "%12" SCNdMAX, &dateval);
sscanf (member_header.ar_uid, "%12d", &uidval); sscanf (member_header.ar_uid, "%12d", &uidval);
sscanf (member_header.ar_gid, "%12d", &gidval); sscanf (member_header.ar_gid, "%12d", &gidval);
sscanf (member_header.ar_mode, "%12o", &eltmode); sscanf (member_header.ar_mode, "%12o", &eltmode);
@ -391,10 +706,11 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
&& (name[0] == ' ' || name[0] == '/') && (name[0] == ' ' || name[0] == '/')
&& namemap != 0) && namemap != 0)
{ {
int name_off = atoi (name + 1); const char* err;
int name_len; unsigned int name_off = make_toui (name + 1, &err);
size_t name_len;
if (name_off < 0 || name_off >= namemap_size) if (err|| name_off >= namemap_size)
goto invalid; goto invalid;
name = namemap + name_off; name = namemap + name_off;
@ -407,14 +723,15 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
&& name[1] == '1' && name[1] == '1'
&& name[2] == '/') && name[2] == '/')
{ {
int name_len = atoi (name + 3); const char* err;
unsigned int name_len = make_toui (name + 3, &err);
if (name_len < 1) if (err || name_len == 0 || name_len >= MIN (PATH_MAX, INT_MAX))
goto invalid; goto invalid;
name = alloca (name_len + 1); name = alloca (name_len + 1);
nread = readbuf (desc, name, name_len); nread = readbuf (desc, name, name_len);
if (nread != name_len) if (nread < 0 || (unsigned int) nread != name_len)
goto invalid; goto invalid;
name[name_len] = '\0'; name[name_len] = '\0';
@ -425,8 +742,16 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
} }
#ifndef M_XENIX #ifndef M_XENIX
sscanf (TOCHAR (member_header.ar_mode), "%8o", &eltmode); #define PARSE_INT(_m, _t, _b, _n) \
eltsize = atol (TOCHAR (member_header.ar_size)); (_t) parse_int (TOCHAR (member_header._m), sizeof (member_header._m), \
_b, TYPE_MAXIMUM (_t), _n, archive, name)
eltmode = PARSE_INT (ar_mode, unsigned int, 8, "mode");
eltsize = PARSE_INT (ar_size, long, 10, "size");
eltdate = PARSE_INT (ar_date, intmax_t, 10, "date");
eltuid = PARSE_INT (ar_uid, int, 10, "uid");
eltgid = PARSE_INT (ar_gid, int, 10, "gid");
#undef PARSE_INT
#else /* Xenix. */ #else /* Xenix. */
eltmode = (unsigned short int) member_header.ar_mode; eltmode = (unsigned short int) member_header.ar_mode;
eltsize = member_header.ar_size; eltsize = member_header.ar_size;
@ -436,9 +761,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
(*function) (desc, name, ! long_name, member_offset, (*function) (desc, name, ! long_name, member_offset,
member_offset + AR_HDR_SIZE, eltsize, member_offset + AR_HDR_SIZE, eltsize,
#ifndef M_XENIX #ifndef M_XENIX
atol (TOCHAR (member_header.ar_date)), eltdate, eltuid, eltgid,
atoi (TOCHAR (member_header.ar_uid)),
atoi (TOCHAR (member_header.ar_gid)),
#else /* Xenix. */ #else /* Xenix. */
member_header.ar_date, member_header.ar_date,
member_header.ar_uid, member_header.ar_uid,
@ -518,7 +841,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
close (desc); close (desc);
return -2; return -2;
} }
#endif /* !VMS */
/* Return nonzero iff NAME matches MEM. /* Return nonzero iff NAME matches MEM.
If TRUNCATED is nonzero, MEM may be truncated to If TRUNCATED is nonzero, MEM may be truncated to
@ -578,10 +901,10 @@ ar_name_equal (const char *name, const char *mem, int truncated)
#ifndef VMS #ifndef VMS
/* ARGSUSED */ /* ARGSUSED */
static long int static intmax_t
ar_member_pos (int desc UNUSED, const char *mem, int truncated, ar_member_pos (int desc UNUSED, const char *mem, int truncated,
long int hdrpos, long int datapos UNUSED, long int size UNUSED, long int hdrpos, long int datapos UNUSED, long int size UNUSED,
long int date UNUSED, int uid UNUSED, int gid UNUSED, intmax_t date UNUSED, int uid UNUSED, int gid UNUSED,
unsigned int mode UNUSED, const void *name) unsigned int mode UNUSED, const void *name)
{ {
if (!ar_name_equal (name, mem, truncated)) if (!ar_name_equal (name, mem, truncated))
@ -599,12 +922,13 @@ ar_member_pos (int desc UNUSED, const char *mem, int truncated,
int int
ar_member_touch (const char *arname, const char *memname) ar_member_touch (const char *arname, const char *memname)
{ {
long int pos = ar_scan (arname, ar_member_pos, memname); intmax_t pos = ar_scan (arname, ar_member_pos, memname);
off_t opos;
int fd; int fd;
struct ar_hdr ar_hdr; struct ar_hdr ar_hdr;
off_t o; off_t o;
int r; int r;
unsigned int ui; int datelen;
struct stat statbuf; struct stat statbuf;
if (pos < 0) if (pos < 0)
@ -612,11 +936,13 @@ ar_member_touch (const char *arname, const char *memname)
if (!pos) if (!pos)
return 1; return 1;
opos = (off_t) pos;
EINTRLOOP (fd, open (arname, O_RDWR, 0666)); EINTRLOOP (fd, open (arname, O_RDWR, 0666));
if (fd < 0) if (fd < 0)
return -3; return -3;
/* Read in this member's header */ /* Read in this member's header */
EINTRLOOP (o, lseek (fd, pos, 0)); EINTRLOOP (o, lseek (fd, opos, 0));
if (o < 0) if (o < 0)
goto lose; goto lose;
r = readbuf (fd, &ar_hdr, AR_HDR_SIZE); r = readbuf (fd, &ar_hdr, AR_HDR_SIZE);
@ -628,15 +954,16 @@ ar_member_touch (const char *arname, const char *memname)
goto lose; goto lose;
/* Advance member's time to that time */ /* Advance member's time to that time */
#if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32)
for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) datelen = snprintf (TOCHAR (ar_hdr.ar_date), sizeof ar_hdr.ar_date,
ar_hdr.ar_date[ui] = ' '; "%" PRIdMAX, (intmax_t) statbuf.st_mtime);
sprintf (TOCHAR (ar_hdr.ar_date), "%lu", (long unsigned) statbuf.st_mtime); if (! (0 <= datelen && datelen < (int) sizeof ar_hdr.ar_date))
ar_hdr.ar_date[strlen ((char *) ar_hdr.ar_date)] = ' '; goto lose;
memset (ar_hdr.ar_date + datelen, ' ', sizeof ar_hdr.ar_date - datelen);
#else #else
ar_hdr.ar_date = statbuf.st_mtime; ar_hdr.ar_date = statbuf.st_mtime;
#endif #endif
/* Write back this member's header */ /* Write back this member's header */
EINTRLOOP (o, lseek (fd, pos, 0)); EINTRLOOP (o, lseek (fd, opos, 0));
if (o < 0) if (o < 0)
goto lose; goto lose;
r = writebuf (fd, &ar_hdr, AR_HDR_SIZE); r = writebuf (fd, &ar_hdr, AR_HDR_SIZE);
@ -655,18 +982,21 @@ ar_member_touch (const char *arname, const char *memname)
#ifdef TEST #ifdef TEST
long int intmax_t
describe_member (int desc, const char *name, int truncated, describe_member (int desc, const char *name, int truncated,
long int hdrpos, long int datapos, long int size, long int hdrpos, long int datapos, long int size,
long int date, int uid, int gid, unsigned int mode, intmax_t date, int uid, int gid, unsigned int mode,
const void *arg) const void *arg)
{ {
extern char *ctime (); extern char *ctime ();
time_t d = date;
char const *ds;
printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"), printf (_("Member '%s'%s: %ld bytes at %ld (%ld).\n"),
name, truncated ? _(" (name might be truncated)") : "", name, truncated ? _(" (name might be truncated)") : "",
size, hdrpos, datapos); size, hdrpos, datapos);
printf (_(" Date %s"), ctime (&date)); ds = ctime (&d);
printf (_(" Date %s"), ds ? ds : "?");
printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode); printf (_(" uid = %d, gid = %d, mode = 0%o.\n"), uid, gid, mode);
return 0; return 0;
@ -680,3 +1010,4 @@ main (int argc, char **argv)
} }
#endif /* TEST. */ #endif /* TEST. */
#endif /* NO_ARCHIVES. */

View file

@ -1,74 +0,0 @@
/* basename.c -- return the last element in a file name
Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2020 Free Software
Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/config.h"
/**/
#include "libc/str/str.h"
#include "third_party/make/dirname.h"
/* Return the address of the last file name component of NAME. If
NAME has no relative file name components because it is a file
system root, return the empty string. */
char *
last_component (char const *name)
{
char const *base = name + FILE_SYSTEM_PREFIX_LEN (name);
char const *p;
bool saw_slash = false;
while (ISSLASH (*base))
base++;
for (p = base; *p; p++)
{
if (ISSLASH (*p))
saw_slash = true;
else if (saw_slash)
{
base = p;
saw_slash = false;
}
}
return (char *) base;
}
/* Return the length of the basename NAME. Typically NAME is the
value returned by base_name or last_component. Act like strlen
(NAME), except omit all trailing slashes. */
size_t
base_len (char const *name)
{
size_t len;
size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
for (len = strlen (name); 1 < len && ISSLASH (name[len - 1]); len--)
continue;
if (DOUBLE_SLASH_IS_DISTINCT_ROOT && len == 1
&& ISSLASH (name[0]) && ISSLASH (name[1]) && ! name[2])
return 2;
if (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE && prefix_len
&& len == prefix_len && ISSLASH (name[prefix_len]))
return prefix_len + 1;
return len;
}

View file

@ -1,5 +1,5 @@
/* Command processing for GNU Make. /* Command processing for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,20 +12,22 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
/**/ #include "filedef.h"
#include "third_party/make/dep.h" #include "os.h"
#include "third_party/make/filedef.h" #include "dep.h"
#include "third_party/make/job.h" #include "variable.h"
#include "third_party/make/variable.h" #include "job.h"
/**/ #include "commands.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/sig.h"
#include "third_party/make/commands.h"
#if VMS
# define FILE_LIST_SEPARATOR (vms_comma_separator ? ',' : ' ')
#else
# define FILE_LIST_SEPARATOR ' ' # define FILE_LIST_SEPARATOR ' '
#endif
static unsigned long static unsigned long
dep_hash_1 (const void *key) dep_hash_1 (const void *key)
@ -49,10 +51,13 @@ dep_hash_cmp (const void *x, const void *y)
return strcmp (dep_name (dx), dep_name (dy)); return strcmp (dep_name (dx), dep_name (dy));
} }
/* Set FILE's automatic variables up. */ /* Set FILE's automatic variables up.
* Use STEM to set $*.
* If STEM is 0, then set FILE->STEM and $* to the target name with any
* suffix in the .SUFFIXES list stripped off. */
void void
set_file_variables (struct file *file) set_file_variables (struct file *file, const char *stem)
{ {
struct dep *d; struct dep *d;
const char *at, *percent, *star, *less; const char *at, *percent, *star, *less;
@ -86,7 +91,7 @@ set_file_variables (struct file *file)
} }
/* $* is the stem from an implicit or static pattern rule. */ /* $* is the stem from an implicit or static pattern rule. */
if (file->stem == 0) if (stem == 0)
{ {
/* In Unix make, $* is set to the target name with /* In Unix make, $* is set to the target name with
any suffix in the .SUFFIXES list stripped off for any suffix in the .SUFFIXES list stripped off for
@ -109,24 +114,24 @@ set_file_variables (struct file *file)
for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next) for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
{ {
size_t slen = strlen (dep_name (d)); const char *dn = dep_name (d);
if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) size_t slen = strlen (dn);
if (len > slen && memcmp (dn, name + (len - slen), slen) == 0)
{ {
file->stem = strcache_add_len (name, len - slen); file->stem = stem = strcache_add_len (name, len - slen);
break; break;
} }
} }
if (d == 0) if (d == 0)
file->stem = ""; file->stem = stem = "";
} }
star = file->stem; star = stem;
/* $< is the first not order-only dependency. */ /* $< is the first not order-only dependency. */
less = ""; less = "";
for (d = file->deps; d != 0; d = d->next) for (d = file->deps; d != 0; d = d->next)
if (!d->ignore_mtime && !d->ignore_automatic_vars) if (!d->ignore_mtime && !d->ignore_automatic_vars && !d->need_2nd_expansion)
{ {
if (!d->need_2nd_expansion)
less = dep_name (d); less = dep_name (d);
break; break;
} }
@ -205,8 +210,7 @@ set_file_variables (struct file *file)
#endif #endif
len = strlen (c); len = strlen (c);
memcpy (cp, c, len); cp = mempcpy (cp, c, len);
cp += len;
*cp++ = FILE_LIST_SEPARATOR; *cp++ = FILE_LIST_SEPARATOR;
if (! (d->changed || always_make_flag)) if (! (d->changed || always_make_flag))
qmark_len -= len + 1; /* Don't space in $? for this one. */ qmark_len -= len + 1; /* Don't space in $? for this one. */
@ -276,19 +280,16 @@ set_file_variables (struct file *file)
if (d->ignore_mtime) if (d->ignore_mtime)
{ {
memcpy (bp, c, len); bp = mempcpy (bp, c, len);
bp += len;
*bp++ = FILE_LIST_SEPARATOR; *bp++ = FILE_LIST_SEPARATOR;
} }
else else
{ {
memcpy (cp, c, len); cp = mempcpy (cp, c, len);
cp += len;
*cp++ = FILE_LIST_SEPARATOR; *cp++ = FILE_LIST_SEPARATOR;
if (d->changed || always_make_flag) if (d->changed || always_make_flag)
{ {
memcpy (qp, c, len); qp = mempcpy (qp, c, len);
qp += len;
*qp++ = FILE_LIST_SEPARATOR; *qp++ = FILE_LIST_SEPARATOR;
} }
} }
@ -317,14 +318,12 @@ set_file_variables (struct file *file)
void void
chop_commands (struct commands *cmds) chop_commands (struct commands *cmds)
{ {
unsigned int nlines; unsigned short nlines;
unsigned short idx; unsigned short i;
char **lines; char **lines;
/* If we don't have any commands, /* If we don't have any commands, or we already parsed them, never mind. */
or we already parsed them, never mind. */ if (!cmds || cmds->command_lines != NULL)
if (!cmds || cmds->command_lines != 0)
return; return;
/* Chop CMDS->commands up into lines in CMDS->command_lines. */ /* Chop CMDS->commands up into lines in CMDS->command_lines. */
@ -343,25 +342,27 @@ chop_commands (struct commands *cmds)
} }
else else
{ {
const char *p; const char *p = cmds->commands;
size_t max = 5;
nlines = 5; nlines = 0;
lines = xmalloc (nlines * sizeof (char *)); lines = xmalloc (max * sizeof (char *));
idx = 0;
p = cmds->commands;
while (*p != '\0') while (*p != '\0')
{ {
const char *end = p; const char *end = p;
find_end:; find_end:;
end = strchr (end, '\n'); end = strchr (end, '\n');
if (end == 0) if (end == NULL)
end = p + strlen (p); end = p + strlen (p);
else if (end > p && end[-1] == '\\') else if (end > p && end[-1] == '\\')
{ {
int backslash = 1; int backslash = 1;
if (end > p + 1)
{
const char *b; const char *b;
for (b = end - 2; b >= p && *b == '\\'; --b) for (b = end - 2; b >= p && *b == '\\'; --b)
backslash = !backslash; backslash = !backslash;
}
if (backslash) if (backslash)
{ {
++end; ++end;
@ -369,40 +370,36 @@ chop_commands (struct commands *cmds)
} }
} }
if (idx == nlines) if (nlines == USHRT_MAX)
ON (fatal, &cmds->fileinfo,
_("Recipe has too many lines (limit %hu)"), nlines);
if (nlines == max)
{ {
nlines += 2; max += 2;
lines = xrealloc (lines, nlines * sizeof (char *)); lines = xrealloc (lines, max * sizeof (char *));
} }
lines[idx++] = xstrndup (p, (size_t) (end - p));
lines[nlines++] = xstrndup (p, (size_t) (end - p));
p = end; p = end;
if (*p != '\0') if (*p != '\0')
++p; ++p;
} }
if (idx != nlines)
{
nlines = idx;
lines = xrealloc (lines, nlines * sizeof (char *));
}
} }
/* Finally, set the corresponding CMDS->lines_flags elements and the /* Finally, set the corresponding CMDS->lines_flags elements and the
CMDS->any_recurse flag. */ CMDS->any_recurse flag. */
if (nlines > USHRT_MAX) cmds->ncommand_lines = nlines;
ON (fatal, &cmds->fileinfo, _("Recipe has too many lines (%ud)"), nlines);
cmds->ncommand_lines = (unsigned short)nlines;
cmds->command_lines = lines; cmds->command_lines = lines;
cmds->any_recurse = 0; cmds->any_recurse = 0;
cmds->lines_flags = xmalloc (nlines); cmds->lines_flags = xmalloc (nlines);
for (idx = 0; idx < nlines; ++idx) for (i = 0; i < nlines; ++i)
{ {
unsigned char flags = 0; unsigned char flags = 0;
const char *p = lines[idx]; const char *p = lines[i];
while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+') while (ISBLANK (*p) || *p == '-' || *p == '@' || *p == '+')
switch (*(p++)) switch (*(p++))
@ -419,12 +416,12 @@ chop_commands (struct commands *cmds)
} }
/* If no explicit '+' was given, look for MAKE variable references. */ /* If no explicit '+' was given, look for MAKE variable references. */
if (!(flags & COMMANDS_RECURSE) if (! ANY_SET (flags, COMMANDS_RECURSE)
&& (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0))
flags |= COMMANDS_RECURSE; flags |= COMMANDS_RECURSE;
cmds->lines_flags[idx] = flags; cmds->lines_flags[i] = flags;
cmds->any_recurse |= flags & COMMANDS_RECURSE ? 1 : 0; cmds->any_recurse |= ANY_SET (flags, COMMANDS_RECURSE) ? 1 : 0;
} }
} }
@ -456,12 +453,17 @@ execute_file_commands (struct file *file)
initialize_file_variables (file, 0); initialize_file_variables (file, 0);
set_file_variables (file); set_file_variables (file, file->stem);
/* If this is a loaded dynamic object, unload it before remaking. /* Some systems don't support overwriting a loaded object so if this one
Some systems don't support overwriting a loaded object. */ unload it before remaking. Keep its name in .LOADED: it will be rebuilt
if (file->loaded) and loaded again. If rebuilding or loading again fail, then we'll exit
unload_file (file->name); anyway and it won't matter. */
if (file->loaded && unload_file (file->name) == 0)
{
file->loaded = 0;
file->unloaded = 1;
}
/* Start the commands running. */ /* Start the commands running. */
new_job (file); new_job (file);
@ -470,17 +472,36 @@ execute_file_commands (struct file *file)
/* This is set while we are inside fatal_error_signal, /* This is set while we are inside fatal_error_signal,
so things can avoid nonreentrant operations. */ so things can avoid nonreentrant operations. */
int handling_fatal_signal = 0; volatile sig_atomic_t handling_fatal_signal = 0;
/* Handle fatal signals. */ /* Handle fatal signals. */
RETSIGTYPE void
fatal_error_signal (int sig) fatal_error_signal (int sig)
{ {
#ifdef __MSDOS__
extern int dos_status, dos_command_running;
if (dos_command_running)
{
/* That was the child who got the signal, not us. */
dos_status |= (sig << 8);
return;
}
remove_intermediates (1);
exit (EXIT_FAILURE);
#else /* not __MSDOS__ */
#ifdef _AMIGA
remove_intermediates (1);
if (sig == SIGINT)
fputs (_("*** Break.\n"), stderr);
exit (10);
#else /* not Amiga */
#ifdef WINDOWS32 #ifdef WINDOWS32
extern HANDLE main_thread; extern HANDLE main_thread;
/* Windows creates a sperate thread for handling Ctrl+C, so we need /* Windows creates a separate thread for handling Ctrl+C, so we need
to suspend the main thread, or else we will have race conditions to suspend the main thread, or else we will have race conditions
when both threads call reap_children. */ when both threads call reap_children. */
if (main_thread) if (main_thread)
@ -488,12 +509,12 @@ fatal_error_signal (int sig)
DWORD susp_count = SuspendThread (main_thread); DWORD susp_count = SuspendThread (main_thread);
if (susp_count != 0) if (susp_count != 0)
fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count); fprintf (stderr, "SuspendThread: suspend count = %lu\n", susp_count);
else if (susp_count == (DWORD)-1) else if (susp_count == (DWORD)-1)
{ {
DWORD ierr = GetLastError (); DWORD ierr = GetLastError ();
fprintf (stderr, "SuspendThread: error %ld: %s\n", fprintf (stderr, "SuspendThread: error %lu: %s\n",
ierr, map_windows32_error_to_string (ierr)); ierr, map_windows32_error_to_string (ierr));
} }
} }
@ -504,6 +525,10 @@ fatal_error_signal (int sig)
It is blocked now while we run this handler. */ It is blocked now while we run this handler. */
signal (sig, SIG_DFL); signal (sig, SIG_DFL);
temp_stdin_unlink ();
osync_clear ();
jobserver_clear ();
/* A termination signal won't be sent to the entire /* A termination signal won't be sent to the entire
process group, but it means we want to kill the children. */ process group, but it means we want to kill the children. */
@ -519,9 +544,12 @@ fatal_error_signal (int sig)
wanted to kill make, remove pending targets. */ wanted to kill make, remove pending targets. */
if (sig == SIGTERM || sig == SIGINT if (sig == SIGTERM || sig == SIGINT
#ifdef SIGHUP
|| sig == SIGHUP || sig == SIGHUP
#endif
#ifdef SIGQUIT
|| sig == SIGQUIT || sig == SIGQUIT
|| sig == SIGPIPE #endif
) )
{ {
struct child *c; struct child *c;
@ -533,10 +561,7 @@ fatal_error_signal (int sig)
(void) remote_kill (c->pid, sig); (void) remote_kill (c->pid, sig);
for (c = children; c != 0; c = c->next) for (c = children; c != 0; c = c->next)
{
delete_child_targets (c); delete_child_targets (c);
delete_tmpdir (c);
}
/* Clean up the children. We don't just use the call below because /* Clean up the children. We don't just use the call below because
we don't want to print the "Waiting for children" message. */ we don't want to print the "Waiting for children" message. */
@ -552,10 +577,12 @@ fatal_error_signal (int sig)
remove_intermediates (1); remove_intermediates (1);
#ifdef SIGQUIT
if (sig == SIGQUIT) if (sig == SIGQUIT)
/* We don't want to send ourselves SIGQUIT, because it will /* We don't want to send ourselves SIGQUIT, because it will
cause a core dump. Just exit instead. */ cause a core dump. Just exit instead. */
exit (MAKE_TROUBLE); exit (MAKE_TROUBLE);
#endif
#ifdef WINDOWS32 #ifdef WINDOWS32
if (main_thread) if (main_thread)
@ -566,9 +593,11 @@ fatal_error_signal (int sig)
#else #else
/* Signal the same code; this time it will really be fatal. The signal /* Signal the same code; this time it will really be fatal. The signal
will be unblocked when we return and arrive then to kill us. */ will be unblocked when we return and arrive then to kill us. */
if (kill (getpid (), sig) < 0) if (kill (make_pid (), sig) < 0)
pfatal_with_name ("kill"); pfatal_with_name ("kill");
#endif /* not WINDOWS32 */ #endif /* not WINDOWS32 */
#endif /* not Amiga */
#endif /* not __MSDOS__ */
} }
/* Delete FILE unless it's precious or not actually a file (phony), /* Delete FILE unless it's precious or not actually a file (phony),

View file

@ -1,5 +1,5 @@
/* Definition of data structures describing shell commands for GNU Make. /* Definition of data structures describing shell commands for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,7 +12,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
/* Structure that gives the commands to make a file /* Structure that gives the commands to make a file
and information about where these commands came from. */ and information about where these commands came from. */
@ -34,9 +34,12 @@ struct commands
#define COMMANDS_SILENT 2 /* Silent: @. */ #define COMMANDS_SILENT 2 /* Silent: @. */
#define COMMANDS_NOERROR 4 /* No errors: -. */ #define COMMANDS_NOERROR 4 /* No errors: -. */
RETSIGTYPE fatal_error_signal (int sig); struct file;
struct child;
void fatal_error_signal (int sig);
void execute_file_commands (struct file *file); void execute_file_commands (struct file *file);
void print_commands (const struct commands *cmds); void print_commands (const struct commands *cmds);
void delete_child_targets (struct child *child); void delete_child_targets (struct child *child);
void chop_commands (struct commands *cmds); void chop_commands (struct commands *cmds);
void set_file_variables (struct file *file); void set_file_variables (struct file *file, const char *stem);

View file

@ -1,26 +1,31 @@
/* Construct a full filename from a directory and a relative filename. /* Construct a full filename from a directory and a relative filename.
Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc. Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify it This file is free software: you can redistribute it and/or modify
under the terms of the GNU General Public License as published by the it under the terms of the GNU Lesser General Public License as
Free Software Foundation; either version 3 of the License, or any published by the Free Software Foundation; either version 2.1 of the
later version. License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <haible@clisp.cons.org>. */ /* Written by Bruno Haible <haible@clisp.cons.org>. */
#include "libc/mem/mem.h" #include "config.h"
#include "libc/str/str.h"
#include "third_party/make/concat-filename.h" /* Specification. */
#include "third_party/make/filename.h" #include "concat-filename.h"
#include "third_party/make/config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "filename.h"
/* Concatenate a directory filename, a relative filename and an optional /* Concatenate a directory filename, a relative filename and an optional
suffix. The directory may end with the directory separator. The second suffix. The directory may end with the directory separator. The second

View file

@ -1,22 +1,24 @@
/* Construct a full filename from a directory and a relative filename. /* Construct a full filename from a directory and a relative filename.
Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc. Copyright (C) 2001-2004, 2007-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU Lesser General Public License as
the Free Software Foundation; either version 3 of the License, or published by the Free Software Foundation; either version 2.1 of the
(at your option) any later version. License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _CONCAT_FILENAME_H #ifndef _CONCAT_FILENAME_H
#define _CONCAT_FILENAME_H #define _CONCAT_FILENAME_H
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -26,12 +28,15 @@ extern "C" {
suffix. Return a freshly allocated filename. Return NULL and set errno suffix. Return a freshly allocated filename. Return NULL and set errno
upon memory allocation failure. */ upon memory allocation failure. */
extern char *concatenated_filename (const char *directory, extern char *concatenated_filename (const char *directory,
const char *filename, const char *suffix); const char *filename, const char *suffix)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
/* Concatenate a directory filename, a relative filename and an optional /* Concatenate a directory filename, a relative filename and an optional
suffix. Return a freshly allocated filename. */ suffix. Return a freshly allocated filename. */
extern char *xconcatenated_filename (const char *directory, extern char *xconcatenated_filename (const char *directory,
const char *filename, const char *suffix); const char *filename, const char *suffix)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
_GL_ATTRIBUTE_RETURNS_NONNULL;
#ifdef __cplusplus #ifdef __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Debugging macros and interface. /* Debugging macros and interface.
Copyright (C) 1999-2020 Free Software Foundation, Inc. Copyright (C) 1999-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,22 +12,22 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/intrin/likely.h"
#define DB_NONE (0x000) #define DB_NONE (0x000)
#define DB_BASIC (0x001) #define DB_BASIC (0x001)
#define DB_VERBOSE (0x002) #define DB_VERBOSE (0x002)
#define DB_JOBS (0x004) #define DB_JOBS (0x004)
#define DB_IMPLICIT (0x008) #define DB_IMPLICIT (0x008)
#define DB_PRINT (0x010)
#define DB_WHY (0x020)
#define DB_MAKEFILES (0x100) #define DB_MAKEFILES (0x100)
#define DB_ALL (0xfff) #define DB_ALL (0xfff)
extern int db_level; extern int db_level;
#define ISDB(_l) UNLIKELY((_l)&db_level) #define ISDB(_l) ((_l)&db_level)
/* When adding macros to this list be sure to update the value of /* When adding macros to this list be sure to update the value of
XGETTEXT_OPTIONS in the po/Makevars file. */ XGETTEXT_OPTIONS in the po/Makevars file. */

View file

@ -1,5 +1,5 @@
/* Data base of default implicit rules for GNU Make. /* Data base of default implicit rules for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,37 +12,74 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "makeint.h"
#include <assert.h>
#include "filedef.h"
#include "variable.h"
#include "rule.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
/* Define GCC_IS_NATIVE if gcc is the native development environment on
your system (gcc/bison/flex vs cc/yacc/lex). */
#if defined(__MSDOS__) || defined(__EMX__)
# define GCC_IS_NATIVE
#endif
#include "third_party/make/makeint.inc"
/**/
#include "third_party/make/filedef.h"
#include "third_party/make/variable.h"
#include "third_party/make/rule.h"
#include "third_party/make/dep.h"
#include "third_party/make/job.h"
#include "libc/assert.h"
#include "third_party/make/commands.h"
/* This is the default list of suffixes for suffix rules. /* This is the default list of suffixes for suffix rules.
'.s' must come last, so that a '.o' file will be made from '.s' must come last, so that a '.o' file will be made from
a '.c' or '.p' or ... file rather than from a .s file. */ a '.c' or '.p' or ... file rather than from a .s file. */
static char default_suffixes[] static char default_suffixes[]
#ifdef VMS
/* VMS should include all UNIX/POSIX + some VMS extensions */
= ".out .exe .a .olb .hlb .tlb .mlb .ln .o .obj .c .cxx .cc .cpp .pas .p \
.for .f .r .y .l .ym .yl .mar .s .ss .i .ii .mod .sym .def .h .info .dvi \
.tex .texinfo .texi .txinfo .mem .hlp .brn .rnh .rno .rnt .rnx .w .ch .cweb \
.web .com .sh .elc .el";
#elif defined(__EMX__)
= ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \
.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \
.w .ch .web .sh .elc .el .obj .exe .dll .lib";
#else
= ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \ = ".out .a .ln .o .c .cc .C .cpp .p .f .F .m .r .y .l .ym .yl .s .S \
.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \
.w .ch .web .sh .elc .el"; .w .ch .web .sh .elc .el";
#endif
static struct pspec default_pattern_rules[] = static struct pspec default_pattern_rules[] =
{ {
#ifdef VMS
{ "(%)", "%",
"@if f$$search(\"$@\") .eqs. \"\" then $(LIBRARY)/CREATE/"
"$(or "
"$(patsubst %,TEXT,$(filter %.tlb %.TLB,$@)),"
"$(patsubst %,HELP,$(filter %.hlb %.HLB,$@)),"
"$(patsubst %,MACRO,$(filter %.mlb %.MLB,$@)),"
"$(and "
"$(patsubst %,SHARE,$(filter %.olb %.OLB,$@)),"
"$(patsubst %,SHARE,$(filter %.exe %.EXE,$<))),"
"OBJECT)"
" $@\n"
"$(AR) $(ARFLAGS) $@ $<" },
#else
{ "(%)", "%", { "(%)", "%",
"$(AR) $(ARFLAGS) $@ $<" }, "$(AR) $(ARFLAGS) $@ $<" },
#endif
/* The X.out rules are only in BSD's default set because /* The X.out rules are only in BSD's default set because
BSD Make has no null-suffix rules, so 'foo.out' and BSD Make has no null-suffix rules, so 'foo.out' and
'foo' are the same thing. */ 'foo' are the same thing. */
#ifdef __COSMOPOLITAN__ #ifdef VMS
{ "%.exe", "%", { "%.exe", "%",
"$(CP) $< $@" }, "$(CP) $< $@" },
#endif #endif
{ "%.out", "%", { "%.out", "%",
"@rm -f $@ \n cp $< $@" }, "@rm -f $@ \n cp $< $@" },
@ -58,6 +95,22 @@ static struct pspec default_pattern_rules[] =
static struct pspec default_terminal_rules[] = static struct pspec default_terminal_rules[] =
{ {
#ifdef VMS
/* RCS. */
{ "%", "%$$5lv", /* Multinet style */
"if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" },
{ "%", "[.$$rcs]%$$5lv", /* Multinet style */
"if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" },
{ "%", "%_v", /* Normal style */
"if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" },
{ "%", "[.rcs]%_v", /* Normal style */
"if f$$search(\"$@\") .nes. \"\" then +$(CHECKOUT,v)" },
/* SCCS. */
/* ain't no SCCS on vms */
#else
/* RCS. */ /* RCS. */
{ "%", "%,v", { "%", "%,v",
"$(CHECKOUT,v)" }, "$(CHECKOUT,v)" },
@ -71,12 +124,147 @@ static struct pspec default_terminal_rules[] =
"$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
{ "%", "SCCS/s.%", { "%", "SCCS/s.%",
"$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" }, "$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
#endif /* !VMS */
{ 0, 0, 0 } { 0, 0, 0 }
}; };
static const char *default_suffix_rules[] = static const char *default_suffix_rules[] =
{ {
#ifdef VMS
".o",
"$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".obj",
"$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".s",
"$(LINK.s) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".S",
"$(LINK.S) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".c",
"$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".cc",
"$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".C",
"$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".cpp",
"$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".f",
"$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".m",
"$(LINK.m) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".p",
"$(LINK.p) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".F",
"$(LINK.F) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".r",
"$(LINK.r) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".mod",
"$(COMPILE.mod) -o $@ -e $@ $^",
".def.sym",
"$(COMPILE.def) -o $@ $<",
".sh",
"copy $< >$@",
".obj.exe",
"$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@",
".mar.exe",
"$(COMPILE.mar) $^ \n $(LINK.obj) $(subst .mar,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@",
".s.o",
"$(COMPILE.s) -o $@ $<",
".s.exe",
"$(COMPILE.s) $^ \n $(LINK.obj) $(subst .s,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@",
".c.exe",
"$(COMPILE.c) $^ \n $(LINK.obj) $(subst .c,.obj,$^) $(LOADLIBES) $(LDLIBS) $(CRT0) /exe=$@",
".cc.exe",
#ifdef GCC_IS_NATIVE
"$(COMPILE.cc) $^ \n $(LINK.obj) $(CXXSTARTUP),sys$$disk:[]$(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@",
#else
"$(COMPILE.cc) $^ \n $(CXXLINK.obj) $(subst .cc,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@",
".cxx.exe",
"$(COMPILE.cxx) $^ \n $(CXXLINK.obj) $(subst .cxx,.obj,$^) $(LOADLIBES) $(LXLIBS) $(LDLIBS) $(CXXRT0) /exe=$@",
#endif
".for.exe",
"$(COMPILE.for) $^ \n $(LINK.obj) $(subst .for,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
".pas.exe",
"$(COMPILE.pas) $^ \n $(LINK.obj) $(subst .pas,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
".com",
"copy $< >$@",
".mar.obj",
"$(COMPILE.mar) /obj=$@ $<",
".s.obj",
"$(COMPILE.s) /obj=$@ $<",
".ss.obj",
"$(COMPILE.s) /obj=$@ $<",
".c.i",
"$(COMPILE.c)/prep /list=$@ $<",
".c.s",
"$(COMPILE.c)/noobj/machine /list=$@ $<",
".i.s",
"$(COMPILE.c)/noprep/noobj/machine /list=$@ $<",
".c.obj",
"$(COMPILE.c) /obj=$@ $<",
".c.o",
"$(COMPILE.c) /obj=$@ $<",
".cc.ii",
"$(COMPILE.cc)/prep /list=$@ $<",
".cc.ss",
"$(COMPILE.cc)/noobj/machine /list=$@ $<",
".ii.ss",
"$(COMPILE.cc)/noprep/noobj/machine /list=$@ $<",
".cc.obj",
"$(COMPILE.cc) /obj=$@ $<",
".cc.o",
"$(COMPILE.cc) /obj=$@ $<",
".cxx.obj",
"$(COMPILE.cxx) /obj=$@ $<",
".cxx.o",
"$(COMPILE.cxx) /obj=$@ $<",
".for.obj",
"$(COMPILE.for) /obj=$@ $<",
".for.o",
"$(COMPILE.for) /obj=$@ $<",
".pas.obj",
"$(COMPILE.pas) /obj=$@ $<",
".pas.o",
"$(COMPILE.pas) /obj=$@ $<",
".y.c",
"$(YACC.y) $< \n rename y_tab.c $@",
".l.c",
"$(LEX.l) $< \n rename lexyy.c $@",
".texinfo.info",
"$(MAKEINFO) $<",
".tex.dvi",
"$(TEX) $<",
".cpp.o",
"$(COMPILE.cpp) $(OUTPUT_OPTION) $<",
".f.o",
"$(COMPILE.f) $(OUTPUT_OPTION) $<",
".m.o",
"$(COMPILE.m) $(OUTPUT_OPTION) $<",
".p.o",
"$(COMPILE.p) $(OUTPUT_OPTION) $<",
".r.o",
"$(COMPILE.r) $(OUTPUT_OPTION) $<",
".mod.o",
"$(COMPILE.mod) -o $@ $<",
".c.ln",
"$(LINT.c) -C$* $<",
".y.ln",
"$(YACC.y) $< \n rename y_tab.c $@",
".l.ln",
"@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c",
#else /* ! VMS */
".o", ".o",
"$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@", "$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".s", ".s",
@ -138,12 +326,20 @@ static const char *default_suffix_rules[] =
".c.ln", ".c.ln",
"$(LINT.c) -C$* $<", "$(LINT.c) -C$* $<",
".y.ln", ".y.ln",
#ifndef __MSDOS__
"$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c", "$(YACC.y) $< \n $(LINT.c) -C$* y.tab.c \n $(RM) y.tab.c",
#else
"$(YACC.y) $< \n $(LINT.c) -C$* y_tab.c \n $(RM) y_tab.c",
#endif
".l.ln", ".l.ln",
"@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c", "@$(RM) $*.c\n $(LEX.l) $< > $*.c\n$(LINT.c) -i $*.c -o $@\n $(RM) $*.c",
".y.c", ".y.c",
#ifndef __MSDOS__
"$(YACC.y) $< \n mv -f y.tab.c $@", "$(YACC.y) $< \n mv -f y.tab.c $@",
#else
"$(YACC.y) $< \n mv -f y_tab.c $@",
#endif
".l.c", ".l.c",
"@$(RM) $@ \n $(LEX.l) $< > $@", "@$(RM) $@ \n $(LEX.l) $< > $@",
".ym.m", ".ym.m",
@ -197,24 +393,158 @@ static const char *default_suffix_rules[] =
".web.tex", ".web.tex",
"$(WEAVE) $<", "$(WEAVE) $<",
#endif /* !VMS */
0, 0, 0, 0,
}; };
static const char *default_variables[] = static const char *default_variables[] =
{ {
#ifdef VMS
#ifdef __ALPHA
"ARCH", "ALPHA",
#endif
#ifdef __ia64
"ARCH", "IA64",
#endif
#ifdef __VAX
"ARCH", "VAX",
#endif
"AR", "library",
"LIBRARY", "library",
"ARFLAGS", "/replace",
"AS", "macro",
"MACRO", "macro",
#ifdef GCC_IS_NATIVE
"CC", "gcc",
#else
"CC", "cc",
#endif
"CD", "builtin_cd",
"ECHO", "builtin_echo",
#ifdef GCC_IS_NATIVE
"C++", "gcc/plus",
"CXX", "gcc/plus",
#else
"C++", "cxx",
"CXX", "cxx",
#ifndef __ia64
"CXXLD", "cxxlink",
"CXXLINK", "cxxlink",
#else
/* CXXLINK is not used on VMS/IA64 */
"CXXLD", "link",
"CXXLINK", "link",
#endif
#endif
"CO", "co",
"CPP", "$(CC) /preprocess_only",
"FC", "fortran",
/* System V uses these, so explicit rules using them should work.
However, there is no way to make implicit rules use them and FC. */
"F77", "$(FC)",
"F77FLAGS", "$(FFLAGS)",
"LD", "link",
"LEX", "lex",
"PC", "pascal",
"YACC", "bison/yacc",
"YFLAGS", "/Define/Verbose",
"BISON", "bison",
"MAKEINFO", "makeinfo",
"TEX", "tex",
"TEXINDEX", "texindex",
"RM", "delete/nolog",
"CSTARTUP", "",
#ifdef GCC_IS_NATIVE
"CRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crt0.obj",
"CXXSTARTUP", "gnu_cc_library:crtbegin.obj",
"CXXRT0", ",sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crtend.obj,gnu_cc_library:gxx_main.obj",
"LXLIBS", ",gnu_cc_library:libstdcxx.olb/lib,gnu_cc_library:libgccplus.olb/lib",
"LDLIBS", ",gnu_cc_library:libgcc.olb/lib",
#else
"CRT0", "",
"CXXSTARTUP", "",
"CXXRT0", "",
"LXLIBS", "",
"LDLIBS", "",
#endif
"LINK.o", "$(LD) $(LDFLAGS)",
"LINK.obj", "$(LD) $(LDFLAGS)",
#ifndef GCC_IS_NATIVE
"CXXLINK.obj", "$(CXXLD) $(LDFLAGS)",
"COMPILE.cxx", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
#endif
"COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
"LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
"COMPILE.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
"LINK.m", "$(OBJC) $(OBJCFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
"COMPILE.C", "$(COMPILE.cc)",
"COMPILE.cpp", "$(COMPILE.cc)",
"LINK.C", "$(LINK.cc)",
"LINK.cpp", "$(LINK.cc)",
"YACC.y", "$(YACC) $(YFLAGS)",
"LEX.l", "$(LEX) $(LFLAGS)",
"YACC.m", "$(YACC) $(YFLAGS)",
"LEX.m", "$(LEX) $(LFLAGS) -t",
"COMPILE.for", "$(FC) $(FFLAGS) $(TARGET_ARCH)",
"COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c",
"LINK.f", "$(FC) $(FFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
"LINK.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -c",
"LINK.r", "$(FC) $(FFLAGS) $(RFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.pas", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
"COMPILE.def", "$(M2C) $(M2FLAGS) $(DEFFLAGS) $(TARGET_ARCH)",
"COMPILE.mod", "$(M2C) $(M2FLAGS) $(MODFLAGS) $(TARGET_ARCH)",
"COMPILE.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
"LINK.p", "$(PC) $(PFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)",
"COMPILE.mar", "$(MACRO) $(MACROFLAGS)",
"COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
"LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)",
"COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c",
"PREPROCESS.S", "$(CPP) $(CPPFLAGS)",
"PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F",
"PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
"LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
"MV", "rename/new_version",
"CP", "copy",
".LIBPATTERNS", "%.olb lib%.a",
#else /* !VMS */
"AR", "ar", "AR", "ar",
"ARFLAGS", "rv", #ifdef _AIX
/* AIX requires object file format specification: choose -Xany. */
"ARFLAGS", "-Xany -rv",
#else
"ARFLAGS", "-rv",
#endif
"AS", "as", "AS", "as",
#ifdef GCC_IS_NATIVE #ifdef GCC_IS_NATIVE
"CC", "gcc", "CC", "gcc",
"CXX", "gcc",
"OBJC", "gcc", "OBJC", "gcc",
#else #else
"CC", "cc", "CC", "cc",
"CXX", "g++",
"OBJC", "cc", "OBJC", "cc",
#endif #endif
#ifdef MAKE_CXX
"CXX", MAKE_CXX,
#else
# ifdef GCC_IS_NATIVE
# ifdef __MSDOS__
"CXX", "gpp", /* g++ is an invalid name on MSDOS */
# else
"CXX", "gcc",
# endif /* __MSDOS__ */
# else
"CXX", "g++",
# endif
#endif
/* This expands to $(CO) $(COFLAGS) $< $@ if $@ does not exist, /* This expands to $(CO) $(COFLAGS) $< $@ if $@ does not exist,
and to the empty string if $@ does exist. */ and to the empty string if $@ does exist. */
"CHECKOUT,v", "+$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)", "CHECKOUT,v", "+$(if $(wildcard $@),,$(CO) $(COFLAGS) $< $@)",
@ -222,11 +552,27 @@ static const char *default_variables[] =
"COFLAGS", "", "COFLAGS", "",
"CPP", "$(CC) -E", "CPP", "$(CC) -E",
#ifdef CRAY
"CF77PPFLAGS", "-P",
"CF77PP", "/lib/cpp",
"CFT", "cft77",
"CF", "cf77",
"FC", "$(CF)",
#else /* Not CRAY. */
#ifdef _IBMR2
"FC", "xlf",
#else
#ifdef __convex__
"FC", "fc",
#else
"FC", "f77", "FC", "f77",
#endif /* __convex__ */
#endif /* _IBMR2 */
/* System V uses these, so explicit rules using them should work. /* System V uses these, so explicit rules using them should work.
However, there is no way to make implicit rules use them and FC. */ However, there is no way to make implicit rules use them and FC. */
"F77", "$(FC)", "F77", "$(FC)",
"F77FLAGS", "$(FFLAGS)", "F77FLAGS", "$(FFLAGS)",
#endif /* Cray. */
"GET", SCCS_GET, "GET", SCCS_GET,
"LD", "ld", "LD", "ld",
#ifdef GCC_IS_NATIVE #ifdef GCC_IS_NATIVE
@ -238,8 +584,13 @@ static const char *default_variables[] =
"M2C", "m2c", "M2C", "m2c",
#ifdef pyr #ifdef pyr
"PC", "pascal", "PC", "pascal",
#else
#ifdef CRAY
"PC", "PASCAL",
"SEGLDR", "segldr",
#else #else
"PC", "pc", "PC", "pc",
#endif /* CRAY. */
#endif /* pyr. */ #endif /* pyr. */
#ifdef GCC_IS_NATIVE #ifdef GCC_IS_NATIVE
"YACC", "bison -y", "YACC", "bison -y",
@ -296,14 +647,34 @@ static const char *default_variables[] =
"COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)", "COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
"LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)", "LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)",
"COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c", "COMPILE.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c",
"PREPROCESS.S", "$(CC) -E $(CPPFLAGS)", "PREPROCESS.S", "$(CPP) $(CPPFLAGS)",
"PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F", "PREPROCESS.F", "$(FC) $(FFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -F",
"PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F", "PREPROCESS.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
"LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)", "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
#ifndef NO_MINUS_C_MINUS_O
"OUTPUT_OPTION", "-o $@", "OUTPUT_OPTION", "-o $@",
#endif
#ifdef SCCS_GET_MINUS_G
"SCCS_OUTPUT_OPTION", "-G$@",
#endif
#if defined(_AMIGA)
".LIBPATTERNS", "%.lib",
#elif defined(__MSDOS__)
".LIBPATTERNS", "lib%.a $(DJDIR)/lib/lib%.a",
#elif defined(__APPLE__)
".LIBPATTERNS", "lib%.dylib lib%.a",
#elif defined(__CYGWIN__) || defined(WINDOWS32)
".LIBPATTERNS", "lib%.dll.a %.dll.a lib%.a %.lib lib%.dll %.dll",
#else
".LIBPATTERNS", "lib%.so lib%.a", ".LIBPATTERNS", "lib%.so lib%.a",
#endif
#endif /* !VMS */
/* Make this assignment to avoid undefined variable warnings. */ /* Make this assignment to avoid undefined variable warnings. */
"GNUMAKEFLAGS", "", GNUMAKEFLAGS_NAME, "",
0, 0 0, 0
}; };
@ -336,7 +707,7 @@ set_default_suffixes (void)
installed after. */ installed after. */
void void
install_default_suffix_rules (void) install_default_suffix_rules ()
{ {
const char **s; const char **s;
@ -346,16 +717,18 @@ install_default_suffix_rules (void)
for (s = default_suffix_rules; *s != 0; s += 2) for (s = default_suffix_rules; *s != 0; s += 2)
{ {
struct file *f = enter_file (strcache_add (s[0])); struct file *f = enter_file (strcache_add (s[0]));
/* This function should run before any makefile is parsed. */ /* Install the default rule only if there is no user defined rule. */
assert (f->cmds == 0); if (!f->cmds)
{
f->cmds = xmalloc (sizeof (struct commands)); f->cmds = xmalloc (sizeof (struct commands));
f->cmds->fileinfo.filenm = 0; f->cmds->fileinfo.filenm = NULL;
f->cmds->commands = xstrdup (s[1]); f->cmds->commands = xstrdup (s[1]);
f->cmds->command_lines = 0; f->cmds->command_lines = NULL;
f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT; f->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT;
f->builtin = 1; f->builtin = 1;
} }
} }
}
/* Install the default pattern rules. */ /* Install the default pattern rules. */

View file

@ -1,5 +1,5 @@
/* Definitions of dependency data structures for GNU Make. /* Definitions of dependency data structures for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,9 +12,8 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/x/x.h"
/* Structure used in chains of names, for parsing and globbing. */ /* Structure used in chains of names, for parsing and globbing. */
@ -31,26 +30,32 @@ struct nameseq
These flags are saved in the 'flags' field of each These flags are saved in the 'flags' field of each
'struct goaldep' in the chain returned by 'read_all_makefiles'. */ 'struct goaldep' in the chain returned by 'read_all_makefiles'. */
#define RM_NOFLAG 0
#define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */ #define RM_NO_DEFAULT_GOAL (1 << 0) /* Do not set default goal. */
#define RM_INCLUDED (1 << 1) /* Search makefile search path. */ #define RM_INCLUDED (1 << 1) /* Search makefile search path. */
#define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */ #define RM_DONTCARE (1 << 2) /* No error if it doesn't exist. */
#define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */ #define RM_NO_TILDE (1 << 3) /* Don't expand ~ in file name. */
#define RM_NOFLAG 0
/* Structure representing one dependency of a file. /* Structure representing one dependency of a file.
Each struct file's 'deps' points to a chain of these, through 'next'. Each struct file's 'deps' points to a chain of these, through 'next'.
'stem' is the stem for this dep line of static pattern rule or NULL. */ 'stem' is the stem for this dep line of static pattern rule or NULL.
explicit is set when implicit rule search is performed and the prerequisite
does not contain %. When explicit is set the file is not intermediate. */
#define DEP(_t) \ #define DEP(_t) \
NAMESEQ (_t); \ NAMESEQ (_t); \
struct file *file; \ struct file *file; \
_t *shuf; \
const char *stem; \ const char *stem; \
unsigned int flags : 8; \ unsigned int flags : 8; \
unsigned int changed : 1; \ unsigned int changed : 1; \
unsigned int ignore_mtime : 1; \ unsigned int ignore_mtime : 1; \
unsigned int staticpattern : 1; \ unsigned int staticpattern : 1; \
unsigned int need_2nd_expansion : 1; \ unsigned int need_2nd_expansion : 1; \
unsigned int ignore_automatic_vars : 1 unsigned int ignore_automatic_vars : 1; \
unsigned int is_explicit : 1; \
unsigned int wait_here : 1
struct dep struct dep
{ {
@ -77,6 +82,7 @@ struct goaldep
#define PARSEFS_EXISTS 0x0008 #define PARSEFS_EXISTS 0x0008
#define PARSEFS_NOCACHE 0x0010 #define PARSEFS_NOCACHE 0x0010
#define PARSEFS_ONEWORD 0x0020 #define PARSEFS_ONEWORD 0x0020
#define PARSEFS_WAIT 0x0040
#define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \ #define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \
(_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f)) (_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f))
@ -98,20 +104,19 @@ struct nameseq *ar_glob (const char *arname, const char *member_pattern, size_t
#define dep_name(d) ((d)->name ? (d)->name : (d)->file->name) #define dep_name(d) ((d)->name ? (d)->name : (d)->file->name)
#define alloc_seq_elt(_t) xcalloc (1, sizeof (_t)) #define alloc_seq_elt(_t) xcalloc (sizeof (_t))
void free_ns_chain (struct nameseq *n); void free_ns_chain (struct nameseq *n);
#if defined(MAKE_MAINTAINER_MODE) && defined(__GNUC__) && !defined(__STRICT_ANSI__) #if defined(MAKE_MAINTAINER_MODE) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Use inline to get real type-checking. */ /* Use inline to get real type-checking. */
#define SI static inline #define SI static inline
SI struct nameseq *alloc_ns() { return alloc_seq_elt (struct nameseq); } SI struct nameseq *alloc_ns (void) { return alloc_seq_elt (struct nameseq); }
SI struct dep *alloc_dep() { return alloc_seq_elt (struct dep); } SI struct dep *alloc_dep (void) { return alloc_seq_elt (struct dep); }
SI struct goaldep *alloc_goaldep() { return alloc_seq_elt (struct goaldep); } SI struct goaldep *alloc_goaldep (void) { return alloc_seq_elt (struct goaldep); }
SI void free_ns (struct nameseq *n) { free (n); } SI void free_ns (struct nameseq *n) { free (n); }
SI void free_dep (struct dep *d) { free_ns ((struct nameseq *)d); } SI void free_dep (struct dep *d) { free_ns ((struct nameseq *)d); }
SI void free_goaldep (struct goaldep *g) { free_dep ((struct dep *)g); } SI void free_goaldep (struct goaldep *g) { free_dep ((struct dep *)g); }
SI void free_dep_chain (struct dep *d) { free_ns_chain((struct nameseq *)d); } SI void free_dep_chain (struct dep *d) { free_ns_chain((struct nameseq *)d); }
SI void free_goal_chain (struct goaldep *g) { free_dep_chain((struct dep *)g); } SI void free_goal_chain (struct goaldep *g) { free_dep_chain((struct dep *)g); }
#else #else

899
third_party/make/dir.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,85 +0,0 @@
/* dirname.c -- return all but the last element in a file name
Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2020 Free Software
Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/config.h"
/**/
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/make/dirname.h"
/* Return the length of the prefix of FILE that will be used by
dir_name. If FILE is in the working directory, this returns zero
even though 'dir_name (FILE)' will return ".". Works properly even
if there are trailing slashes (by effectively ignoring them). */
size_t
dir_len (char const *file)
{
size_t prefix_length = FILE_SYSTEM_PREFIX_LEN (file);
size_t length;
/* Advance prefix_length beyond important leading slashes. */
prefix_length += (prefix_length != 0
? (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
&& ISSLASH (file[prefix_length]))
: (ISSLASH (file[0])
? ((DOUBLE_SLASH_IS_DISTINCT_ROOT
&& ISSLASH (file[1]) && ! ISSLASH (file[2])
? 2 : 1))
: 0));
/* Strip the basename and any redundant slashes before it. */
for (length = last_component (file) - file;
prefix_length < length; length--)
if (! ISSLASH (file[length - 1]))
break;
return length;
}
/* In general, we can't use the builtin 'dirname' function if available,
since it has different meanings in different environments.
In some environments the builtin 'dirname' modifies its argument.
Return the leading directories part of FILE, allocated with malloc.
Works properly even if there are trailing slashes (by effectively
ignoring them). Return NULL on failure.
If lstat (FILE) would succeed, then { chdir (dir_name (FILE));
lstat (base_name (FILE)); } will access the same file. Likewise,
if the sequence { chdir (dir_name (FILE));
rename (base_name (FILE), "foo"); } succeeds, you have renamed FILE
to "foo" in the same directory FILE was in. */
char *
mdir_name (char const *file)
{
size_t length = dir_len (file);
bool append_dot = (length == 0
|| (FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
&& length == FILE_SYSTEM_PREFIX_LEN (file)
&& file[2] != '\0' && ! ISSLASH (file[2])));
char *dir = malloc (length + append_dot + 1);
if (!dir)
return NULL;
memcpy (dir, file, length);
if (append_dot)
dir[length++] = '.';
dir[length] = '\0';
return dir;
}

View file

@ -1,52 +0,0 @@
/* Take file names apart into directory and base names.
Copyright (C) 1998, 2001, 2003-2006, 2009-2020 Free Software Foundation,
Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef DIRNAME_H_
# define DIRNAME_H_ 1
#include "third_party/make/filename.h"
# ifndef DIRECTORY_SEPARATOR
# define DIRECTORY_SEPARATOR '/'
# endif
# ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
# endif
#ifdef __cplusplus
extern "C" {
#endif
# if GNULIB_DIRNAME
char *base_name (char const *file) _GL_ATTRIBUTE_MALLOC;
char *dir_name (char const *file);
# endif
char *mdir_name (char const *file);
size_t base_len (char const *file) _GL_ATTRIBUTE_PURE;
size_t dir_len (char const *file) _GL_ATTRIBUTE_PURE;
char *last_component (char const *file) _GL_ATTRIBUTE_PURE;
bool strip_trailing_slashes (char *file);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* not DIRNAME_H_ */

View file

@ -1,187 +0,0 @@
/* Error handler for noninteractive utilities
Copyright (C) 1990-1998, 2000-2007, 2009-2020 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
#include "libc/sysv/consts/f.h"
#include "libc/calls/calls.h"
#include "third_party/make/config.h"
#include "third_party/make/error.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "third_party/make/stdio.h"
#if !_LIBC && ENABLE_NLS
#include "third_party/make/gettext.h"
# define _(msgid) gettext (msgid)
#endif
#ifdef _LIBC
# define mbsrtowcs __mbsrtowcs
# define USE_UNLOCKED_IO 0
# define _GL_ATTRIBUTE_FORMAT_PRINTF(a, b)
# define _GL_ARG_NONNULL(a)
#else
#include "third_party/make/getprogname.h"
#endif
#ifndef _
# define _(String) String
#endif
/* If NULL, error will flush stdout, then print on stderr the program
name, a colon and a space. Otherwise, error will call this
function without parameters instead. */
void (*error_print_progname) (void);
/* This variable is incremented each time 'error' is called. */
unsigned int error_message_count;
#undef fcntl
#define program_name getprogname ()
#define __strerror_r strerror_r
/* Return non-zero if FD is open. */
static int
is_open (int fd)
{
return 0 <= fcntl (fd, F_GETFL);
}
static void
flush_stdout (void)
{
#if !_LIBC
int stdout_fd;
# if GNULIB_FREOPEN_SAFER
/* Use of gnulib's freopen-safer module normally ensures that
fileno (stdout) == 1
whenever stdout is open. */
stdout_fd = STDOUT_FILENO;
# else
/* POSIX states that fileno (stdout) after fclose is unspecified. But in
practice it is not a problem, because stdout is statically allocated and
the fd of a FILE stream is stored as a field in its allocated memory. */
stdout_fd = fileno (stdout);
# endif
/* POSIX states that fflush (stdout) after fclose is unspecified; it
is safe in glibc, but not on all other platforms. fflush (NULL)
is always defined, but too draconian. */
if (0 <= stdout_fd && is_open (stdout_fd))
#endif
fflush (stdout);
}
static void
print_errno_message (int errnum)
{
char const *s;
s = strerror (errnum);
if (! s)
s = _("Unknown system error");
fprintf (stderr, ": %s", s);
}
static void _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) _GL_ARG_NONNULL ((3))
error_tail (int status, int errnum, const char *message, va_list args)
{
vfprintf (stderr, message, args);
++error_message_count;
if (errnum)
print_errno_message (errnum);
putc ('\n', stderr);
fflush (stderr);
if (status)
exit (status);
}
/* Print the program name and error message MESSAGE, which is a printf-style
format string with optional args.
If ERRNUM is nonzero, print its corresponding system error message.
Exit with status STATUS if it is nonzero. */
void
error (int status, int errnum, const char *message, ...)
{
va_list args;
flush_stdout ();
if (error_print_progname)
(*error_print_progname) ();
else
{
fprintf (stderr, "%s: ", program_name);
}
va_start (args, message);
error_tail (status, errnum, message, args);
va_end (args);
}
/* Sometimes we want to have at most one error per line. This
variable controls whether this mode is selected or not. */
int error_one_per_line;
void
error_at_line (int status, int errnum, const char *file_name,
unsigned int line_number, const char *message, ...)
{
va_list args;
if (error_one_per_line)
{
static const char *old_file_name;
static unsigned int old_line_number;
if (old_line_number == line_number
&& (file_name == old_file_name
|| (old_file_name != NULL
&& file_name != NULL
&& strcmp (old_file_name, file_name) == 0)))
/* Simply return and print nothing. */
return;
old_file_name = file_name;
old_line_number = line_number;
}
flush_stdout ();
if (error_print_progname)
(*error_print_progname) ();
else
{
fprintf (stderr, "%s:", program_name);
}
fprintf (stderr, file_name != NULL ? "%s:%u: " : " ",
file_name, line_number);
va_start (args, message);
error_tail (status, errnum, message, args);
va_end (args);
}
#ifdef _LIBC
/* Make the weak alias. */
# undef error
# undef error_at_line
weak_alias (__error, error)
weak_alias (__error_at_line, error_at_line)
#endif

View file

@ -1,75 +0,0 @@
/* Declaration for error-reporting function
Copyright (C) 1995-1997, 2003, 2006, 2008-2020 Free Software Foundation,
Inc.
This file is part of the GNU C Library.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _ERROR_H
#define _ERROR_H 1
/* The __attribute__ feature is available in gcc versions 2.5 and later.
The __-protected variants of the attributes 'format' and 'printf' are
accepted by gcc versions 2.6.4 (effectively 2.7) and later.
We enable _GL_ATTRIBUTE_FORMAT only if these are supported too, because
gnulib and libintl do '#define printf __printf__' when they override
the 'printf' function. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
#else
# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */
#endif
/* On mingw, the flavor of printf depends on whether the extensions module
* is in use; the check for <stdio.h> determines the witness macro. */
#ifndef _GL_ATTRIBUTE_SPEC_PRINTF
# if GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU
# define _GL_ATTRIBUTE_SPEC_PRINTF __gnu_printf__
# else
# define _GL_ATTRIBUTE_SPEC_PRINTF __printf__
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Print a message with 'fprintf (stderr, FORMAT, ...)';
if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM).
If STATUS is nonzero, terminate the program with 'exit (STATUS)'. */
extern void error (int __status, int __errnum, const char *__format, ...)
_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF, 3, 4));
extern void error_at_line (int __status, int __errnum, const char *__fname,
unsigned int __lineno, const char *__format, ...)
_GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF, 5, 6));
/* If NULL, error will flush stdout, then print on stderr the program
name, a colon and a space. Otherwise, error will call this
function without parameters instead. */
extern void (*error_print_progname) (void);
/* This variable is incremented each time 'error' is called. */
extern unsigned int error_message_count;
/* Sometimes we want to have at most one error per line. This
variable controls whether this mode is selected or not. */
extern int error_one_per_line;
#ifdef __cplusplus
}
#endif
#endif /* error.h */

View file

@ -1,18 +0,0 @@
/* Failure exit status
Copyright (C) 2002-2003, 2005-2007, 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
int volatile exit_failure = 1; /*TODO: this should be EXIT_FAILURE; */

View file

@ -1,18 +0,0 @@
/* Failure exit status
Copyright (C) 2002, 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
extern int volatile exit_failure;

View file

@ -1,5 +1,5 @@
/* Variable expansion functions for GNU Make. /* Variable expansion functions for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,16 +12,18 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
/**/
#include "third_party/make/filedef.h" #include <assert.h>
#include "third_party/make/job.h"
#include "third_party/make/commands.h" #include "commands.h"
#include "third_party/make/variable.h" #include "debug.h"
#include "libc/x/x.h" #include "filedef.h"
#include "third_party/make/rule.h" #include "job.h"
#include "variable.h"
#include "rule.h"
/* Initially, any errors reported when expanding strings will be reported /* Initially, any errors reported when expanding strings will be reported
against the file where the error appears. */ against the file where the error appears. */
@ -66,14 +68,14 @@ variable_buffer_output (char *ptr, const char *string, size_t length)
ptr = variable_buffer + offset; ptr = variable_buffer + offset;
} }
memcpy (ptr, string, length); return mempcpy (ptr, string, length);
return ptr + length;
} }
/* Return a pointer to the beginning of the variable buffer. */ /* Return a pointer to the beginning of the variable buffer.
This is called from main() and it should never be null afterward. */
static char * char *
initialize_variable_output (void) initialize_variable_output ()
{ {
/* If we don't have a variable output buffer yet, get one. */ /* If we don't have a variable output buffer yet, get one. */
@ -100,6 +102,29 @@ recursively_expand_for_file (struct variable *v, struct file *file)
struct variable_set_list *save = 0; struct variable_set_list *save = 0;
int set_reading = 0; int set_reading = 0;
/* If we're expanding to put into the environment of a shell function then
ignore any recursion issues: for backward-compatibility we will use
the value of the environment variable we were started with. */
if (v->expanding && env_recursion)
{
size_t nl = strlen (v->name);
char **ep;
DB (DB_VERBOSE,
(_("%s:%lu: not recursively expanding %s to export to shell function\n"),
v->fileinfo.filenm, v->fileinfo.lineno, v->name));
/* We could create a hash for the original environment for speed, but a
reasonably written makefile shouldn't hit this situation... */
for (ep = environ; *ep != 0; ++ep)
if ((*ep)[nl] == '=' && strncmp (*ep, v->name, nl) == 0)
return xstrdup ((*ep) + nl + 1);
/* If there's nothing in the parent environment, use the empty string.
This isn't quite correct since the variable should not exist at all,
but getting that to work would be involved. */
return xstrdup ("");
}
/* Don't install a new location if this location is empty. /* Don't install a new location if this location is empty.
This can happen for command-line variables, builtin variables, etc. */ This can happen for command-line variables, builtin variables, etc. */
saved_varp = expanding_var; saved_varp = expanding_var;
@ -152,7 +177,10 @@ recursively_expand_for_file (struct variable *v, struct file *file)
/* Expand a simple reference to variable NAME, which is LENGTH chars long. */ /* Expand a simple reference to variable NAME, which is LENGTH chars long. */
static inline char * #ifdef __GNUC__
__inline
#endif
static char *
reference_variable (char *o, const char *name, size_t length) reference_variable (char *o, const char *name, size_t length)
{ {
struct variable *v; struct variable *v;
@ -203,7 +231,7 @@ variable_expand_string (char *line, const char *string, size_t length)
if (length == 0) if (length == 0)
{ {
variable_buffer_output (o, "", 1); variable_buffer_output (o, "", 1);
return (variable_buffer); return variable_buffer;
} }
/* We need a copy of STRING: due to eval, it's possible that it will get /* We need a copy of STRING: due to eval, it's possible that it will get
@ -441,7 +469,6 @@ expand_argument (const char *str, const char *end)
r = allocated_variable_expand (tmp); r = allocated_variable_expand (tmp);
if (alloc)
free (alloc); free (alloc);
return r; return r;

View file

@ -1,555 +0,0 @@
/* Provide file descriptor control.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Eric Blake <ebb9@byu.net>. */
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/sysv/consts/f.h"
#include "third_party/make/config.h"
/* Specification. */
#include "third_party/make/fcntl.h"
#if defined _WIN32 && !defined __CYGWIN__
/* Get declarations of the native Windows API functions. */
/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */
#define OPEN_MAX_MAX 0x10000
/* Duplicate OLDFD into the first available slot of at least NEWFD,
which must be positive, with FLAGS determining whether the duplicate
will be inheritable. */
static int dupfd(int oldfd, int newfd, int flags) {
/* Mingw has no way to create an arbitrary fd. Iterate until all
file descriptors less than newfd are filled up. */
HANDLE curr_process = GetCurrentProcess();
HANDLE old_handle = (HANDLE)_get_osfhandle(oldfd);
unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
unsigned int fds_to_close_bound = 0;
int result;
BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
int mode;
if (newfd < 0 || getdtablesize() <= newfd) {
errno = EINVAL;
return -1;
}
if (old_handle == INVALID_HANDLE_VALUE ||
(mode = setmode(oldfd, O_BINARY)) == -1) {
/* oldfd is not open, or is an unassigned standard file
descriptor. */
errno = EBADF;
return -1;
}
setmode(oldfd, mode);
flags |= mode;
for (;;) {
HANDLE new_handle;
int duplicated_fd;
unsigned int index;
if (!DuplicateHandle(curr_process, /* SourceProcessHandle */
old_handle, /* SourceHandle */
curr_process, /* TargetProcessHandle */
(PHANDLE)&new_handle, /* TargetHandle */
(DWORD)0, /* DesiredAccess */
inherit, /* InheritHandle */
DUPLICATE_SAME_ACCESS)) /* Options */
{
switch (GetLastError()) {
case ERROR_TOO_MANY_OPEN_FILES:
errno = EMFILE;
break;
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_TARGET_HANDLE:
case ERROR_DIRECT_ACCESS_HANDLE:
errno = EBADF;
break;
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_ACCESS:
errno = EINVAL;
break;
default:
errno = EACCES;
break;
}
result = -1;
break;
}
duplicated_fd = _open_osfhandle((intptr_t)new_handle, flags);
if (duplicated_fd < 0) {
CloseHandle(new_handle);
result = -1;
break;
}
if (newfd <= duplicated_fd) {
result = duplicated_fd;
break;
}
/* Set the bit duplicated_fd in fds_to_close[]. */
index = (unsigned int)duplicated_fd / CHAR_BIT;
if (fds_to_close_bound <= index) {
if (sizeof fds_to_close <= index) /* Need to increase OPEN_MAX_MAX. */
abort();
memset(fds_to_close + fds_to_close_bound, '\0',
index + 1 - fds_to_close_bound);
fds_to_close_bound = index + 1;
}
fds_to_close[index] |= 1 << ((unsigned int)duplicated_fd % CHAR_BIT);
}
/* Close the previous fds that turned out to be too small. */
{
int saved_errno = errno;
unsigned int duplicated_fd;
for (duplicated_fd = 0; duplicated_fd < fds_to_close_bound * CHAR_BIT;
duplicated_fd++)
if ((fds_to_close[duplicated_fd / CHAR_BIT] >>
(duplicated_fd % CHAR_BIT)) &
1)
close(duplicated_fd);
errno = saved_errno;
}
#if REPLACE_FCHDIR
if (0 <= result) result = _gl_register_dup(oldfd, result);
#endif
return result;
}
#endif /* W32 */
/* Forward declarations, because we '#undef fcntl' in the middle of this
compilation unit. */
/* Our implementation of fcntl (fd, F_DUPFD, target). */
static int rpl_fcntl_DUPFD(int fd, int target);
/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target). */
static int rpl_fcntl_DUPFD_CLOEXEC(int fd, int target);
#ifdef __KLIBC__
/* Adds support for fcntl on directories. */
static int klibc_fcntl(int fd, int action, /* arg */...);
#endif
/* Perform the specified ACTION on the file descriptor FD, possibly
using the argument ARG further described below. This replacement
handles the following actions, and forwards all others on to the
native fcntl. An unrecognized ACTION returns -1 with errno set to
EINVAL.
F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
If successful, return the duplicate, which will be inheritable;
otherwise return -1 and set errno.
F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
target fd. If successful, return the duplicate, which will not be
inheritable; otherwise return -1 and set errno.
F_GETFD - ARG need not be present. If successful, return a
non-negative value containing the descriptor flags of FD (only
FD_CLOEXEC is portable, but other flags may be present); otherwise
return -1 and set errno. */
int fcntl_(int fd, int action, /* arg */...)
#undef fcntl
#ifdef __KLIBC__
#define fcntl_ klibc_fcntl
#endif
{
va_list arg;
int result = -1;
va_start(arg, action);
if (action == F_DUPFD) {
int target = va_arg(arg, int);
result = rpl_fcntl_DUPFD(fd, target);
}
else if (action == F_DUPFD_CLOEXEC) {
int target = va_arg(arg, int);
result = rpl_fcntl_DUPFD_CLOEXEC(fd, target);
}
#if !HAVE_FCNTL
else if (action == F_GETFD) {
#if defined _WIN32 && !defined __CYGWIN__
HANDLE handle = (HANDLE)_get_osfhandle(fd);
DWORD flags;
if (handle == INVALID_HANDLE_VALUE ||
GetHandleInformation(handle, &flags) == 0)
errno = EBADF;
else
result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
#else /* !W32 */
/* Use dup2 to reject invalid file descriptors. No way to
access this information, so punt. */
if (0 <= dup2(fd, fd)) result = 0;
#endif /* !W32 */
} /* F_GETFD */
#endif /* !HAVE_FCNTL */
/* Implementing F_SETFD on mingw is not trivial - there is no
API for changing the O_NOINHERIT bit on an fd, and merely
changing the HANDLE_FLAG_INHERIT bit on the underlying handle
can lead to odd state. It may be possible by duplicating the
handle, using _open_osfhandle with the right flags, then
using dup2 to move the duplicate onto the original, but that
is not supported for now. */
else {
#if 0
switch (action)
{
#ifdef F_BARRIERFSYNC /* macOS */
case F_BARRIERFSYNC:
#endif
#ifdef F_CHKCLEAN /* macOS */
case F_CHKCLEAN:
#endif
#ifdef F_CLOSEM /* NetBSD, HP-UX */
case F_CLOSEM:
#endif
#ifdef F_FLUSH_DATA /* macOS */
case F_FLUSH_DATA:
#endif
#ifdef F_FREEZE_FS /* macOS */
case F_FREEZE_FS:
#endif
#ifdef F_FULLFSYNC /* macOS */
case F_FULLFSYNC:
#endif
#ifdef F_GETCONFINED /* macOS */
case F_GETCONFINED:
#endif
#ifdef F_GETDEFAULTPROTLEVEL /* macOS */
case F_GETDEFAULTPROTLEVEL:
#endif
#ifdef F_GETFD /* POSIX */
case F_GETFD:
#endif
#ifdef F_GETFL /* POSIX */
case F_GETFL:
#endif
#ifdef F_GETLEASE /* Linux */
case F_GETLEASE:
#endif
#ifdef F_GETNOSIGPIPE /* macOS */
case F_GETNOSIGPIPE:
#endif
#ifdef F_GETOWN /* POSIX */
case F_GETOWN:
#endif
#ifdef F_GETPIPE_SZ /* Linux */
case F_GETPIPE_SZ:
#endif
#ifdef F_GETPROTECTIONCLASS /* macOS */
case F_GETPROTECTIONCLASS:
#endif
#ifdef F_GETPROTECTIONLEVEL /* macOS */
case F_GETPROTECTIONLEVEL:
#endif
#ifdef F_GET_SEALS /* Linux */
case F_GET_SEALS:
#endif
#ifdef F_GETSIG /* Linux */
case F_GETSIG:
#endif
#ifdef F_MAXFD /* NetBSD */
case F_MAXFD:
#endif
#ifdef F_RECYCLE /* macOS */
case F_RECYCLE:
#endif
#ifdef F_SETFIFOENH /* HP-UX */
case F_SETFIFOENH:
#endif
#ifdef F_THAW_FS /* macOS */
case F_THAW_FS:
#endif
/* These actions take no argument. */
result = fcntl (fd, action);
break;
#ifdef F_ADD_SEALS /* Linux */
case F_ADD_SEALS:
#endif
#ifdef F_BADFD /* Solaris */
case F_BADFD:
#endif
#ifdef F_CHECK_OPENEVT /* macOS */
case F_CHECK_OPENEVT:
#endif
#ifdef F_DUP2FD /* FreeBSD, AIX, Solaris */
case F_DUP2FD:
#endif
#ifdef F_DUP2FD_CLOEXEC /* FreeBSD, Solaris */
case F_DUP2FD_CLOEXEC:
#endif
#ifdef F_DUP2FD_CLOFORK /* Solaris */
case F_DUP2FD_CLOFORK:
#endif
#ifdef F_DUPFD /* POSIX */
case F_DUPFD:
#endif
#ifdef F_DUPFD_CLOEXEC /* POSIX */
case F_DUPFD_CLOEXEC:
#endif
#ifdef F_DUPFD_CLOFORK /* Solaris */
case F_DUPFD_CLOFORK:
#endif
#ifdef F_GETXFL /* Solaris */
case F_GETXFL:
#endif
#ifdef F_GLOBAL_NOCACHE /* macOS */
case F_GLOBAL_NOCACHE:
#endif
#ifdef F_MAKECOMPRESSED /* macOS */
case F_MAKECOMPRESSED:
#endif
#ifdef F_MOVEDATAEXTENTS /* macOS */
case F_MOVEDATAEXTENTS:
#endif
#ifdef F_NOCACHE /* macOS */
case F_NOCACHE:
#endif
#ifdef F_NODIRECT /* macOS */
case F_NODIRECT:
#endif
#ifdef F_NOTIFY /* Linux */
case F_NOTIFY:
#endif
#ifdef F_OPLKACK /* IRIX */
case F_OPLKACK:
#endif
#ifdef F_OPLKREG /* IRIX */
case F_OPLKREG:
#endif
#ifdef F_RDAHEAD /* macOS */
case F_RDAHEAD:
#endif
#ifdef F_SETBACKINGSTORE /* macOS */
case F_SETBACKINGSTORE:
#endif
#ifdef F_SETCONFINED /* macOS */
case F_SETCONFINED:
#endif
#ifdef F_SETFD /* POSIX */
case F_SETFD:
#endif
#ifdef F_SETFL /* POSIX */
case F_SETFL:
#endif
#ifdef F_SETLEASE /* Linux */
case F_SETLEASE:
#endif
#ifdef F_SETNOSIGPIPE /* macOS */
case F_SETNOSIGPIPE:
#endif
#ifdef F_SETOWN /* POSIX */
case F_SETOWN:
#endif
#ifdef F_SETPIPE_SZ /* Linux */
case F_SETPIPE_SZ:
#endif
#ifdef F_SETPROTECTIONCLASS /* macOS */
case F_SETPROTECTIONCLASS:
#endif
#ifdef F_SETSIG /* Linux */
case F_SETSIG:
#endif
#ifdef F_SINGLE_WRITER /* macOS */
case F_SINGLE_WRITER:
#endif
/* These actions take an 'int' argument. */
{
int x = va_arg (arg, int);
result = fcntl (fd, action, x);
}
break;
default:
/* Other actions take a pointer argument. */
{
void *p = va_arg (arg, void *);
result = fcntl (fd, action, p);
}
break;
}
#else
errno = EINVAL;
#endif
}
va_end(arg);
return result;
}
static int rpl_fcntl_DUPFD(int fd, int target) {
int result;
#if !HAVE_FCNTL
result = dupfd(fd, target, 0);
#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
/* Detect invalid target; needed for cygwin 1.5.x. */
if (target < 0 || getdtablesize() <= target) {
result = -1;
errno = EINVAL;
} else {
/* Haiku alpha 2 loses fd flags on original. */
int flags = fcntl(fd, F_GETFD);
if (flags < 0)
result = -1;
else {
result = fcntl(fd, F_DUPFD, target);
if (0 <= result && fcntl(fd, F_SETFD, flags) == -1) {
int saved_errno = errno;
close(result);
result = -1;
errno = saved_errno;
}
#if REPLACE_FCHDIR
if (0 <= result) result = _gl_register_dup(fd, result);
#endif
}
}
#else
result = fcntl(fd, F_DUPFD, target);
#endif
return result;
}
static int rpl_fcntl_DUPFD_CLOEXEC(int fd, int target) {
int result;
#if !HAVE_FCNTL
result = dupfd(fd, target, O_CLOEXEC);
#else /* HAVE_FCNTL */
#if defined __HAIKU__
/* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets
the FD_CLOEXEC flag on fd, not on target. Therefore avoid the
system fcntl in this case. */
#define have_dupfd_cloexec -1
#else
/* Try the system call first, if the headers claim it exists
(that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
may be running with a glibc that has the macro but with an
older kernel that does not support it. Cache the
information on whether the system call really works, but
avoid caching failure if the corresponding F_DUPFD fails
for any reason. 0 = unknown, 1 = yes, -1 = no. */
static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
if (0 <= have_dupfd_cloexec) {
result = fcntl(fd, F_DUPFD_CLOEXEC, target);
if (0 <= result || errno != EINVAL) {
have_dupfd_cloexec = 1;
#if REPLACE_FCHDIR
if (0 <= result) result = _gl_register_dup(fd, result);
#endif
} else {
result = rpl_fcntl_DUPFD(fd, target);
if (result >= 0) have_dupfd_cloexec = -1;
}
} else
#endif
result = rpl_fcntl_DUPFD(fd, target);
if (0 <= result && have_dupfd_cloexec == -1) {
int flags = fcntl(result, F_GETFD);
if (flags < 0 || fcntl(result, F_SETFD, flags | FD_CLOEXEC) == -1) {
int saved_errno = errno;
close(result);
errno = saved_errno;
result = -1;
}
}
#endif /* HAVE_FCNTL */
return result;
}
#undef fcntl
#ifdef __KLIBC__
static int klibc_fcntl(int fd, int action, /* arg */...) {
va_list arg_ptr;
int arg;
struct stat sbuf;
int result;
va_start(arg_ptr, action);
arg = va_arg(arg_ptr, int);
result = fcntl(fd, action, arg);
/* EPERM for F_DUPFD, ENOTSUP for others */
if (result == -1 && (errno == EPERM || errno == ENOTSUP) &&
!fstat(fd, &sbuf) && S_ISDIR(sbuf.st_mode)) {
ULONG ulMode;
switch (action) {
case F_DUPFD:
/* Find available fd */
while (fcntl(arg, F_GETFL) != -1 || errno != EBADF) arg++;
result = dup2(fd, arg);
break;
/* Using underlying APIs is right ? */
case F_GETFD:
if (DosQueryFHState(fd, &ulMode)) break;
result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
break;
case F_SETFD:
if (arg & ~FD_CLOEXEC) break;
if (DosQueryFHState(fd, &ulMode)) break;
if (arg & FD_CLOEXEC)
ulMode |= OPEN_FLAGS_NOINHERIT;
else
ulMode &= ~OPEN_FLAGS_NOINHERIT;
/* Filter supported flags. */
ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR |
OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
if (DosSetFHState(fd, ulMode)) break;
result = 0;
break;
case F_GETFL:
result = 0;
break;
case F_SETFL:
if (arg != 0) break;
result = 0;
break;
default:
errno = EINVAL;
break;
}
}
va_end(arg_ptr);
return result;
}
#endif

View file

@ -1,810 +0,0 @@
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
/* Like <fcntl.h>, but with non-working flags defined to 0.
Copyright (C) 2006-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* written by Paul Eggert */
#if __GNUC__ >= 3
#pragma GCC system_header
#endif
#if defined __need_system_fcntl_h
/* Special invocation convention. */
/* Needed before <sys/stat.h>.
May also define off_t to a 64-bit type on native Windows. */
/* Native Windows platforms declare open(), creat() in <io.h>. */
#if (0 || 0 || defined GNULIB_POSIXCHECK) && \
(defined _WIN32 && !defined __CYGWIN__)
#endif
#else
/* Normal invocation convention. */
#ifndef _GL_FCNTL_H
/* Needed before <sys/stat.h>.
May also define off_t to a 64-bit type on native Windows. */
/* On some systems other than glibc, <sys/stat.h> is a prerequisite of
<fcntl.h>. On glibc systems, we would like to avoid namespace pollution.
But on glibc systems, <fcntl.h> includes <sys/stat.h> inside an
extern "C" { ... } block, which leads to errors in C++ mode with the
overridden <sys/stat.h> from gnulib. These errors are known to be gone
with g++ version >= 4.3. */
#if !(defined __GLIBC__ || defined __UCLIBC__) || \
(defined __cplusplus && defined GNULIB_NAMESPACE && \
(defined __ICC || \
!(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))))
#endif
/* The include_next requires a split double-inclusion guard. */
/* Native Windows platforms declare open(), creat() in <io.h>. */
#if (0 || 0 || defined GNULIB_POSIXCHECK) && \
(defined _WIN32 && !defined __CYGWIN__)
#endif
#ifndef _GL_FCNTL_H
#define _GL_FCNTL_H
/* The definitions of _GL_FUNCDECL_RPL etc. are copied here. */
/* C++ compatible function declaration macros.
Copyright (C) 2010-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GL_CXXDEFS_H
#define _GL_CXXDEFS_H
/* Begin/end the GNULIB_NAMESPACE namespace. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_BEGIN_NAMESPACE namespace GNULIB_NAMESPACE {
#define _GL_END_NAMESPACE }
#else
#define _GL_BEGIN_NAMESPACE
#define _GL_END_NAMESPACE
#endif
/* The three most frequent use cases of these macros are:
* For providing a substitute for a function that is missing on some
platforms, but is declared and works fine on the platforms on which
it exists:
#if @GNULIB_FOO@
# if !@HAVE_FOO@
_GL_FUNCDECL_SYS (foo, ...);
# endif
_GL_CXXALIAS_SYS (foo, ...);
_GL_CXXALIASWARN (foo);
#elif defined GNULIB_POSIXCHECK
...
#endif
* For providing a replacement for a function that exists on all platforms,
but is broken/insufficient and needs to be replaced on some platforms:
#if @GNULIB_FOO@
# if @REPLACE_FOO@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef foo
# define foo rpl_foo
# endif
_GL_FUNCDECL_RPL (foo, ...);
_GL_CXXALIAS_RPL (foo, ...);
# else
_GL_CXXALIAS_SYS (foo, ...);
# endif
_GL_CXXALIASWARN (foo);
#elif defined GNULIB_POSIXCHECK
...
#endif
* For providing a replacement for a function that exists on some platforms
but is broken/insufficient and needs to be replaced on some of them and
is additionally either missing or undeclared on some other platforms:
#if @GNULIB_FOO@
# if @REPLACE_FOO@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef foo
# define foo rpl_foo
# endif
_GL_FUNCDECL_RPL (foo, ...);
_GL_CXXALIAS_RPL (foo, ...);
# else
# if !@HAVE_FOO@ or if !@HAVE_DECL_FOO@
_GL_FUNCDECL_SYS (foo, ...);
# endif
_GL_CXXALIAS_SYS (foo, ...);
# endif
_GL_CXXALIASWARN (foo);
#elif defined GNULIB_POSIXCHECK
...
#endif
*/
/* _GL_EXTERN_C declaration;
performs the declaration with C linkage. */
#if defined __cplusplus
#define _GL_EXTERN_C extern "C"
#else
#define _GL_EXTERN_C extern
#endif
/* _GL_FUNCDECL_RPL (func, rettype, parameters_and_attributes);
declares a replacement function, named rpl_func, with the given prototype,
consisting of return type, parameters, and attributes.
Example:
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
_GL_ARG_NONNULL ((1)));
*/
#define _GL_FUNCDECL_RPL(func, rettype, parameters_and_attributes) \
_GL_FUNCDECL_RPL_1(rpl_##func, rettype, parameters_and_attributes)
#define _GL_FUNCDECL_RPL_1(rpl_func, rettype, parameters_and_attributes) \
_GL_EXTERN_C rettype rpl_func parameters_and_attributes
/* _GL_FUNCDECL_SYS (func, rettype, parameters_and_attributes);
declares the system function, named func, with the given prototype,
consisting of return type, parameters, and attributes.
Example:
_GL_FUNCDECL_SYS (open, int, (const char *filename, int flags, ...)
_GL_ARG_NONNULL ((1)));
*/
#define _GL_FUNCDECL_SYS(func, rettype, parameters_and_attributes) \
_GL_EXTERN_C rettype func parameters_and_attributes
/* _GL_CXXALIAS_RPL (func, rettype, parameters);
declares a C++ alias called GNULIB_NAMESPACE::func
that redirects to rpl_func, if GNULIB_NAMESPACE is defined.
Example:
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
Wrapping rpl_func in an object with an inline conversion operator
avoids a reference to rpl_func unless GNULIB_NAMESPACE::func is
actually used in the program. */
#define _GL_CXXALIAS_RPL(func, rettype, parameters) \
_GL_CXXALIAS_RPL_1(func, rpl_##func, rettype, parameters)
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIAS_RPL_1(func, rpl_func, rettype, parameters) \
namespace GNULIB_NAMESPACE { \
static const struct _gl_##func##_wrapper { \
typedef rettype(*type) parameters; \
\
inline operator type() const { \
return ::rpl_func; \
} \
} func = {}; \
} \
_GL_EXTERN_C int _gl_cxxalias_dummy
#else
#define _GL_CXXALIAS_RPL_1(func, rpl_func, rettype, parameters) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIAS_RPL_CAST_1 (func, rpl_func, rettype, parameters);
is like _GL_CXXALIAS_RPL_1 (func, rpl_func, rettype, parameters);
except that the C function rpl_func may have a slightly different
declaration. A cast is used to silence the "invalid conversion" error
that would otherwise occur. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIAS_RPL_CAST_1(func, rpl_func, rettype, parameters) \
namespace GNULIB_NAMESPACE { \
static const struct _gl_##func##_wrapper { \
typedef rettype(*type) parameters; \
\
inline operator type() const { \
return reinterpret_cast<type>(::rpl_func); \
} \
} func = {}; \
} \
_GL_EXTERN_C int _gl_cxxalias_dummy
#else
#define _GL_CXXALIAS_RPL_CAST_1(func, rpl_func, rettype, parameters) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIAS_SYS (func, rettype, parameters);
declares a C++ alias called GNULIB_NAMESPACE::func
that redirects to the system provided function func, if GNULIB_NAMESPACE
is defined.
Example:
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
Wrapping func in an object with an inline conversion operator
avoids a reference to func unless GNULIB_NAMESPACE::func is
actually used in the program. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIAS_SYS(func, rettype, parameters) \
namespace GNULIB_NAMESPACE { \
static const struct _gl_##func##_wrapper { \
typedef rettype(*type) parameters; \
\
inline operator type() const { \
return ::func; \
} \
} func = {}; \
} \
_GL_EXTERN_C int _gl_cxxalias_dummy
#else
#define _GL_CXXALIAS_SYS(func, rettype, parameters) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIAS_SYS_CAST (func, rettype, parameters);
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
except that the C function func may have a slightly different declaration.
A cast is used to silence the "invalid conversion" error that would
otherwise occur. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIAS_SYS_CAST(func, rettype, parameters) \
namespace GNULIB_NAMESPACE { \
static const struct _gl_##func##_wrapper { \
typedef rettype(*type) parameters; \
\
inline operator type() const { \
return reinterpret_cast<type>(::func); \
} \
} func = {}; \
} \
_GL_EXTERN_C int _gl_cxxalias_dummy
#else
#define _GL_CXXALIAS_SYS_CAST(func, rettype, parameters) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIAS_SYS_CAST2 (func, rettype, parameters, rettype2, parameters2);
is like _GL_CXXALIAS_SYS (func, rettype, parameters);
except that the C function is picked among a set of overloaded functions,
namely the one with rettype2 and parameters2. Two consecutive casts
are used to silence the "cannot find a match" and "invalid conversion"
errors that would otherwise occur. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
/* The outer cast must be a reinterpret_cast.
The inner cast: When the function is defined as a set of overloaded
functions, it works as a static_cast<>, choosing the designated variant.
When the function is defined as a single variant, it works as a
reinterpret_cast<>. The parenthesized cast syntax works both ways. */
#define _GL_CXXALIAS_SYS_CAST2(func, rettype, parameters, rettype2, \
parameters2) \
namespace GNULIB_NAMESPACE { \
static const struct _gl_##func##_wrapper { \
typedef rettype(*type) parameters; \
\
inline operator type() const { \
return reinterpret_cast<type>((rettype2(*) parameters2)(::func)); \
} \
} func = {}; \
} \
_GL_EXTERN_C int _gl_cxxalias_dummy
#else
#define _GL_CXXALIAS_SYS_CAST2(func, rettype, parameters, rettype2, \
parameters2) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIASWARN (func);
causes a warning to be emitted when ::func is used but not when
GNULIB_NAMESPACE::func is used. func must be defined without overloaded
variants. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIASWARN(func) _GL_CXXALIASWARN_1(func, GNULIB_NAMESPACE)
#define _GL_CXXALIASWARN_1(func, namespace) _GL_CXXALIASWARN_2(func, namespace)
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
we enable the warning only when not optimizing. */
#if !__OPTIMIZE__
#define _GL_CXXALIASWARN_2(func, namespace) \
_GL_WARN_ON_USE(func, \
"The symbol ::" #func " refers to the system function. " \
"Use " #namespace "::" #func " instead.")
#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
#define _GL_CXXALIASWARN_2(func, namespace) extern __typeof__(func) func
#else
#define _GL_CXXALIASWARN_2(func, namespace) _GL_EXTERN_C int _gl_cxxalias_dummy
#endif
#else
#define _GL_CXXALIASWARN(func) _GL_EXTERN_C int _gl_cxxalias_dummy
#endif
/* _GL_CXXALIASWARN1 (func, rettype, parameters_and_attributes);
causes a warning to be emitted when the given overloaded variant of ::func
is used but not when GNULIB_NAMESPACE::func is used. */
#if defined __cplusplus && defined GNULIB_NAMESPACE
#define _GL_CXXALIASWARN1(func, rettype, parameters_and_attributes) \
_GL_CXXALIASWARN1_1(func, rettype, parameters_and_attributes, \
GNULIB_NAMESPACE)
#define _GL_CXXALIASWARN1_1(func, rettype, parameters_and_attributes, \
namespace) \
_GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, namespace)
/* To work around GCC bug <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43881>,
we enable the warning only when not optimizing. */
#if !__OPTIMIZE__
#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \
namespace) \
_GL_WARN_ON_USE_CXX(func, rettype, parameters_and_attributes, \
"The symbol ::" #func " refers to the system function. " \
"Use " #namespace "::" #func " instead.")
#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \
namespace) \
extern __typeof__(func) func
#else
#define _GL_CXXALIASWARN1_2(func, rettype, parameters_and_attributes, \
namespace) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
#else
#define _GL_CXXALIASWARN1(func, rettype, parameters_and_attributes) \
_GL_EXTERN_C int _gl_cxxalias_dummy
#endif
#endif /* _GL_CXXDEFS_H */
/* The definition of _GL_ARG_NONNULL is copied here. */
/* A C macro for declaring that specific arguments must not be NULL.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
that the values passed as arguments n, ..., m must be non-NULL pointers.
n = 1 stands for the first argument, n = 2 for the second argument etc. */
#ifndef _GL_ARG_NONNULL
#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ > 3
#define _GL_ARG_NONNULL(params) __attribute__((__nonnull__ params))
#else
#define _GL_ARG_NONNULL(params)
#endif
#endif
/* The definition of _GL_WARN_ON_USE is copied here. */
/* A C macro for emitting warnings if a function is used.
Copyright (C) 2010-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* _GL_WARN_ON_USE (function, "literal string") issues a declaration
for FUNCTION which will then trigger a compiler warning containing
the text of "literal string" anywhere that function is called, if
supported by the compiler. If the compiler does not support this
feature, the macro expands to an unused extern declaration.
_GL_WARN_ON_USE_ATTRIBUTE ("literal string") expands to the
attribute used in _GL_WARN_ON_USE. If the compiler does not support
this feature, it expands to empty.
These macros are useful for marking a function as a potential
portability trap, with the intent that "literal string" include
instructions on the replacement function that should be used
instead.
_GL_WARN_ON_USE is for functions with 'extern' linkage.
_GL_WARN_ON_USE_ATTRIBUTE is for functions with 'static' or 'inline'
linkage.
However, one of the reasons that a function is a portability trap is
if it has the wrong signature. Declaring FUNCTION with a different
signature in C is a compilation error, so this macro must use the
same type as any existing declaration so that programs that avoid
the problematic FUNCTION do not fail to compile merely because they
included a header that poisoned the function. But this implies that
_GL_WARN_ON_USE is only safe to use if FUNCTION is known to already
have a declaration. Use of this macro implies that there must not
be any other macro hiding the declaration of FUNCTION; but
undefining FUNCTION first is part of the poisoning process anyway
(although for symbols that are provided only via a macro, the result
is a compilation error rather than a warning containing
"literal string"). Also note that in C++, it is only safe to use if
FUNCTION has no overloads.
For an example, it is possible to poison 'getline' by:
[getline]) in configure.ac, which potentially defines
HAVE_RAW_DECL_GETLINE
- adding this code to a header that wraps the system <stdio.h>:
#undef getline
#if HAVE_RAW_DECL_GETLINE
_GL_WARN_ON_USE (getline, "getline is required by POSIX 2008, but"
"not universally present; use the gnulib module getline");
#endif
It is not possible to directly poison global variables. But it is
possible to write a wrapper accessor function, and poison that
(less common usage, like &environ, will cause a compilation error
rather than issue the nice warning, but the end result of informing
the developer about their portability problem is still achieved):
#if HAVE_RAW_DECL_ENVIRON
static char ***
rpl_environ (void) { return &environ; }
_GL_WARN_ON_USE (rpl_environ, "environ is not always properly declared");
# undef environ
# define environ (*rpl_environ ())
#endif
or better (avoiding contradictory use of 'static' and 'extern'):
#if HAVE_RAW_DECL_ENVIRON
static char ***
_GL_WARN_ON_USE_ATTRIBUTE ("environ is not always properly declared")
rpl_environ (void) { return &environ; }
# undef environ
# define environ (*rpl_environ ())
#endif
*/
#ifndef _GL_WARN_ON_USE
#if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
/* A compiler attribute is available in gcc versions 4.3.0 and later. */
#define _GL_WARN_ON_USE(function, message) \
extern __typeof__(function) function __attribute__((__warning__(message)))
#define _GL_WARN_ON_USE_ATTRIBUTE(message) __attribute__((__warning__(message)))
#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
/* Verify the existence of the function. */
#define _GL_WARN_ON_USE(function, message) extern __typeof__(function) function
#define _GL_WARN_ON_USE_ATTRIBUTE(message)
#else /* Unsupported. */
#define _GL_WARN_ON_USE(function, message) _GL_WARN_EXTERN_C int _gl_warn_on_use
#define _GL_WARN_ON_USE_ATTRIBUTE(message)
#endif
#endif
/* _GL_WARN_ON_USE_CXX (function, rettype, parameters_and_attributes, "string")
is like _GL_WARN_ON_USE (function, "string"), except that the function is
declared with the given prototype, consisting of return type, parameters,
and attributes.
This variant is useful for overloaded functions in C++. _GL_WARN_ON_USE does
not work in this case. */
#ifndef _GL_WARN_ON_USE_CXX
#if 4 < __GNUC__ || (__GNUC__ == 4 && 3 <= __GNUC_MINOR__)
#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \
extern rettype function parameters_and_attributes \
__attribute__((__warning__(msg)))
#elif __GNUC__ >= 3 && GNULIB_STRICT_CHECKING
/* Verify the existence of the function. */
#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \
extern rettype function parameters_and_attributes
#else /* Unsupported. */
#define _GL_WARN_ON_USE_CXX(function, rettype, parameters_and_attributes, msg) \
_GL_WARN_EXTERN_C int _gl_warn_on_use
#endif
#endif
/* _GL_WARN_EXTERN_C declaration;
performs the declaration with C linkage. */
#ifndef _GL_WARN_EXTERN_C
#if defined __cplusplus
#define _GL_WARN_EXTERN_C extern "C"
#else
#define _GL_WARN_EXTERN_C extern
#endif
#endif
/* Declare overridden functions. */
#if 0
#if 0
#if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#undef creat
#define creat rpl_creat
#endif
_GL_FUNCDECL_RPL (creat, int, (const char *filename, mode_t mode)
_GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (creat, int, (const char *filename, mode_t mode));
#else
_GL_CXXALIAS_SYS (creat, int, (const char *filename, mode_t mode));
#endif
_GL_CXXALIASWARN (creat);
#elif defined GNULIB_POSIXCHECK
#undef creat
/* Assume creat is always declared. */
_GL_WARN_ON_USE(creat, "creat is not always POSIX compliant - "
"use gnulib module creat for portability");
#endif
#if 1
#if 1
#if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#undef fcntl
#define fcntl rpl_fcntl
#endif
_GL_FUNCDECL_RPL(fcntl, int, (int fd, int action, ...));
_GL_CXXALIAS_RPL(fcntl, int, (int fd, int action, ...));
#else
#if !1
_GL_FUNCDECL_SYS(fcntl, int, (int fd, int action, ...));
#endif
_GL_CXXALIAS_SYS(fcntl, int, (int fd, int action, ...));
#endif
_GL_CXXALIASWARN(fcntl);
#elif defined GNULIB_POSIXCHECK
#undef fcntl
#if HAVE_RAW_DECL_FCNTL
_GL_WARN_ON_USE(fcntl, "fcntl is not always POSIX compliant - "
"use gnulib module fcntl for portability");
#endif
#endif
#if 0
#if 0
#if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#undef open
#define open rpl_open
#endif
_GL_FUNCDECL_RPL (open, int, (const char *filename, int flags, ...)
_GL_ARG_NONNULL ((1)));
_GL_CXXALIAS_RPL (open, int, (const char *filename, int flags, ...));
#else
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
#endif
/* On HP-UX 11, in C++ mode, open() is defined as an inline function with a
default argument. _GL_CXXALIASWARN does not work in this case. */
#if !defined __hpux
_GL_CXXALIASWARN (open);
#endif
#elif defined GNULIB_POSIXCHECK
#undef open
/* Assume open is always declared. */
_GL_WARN_ON_USE(open, "open is not always POSIX compliant - "
"use gnulib module open for portability");
#endif
#if 0
#if 0
#if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#undef openat
#define openat rpl_openat
#endif
_GL_FUNCDECL_RPL (openat, int,
(int fd, char const *file, int flags, /* mode_t mode */ ...)
_GL_ARG_NONNULL ((2)));
_GL_CXXALIAS_RPL (openat, int,
(int fd, char const *file, int flags, /* mode_t mode */ ...));
#else
#if !1
_GL_FUNCDECL_SYS (openat, int,
(int fd, char const *file, int flags, /* mode_t mode */ ...)
_GL_ARG_NONNULL ((2)));
#endif
_GL_CXXALIAS_SYS (openat, int,
(int fd, char const *file, int flags, /* mode_t mode */ ...));
#endif
_GL_CXXALIASWARN (openat);
#elif defined GNULIB_POSIXCHECK
#undef openat
#if HAVE_RAW_DECL_OPENAT
_GL_WARN_ON_USE(openat, "openat is not portable - "
"use gnulib module openat for portability");
#endif
#endif
/* Fix up the FD_* macros, only known to be missing on mingw. */
#ifndef FD_CLOEXEC
#define FD_CLOEXEC 1
#endif
/* Fix up the supported F_* macros. Intentionally leave other F_*
macros undefined. Only known to be missing on mingw. */
#ifndef F_DUPFD_CLOEXEC
#define F_DUPFD_CLOEXEC 0x40000000
/* Witness variable: 1 if gnulib defined F_DUPFD_CLOEXEC, 0 otherwise. */
#define GNULIB_defined_F_DUPFD_CLOEXEC 1
#else
#define GNULIB_defined_F_DUPFD_CLOEXEC 0
#endif
#ifndef F_DUPFD
#define F_DUPFD 1
#endif
#ifndef F_GETFD
#define F_GETFD 2
#endif
/* Fix up the O_* macros. */
#if !defined O_DIRECT && defined O_DIRECTIO
/* Tru64 spells it 'O_DIRECTIO'. */
#define O_DIRECT O_DIRECTIO
#endif
#if !defined O_CLOEXEC && defined O_NOINHERIT
/* Mingw spells it 'O_NOINHERIT'. */
#define O_CLOEXEC O_NOINHERIT
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 0x40000000 /* Try to not collide with system O_* flags. */
#define GNULIB_defined_O_CLOEXEC 1
#else
#define GNULIB_defined_O_CLOEXEC 0
#endif
#ifndef O_DIRECT
#define O_DIRECT 0
#endif
#ifndef O_DIRECTORY
#define O_DIRECTORY 0
#endif
#ifndef O_DSYNC
#define O_DSYNC 0
#endif
#ifndef O_EXEC
#define O_EXEC O_RDONLY /* This is often close enough in older systems. */
#endif
#ifndef O_IGNORE_CTTY
#define O_IGNORE_CTTY 0
#endif
#ifndef O_NDELAY
#define O_NDELAY 0
#endif
#ifndef O_NOATIME
#define O_NOATIME 0
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK O_NDELAY
#endif
/* If the gnulib module 'nonblocking' is in use, guarantee a working non-zero
value of O_NONBLOCK. Otherwise, O_NONBLOCK is defined (above) to O_NDELAY
or to 0 as fallback. */
#if 0
#if O_NONBLOCK
#define GNULIB_defined_O_NONBLOCK 0
#else
#define GNULIB_defined_O_NONBLOCK 1
#undef O_NONBLOCK
#define O_NONBLOCK 0x40000000
#endif
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 0
#endif
#ifndef O_NOLINK
#define O_NOLINK 0
#endif
#ifndef O_NOLINKS
#define O_NOLINKS 0
#endif
#ifndef O_NOTRANS
#define O_NOTRANS 0
#endif
#ifndef O_RSYNC
#define O_RSYNC 0
#endif
#ifndef O_SEARCH
#define O_SEARCH O_RDONLY /* This is often close enough in older systems. */
#endif
#ifndef O_SYNC
#define O_SYNC 0
#endif
#ifndef O_TTY_INIT
#define O_TTY_INIT 0
#endif
#if ~O_ACCMODE & (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH)
#undef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR | O_EXEC | O_SEARCH)
#endif
/* For systems that distinguish between text and binary I/O.
O_BINARY is usually declared in fcntl.h */
#if !defined O_BINARY && defined _O_BINARY
/* For MSC-compatible compilers. */
#define O_BINARY _O_BINARY
#define O_TEXT _O_TEXT
#endif
#if defined __BEOS__ || defined __HAIKU__
/* BeOS 5 and Haiku have O_BINARY and O_TEXT, but they have no effect. */
#undef O_BINARY
#undef O_TEXT
#endif
#ifndef O_BINARY
#define O_BINARY 0
#define O_TEXT 0
#endif
/* Fix up the AT_* macros. */
/* Work around a bug in Solaris 9 and 10: AT_FDCWD is positive. Its
value exceeds INT_MAX, so its use as an int doesn't conform to the
C standard, and GCC and Sun C complain in some cases. If the bug
is present, undef AT_FDCWD here, so it can be redefined below. */
#if 0 < AT_FDCWD && AT_FDCWD == 0xffd19553
#undef AT_FDCWD
#endif
/* Use the same bit pattern as Solaris 9, but with the proper
signedness. The bit pattern is important, in case this actually is
Solaris with the above workaround. */
#ifndef AT_FDCWD
#define AT_FDCWD (-3041965)
#endif
/* Use the same values as Solaris 9. This shouldn't matter, but
there's no real reason to differ. */
#ifndef AT_SYMLINK_NOFOLLOW
#define AT_SYMLINK_NOFOLLOW 4096
#endif
#ifndef AT_REMOVEDIR
#define AT_REMOVEDIR 1
#endif
/* Solaris 9 lacks these two, so just pick unique values. */
#ifndef AT_SYMLINK_FOLLOW
#define AT_SYMLINK_FOLLOW 2
#endif
#ifndef AT_EACCESS
#define AT_EACCESS 4
#endif
#endif /* _GL_FCNTL_H */
#endif /* _GL_FCNTL_H */
#endif

View file

@ -1,114 +0,0 @@
/* Hook for making file descriptor functions close(), ioctl() extensible.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
Written by Bruno Haible <bruno@clisp.org>, 2009.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/config.h"
/* Specification. */
#include "third_party/make/fd-hook.h"
/* Currently, this entire code is only needed for the handling of sockets
on native Windows platforms. */
#if WINDOWS_SOCKETS
/* The first and last link in the doubly linked list.
Initially the list is empty. */
static struct fd_hook anchor = { &anchor, &anchor, NULL, NULL };
int
execute_close_hooks (const struct fd_hook *remaining_list, gl_close_fn primary,
int fd)
{
if (remaining_list == &anchor)
/* End of list reached. */
return primary (fd);
else
return remaining_list->private_close_fn (remaining_list->private_next,
primary, fd);
}
int
execute_all_close_hooks (gl_close_fn primary, int fd)
{
return execute_close_hooks (anchor.private_next, primary, fd);
}
int
execute_ioctl_hooks (const struct fd_hook *remaining_list, gl_ioctl_fn primary,
int fd, int request, void *arg)
{
if (remaining_list == &anchor)
/* End of list reached. */
return primary (fd, request, arg);
else
return remaining_list->private_ioctl_fn (remaining_list->private_next,
primary, fd, request, arg);
}
int
execute_all_ioctl_hooks (gl_ioctl_fn primary,
int fd, int request, void *arg)
{
return execute_ioctl_hooks (anchor.private_next, primary, fd, request, arg);
}
void
register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook, struct fd_hook *link)
{
if (close_hook == NULL)
close_hook = execute_close_hooks;
if (ioctl_hook == NULL)
ioctl_hook = execute_ioctl_hooks;
if (link->private_next == NULL && link->private_prev == NULL)
{
/* Add the link to the doubly linked list. */
link->private_next = anchor.private_next;
link->private_prev = &anchor;
link->private_close_fn = close_hook;
link->private_ioctl_fn = ioctl_hook;
anchor.private_next->private_prev = link;
anchor.private_next = link;
}
else
{
/* The link is already in use. */
if (link->private_close_fn != close_hook
|| link->private_ioctl_fn != ioctl_hook)
abort ();
}
}
void
unregister_fd_hook (struct fd_hook *link)
{
struct fd_hook *next = link->private_next;
struct fd_hook *prev = link->private_prev;
if (next != NULL && prev != NULL)
{
/* The link is in use. Remove it from the doubly linked list. */
prev->private_next = next;
next->private_prev = prev;
/* Clear the link, to mark it unused. */
link->private_next = NULL;
link->private_prev = NULL;
link->private_close_fn = NULL;
link->private_ioctl_fn = NULL;
}
}
#endif

View file

@ -1,119 +0,0 @@
/* Hook for making file descriptor functions close(), ioctl() extensible.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef FD_HOOK_H
#define FD_HOOK_H
#ifdef __cplusplus
extern "C" {
#endif
/* Currently, this entire code is only needed for the handling of sockets
on native Windows platforms. */
#if WINDOWS_SOCKETS
/* Type of function that closes FD. */
typedef int (*gl_close_fn) (int fd);
/* Type of function that applies a control request to FD. */
typedef int (*gl_ioctl_fn) (int fd, int request, void *arg);
/* An element of the list of file descriptor hooks.
In CLOS (Common Lisp Object System) speak, it consists of an "around"
method for the close() function and an "around" method for the ioctl()
function.
The fields of this structure are considered private. */
struct fd_hook
{
/* Doubly linked list. */
struct fd_hook *private_next;
struct fd_hook *private_prev;
/* Function that treats the types of FD that it knows about and calls
execute_close_hooks (REMAINING_LIST, PRIMARY, FD) as a fallback. */
int (*private_close_fn) (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd);
/* Function that treats the types of FD that it knows about and calls
execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG) as a
fallback. */
int (*private_ioctl_fn) (const struct fd_hook *remaining_list,
gl_ioctl_fn primary,
int fd, int request, void *arg);
};
/* This type of function closes FD, applying special knowledge for the FD
types it knows about, and calls
execute_close_hooks (REMAINING_LIST, PRIMARY, FD)
for the other FD types.
In CLOS speak, REMAINING_LIST is the remaining list of "around" methods,
and PRIMARY is the "primary" method for close(). */
typedef int (*close_hook_fn) (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd);
/* Execute the close hooks in REMAINING_LIST, with PRIMARY as "primary" method.
Return 0 or -1, like close() would do. */
extern int execute_close_hooks (const struct fd_hook *remaining_list,
gl_close_fn primary,
int fd);
/* Execute all close hooks, with PRIMARY as "primary" method.
Return 0 or -1, like close() would do. */
extern int execute_all_close_hooks (gl_close_fn primary, int fd);
/* This type of function applies a control request to FD, applying special
knowledge for the FD types it knows about, and calls
execute_ioctl_hooks (REMAINING_LIST, PRIMARY, FD, REQUEST, ARG)
for the other FD types.
In CLOS speak, REMAINING_LIST is the remaining list of "around" methods,
and PRIMARY is the "primary" method for ioctl(). */
typedef int (*ioctl_hook_fn) (const struct fd_hook *remaining_list,
gl_ioctl_fn primary,
int fd, int request, void *arg);
/* Execute the ioctl hooks in REMAINING_LIST, with PRIMARY as "primary" method.
Return 0 or -1, like ioctl() would do. */
extern int execute_ioctl_hooks (const struct fd_hook *remaining_list,
gl_ioctl_fn primary,
int fd, int request, void *arg);
/* Execute all ioctl hooks, with PRIMARY as "primary" method.
Return 0 or -1, like ioctl() would do. */
extern int execute_all_ioctl_hooks (gl_ioctl_fn primary,
int fd, int request, void *arg);
/* Add a function pair to the list of file descriptor hooks.
CLOSE_HOOK and IOCTL_HOOK may be NULL, indicating no change.
The LINK variable points to a piece of memory which is guaranteed to be
accessible until the corresponding call to unregister_fd_hook. */
extern void register_fd_hook (close_hook_fn close_hook, ioctl_hook_fn ioctl_hook,
struct fd_hook *link);
/* Removes a hook from the list of file descriptor hooks. */
extern void unregister_fd_hook (struct fd_hook *link);
#endif
#ifdef __cplusplus
}
#endif
#endif /* FD_HOOK_H */

View file

@ -1,5 +1,5 @@
/* Target file management for GNU Make. /* Target file management for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,20 +12,20 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
/**/
#include "third_party/make/filedef.h" #include <assert.h>
#include "third_party/make/dep.h"
#include "third_party/make/job.h" #include "filedef.h"
#include "third_party/make/commands.h" #include "dep.h"
#include "third_party/make/variable.h" #include "job.h"
#include "third_party/make/debug.h" #include "commands.h"
#include "libc/assert.h" #include "variable.h"
#include "libc/sysv/consts/clock.h" #include "debug.h"
#include "libc/runtime/runtime.h" #include "hash.h"
#include "third_party/make/hash.h" #include "shuffle.h"
/* Remember whether snap_deps has been invoked: we need this to be sure we /* Remember whether snap_deps has been invoked: we need this to be sure we
@ -73,23 +73,42 @@ lookup_file (const char *name)
{ {
struct file *f; struct file *f;
struct file file_key; struct file file_key;
#ifdef VMS
int want_vmsify;
#ifndef WANT_CASE_SENSITIVE_TARGETS
char *lname;
#endif
#endif
assert (*name != '\0'); assert (*name != '\0');
while (name[0] == '.' /* This is also done in parse_file_seq, so this is redundant
#ifdef HAVE_DOS_PATHS for names read from makefiles. It is here for names passed
&& (name[1] == '/' || name[1] == '\\') on the command line. */
#else #ifdef VMS
&& name[1] == '/' want_vmsify = (strpbrk (name, "]>:^") != NULL);
# ifndef WANT_CASE_SENSITIVE_TARGETS
if (*name != '.')
{
const char *n;
char *ln;
lname = xstrdup (name);
for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
*ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n;
*ln = '\0';
name = lname;
}
# endif # endif
&& name[2] != '\0')
while (name[0] == '[' && name[1] == ']' && name[2] != '\0')
name += 2;
while (name[0] == '<' && name[1] == '>' && name[2] != '\0')
name += 2;
#endif
while (name[0] == '.' && ISDIRSEP (name[1]) && name[2] != '\0')
{ {
name += 2; name += 2;
while (*name == '/' while (ISDIRSEP (*name))
#ifdef HAVE_DOS_PATHS
|| *name == '\\'
#endif
)
/* Skip following slashes: ".//foo" is "foo", not "/foo". */ /* Skip following slashes: ".//foo" is "foo", not "/foo". */
++name; ++name;
} }
@ -97,10 +116,23 @@ lookup_file (const char *name)
if (*name == '\0') if (*name == '\0')
{ {
/* It was all slashes after a dot. */ /* It was all slashes after a dot. */
#if defined(_AMIGA)
name = "";
#else
name = "./"; name = "./";
#endif
#if defined(VMS)
/* TODO - This section is probably not needed. */
if (want_vmsify)
name = "[]";
#endif
} }
file_key.hname = name; file_key.hname = name;
f = hash_find_item (&files, &file_key); f = hash_find_item (&files, &file_key);
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
if (*name != '.')
free (lname);
#endif
return f; return f;
} }
@ -121,6 +153,24 @@ enter_file (const char *name)
assert (*name != '\0'); assert (*name != '\0');
assert (! verify_flag || strcache_iscached (name)); assert (! verify_flag || strcache_iscached (name));
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
if (*name != '.')
{
const char *n;
char *lname, *ln;
lname = xstrdup (name);
for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
if (isupper ((unsigned char)*n))
*ln = tolower ((unsigned char)*n);
else
*ln = *n;
*ln = '\0';
name = strcache_add (lname);
free (lname);
}
#endif
file_key.hname = name; file_key.hname = name;
file_slot = (struct file **) hash_find_slot (&files, &file_key); file_slot = (struct file **) hash_find_slot (&files, &file_key);
f = *file_slot; f = *file_slot;
@ -130,7 +180,7 @@ enter_file (const char *name)
return f; return f;
} }
new = xcalloc (1, sizeof (struct file)); new = xcalloc (sizeof (struct file));
new->name = new->hname = name; new->name = new->hname = name;
new->update_status = us_none; new->update_status = us_none;
@ -211,14 +261,14 @@ rehash_file (struct file *from_file, const char *to_hname)
{ {
size_t l = strlen (from_file->name); size_t l = strlen (from_file->name);
/* We have two sets of commands. We will go with the /* We have two sets of commands. We will go with the
one given in the rule explicitly mentioning this name, one given in the rule found through directory search,
but give a message to let the user know what's going on. */ but give a message to let the user know what's going on. */
if (to_file->cmds->fileinfo.filenm != 0) if (to_file->cmds->fileinfo.filenm != 0)
error (&from_file->cmds->fileinfo, error (&from_file->cmds->fileinfo,
l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH, l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH,
_("Recipe was specified for file '%s' at %s:%lu,"), _("Recipe was specified for file '%s' at %s:%lu,"),
from_file->name, to_file->cmds->fileinfo.filenm, from_file->name, from_file->cmds->fileinfo.filenm,
to_file->cmds->fileinfo.lineno); from_file->cmds->fileinfo.lineno);
else else
error (&from_file->cmds->fileinfo, l, error (&from_file->cmds->fileinfo, l,
_("Recipe for file '%s' was found by implicit rule search,"), _("Recipe for file '%s' was found by implicit rule search,"),
@ -229,7 +279,7 @@ rehash_file (struct file *from_file, const char *to_hname)
from_file->name, to_hname); from_file->name, to_hname);
error (&from_file->cmds->fileinfo, l, error (&from_file->cmds->fileinfo, l,
_("Recipe for '%s' will be ignored in favor of the one for '%s'."), _("Recipe for '%s' will be ignored in favor of the one for '%s'."),
to_hname, from_file->name); from_file->name, to_hname);
} }
} }
@ -268,14 +318,19 @@ rehash_file (struct file *from_file, const char *to_hname)
#define MERGE(field) to_file->field |= from_file->field #define MERGE(field) to_file->field |= from_file->field
MERGE (precious); MERGE (precious);
MERGE (loaded);
MERGE (tried_implicit); MERGE (tried_implicit);
MERGE (updating); MERGE (updating);
MERGE (updated); MERGE (updated);
MERGE (is_target); MERGE (is_target);
MERGE (cmd_target); MERGE (cmd_target);
MERGE (phony); MERGE (phony);
MERGE (loaded); /* Don't merge intermediate because this file might be pre-existing */
MERGE (is_explicit);
MERGE (secondary);
MERGE (notintermediate);
MERGE (ignore_vpath); MERGE (ignore_vpath);
MERGE (snapped);
#undef MERGE #undef MERGE
to_file->builtin = 0; to_file->builtin = 0;
@ -310,7 +365,7 @@ remove_intermediates (int sig)
int doneany = 0; int doneany = 0;
/* If there's no way we will ever remove anything anyway, punt early. */ /* If there's no way we will ever remove anything anyway, punt early. */
if (question_flag || touch_flag || all_secondary) if (question_flag || touch_flag || all_secondary || no_intermediates)
return; return;
if (sig && just_print_flag) if (sig && just_print_flag)
@ -327,7 +382,7 @@ remove_intermediates (int sig)
given on the command line, and it's either a -include makefile or given on the command line, and it's either a -include makefile or
it's not precious. */ it's not precious. */
if (f->intermediate && (f->dontcare || !f->precious) if (f->intermediate && (f->dontcare || !f->precious)
&& !f->secondary && !f->cmd_target) && !f->secondary && !f->notintermediate && !f->cmd_target)
{ {
int status; int status;
if (f->update_status == us_none) if (f->update_status == us_none)
@ -365,7 +420,11 @@ remove_intermediates (int sig)
} }
} }
if (status < 0) if (status < 0)
perror_with_name ("unlink: ", f->name); {
perror_with_name ("\nunlink: ", f->name);
/* Start printing over. */
doneany = 0;
}
} }
} }
} }
@ -383,8 +442,7 @@ remove_intermediates (int sig)
struct dep * struct dep *
split_prereqs (char *p) split_prereqs (char *p)
{ {
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_WAIT);
PARSEFS_NONE);
if (*p) if (*p)
{ {
@ -393,7 +451,7 @@ split_prereqs (char *p)
struct dep *ood; struct dep *ood;
++p; ++p;
ood = PARSE_SIMPLE_SEQ (&p, struct dep); ood = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_WAIT);
if (! new) if (! new)
new = ood; new = ood;
@ -427,7 +485,6 @@ enter_prereqs (struct dep *deps, const char *stem)
if (stem) if (stem)
{ {
const char *pattern = "%"; const char *pattern = "%";
char *buffer = variable_expand ("");
struct dep *dp = deps, *dl = 0; struct dep *dp = deps, *dl = 0;
while (dp != 0) while (dp != 0)
@ -447,14 +504,15 @@ enter_prereqs (struct dep *deps, const char *stem)
if (stem[0] == '\0') if (stem[0] == '\0')
{ {
memmove (percent, percent+1, strlen (percent)); memmove (percent, percent+1, strlen (percent));
o = variable_buffer_output (buffer, nm, strlen (nm) + 1); o = variable_buffer_output (variable_buffer, nm,
strlen (nm) + 1);
} }
else else
o = patsubst_expand_pat (buffer, stem, pattern, nm, o = patsubst_expand_pat (variable_buffer, stem, pattern, nm,
pattern+1, percent+1); pattern+1, percent+1);
/* If the name expanded to the empty string, ignore it. */ /* If the name expanded to the empty string, ignore it. */
if (buffer[0] == '\0') if (variable_buffer[0] == '\0')
{ {
struct dep *df = dp; struct dep *df = dp;
if (dp == deps) if (dp == deps)
@ -466,7 +524,8 @@ enter_prereqs (struct dep *deps, const char *stem)
} }
/* Save the name. */ /* Save the name. */
dp->name = strcache_add_len (buffer, o - buffer); dp->name = strcache_add_len (variable_buffer,
o - variable_buffer);
} }
dp->stem = stem; dp->stem = stem;
dp->staticpattern = 1; dp->staticpattern = 1;
@ -486,21 +545,29 @@ enter_prereqs (struct dep *deps, const char *stem)
d1->file = enter_file (d1->name); d1->file = enter_file (d1->name);
d1->staticpattern = 0; d1->staticpattern = 0;
d1->name = 0; d1->name = 0;
if (!stem)
/* This file is explicitly mentioned as a prereq. */
d1->file->is_explicit = 1;
} }
return deps; return deps;
} }
/* Expand and parse each dependency line. */ /* Expand and parse each dependency line.
static void For each dependency of the file, make the 'struct dep' point
at the appropriate 'struct file' (which may have to be created). */
void
expand_deps (struct file *f) expand_deps (struct file *f)
{ {
struct dep *d; struct dep *d;
struct dep **dp; struct dep **dp;
const char *file_stem = f->stem; const char *fstem;
int initialized = 0; int initialized = 0;
int changed_dep = 0;
f->updating = 0; if (f->snapped)
return;
f->snapped = 1;
/* Walk through the dependencies. For any dependency that needs 2nd /* Walk through the dependencies. For any dependency that needs 2nd
expansion, expand it then insert the result into the list. */ expansion, expand it then insert the result into the list. */
@ -510,7 +577,6 @@ expand_deps (struct file *f)
{ {
char *p; char *p;
struct dep *new, *next; struct dep *new, *next;
char *name = (char *)d->name;
if (! d->name || ! d->need_2nd_expansion) if (! d->name || ! d->need_2nd_expansion)
{ {
@ -520,16 +586,46 @@ expand_deps (struct file *f)
continue; continue;
} }
/* If it's from a static pattern rule, convert the patterns into /* If it's from a static pattern rule, convert the initial pattern in
"$*" so they'll expand properly. */ each word to "$*" so they'll expand properly. */
if (d->staticpattern) if (d->staticpattern)
{ {
char *o = variable_expand (""); const char *cs = d->name;
o = subst_expand (o, name, "%", "$*", 1, 2, 0); size_t nperc = 0;
*o = '\0';
free (name); /* Count the number of % in the string. */
d->name = name = xstrdup (variable_buffer); while ((cs = strchr (cs, '%')) != NULL)
d->staticpattern = 0; {
++nperc;
++cs;
}
if (nperc)
{
/* Allocate enough space to replace all % with $*. */
size_t slen = strlen (d->name) + nperc + 1;
const char *pcs = d->name;
char *name = xmalloc (slen);
char *s = name;
/* Substitute the first % in each word. */
cs = strchr (pcs, '%');
while (cs)
{
s = mempcpy (s, pcs, cs - pcs);
*(s++) = '$';
*(s++) = '*';
pcs = ++cs;
/* Find the first % after the next whitespace. */
cs = strchr (end_of_token (cs), '%');
}
strcpy (s, pcs);
free ((char*)d->name);
d->name = name;
}
} }
/* We're going to do second expansion so initialize file variables for /* We're going to do second expansion so initialize file variables for
@ -541,39 +637,53 @@ expand_deps (struct file *f)
initialized = 1; initialized = 1;
} }
if (d->stem != 0) set_file_variables (f, d->stem ? d->stem : f->stem);
f->stem = d->stem;
set_file_variables (f);
/* Perform second expansion. */
p = variable_expand_for_file (d->name, f); p = variable_expand_for_file (d->name, f);
if (d->stem != 0) /* Free the un-expanded name. */
f->stem = file_stem; free ((char*)d->name);
/* At this point we don't need the name anymore: free it. */
free (name);
/* Parse the prerequisites and enter them into the file database. */ /* Parse the prerequisites and enter them into the file database. */
new = enter_prereqs (split_prereqs (p), d->stem); new = split_prereqs (p);
/* If there were no prereqs here (blank!) then throw this one out. */ /* If there were no prereqs here (blank!) then throw this one out. */
if (new == 0) if (new == 0)
{ {
*dp = d->next; *dp = d->next;
changed_dep = 1;
free_dep (d); free_dep (d);
d = *dp; d = *dp;
continue; continue;
} }
/* Add newly parsed prerequisites. */ /* Add newly parsed prerequisites. */
fstem = d->stem;
next = d->next; next = d->next;
changed_dep = 1;
free_dep (d);
*dp = new; *dp = new;
for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next) for (dp = &new, d = new; d != 0; dp = &d->next, d = d->next)
; {
d->file = lookup_file (d->name);
if (d->file == 0)
d->file = enter_file (d->name);
d->name = 0;
d->stem = fstem;
if (!fstem)
/* This file is explicitly mentioned as a prereq. */
d->file->is_explicit = 1;
}
*dp = next; *dp = next;
d = *dp; d = *dp;
} }
/* Shuffle mode assumes '->next' and '->shuf' links both traverse the same
dependencies (in different sequences). Regenerate '->shuf' so we don't
refer to stale data. */
if (changed_dep)
shuffle_deps_recursive (f->deps);
} }
/* Add extra prereqs to the file in question. */ /* Add extra prereqs to the file in question. */
@ -608,10 +718,18 @@ snap_file (const void *item, void *arg)
if (!second_expansion) if (!second_expansion)
f->updating = 0; f->updating = 0;
/* If .SECONDARY is set with no deps, mark all targets as intermediate. */ /* More specific setting has priority. */
if (all_secondary)
/* If .SECONDARY is set with no deps, mark all targets as intermediate,
unless the target is a prereq of .NOTINTERMEDIATE. */
if (all_secondary && !f->notintermediate)
f->intermediate = 1; f->intermediate = 1;
/* If .NOTINTERMEDIATE is set with no deps, mark all targets as
notintermediate, unless the target is a prereq of .INTERMEDIATE. */
if (no_intermediates && !f->intermediate && !f->secondary)
f->notintermediate = 1;
/* If .EXTRA_PREREQS is set, add them as ignored by automatic variables. */ /* If .EXTRA_PREREQS is set, add them as ignored by automatic variables. */
if (f->variables) if (f->variables)
prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set)); prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set));
@ -642,10 +760,7 @@ snap_file (const void *item, void *arg)
} }
} }
/* For each dependency of each file, make the 'struct dep' point /* Mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
at the appropriate 'struct file' (which may have to be created).
Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
and various other special targets. */ and various other special targets. */
void void
@ -659,37 +774,6 @@ snap_deps (void)
longer define new targets. */ longer define new targets. */
snapped_deps = 1; snapped_deps = 1;
/* Perform second expansion and enter each dependency name as a file. We
must use hash_dump() here because within these loops we likely add new
files to the table, possibly causing an in-situ table expansion.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. If we
ever change make to be able to unset .SECONDARY_EXPANSION this will have
to change. */
if (second_expansion)
{
struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
struct file **file_end = file_slot_0 + files.ht_fill;
struct file **file_slot;
const char *suffixes;
/* Expand .SUFFIXES: its prerequisites are used for $$* calc. */
f = lookup_file (".SUFFIXES");
suffixes = f ? f->name : 0;
for (; f != 0; f = f->prev)
expand_deps (f);
/* For every target that's not .SUFFIXES, expand its prerequisites. */
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
for (f = *file_slot; f != 0; f = f->prev)
if (f->name != suffixes)
expand_deps (f);
free (file_slot_0);
}
/* Now manage all the special targets. */ /* Now manage all the special targets. */
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
@ -713,10 +797,31 @@ snap_deps (void)
f2->mtime_before_update = NONEXISTENT_MTIME; f2->mtime_before_update = NONEXISTENT_MTIME;
} }
for (f = lookup_file (".NOTINTERMEDIATE"); f != 0; f = f->prev)
/* Mark .NOTINTERMEDIATE deps as notintermediate files. */
if (f->deps)
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->notintermediate = 1;
/* .NOTINTERMEDIATE with no deps marks all files as notintermediate. */
else
no_intermediates = 1;
/* The same file cannot be both .INTERMEDIATE and .NOTINTERMEDIATE.
However, it is possible for a file to be .INTERMEDIATE and also match a
.NOTINTERMEDIATE pattern. In that case, the intermediate file has
priority over the notintermediate pattern. This priority is enforced by
pattern_search. */
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
/* Mark .INTERMEDIATE deps as intermediate files. */ /* Mark .INTERMEDIATE deps as intermediate files. */
for (d = f->deps; d != 0; d = d->next) for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev) for (f2 = d->file; f2 != 0; f2 = f2->prev)
if (f2->notintermediate)
OS (fatal, NILF,
_("%s cannot be both .NOTINTERMEDIATE and .INTERMEDIATE"),
f2->name);
else
f2->intermediate = 1; f2->intermediate = 1;
/* .INTERMEDIATE with no deps does nothing. /* .INTERMEDIATE with no deps does nothing.
Marking all files as intermediates is useless since the goal targets Marking all files as intermediates is useless since the goal targets
@ -727,11 +832,20 @@ snap_deps (void)
if (f->deps) if (f->deps)
for (d = f->deps; d != 0; d = d->next) for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev) for (f2 = d->file; f2 != 0; f2 = f2->prev)
if (f2->notintermediate)
OS (fatal, NILF,
_("%s cannot be both .NOTINTERMEDIATE and .SECONDARY"),
f2->name);
else
f2->intermediate = f2->secondary = 1; f2->intermediate = f2->secondary = 1;
/* .SECONDARY with no deps listed marks *all* files that way. */ /* .SECONDARY with no deps listed marks *all* files that way. */
else else
all_secondary = 1; all_secondary = 1;
if (no_intermediates && all_secondary)
O (fatal, NILF,
_(".NOTINTERMEDIATE and .SECONDARY are mutually exclusive"));
f = lookup_file (".EXPORT_ALL_VARIABLES"); f = lookup_file (".EXPORT_ALL_VARIABLES");
if (f != 0 && f->is_target) if (f != 0 && f->is_target)
export_all_variables = 1; export_all_variables = 1;
@ -760,7 +874,19 @@ snap_deps (void)
f = lookup_file (".NOTPARALLEL"); f = lookup_file (".NOTPARALLEL");
if (f != 0 && f->is_target) if (f != 0 && f->is_target)
{
struct dep *d2;
if (!f->deps)
not_parallel = 1; not_parallel = 1;
else
/* Set a wait point between every prerequisite of each target. */
for (d = f->deps; d != NULL; d = d->next)
for (f2 = d->file; f2 != NULL; f2 = f2->prev)
if (f2->deps)
for (d2 = f2->deps->next; d2 != NULL; d2 = d2->next)
d2->wait_here = 1;
}
{ {
struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS"))); struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS")));
@ -812,7 +938,7 @@ file_timestamp_cons (const char *fname, time_t stamp, long int ns)
char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
const char *f = fname ? fname : _("Current time"); const char *f = fname ? fname : _("Current time");
ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX; ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX;
file_timestamp_sprintf (buf, sizeof(buf), ts); file_timestamp_sprintf (buf, ts);
OSS (error, NILF, OSS (error, NILF,
_("%s: Timestamp out of range; substituting %s"), f, buf); _("%s: Timestamp out of range; substituting %s"), f, buf);
} }
@ -832,6 +958,8 @@ file_timestamp_now (int *resolution)
/* Don't bother with high-resolution clocks if file timestamps have /* Don't bother with high-resolution clocks if file timestamps have
only one-second resolution. The code below should work, but it's only one-second resolution. The code below should work, but it's
not worth the hassle of debugging it on hosts where it fails. */ not worth the hassle of debugging it on hosts where it fails. */
#if FILE_TIMESTAMP_HI_RES
# if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME
{ {
struct timespec timespec; struct timespec timespec;
if (clock_gettime (CLOCK_REALTIME, &timespec) == 0) if (clock_gettime (CLOCK_REALTIME, &timespec) == 0)
@ -842,6 +970,8 @@ file_timestamp_now (int *resolution)
goto got_time; goto got_time;
} }
} }
# endif
# if HAVE_GETTIMEOFDAY
{ {
struct timeval timeval; struct timeval timeval;
if (gettimeofday (&timeval, 0) == 0) if (gettimeofday (&timeval, 0) == 0)
@ -852,12 +982,16 @@ file_timestamp_now (int *resolution)
goto got_time; goto got_time;
} }
} }
# endif
#endif
r = 1000000000; r = 1000000000;
s = time ((time_t *) 0); s = time ((time_t *) 0);
ns = 0; ns = 0;
#if FILE_TIMESTAMP_HI_RES
got_time: got_time:
#endif
*resolution = r; *resolution = r;
return file_timestamp_cons (0, s, ns); return file_timestamp_cons (0, s, ns);
} }
@ -865,37 +999,30 @@ file_timestamp_now (int *resolution)
/* Place into the buffer P a printable representation of the file /* Place into the buffer P a printable representation of the file
timestamp TS. */ timestamp TS. */
void void
file_timestamp_sprintf (char *p, int n, FILE_TIMESTAMP ts) file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
{ {
/*
* [jart] patch weakness upstream because buffer can probably overflow
* if integer timestamp is irreguular
*/
int m;
time_t t = FILE_TIMESTAMP_S (ts); time_t t = FILE_TIMESTAMP_S (ts);
struct tm *tm = localtime (&t); struct tm *tm = localtime (&t);
if (tm) if (tm)
snprintf (p, n, "%04d-%02d-%02d %02d:%02d:%02d", {
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, intmax_t year = tm->tm_year;
sprintf (p, "%04" PRIdMAX "-%02d-%02d %02d:%02d:%02d",
year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_hour, tm->tm_min, tm->tm_sec);
}
else if (t < 0) else if (t < 0)
snprintf (p, n, "%ld", (long) t); sprintf (p, "%" PRIdMAX, (intmax_t) t);
else else
snprintf (p, n, "%lu", (unsigned long) t); sprintf (p, "%" PRIuMAX, (uintmax_t) t);
m = strlen (p); p += strlen (p);
p += m;
n -= m;
if (n <= 0) return;
/* Append nanoseconds as a fraction, but remove trailing zeros. We don't /* Append nanoseconds as a fraction, but remove trailing zeros. We don't
know the actual timestamp resolution, since clock_getres applies only to know the actual timestamp resolution, since clock_getres applies only to
local times, whereas this timestamp might come from a remote filesystem. local times, whereas this timestamp might come from a remote filesystem.
So removing trailing zeros is the best guess that we can do. */ So removing trailing zeros is the best guess that we can do. */
snprintf (p, n, ".%09d", FILE_TIMESTAMP_NS (ts)); sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts));
m = strlen (p) - 1; p += strlen (p) - 1;
p += m;
n += m;
while (*p == '0') while (*p == '0')
p--; p--;
p += *p != '.'; p += *p != '.';
@ -913,17 +1040,17 @@ print_prereqs (const struct dep *deps)
/* Print all normal dependencies; note any order-only deps. */ /* Print all normal dependencies; note any order-only deps. */
for (; deps != 0; deps = deps->next) for (; deps != 0; deps = deps->next)
if (! deps->ignore_mtime) if (! deps->ignore_mtime)
printf (" %s", dep_name (deps)); printf (" %s%s", deps->wait_here ? ".WAIT " : "", dep_name (deps));
else if (! ood) else if (! ood)
ood = deps; ood = deps;
/* Print order-only deps, if we have any. */ /* Print order-only deps, if we have any. */
if (ood) if (ood)
{ {
printf (" | %s", dep_name (ood)); printf (" | %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood));
for (ood = ood->next; ood != 0; ood = ood->next) for (ood = ood->next; ood != 0; ood = ood->next)
if (ood->ignore_mtime) if (ood->ignore_mtime)
printf (" %s", dep_name (ood)); printf (" %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood));
} }
putchar ('\n'); putchar ('\n');
@ -977,6 +1104,10 @@ print_file (const void *item)
printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem); printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem);
if (f->intermediate) if (f->intermediate)
puts (_("# File is an intermediate prerequisite.")); puts (_("# File is an intermediate prerequisite."));
if (f->notintermediate)
puts (_("# File is a prerequisite of .NOTINTERMEDIATE."));
if (f->secondary)
puts (_("# File is secondary (prerequisite of .SECONDARY)."));
if (f->also_make != 0) if (f->also_make != 0)
{ {
const struct dep *d; const struct dep *d;
@ -994,7 +1125,7 @@ print_file (const void *item)
else else
{ {
char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
file_timestamp_sprintf (buf, sizeof(buf), f->last_mtime); file_timestamp_sprintf (buf, f->last_mtime);
printf (_("# Last modified %s\n"), buf); printf (_("# Last modified %s\n"), buf);
} }
puts (f->updated puts (f->updated
@ -1124,8 +1255,7 @@ build_target_list (char *value)
p = &value[off]; p = &value[off];
} }
memcpy (p, f->name, l); p = mempcpy (p, f->name, l);
p += l;
*(p++) = ' '; *(p++) = ' ';
} }
*(p-1) = '\0'; *(p-1) = '\0';
@ -1139,8 +1269,7 @@ build_target_list (char *value)
void void
init_hash_files (void) init_hash_files (void)
{ {
// [jart] increased from 1000 hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp);
hash_init (&files, 32768, file_hash_1, file_hash_2, file_hash_cmp);
} }
/* EOF */ /* EOF */

View file

@ -1,5 +1,5 @@
/* Definition of target file data structures for GNU Make. /* Definition of target file data structures for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,13 +12,14 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
/* Structure that represents the info on one file /* Structure that represents the info on one file
that the makefile says how to make. that the makefile says how to make.
All of these are chained together through 'next'. */ All of these are chained together through 'next'. */
#include "third_party/make/hash.h" #include "hash.h"
struct commands; struct commands;
struct dep; struct dep;
@ -62,8 +63,6 @@ struct file
FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */ FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */
FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating
has been performed. */ has been performed. */
FILE_TIMESTAMP touched; /* Set if file was created in order for
Landlock LSM to sandbox it. */
unsigned int considered; /* equal to 'considered' if file has been unsigned int considered; /* equal to 'considered' if file has been
considered on current scan of goal chain */ considered on current scan of goal chain */
int command_flags; /* Flags OR'd in for cmds; see commands.h. */ int command_flags; /* Flags OR'd in for cmds; see commands.h. */
@ -85,6 +84,7 @@ struct file
unsigned int builtin:1; /* True if the file is a builtin rule. */ unsigned int builtin:1; /* True if the file is a builtin rule. */
unsigned int precious:1; /* Non-0 means don't delete file on quit */ unsigned int precious:1; /* Non-0 means don't delete file on quit */
unsigned int loaded:1; /* True if the file is a loaded object. */ unsigned int loaded:1; /* True if the file is a loaded object. */
unsigned int unloaded:1; /* True if this loaded object was unloaded. */
unsigned int low_resolution_time:1; /* Nonzero if this file's time stamp unsigned int low_resolution_time:1; /* Nonzero if this file's time stamp
has only one-second resolution. */ has only one-second resolution. */
unsigned int tried_implicit:1; /* Nonzero if have searched unsigned int tried_implicit:1; /* Nonzero if have searched
@ -97,8 +97,11 @@ struct file
unsigned int phony:1; /* Nonzero if this is a phony file unsigned int phony:1; /* Nonzero if this is a phony file
i.e., a prerequisite of .PHONY. */ i.e., a prerequisite of .PHONY. */
unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */
unsigned int is_explicit:1; /* Nonzero if explicitly mentioned. */
unsigned int secondary:1; /* Nonzero means remove_intermediates should unsigned int secondary:1; /* Nonzero means remove_intermediates should
not delete it. */ not delete it. */
unsigned int notintermediate:1; /* Nonzero means a file is a prereq to
.NOTINTERMEDIATE. */
unsigned int dontcare:1; /* Nonzero if no complaint is to be made if unsigned int dontcare:1; /* Nonzero if no complaint is to be made if
this target cannot be remade. */ this target cannot be remade. */
unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */ unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */
@ -106,6 +109,10 @@ struct file
pattern-specific variables. */ pattern-specific variables. */
unsigned int no_diag:1; /* True if the file failed to update and no unsigned int no_diag:1; /* True if the file failed to update and no
diagnostics has been issued (dontcare). */ diagnostics has been issued (dontcare). */
unsigned int was_shuffled:1; /* Did we already shuffle 'deps'? used when
--shuffle passes through the graph. */
unsigned int snapped:1; /* True if the deps of this file have been
secondary expanded. */
}; };
@ -116,6 +123,7 @@ struct file *lookup_file (const char *name);
struct file *enter_file (const char *name); struct file *enter_file (const char *name);
struct dep *split_prereqs (char *prereqstr); struct dep *split_prereqs (char *prereqstr);
struct dep *enter_prereqs (struct dep *prereqs, const char *stem); struct dep *enter_prereqs (struct dep *prereqs, const char *stem);
void expand_deps (struct file *f);
struct dep *expand_extra_prereqs (const struct variable *extra); struct dep *expand_extra_prereqs (const struct variable *extra);
void remove_intermediates (int sig); void remove_intermediates (int sig);
void snap_deps (void); void snap_deps (void);
@ -165,14 +173,14 @@ int stemlen_compare (const void *v1, const void *v2);
add 4 to allow for any 4-digit epoch year (e.g. 1970); add 4 to allow for any 4-digit epoch year (e.g. 1970);
add 25 to allow for "-MM-DD HH:MM:SS.NNNNNNNNN". */ add 25 to allow for "-MM-DD HH:MM:SS.NNNNNNNNN". */
#define FLOOR_LOG2_SECONDS_PER_YEAR 24 #define FLOOR_LOG2_SECONDS_PER_YEAR 24
#define FILE_TIMESTAMP_PRINT_LEN_BOUND /* 62 */ \ #define FILE_TIMESTAMP_PRINT_LEN_BOUND \
(((sizeof (FILE_TIMESTAMP) * CHAR_BIT - 1 - FLOOR_LOG2_SECONDS_PER_YEAR) \ (((sizeof (FILE_TIMESTAMP) * CHAR_BIT - 1 - FLOOR_LOG2_SECONDS_PER_YEAR) \
* 302 / 1000) \ * 302 / 1000) \
+ 1 + 1 + 4 + 25) + 1 + 1 + 4 + 25)
FILE_TIMESTAMP file_timestamp_cons (char const *, time_t, long int); FILE_TIMESTAMP file_timestamp_cons (char const *, time_t, long int);
FILE_TIMESTAMP file_timestamp_now (int *); FILE_TIMESTAMP file_timestamp_now (int *);
void file_timestamp_sprintf (char *, int, FILE_TIMESTAMP ); void file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts);
/* Return the mtime of file F (a struct file *), caching it. /* Return the mtime of file F (a struct file *), caching it.
The value is NONEXISTENT_MTIME if the file does not exist. */ The value is NONEXISTENT_MTIME if the file does not exist. */
@ -204,6 +212,8 @@ FILE_TIMESTAMP f_mtime (struct file *file, int search);
<< FILE_TIMESTAMP_LO_BITS) \ << FILE_TIMESTAMP_LO_BITS) \
+ ORDINARY_MTIME_MIN + FILE_TIMESTAMPS_PER_S - 1) + ORDINARY_MTIME_MIN + FILE_TIMESTAMPS_PER_S - 1)
#define is_ordinary_mtime(_t) ((_t) >= ORDINARY_MTIME_MIN && (_t) <= ORDINARY_MTIME_MAX)
/* Modtime value to use for 'infinitely new'. We used to get the current time /* Modtime value to use for 'infinitely new'. We used to get the current time
from the system and use that whenever we wanted 'new'. But that causes from the system and use that whenever we wanted 'new'. But that causes
trouble when the machine running make and the machine holding a file have trouble when the machine running make and the machine holding a file have

View file

@ -1,33 +1,95 @@
/* Basic filename support macros. /* Basic filename support macros.
Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc. Copyright (C) 2001-2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software: you can redistribute it and/or modify The GNU C Library is free software; you can redistribute it and/or
it under the terms of the GNU General Public License as published by modify it under the terms of the GNU Lesser General Public
the Free Software Foundation; either version 3 of the License, or License as published by the Free Software Foundation; either
(at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
GNU General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public
along with this program. If not, see <https://www.gnu.org/licenses/>. */ License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* From Paul Eggert and Jim Meyering. */
#ifndef _FILENAME_H #ifndef _FILENAME_H
#define _FILENAME_H #define _FILENAME_H
#include <string.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Pathname support. /* Filename support.
ISSLASH(C) tests whether C is a directory separator character. ISSLASH(C) tests whether C is a directory separator
IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, character.
it may be concatenated to a directory pathname. HAS_DEVICE(Filename) tests whether Filename contains a device
IS_PATH_WITH_DIR(P) tests whether P contains a directory specification. specification.
FILE_SYSTEM_PREFIX_LEN(Filename) length of the device specification
at the beginning of Filename,
index of the part consisting of
alternating components and slashes.
FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
1 when a non-empty device specification
can be followed by an empty or relative
part,
0 when a non-empty device specification
must be followed by a slash,
0 when device specification don't exist.
IS_ABSOLUTE_FILE_NAME(Filename)
tests whether Filename is independent of
any notion of "current directory".
IS_RELATIVE_FILE_NAME(Filename)
tests whether Filename may be concatenated
to a directory filename.
Note: On native Windows, OS/2, DOS, "c:" is neither an absolute nor a
relative file name!
IS_FILE_NAME_WITH_DIR(Filename) tests whether Filename contains a device
or directory specification.
*/ */
#if defined _WIN32 || defined __CYGWIN__ \
|| defined __EMX__ || defined __MSDOS__ || defined __DJGPP__
/* Native Windows, Cygwin, OS/2, DOS */
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
/* Internal macro: Tests whether a character is a drive letter. */
# define _IS_DRIVE_LETTER(C) \
(((C) >= 'A' && (C) <= 'Z') || ((C) >= 'a' && (C) <= 'z'))
/* Help the compiler optimizing it. This assumes ASCII. */
# undef _IS_DRIVE_LETTER
# define _IS_DRIVE_LETTER(C) \
(((unsigned int) (C) | ('a' - 'A')) - 'a' <= 'z' - 'a')
# define HAS_DEVICE(Filename) \
(_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':')
# define FILE_SYSTEM_PREFIX_LEN(Filename) (HAS_DEVICE (Filename) ? 2 : 0)
# ifdef __CYGWIN__
# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
# else
/* On native Windows, OS/2, DOS, the system has the notion of a
"current directory" on each drive. */
# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1
# endif
# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
# define IS_ABSOLUTE_FILE_NAME(Filename) \
ISSLASH ((Filename)[FILE_SYSTEM_PREFIX_LEN (Filename)])
# else
# define IS_ABSOLUTE_FILE_NAME(Filename) \
(ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename))
# endif
# define IS_RELATIVE_FILE_NAME(Filename) \
(! (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename)))
# define IS_FILE_NAME_WITH_DIR(Filename) \
(strchr ((Filename), '/') != NULL || strchr ((Filename), '\\') != NULL \
|| HAS_DEVICE (Filename))
#else
/* Unix */
# define ISSLASH(C) ((C) == '/') # define ISSLASH(C) ((C) == '/')
# define HAS_DEVICE(Filename) ((void) (Filename), 0) # define HAS_DEVICE(Filename) ((void) (Filename), 0)
# define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0) # define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0)
@ -35,6 +97,12 @@ extern "C" {
# define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0]) # define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0])
# define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0])) # define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0]))
# define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL) # define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL)
#endif
/* Deprecated macros. For backward compatibility with old users of the
'filename' module. */
#define IS_ABSOLUTE_PATH IS_ABSOLUTE_FILE_NAME
#define IS_PATH_WITH_DIR IS_FILE_NAME_WITH_DIR
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -1,37 +1,34 @@
/* Locating a program in a given path. /* Locating a program in a given path.
Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc. Copyright (C) 2001-2004, 2006-2023 Free Software Foundation, Inc.
Written by Bruno Haible <haible@clisp.cons.org>, 2001, 2019. Written by Bruno Haible <haible@clisp.cons.org>, 2001, 2019.
This program is free software: you can redistribute it and/or modify This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU Lesser General Public License as
the Free Software Foundation; either version 3 of the License, or published by the Free Software Foundation; either version 2.1 of the
(at your option) any later version. License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/errno.h" #include "config.h"
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "third_party/make/filename.h"
#include "libc/calls/struct/stat.h"
#include "libc/sysv/consts/s.h"
#include "third_party/make/config.h"
/* Specification. */ /* Specification. */
#include "third_party/make/findprog.h" #include "findprog.h"
#include "libc/sysv/consts/ok.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "third_party/make/filename.h" #include "filename.h"
#include "third_party/make/concat-filename.h" #include "concat-filename.h"
#include "third_party/make/xalloc.h"
#if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__ #if (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__ || defined __DJGPP__
/* Native Windows, OS/2, DOS */ /* Native Windows, OS/2, DOS */

View file

@ -1,18 +1,18 @@
/* Locating a program in PATH. /* Locating a program in PATH.
Copyright (C) 2001-2003, 2009-2020 Free Software Foundation, Inc. Copyright (C) 2001-2003, 2009-2023 Free Software Foundation, Inc.
Written by Bruno Haible <haible@clisp.cons.org>, 2001. Written by Bruno Haible <haible@clisp.cons.org>, 2001.
This program is free software: you can redistribute it and/or modify This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU Lesser General Public License as
the Free Software Foundation; either version 3 of the License, or published by the Free Software Foundation; either version 2.1 of the
(at your option) any later version. License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _FINDPROG_H #ifndef _FINDPROG_H

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@ NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to drepper@gnu.org "Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it! before changing it!
Copyright (C) 1987-2020 Free Software Foundation, Inc. Copyright (C) 1987-2023 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library. NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org. Bugs can be reported to bug-glibc@gnu.org.
@ -18,10 +18,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */ Ditto for AIX 3.2 and <stdlib.h>. */
@ -30,9 +27,18 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#endif #endif
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "third_party/make/config.h" #include "config.h"
#endif #endif
#pragma GCC diagnostic ignored "-Wredundant-decls"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
# ifndef const
# define const
# endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not /* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C actually compiling the library itself. This code is part of the GNU C
@ -44,6 +50,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#define GETOPT_INTERFACE_VERSION 2 #define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
# include <gnu-versions.h>
# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
# define ELIDE_CODE # define ELIDE_CODE
# endif # endif
@ -51,9 +58,26 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef ELIDE_CODE #ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
# include <stdlib.h>
# include <unistd.h>
#endif /* GNU C library. */
#ifdef VMS
# include <unixlib.h>
# if HAVE_STRING_H - 0
# include <string.h>
# endif
#endif
/* This is for other GNU distributions with internationalized messages. /* This is for other GNU distributions with internationalized messages.
When compiling libc, the _ macro is predefined. */ When compiling libc, the _ macro is predefined. */
#include "third_party/make/gettext.h" #include "gettext.h"
#define _(msgid) gettext (msgid) #define _(msgid) gettext (msgid)
@ -71,7 +95,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
GNU application programs can use a third alternative mode in which GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */ they can distinguish the relative order of options and other arguments. */
#include "third_party/make/getopt.h" #include "getopt.h"
/* For communication from `getopt' to the caller. /* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument, When `getopt' finds an option that takes an argument,
@ -164,9 +188,16 @@ static char *posixly_correct;
because there are many ways it can cause trouble. because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work On some systems, it contains special magic macros that don't work
in GCC. */ in GCC. */
# include <string.h>
# define my_index strchr # define my_index strchr
#else #else
# if HAVE_STRING_H
# include <string.h>
# else
# include <strings.h>
# endif
/* Avoid depending on library functions or files /* Avoid depending on library functions or files
whose names are inconsistent. */ whose names are inconsistent. */
@ -405,6 +436,10 @@ _getopt_initialize (int argc, char *const *argv, const char *optstring)
nonoption_flags_len = 0; nonoption_flags_len = 0;
#endif #endif
/* Make the compiler happy. */
(void)argc;
(void)argv;
return optstring; return optstring;
} }
@ -645,7 +680,8 @@ _getopt_internal (int argc, char *const *argv, const char *optstring,
optarg = nameend + 1; optarg = nameend + 1;
else else
{ {
if (opterr) { if (opterr)
{
if (argv[optind - 1][1] == '-') if (argv[optind - 1][1] == '-')
/* --option */ /* --option */
fprintf (stderr, fprintf (stderr,

View file

@ -1,5 +1,5 @@
/* Declarations for getopt. /* Declarations for getopt.
Copyright (C) 1989-2020 Free Software Foundation, Inc. Copyright (C) 1989-2023 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library. NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org. Bugs can be reported to bug-glibc@gnu.org.
@ -14,8 +14,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GETOPT_H #ifndef _GETOPT_H
#define _GETOPT_H 1 #define _GETOPT_H 1
@ -128,10 +127,4 @@ extern int _getopt_internal ();
} }
#endif #endif
#else
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#endif /* getopt.h */ #endif /* getopt.h */

View file

@ -1,5 +1,5 @@
/* getopt_long and getopt_long_only entry points for GNU getopt. /* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987-1994, 1996-2020 Free Software Foundation, Inc. Copyright (C) 1987-1994, 1996-2023 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library. NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org. Bugs can be reported to bug-glibc@gnu.org.
@ -14,14 +14,24 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/getopt.h"
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "third_party/make/config.h" #include "config.h"
#endif #endif
#include "getopt.h"
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
/* Comment out all this code if we are using the GNU C Library, and are not /* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling Library, but also included in many other GNU distributions. Compiling
@ -32,6 +42,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#define GETOPT_INTERFACE_VERSION 2 #define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE #define ELIDE_CODE
#endif #endif
@ -39,6 +50,17 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef ELIDE_CODE #ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int int
getopt_long (int argc, char *const *argv, const char *options, getopt_long (int argc, char *const *argv, const char *options,
const struct option *long_options, int *opt_index) const struct option *long_options, int *opt_index)
@ -63,6 +85,8 @@ getopt_long_only (int argc, char *const *argv, const char *options,
#ifdef TEST #ifdef TEST
#include <stdio.h>
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {

View file

@ -1,34 +0,0 @@
/* Program name management.
Copyright (C) 2016-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/config.h"
#include "third_party/make/getprogname.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/errno.h"
#include "third_party/make/dirname.h"
char const *
getprogname (void)
{
return firstnonnull(program_invocation_short_name, "unknown");
}
/*
* Hey Emacs!
* Local Variables:
* coding: utf-8
* End:
*/

View file

@ -1,38 +0,0 @@
/* Program name management.
Copyright (C) 2016-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GL_GETPROGNAME_H
#define _GL_GETPROGNAME_H
#ifdef __cplusplus
extern "C" {
#endif
/* Return the base name of the executing program.
On native Windows this will usually end in ".exe" or ".EXE". */
#ifndef HAVE_GETPROGNAME
extern char const *getprogname(void)
#ifdef HAVE_DECL_PROGRAM_INVOCATION_NAME
_GL_ATTRIBUTE_PURE
#endif
;
#endif
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,99 +1,50 @@
/* Convenience header for conditional use of GNU <libintl.h>. /* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2020 Free Software Copyright (C) 1995-2023 Free Software Foundation, Inc.
Foundation, Inc. This file is part of GNU Make.
This program is free software; you can redistribute it and/or modify GNU Make is free software; you can redistribute it and/or modify it under the
it under the terms of the GNU General Public License as published by terms of the GNU General Public License as published by the Free Software
the Free Software Foundation; either version 3, or (at your option) Foundation; either version 3 of the License, or (at your option) any later
any later version. version.
This program is distributed in the hope that it will be useful, GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
but WITHOUT ANY WARRANTY; without even the implied warranty of WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the A PARTICULAR PURPOSE. See the GNU General Public License for more details.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License along with
with this program; if not, see <https://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _LIBGETTEXT_H #ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1 #define _LIBGETTEXT_H 1
#include "libc/str/str.h"
/* NLS can be disabled through the configure --disable-nls option /* NLS can be disabled through the configure --disable-nls option. */
or through "#define ENABLE NLS 0" before including this file. */ #if ENABLE_NLS
#if defined ENABLE_NLS && ENABLE_NLS
/* Get declarations of GNU message catalog functions. */ /* Get declarations of GNU message catalog functions. */
# include <libintl.h>
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
the gettext() and ngettext() macros. This is an alternative to calling
textdomain(), and is useful for libraries. */
# ifdef DEFAULT_TEXT_DOMAIN
# undef gettext
# define gettext(Msgid) \
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
# endif
#else #else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
#endif
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
it now, to make later inclusions of <libintl.h> a NOP. */
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
# endif
#endif
/* Disabled NLS. /* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions. for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */ contain "#define const". */
# undef gettext
# define gettext(Msgid) ((const char *) (Msgid)) # define gettext(Msgid) ((const char *) (Msgid))
# undef dgettext # define dgettext(Domainname, Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) # define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
# undef dcgettext
# define dcgettext(Domainname, Msgid, Category) \
((void) (Category), dgettext (Domainname, Msgid))
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \ # define ngettext(Msgid1, Msgid2, N) \
((N) == 1 \ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
? ((void) (Msgid2), (const char *) (Msgid1)) \
: ((void) (Msgid1), (const char *) (Msgid2)))
# undef dngettext
# define dngettext(Domainname, Msgid1, Msgid2, N) \ # define dngettext(Domainname, Msgid1, Msgid2, N) \
((void) (Domainname), ngettext (Msgid1, Msgid2, N)) ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# undef dcngettext
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# undef textdomain
# define textdomain(Domainname) ((const char *) (Domainname)) # define textdomain(Domainname) ((const char *) (Domainname))
# undef bindtextdomain # define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
# define bindtextdomain(Domainname, Dirname) \ # define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
((void) (Domainname), (const char *) (Dirname))
# undef bind_textdomain_codeset
# define bind_textdomain_codeset(Domainname, Codeset) \
((void) (Domainname), (const char *) (Codeset))
#endif #endif
/* Prefer gnulib's setlocale override over libintl's setlocale override. */
#ifdef GNULIB_defined_setlocale
# undef setlocale
# define setlocale rpl_setlocale
#endif
/* A pseudo function call that serves as a marker for the automated /* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code. translation is done at a different place in the code.
@ -103,192 +54,4 @@
initializer for static 'char[]' or 'const char[]' variables. */ initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String #define gettext_noop(String) String
/* The separator between msgctxt and msgid in a .mo file. */
#define GETTEXT_CONTEXT_GLUE "\004"
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
short and rarely need to change.
The letter 'p' stands for 'particular' or 'special'. */
#ifdef DEFAULT_TEXT_DOMAIN
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#else
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#endif
#define dpgettext(Domainname, Msgctxt, Msgid) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
#ifdef DEFAULT_TEXT_DOMAIN
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#else
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#endif
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
pgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
int category)
{
const char *translation = dcgettext (domain, msg_ctxt_id, category);
if (translation == msg_ctxt_id)
return msgid;
else
return translation;
}
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
npgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
const char *translation =
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
if (translation == msg_ctxt_id || translation == msgid_plural)
return (n == 1 ? msgid : msgid_plural);
else
return translation;
}
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
can be arbitrary expressions. But for string literals these macros are
less efficient than those above. */
/* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported.
This relates to the -Wvla and -Wvla-larger-than warnings, enabled in
the default GCC many warnings set. This allows programs to disable use
of VLAs, which may be unintended, or may be awkward to support portably,
or may have security implications due to non-deterministic stack usage. */
#if (!defined GNULIB_NO_VLA \
&& (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
/* || (__STDC_VERSION__ == 199901L && !defined __HP_cc)
|| (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */ ))
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
#else
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
#endif
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
#endif
#define pgettext_expr(Msgctxt, Msgid) \
dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category);
found_translation = (translation != msg_ctxt_id);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (found_translation)
return translation;
}
return msgid;
}
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcnpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (found_translation)
return translation;
}
return (n == 1 ? msgid : msgid_plural);
}
#endif /* _LIBGETTEXT_H */ #endif /* _LIBGETTEXT_H */

1318
third_party/make/glob.c vendored Normal file

File diff suppressed because it is too large Load diff

163
third_party/make/glob.h vendored Normal file
View file

@ -0,0 +1,163 @@
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
/* Copyright (C) 1991, 1992, 1995, 1996, 1997, 1998, 2023 Free Software
Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA. */
#ifndef _GLOB_H
#define _GLOB_H 1
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Bits set in the FLAGS argument to `glob'. */
#define GLOB_ERR (1 << 0)/* Return on read errors. */
#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
|| defined _GNU_SOURCE)
# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
if the user name is not available. */
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
#else
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
GLOB_PERIOD)
#endif
/* Error returns from `glob'. */
#define GLOB_NOSPACE 1 /* Ran out of memory. */
#define GLOB_ABORTED 2 /* Read error. */
#define GLOB_NOMATCH 3 /* No matches found. */
#define GLOB_NOSYS 4 /* Not implemented. */
#ifdef _GNU_SOURCE
/* Previous versions of this file defined GLOB_ABEND instead of
GLOB_ABORTED. Provide a compatibility definition here. */
# define GLOB_ABEND GLOB_ABORTED
#endif
/* Structure describing a globbing run. */
#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
struct stat;
#endif
typedef struct
{
size_t gl_pathc; /* Count of paths matched by the pattern. */
char **gl_pathv; /* List of matched pathnames. */
size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
void (*gl_closedir) (void *);
struct dirent *(*gl_readdir) (void *);
void * (*gl_opendir) (const char *);
int (*gl_lstat) (const char *, struct stat *);
#if defined(VMS) && defined(__DECC) && !defined(_POSIX_C_SOURCE)
int (*gl_stat) (const char *, struct stat *, ...);
#else
int (*gl_stat) (const char *, struct stat *);
#endif
} glob_t;
#ifdef _LARGEFILE64_SOURCE
struct stat64;
typedef struct
{
size_t gl_pathc;
char **gl_pathv;
size_t gl_offs;
int gl_flags;
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
void (*gl_closedir) (void *);
struct dirent64 *(*gl_readdir) (void *);
void * (*gl_opendir) (const char *);
int (*gl_lstat) (const char *, struct stat64 *);
int (*gl_stat) (const char *, struct stat64 *);
} glob64_t;
#endif
#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2
# define glob glob64
# define globfree globfree64
#else
# ifdef _LARGEFILE64_SOURCE
extern int glob64 (const char *pattern, int flags,
int (*errfunc) (const char *, int),
glob64_t *pglob);
extern void globfree64 (glob64_t *pglob);
# endif
#endif
/* Do glob searching for PATTERN, placing results in PGLOB.
The bits defined above may be set in FLAGS.
If a directory cannot be opened or read and ERRFUNC is not nil,
it is called with the pathname that caused the error, and the
`errno' value from the failing call; if it returns non-zero
`glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
Otherwise, `glob' returns zero. */
#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2
extern int glob (const char *pattern, int flags,
int (*errfunc) (const char *, int),
glob_t *pglob);
/* Free storage allocated in PGLOB by a previous `glob' call. */
extern void globfree (glob_t *pglob);
#else
extern int glob (const char *pattern, int flags,
int (*errfunc) (const char *, int),
glob_t *pglob) __asm__ ("glob64");
extern void globfree (glob_t *pglob) __asm__ ("globfree64");
#endif
#ifdef _GNU_SOURCE
/* Return nonzero if PATTERN contains any metacharacters.
Metacharacters can be quoted with backslashes if QUOTE is nonzero.
This function is not part of the interface specified by POSIX.2
but several programs want to use it. */
extern int glob_pattern_p (const char *pattern, int quote);
#endif
#ifdef __cplusplus
}
#endif
#endif /* glob.h */

View file

@ -1,7 +1,7 @@
/* External interfaces usable by dynamic objects loaded into GNU Make. /* External interfaces usable by dynamic objects loaded into GNU Make.
--THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE-- --THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE--
Copyright (C) 2013-2020 Free Software Foundation, Inc. Copyright (C) 2013-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -14,7 +14,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _GNUMAKE_H_ #ifndef _GNUMAKE_H_
#define _GNUMAKE_H_ #define _GNUMAKE_H_
@ -41,23 +41,23 @@ typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
/* Free memory returned by the gmk_expand() function. */ /* Free memory returned by the gmk_expand() function. */
GMK_EXPORT void gmk_free (char *str); GMK_EXPORT void gmk_free (char *str);
/* Allocate memory in GNU make's context. */ /* Allocate memory in GNU Make's context. */
GMK_EXPORT char *gmk_alloc (unsigned int len); GMK_EXPORT char *gmk_alloc (unsigned int len);
/* Run $(eval ...) on the provided string BUFFER. */ /* Run $(eval ...) on the provided string BUFFER. */
GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc); GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc);
/* Run GNU make expansion on the provided string STR. /* Run GNU Make expansion on the provided string STR.
Returns an allocated buffer that the caller must free with gmk_free(). */ Returns an allocated buffer that the caller must free with gmk_free(). */
GMK_EXPORT char *gmk_expand (const char *str); GMK_EXPORT char *gmk_expand (const char *str);
/* Register a new GNU make function NAME (maximum of 255 chars long). /* Register a new GNU Make function NAME (maximum of 255 chars long).
When the function is expanded in the makefile, FUNC will be invoked with When the function is expanded in the makefile, FUNC will be invoked with
the appropriate arguments. the appropriate arguments.
The return value of FUNC must be either NULL, in which case it expands to The return value of FUNC must be either NULL, in which case it expands to
the empty string, or a pointer to the result of the expansion in a string the empty string, or a pointer to the result of the expansion in a string
created by gmk_alloc(). GNU make will free the memory when it's done. created by gmk_alloc(). GNU Make will free the memory when it's done.
MIN_ARGS is the minimum number of arguments the function requires. MIN_ARGS is the minimum number of arguments the function requires.
MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum). MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum).

View file

@ -1,5 +1,5 @@
/* GNU Guile interface for GNU Make. /* GNU Guile interface for GNU Make.
Copyright (C) 2011-2020 Free Software Foundation, Inc. Copyright (C) 2011-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,12 +12,148 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#ifdef HAVE_GUILE
#include "gnumake.h"
#include "debug.h"
#include "filedef.h"
#include "dep.h"
#include "variable.h"
#include <libguile.h>
/* Pre-2.0 versions of Guile don't have a typedef for gsubr function types. */
#if SCM_MAJOR_VERSION < 2
# define GSUBR_TYPE SCM (*) ()
/* Guile 1.x doesn't really support i18n. */
# define EVAL_STRING(_s) scm_c_eval_string (_s)
#else
# define GSUBR_TYPE scm_t_subr
# define EVAL_STRING(_s) scm_eval_string (scm_from_utf8_string (_s))
#endif
static SCM make_mod = SCM_EOL;
static SCM obj_to_str = SCM_EOL;
/* Convert an SCM object into a string. */
static char *
cvt_scm_to_str (SCM obj)
{
return scm_to_locale_string (scm_call_1 (obj_to_str, obj));
}
/* Perform the GNU Make expansion function. */
static SCM
guile_expand_wrapper (SCM obj)
{
char *str = cvt_scm_to_str (obj);
SCM ret;
char *res;
DB (DB_BASIC, (_("guile: Expanding '%s'\n"), str));
res = gmk_expand (str);
ret = scm_from_locale_string (res);
free (str);
free (res);
return ret;
}
/* Perform the GNU Make eval function. */
static SCM
guile_eval_wrapper (SCM obj)
{
char *str = cvt_scm_to_str (obj);
DB (DB_BASIC, (_("guile: Evaluating '%s'\n"), str));
gmk_eval (str, 0);
return SCM_BOOL_F;
}
/* Invoked by scm_c_define_module(), in the context of the GNU Make module. */
static void
guile_define_module (void *data UNUSED)
{
/* Ingest the predefined Guile module for GNU Make. */
//#include "gmk-default.h"
/* Register a subr for GNU Make's eval capability. */
scm_c_define_gsubr ("gmk-expand", 1, 0, 0, (GSUBR_TYPE) guile_expand_wrapper);
/* Register a subr for GNU Make's eval capability. */
scm_c_define_gsubr ("gmk-eval", 1, 0, 0, (GSUBR_TYPE) guile_eval_wrapper);
/* Define the rest of the module. */
scm_c_eval_string (GUILE_module_defn);
}
/* Initialize the GNU Make Guile module. */
static void *
guile_init (void *arg UNUSED)
{
/* Define the module. */
make_mod = scm_c_define_module ("gnu make", guile_define_module, NULL);
/* Get a reference to the object-to-string translator, for later. */
obj_to_str = scm_variable_ref (scm_c_module_lookup (make_mod, "obj-to-str"));
/* Import the GNU Make module exports into the generic space. */
scm_c_eval_string ("(use-modules (gnu make))");
return NULL;
}
static void *
internal_guile_eval (void *arg)
{
return cvt_scm_to_str (EVAL_STRING (arg));
}
/* This is the function registered with make */
static char *
func_guile (const char *funcname UNUSED, unsigned int argc UNUSED, char **argv)
{
static int init = 0;
if (! init)
{
/* Initialize the Guile interpreter. */
scm_with_guile (guile_init, NULL);
init = 1;
}
if (argv[0] && argv[0][0] != '\0')
return scm_with_guile (internal_guile_eval, argv[0]);
return NULL;
}
/* ----- Public interface ----- */
/* We could send the flocp to define_new_function(), but since guile is
"kind of" built-in, that didn't seem so useful. */
int
guile_gmake_setup (const floc *flocp UNUSED)
{
/* Create a make function "guile". */
gmk_add_function ("guile", func_guile, 0, 1, GMK_FUNC_DEFAULT);
return 1;
}
#else
int int
guile_gmake_setup (const floc *flocp UNUSED) guile_gmake_setup (const floc *flocp UNUSED)
{ {
return 1; return 1;
} }
#endif

View file

@ -12,20 +12,13 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
/**/ #include "hash.h"
#include "libc/assert.h" #include <assert.h>
#include "libc/intrin/bsr.h"
#include "libc/intrin/likely.h"
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/x/x.h"
#include "libc/serialize.h"
#include "third_party/make/hash.h"
#define CALLOC(t, n) ((t *) xcalloc (1, sizeof (t) * (n))) #define CALLOC(t, n) ((t *) xcalloc (sizeof (t) * (n)))
#define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n))) #define MALLOC(t, n) ((t *) xmalloc (sizeof (t) * (n)))
#define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n))) #define REALLOC(o, t, n) ((t *) xrealloc ((o), sizeof (t) * (n)))
#define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n))) #define CLONE(o, t, n) ((t *) memcpy (MALLOC (t, (n)), (o), sizeof (t) * (n)))
@ -51,11 +44,11 @@ hash_init (struct hash_table *ht, unsigned long size,
{ {
ht->ht_size = round_up_2 (size); ht->ht_size = round_up_2 (size);
ht->ht_empty_slots = ht->ht_size; ht->ht_empty_slots = ht->ht_size;
ht->ht_vec = (void**) CALLOC (struct token *, ht->ht_size); ht->ht_vec = CALLOC (void *, ht->ht_size);
if (ht->ht_vec == 0) if (ht->ht_vec == 0)
{ {
fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"), fprintf (stderr, _("can't allocate %lu bytes for hash table: memory exhausted"),
ht->ht_size * (unsigned long) sizeof (struct token *)); ht->ht_size * (unsigned long) sizeof (void *));
exit (MAKE_TROUBLE); exit (MAKE_TROUBLE);
} }
@ -267,7 +260,7 @@ hash_rehash (struct hash_table *ht)
ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4); ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4);
} }
ht->ht_rehashes++; ht->ht_rehashes++;
ht->ht_vec = (void **) CALLOC (struct token *, ht->ht_size); ht->ht_vec = CALLOC (void *, ht->ht_size);
for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++) for (ovp = old_vec; ovp < &old_vec[old_ht_size]; ovp++)
{ {
@ -322,8 +315,18 @@ hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare)
static unsigned long static unsigned long
round_up_2 (unsigned long n) round_up_2 (unsigned long n)
{ {
if (UNLIKELY(!n)) return 1; n |= (n >> 1);
return 2ul << _bsrl(n); n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
#if !defined(HAVE_LIMITS_H) || ULONG_MAX > 4294967295
/* We only need this on systems where unsigned long is >32 bits. */
n |= (n >> 32);
#endif
return n + 1;
} }
#define rol32(v, n) \ #define rol32(v, n) \
@ -409,9 +412,31 @@ jhash(unsigned const char *k, int length)
#define UINTSZ sizeof (unsigned int) #define UINTSZ sizeof (unsigned int)
#ifdef WORDS_BIGENDIAN
/* The ifs are ordered from the first byte in memory to the last.
Help the compiler optimize by using static memcpy length. */
#define sum_up_to_nul(r, p, plen, flag) \
do { \
unsigned int val = 0; \
size_t pn = (plen); \
if (pn >= UINTSZ) \
memcpy (&val, (p), UINTSZ); \
else \
memcpy (&val, (p), pn); \
if ((val & 0xFF000000) == 0) \
flag = 1; \
else if ((val & 0xFF0000) == 0) \
r += val & ~0xFFFF, flag = 1; \
else if ((val & 0xFF00) == 0) \
r += val & ~0xFF, flag = 1; \
else \
r += val, flag = (val & 0xFF) == 0; \
} while (0)
#else
/* First detect the presence of zeroes. If there is none, we can /* First detect the presence of zeroes. If there is none, we can
sum the 4 bytes directly. Otherwise, the ifs are ordered as in the sum the 4 bytes directly. Otherwise, the ifs are ordered as in the
big endian case, from the first byte in memory to the last. */ big endian case, from the first byte in memory to the last.
Help the compiler optimize by using static memcpy length. */
#define sum_up_to_nul(r, p, plen, flag) \ #define sum_up_to_nul(r, p, plen, flag) \
do { \ do { \
unsigned int val = 0; \ unsigned int val = 0; \
@ -433,6 +458,7 @@ jhash(unsigned const char *k, int length)
r += val; \ r += val; \
} \ } \
} while (0) } while (0)
#endif
unsigned int unsigned int
jhash_string(unsigned const char *k) jhash_string(unsigned const char *k)
@ -445,35 +471,27 @@ jhash_string(unsigned const char *k)
/* Set up the internal state */ /* Set up the internal state */
a = b = c = JHASH_INITVAL; a = b = c = JHASH_INITVAL;
for (; klen > 12; k += 12, klen -= 12)
{
a += READ32LE (k + 0);
b += READ32LE (k + 4);
c += READ32LE (k + 8);
jhash_mix (a, b, c);
}
/* All but the last block: affect some 32 bits of (a,b,c) */ /* All but the last block: affect some 32 bits of (a,b,c) */
for (;;) { for (;;) {
sum_up_to_nul(a, k, klen, have_nul); sum_up_to_nul(a, k, klen, have_nul);
if (have_nul) if (have_nul)
break; break;
k += UINTSZ; k += UINTSZ;
DCHECK (klen >= UINTSZ); assert (klen >= UINTSZ);
klen -= UINTSZ; klen -= UINTSZ;
sum_up_to_nul(b, k, klen, have_nul); sum_up_to_nul(b, k, klen, have_nul);
if (have_nul) if (have_nul)
break; break;
k += UINTSZ; k += UINTSZ;
DCHECK (klen >= UINTSZ); assert (klen >= UINTSZ);
klen -= UINTSZ; klen -= UINTSZ;
sum_up_to_nul(c, k, klen, have_nul); sum_up_to_nul(c, k, klen, have_nul);
if (have_nul) if (have_nul)
break; break;
k += UINTSZ; k += UINTSZ;
DCHECK (klen >= UINTSZ); assert (klen >= UINTSZ);
klen -= UINTSZ; klen -= UINTSZ;
jhash_mix(a, b, c); jhash_mix(a, b, c);
} }

View file

@ -12,11 +12,14 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef _hash_h_ #ifndef _hash_h_
#define _hash_h_ #define _hash_h_
#include <stdio.h>
#include <ctype.h>
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 #if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
# if !defined __GLIBC__ || !defined __P # if !defined __GLIBC__ || !defined __P
# undef __P # undef __P
@ -151,7 +154,7 @@ extern void *hash_deleted_item;
#define ISTRING_HASH_1(KEY, RESULT) do { \ #define ISTRING_HASH_1(KEY, RESULT) do { \
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
while (*++_key_) \ while (*++_key_) \
(RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0xf)); \ (RESULT) += (tolower (*_key_) << (_key_[1] & 0xf)); \
} while (0) } while (0)
#define return_ISTRING_HASH_1(KEY) do { \ #define return_ISTRING_HASH_1(KEY) do { \
unsigned long _result_ = 0; \ unsigned long _result_ = 0; \
@ -162,7 +165,7 @@ extern void *hash_deleted_item;
#define ISTRING_HASH_2(KEY, RESULT) do { \ #define ISTRING_HASH_2(KEY, RESULT) do { \
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \ unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
while (*++_key_) \ while (*++_key_) \
(RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0x7)); \ (RESULT) += (tolower (*_key_) << (_key_[1] & 0x7)); \
} while (0) } while (0)
#define return_ISTRING_HASH_2(KEY) do { \ #define return_ISTRING_HASH_2(KEY) do { \
unsigned long _result_ = 0; \ unsigned long _result_ = 0; \

View file

@ -1,5 +1,5 @@
/* Implicit rule searching for GNU Make. /* Implicit rule searching for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,19 +12,22 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h" #include "filedef.h"
#include "third_party/make/rule.h" #include "rule.h"
#include "third_party/make/dep.h" #include "dep.h"
#include "third_party/make/debug.h" #include "debug.h"
#include "third_party/make/variable.h" #include "variable.h"
#include "third_party/make/job.h" /* struct child, used inside commands.h */ #include "job.h" /* struct child, used inside commands.h */
#include "third_party/make/commands.h" /* set_file_variables */ #include "commands.h" /* set_file_variables */
#include "shuffle.h"
#include <assert.h>
static int pattern_search (struct file *file, int archive, static int pattern_search (struct file *file, int archive,
unsigned int depth, unsigned int recursions); unsigned int depth, unsigned int recursions,
int allow_compat_rules);
/* For a FILE which has no commands specified, try to figure out some /* For a FILE which has no commands specified, try to figure out some
from the implicit pattern rules. from the implicit pattern rules.
@ -42,7 +45,7 @@ try_implicit_rule (struct file *file, unsigned int depth)
(the archive search omits the archive name), it is more specific and (the archive search omits the archive name), it is more specific and
should come first. */ should come first. */
if (pattern_search (file, 0, depth, 0)) if (pattern_search (file, 0, depth, 0, 0))
return 1; return 1;
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
@ -52,8 +55,11 @@ try_implicit_rule (struct file *file, unsigned int depth)
{ {
DBF (DB_IMPLICIT, DBF (DB_IMPLICIT,
_("Looking for archive-member implicit rule for '%s'.\n")); _("Looking for archive-member implicit rule for '%s'.\n"));
if (pattern_search (file, 1, depth, 0)) if (pattern_search (file, 1, depth, 0, 0))
return 1; return 1;
DBS (DB_IMPLICIT,
(_("No archive-member implicit rule found for '%s'.\n"),
file->name));
} }
#endif #endif
@ -153,6 +159,8 @@ struct patdeps
struct file *file; struct file *file;
unsigned int ignore_mtime : 1; unsigned int ignore_mtime : 1;
unsigned int ignore_automatic_vars : 1; unsigned int ignore_automatic_vars : 1;
unsigned int is_explicit : 1;
unsigned int wait_here : 1;
}; };
/* This structure stores information about pattern rules that we need /* This structure stores information about pattern rules that we need
@ -200,7 +208,8 @@ stemlen_compare (const void *v1, const void *v2)
static int static int
pattern_search (struct file *file, int archive, pattern_search (struct file *file, int archive,
unsigned int depth, unsigned int recursions) unsigned int depth, unsigned int recursions,
int allow_compat_rules)
{ {
/* Filename we are searching for a rule for. */ /* Filename we are searching for a rule for. */
const char *filename = archive ? strchr (file->name, '(') : file->name; const char *filename = archive ? strchr (file->name, '(') : file->name;
@ -223,7 +232,11 @@ pattern_search (struct file *file, int archive,
/* Names of possible dependencies are constructed in this buffer. /* Names of possible dependencies are constructed in this buffer.
We may replace % by $(*F) for second expansion, increasing the length. */ We may replace % by $(*F) for second expansion, increasing the length. */
char *depname = alloca (namelen + max_pattern_dep_length + 4); size_t deplen = namelen + max_pattern_dep_length + 4;
char *depname = alloca (deplen);
#ifndef NDEBUG
char *dend = depname + deplen;
#endif
/* The start and length of the stem of FILENAME for the current rule. */ /* The start and length of the stem of FILENAME for the current rule. */
const char *stem = 0; const char *stem = 0;
@ -251,6 +264,7 @@ pattern_search (struct file *file, int archive,
int specific_rule_matched = 0; int specific_rule_matched = 0;
unsigned int ri; /* uninit checks OK */ unsigned int ri; /* uninit checks OK */
int found_compat_rule = 0;
struct rule *rule; struct rule *rule;
char *pathdir = NULL; char *pathdir = NULL;
@ -258,6 +272,8 @@ pattern_search (struct file *file, int archive,
PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */ PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */
++depth;
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
if (archive || ar_name (filename)) if (archive || ar_name (filename))
lastslash = 0; lastslash = 0;
@ -268,6 +284,14 @@ pattern_search (struct file *file, int archive,
but not counting any slash at the end. (foo/bar/ counts as but not counting any slash at the end. (foo/bar/ counts as
bar/ in directory foo/, not empty in directory foo/bar/.) */ bar/ in directory foo/, not empty in directory foo/bar/.) */
lastslash = memrchr (filename, '/', namelen - 1); lastslash = memrchr (filename, '/', namelen - 1);
#ifdef VMS
if (lastslash == NULL)
lastslash = strrchr (filename, ']');
if (lastslash == NULL)
lastslash = strrchr (filename, '>');
if (lastslash == NULL)
lastslash = strrchr (filename, ':');
#endif
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* Handle backslashes (possibly mixed with forward slashes) /* Handle backslashes (possibly mixed with forward slashes)
and the case of "d:file". */ and the case of "d:file". */
@ -300,7 +324,9 @@ pattern_search (struct file *file, int archive,
don't use it here. */ don't use it here. */
if (rule->in_use) if (rule->in_use)
{ {
DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n"))); DBS (DB_IMPLICIT,
(_("Avoiding implicit rule recursion for rule '%s'.\n"),
get_rule_defn (rule)));
continue; continue;
} }
@ -331,7 +357,11 @@ pattern_search (struct file *file, int archive,
check_lastslash = 0; check_lastslash = 0;
if (lastslash) if (lastslash)
{ {
#ifdef VMS
check_lastslash = strpbrk (target, "/]>:") == NULL;
#else
check_lastslash = strchr (target, '/') == 0; check_lastslash = strchr (target, '/') == 0;
#endif
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* Didn't find it yet: check for DOS-type directories. */ /* Didn't find it yet: check for DOS-type directories. */
if (check_lastslash) if (check_lastslash)
@ -419,6 +449,8 @@ pattern_search (struct file *file, int archive,
for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok) for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok)
{ {
pat = deplist; pat = deplist;
if (intermed_ok)
DBS (DB_IMPLICIT, (_("Trying harder.\n")));
/* Try each pattern rule till we find one that applies. If it does, /* Try each pattern rule till we find one that applies. If it does,
expand its dependencies (as substituted) and chain them in DEPS. */ expand its dependencies (as substituted) and chain them in DEPS. */
@ -467,6 +499,10 @@ pattern_search (struct file *file, int archive,
} }
} }
DBS (DB_IMPLICIT,
(_("Trying pattern rule '%s' with stem '%.*s'.\n"),
get_rule_defn (rule), (int) stemlen, stem));
if (stemlen + (check_lastslash ? pathlen : 0) > GET_PATH_MAX) if (stemlen + (check_lastslash ? pathlen : 0) > GET_PATH_MAX)
{ {
DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"), DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"),
@ -475,9 +511,6 @@ pattern_search (struct file *file, int archive,
continue; continue;
} }
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"),
(int) stemlen, stem));
if (!check_lastslash) if (!check_lastslash)
{ {
memcpy (stem_str, stem, stemlen); memcpy (stem_str, stem, stemlen);
@ -496,10 +529,6 @@ pattern_search (struct file *file, int archive,
if (rule->deps == 0) if (rule->deps == 0)
break; break;
/* Temporary assign STEM to file->stem (needed to set file
variables below). */
file->stem = stem_str;
/* Mark this rule as in use so a recursive pattern_search won't try /* Mark this rule as in use so a recursive pattern_search won't try
to use it. */ to use it. */
rule->in_use = 1; rule->in_use = 1;
@ -514,7 +543,6 @@ pattern_search (struct file *file, int archive,
while (1) while (1)
{ {
struct dep *dl, *d; struct dep *dl, *d;
char *p;
/* If we're out of name to parse, start the next prereq. */ /* If we're out of name to parse, start the next prereq. */
if (! nptr) if (! nptr)
@ -528,32 +556,33 @@ pattern_search (struct file *file, int archive,
/* If we don't need a second expansion, just replace the %. */ /* If we don't need a second expansion, just replace the %. */
if (! dep->need_2nd_expansion) if (! dep->need_2nd_expansion)
{ {
p = strchr (nptr, '%'); char *p;
if (p == 0) int is_explicit = 1;
const char *cp = strchr (nptr, '%');
if (cp == 0)
strcpy (depname, nptr); strcpy (depname, nptr);
else else
{ {
char *o = depname; char *o = depname;
if (check_lastslash) if (check_lastslash)
{ o = mempcpy (o, filename, pathlen);
memcpy (o, filename, pathlen); o = mempcpy (o, nptr, cp - nptr);
o += pathlen; o = mempcpy (o, stem, stemlen);
} strcpy (o, cp + 1);
memcpy (o, nptr, p - nptr); is_explicit = 0;
o += p - nptr;
memcpy (o, stem, stemlen);
o += stemlen;
strcpy (o, p + 1);
} }
/* Parse the expanded string. It might have wildcards. */ /* Parse the expanded string. It might have wildcards. */
p = depname; p = depname;
dl = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_ONEWORD); dl = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL,
PARSEFS_ONEWORD|PARSEFS_WAIT);
for (d = dl; d != NULL; d = d->next) for (d = dl; d != NULL; d = d->next)
{ {
++deps_found; ++deps_found;
d->ignore_mtime = dep->ignore_mtime; d->ignore_mtime = dep->ignore_mtime;
d->ignore_automatic_vars = dep->ignore_automatic_vars; d->ignore_automatic_vars = dep->ignore_automatic_vars;
d->wait_here |= dep->wait_here;
d->is_explicit = is_explicit;
} }
/* We've used up this dep, so next time get a new one. */ /* We've used up this dep, so next time get a new one. */
@ -573,17 +602,22 @@ pattern_search (struct file *file, int archive,
{ {
int add_dir = 0; int add_dir = 0;
size_t len; size_t len;
const char *end;
struct dep **dptr; struct dep **dptr;
int is_explicit;
const char *cp;
char *p;
nptr = get_next_word (nptr, &len); nptr = get_next_word (nptr, &len);
if (nptr == 0) if (nptr == 0)
continue; continue;
end = nptr + len;
/* See this is a transition to order-only prereqs. */ /* See if this is a transition to order-only prereqs. */
if (! order_only && len == 1 && nptr[0] == '|') if (! order_only && len == 1 && nptr[0] == '|')
{ {
order_only = 1; order_only = 1;
nptr += len; nptr = end;
continue; continue;
} }
@ -598,49 +632,76 @@ pattern_search (struct file *file, int archive,
(since $* and $(*F) are simple variables) there won't be (since $* and $(*F) are simple variables) there won't be
additional re-expansion of the stem. */ additional re-expansion of the stem. */
p = lindex (nptr, nptr + len, '%'); cp = lindex (nptr, end, '%');
if (p == 0) if (cp == 0)
{ {
memcpy (depname, nptr, len); memcpy (depname, nptr, len);
depname[len] = '\0'; depname[len] = '\0';
is_explicit = 1;
} }
else else
{ {
size_t i = p - nptr; /* Go through all % between NPTR and END.
Copy contents of [NPTR, END) to depname, with the
first % after NPTR and then each first % after white
space replaced with $* or $(*F). depname has enough
room to substitute each % with $(*F). */
char *o = depname; char *o = depname;
memcpy (o, nptr, i);
o += i; is_explicit = 0;
for (;;)
{
size_t i = cp - nptr;
assert (o + i < dend);
o = mempcpy (o, nptr, i);
if (check_lastslash) if (check_lastslash)
{ {
add_dir = 1; add_dir = 1;
memcpy (o, "$(*F)", 5); assert (o + 5 < dend);
o += 5; o = mempcpy (o, "$(*F)", 5);
} }
else else
{ {
memcpy (o, "$*", 2); assert (o + 2 < dend);
o += 2; o = mempcpy (o, "$*", 2);
} }
memcpy (o, p + 1, len - i - 1); assert (o < dend);
o[len - i - 1] = '\0'; ++cp;
assert (cp <= end);
nptr = cp;
if (nptr == end)
break;
/* Skip the rest of this word then find the next %.
No need to worry about order-only, or nested
functions: NPTR went though get_next_word. */
while (cp < end && ! END_OF_TOKEN (*cp))
++cp;
cp = lindex (cp, end, '%');
if (cp == 0)
break;
}
len = end - nptr;
memcpy (o, nptr, len);
o[len] = '\0';
} }
/* Set up for the next word. */ /* Set up for the next word. */
nptr += len; nptr = end;
/* Initialize and set file variables if we haven't already /* Initialize and set file variables if we haven't already
done so. */ done so. */
if (!file_vars_initialized) if (!file_vars_initialized)
{ {
initialize_file_variables (file, 0); initialize_file_variables (file, 0);
set_file_variables (file); set_file_variables (file, stem_str);
file_vars_initialized = 1; file_vars_initialized = 1;
} }
/* Update the stem value in $* for this rule. */ /* Update the stem value in $* for this rule. */
else if (!file_variables_set) else if (!file_variables_set)
{ {
define_variable_for_file ( define_variable_for_file (
"*", 1, file->stem, o_automatic, 0, file); "*", 1, stem_str, o_automatic, 0, file);
file_variables_set = 1; file_variables_set = 1;
} }
@ -654,7 +715,8 @@ pattern_search (struct file *file, int archive,
/* Parse the expanded string. */ /* Parse the expanded string. */
struct dep *dp = PARSE_FILE_SEQ (&p, struct dep, struct dep *dp = PARSE_FILE_SEQ (&p, struct dep,
order_only ? MAP_NUL : MAP_PIPE, order_only ? MAP_NUL : MAP_PIPE,
add_dir ? pathdir : NULL, PARSEFS_NONE); add_dir ? pathdir : NULL,
PARSEFS_WAIT);
*dptr = dp; *dptr = dp;
for (d = dp; d != NULL; d = d->next) for (d = dp; d != NULL; d = d->next)
@ -662,6 +724,7 @@ pattern_search (struct file *file, int archive,
++deps_found; ++deps_found;
if (order_only) if (order_only)
d->ignore_mtime = 1; d->ignore_mtime = 1;
d->is_explicit = is_explicit;
dptr = &d->next; dptr = &d->next;
} }
@ -692,8 +755,10 @@ pattern_search (struct file *file, int archive,
/* Go through the nameseq and handle each as a prereq name. */ /* Go through the nameseq and handle each as a prereq name. */
for (d = dl; d != 0; d = d->next) for (d = dl; d != 0; d = d->next)
{ {
struct dep *expl_d; struct file *df;
int is_rule = d->name == dep_name (dep); int is_rule = d->name == dep_name (dep);
int explicit = 0;
struct dep *dp = 0;
if (file_impossible_p (d->name)) if (file_impossible_p (d->name))
{ {
@ -702,9 +767,11 @@ pattern_search (struct file *file, int archive,
second pass either since we know that will fail. */ second pass either since we know that will fail. */
DBS (DB_IMPLICIT, DBS (DB_IMPLICIT,
(is_rule (is_rule
? _("Rejecting impossible rule prerequisite '%s'.\n") ? _("Rejecting rule '%s' due to impossible rule"
: _("Rejecting impossible implicit prerequisite '%s'.\n"), " prerequisite '%s'.\n")
d->name)); : _("Rejecting rule '%s' due to impossible implicit"
" prerequisite '%s'.\n"),
get_rule_defn (rule), d->name));
tryrules[ri].rule = 0; tryrules[ri].rule = 0;
failed = 1; failed = 1;
@ -714,41 +781,86 @@ pattern_search (struct file *file, int archive,
memset (pat, '\0', sizeof (struct patdeps)); memset (pat, '\0', sizeof (struct patdeps));
pat->ignore_mtime = d->ignore_mtime; pat->ignore_mtime = d->ignore_mtime;
pat->ignore_automatic_vars = d->ignore_automatic_vars; pat->ignore_automatic_vars = d->ignore_automatic_vars;
pat->wait_here = d->wait_here;
pat->is_explicit = d->is_explicit;
DBS (DB_IMPLICIT, DBS (DB_IMPLICIT,
(is_rule (is_rule
? _("Trying rule prerequisite '%s'.\n") ? _("Trying rule prerequisite '%s'.\n")
: _("Trying implicit prerequisite '%s'.\n"), d->name)); : _("Trying implicit prerequisite '%s'.\n"), d->name));
/* If this prereq is also explicitly mentioned for FILE, df = lookup_file (d->name);
skip all tests below since it must be built no matter
which implicit rule we choose. */
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next) if (df && df->is_explicit)
if (streq (dep_name (expl_d), d->name)) pat->is_explicit = 1;
/* If we found a file for the dep, set its intermediate flag.
df->is_explicit is set when the dep file is mentioned
explicitly on some other rule. d->is_explicit is set when
the dep file is mentioned explicitly on this rule. E.g.:
%.x : %.y ; ...
then:
one.x:
one.y: # df->is_explicit
vs.
one.x: one.y # d->is_explicit
*/
if (df && !df->is_explicit && !d->is_explicit)
df->intermediate = 1;
/* If the pattern prereq is also explicitly mentioned for
FILE, skip all tests below since it must be built no
matter which implicit rule we choose. */
if (df && df->is_target)
/* This prerequisite is mentioned explicitly as a target of
some rule. */
explicit = 1;
else
for (dp = file->deps; dp != 0; dp = dp->next)
if (streq (d->name, dep_name (dp)))
break; break;
if (expl_d != 0)
/* If dp is set, this prerequisite is mentioned explicitly as
a prerequisite of the current target. */
if (explicit || dp)
{ {
(pat++)->name = d->name; (pat++)->name = d->name;
DBS (DB_IMPLICIT, (_("'%s' ought to exist.\n"), d->name));
continue; continue;
} }
/* The DEP->changed flag says that this dependency resides if (file_exists_p (d->name))
in a nonexistent directory. So we normally can skip
looking for the file. However, if CHECK_LASTSLASH is
set, then the dependency file we are actually looking for
is in a different directory (the one gotten by prepending
FILENAME's directory), so it might actually exist. */
/* @@ dep->changed check is disabled. */
if (lookup_file (d->name) != 0
/*|| ((!dep->changed || check_lastslash) && */
|| file_exists_p (d->name))
{ {
(pat++)->name = d->name; (pat++)->name = d->name;
DBS (DB_IMPLICIT, (_("Found '%s'.\n"), d->name));
continue; continue;
} }
if (df && allow_compat_rules)
{
(pat++)->name = d->name;
DBS (DB_IMPLICIT,
(_("Using compatibility rule '%s' due to '%s'.\n"),
get_rule_defn (rule), d->name));
continue;
}
if (df)
{
/* This prerequisite is mentioned explicitly as a
prerequisite on some rule, but it is not a
prerequisite of the current target. Therefore, this
prerequisite does not qualify as ought-to-exist. Keep
note of this rule and continue the search. If a more
suitable rule is not found, then use this rule. */
DBS (DB_IMPLICIT,
(_("Prerequisite '%s' of rule '%s' does not qualify"
" as ought to exist.\n"),
d->name, get_rule_defn (rule)));
found_compat_rule = 1;
}
/* This code, given FILENAME = "lib/foo.o", dependency name /* This code, given FILENAME = "lib/foo.o", dependency name
"lib/foo.c", and VPATH=src, searches for "lib/foo.c", and VPATH=src, searches for
"src/lib/foo.c". */ "src/lib/foo.c". */
@ -757,7 +869,7 @@ pattern_search (struct file *file, int archive,
if (vname) if (vname)
{ {
DBS (DB_IMPLICIT, DBS (DB_IMPLICIT,
(_("Found prerequisite '%s' as VPATH '%s'\n"), (_("Found prerequisite '%s' as VPATH '%s'.\n"),
d->name, vname)); d->name, vname));
(pat++)->name = d->name; (pat++)->name = d->name;
continue; continue;
@ -765,13 +877,15 @@ pattern_search (struct file *file, int archive,
} }
/* We could not find the file in any place we should look. /* We could not find the file in any place we should look.
Try to make this dependency as an intermediate file, but Look for an implicit rule to make this dependency, but
only on the second pass. */ only on the second pass. */
if (intermed_ok) if (intermed_ok)
{ {
DBS (DB_IMPLICIT, DBS (DB_IMPLICIT,
(_("Looking for a rule with intermediate file '%s'.\n"), (d->is_explicit || (df && df->is_explicit)
? _("Looking for a rule with explicit file '%s'.\n")
: _("Looking for a rule with intermediate file '%s'.\n"),
d->name)); d->name));
if (int_file == 0) if (int_file == 0)
@ -781,8 +895,9 @@ pattern_search (struct file *file, int archive,
if (pattern_search (int_file, if (pattern_search (int_file,
0, 0,
depth + 1, depth,
recursions + 1)) recursions + 1,
allow_compat_rules))
{ {
pat->pattern = int_file->name; pat->pattern = int_file->name;
int_file->name = d->name; int_file->name = d->name;
@ -799,11 +914,24 @@ pattern_search (struct file *file, int archive,
free_variable_set (int_file->variables); free_variable_set (int_file->variables);
if (int_file->pat_variables) if (int_file->pat_variables)
free_variable_set (int_file->pat_variables); free_variable_set (int_file->pat_variables);
/* Keep prerequisites explicitly mentioned on unrelated
rules as "possible" to let compatibility search find
such prerequisites. */
if (df == 0)
file_impossible (d->name); file_impossible (d->name);
} }
/* A dependency of this rule does not exist. Therefore, this /* A dependency of this rule does not exist. Therefore, this
rule fails. */ rule fails. */
if (intermed_ok)
DBS (DB_IMPLICIT,
(_("Rejecting rule '%s' "
"due to impossible prerequisite '%s'.\n"),
get_rule_defn (rule), d->name));
else
DBS (DB_IMPLICIT, (_("Not found '%s'.\n"), d->name));
failed = 1; failed = 1;
break; break;
} }
@ -815,10 +943,6 @@ pattern_search (struct file *file, int archive,
break; break;
} }
/* Reset the stem in FILE. */
file->stem = 0;
/* This rule is no longer 'in use' for recursive searches. */ /* This rule is no longer 'in use' for recursive searches. */
rule->in_use = 0; rule->in_use = 0;
@ -870,24 +994,24 @@ pattern_search (struct file *file, int archive,
struct file *imf = pat->file; struct file *imf = pat->file;
struct file *f = lookup_file (imf->name); struct file *f = lookup_file (imf->name);
/* We don't want to delete an intermediate file that happened if (!f)
to be a prerequisite of some (other) target. Mark it as
secondary. We don't want it to be precious as that disables
DELETE_ON_ERROR etc. */
if (f != 0)
f->secondary = 1;
else
f = enter_file (imf->name); f = enter_file (imf->name);
f->deps = imf->deps; f->deps = imf->deps;
f->cmds = imf->cmds; f->cmds = imf->cmds;
f->stem = imf->stem; f->stem = imf->stem;
f->variables = imf->variables; /* Setting target specific variables for a file causes the file to be
entered to the database as a prerequisite. Implicit search then
treats this file as explicitly mentioned. Preserve target specific
variables of this file. */
merge_variable_set_lists(&f->variables, imf->variables);
f->pat_variables = imf->pat_variables; f->pat_variables = imf->pat_variables;
f->pat_searched = imf->pat_searched; f->pat_searched = imf->pat_searched;
f->also_make = imf->also_make; f->also_make = imf->also_make;
f->is_target = 1; f->is_target = 1;
f->intermediate = 1; f->is_explicit |= imf->is_explicit || pat->is_explicit;
f->notintermediate |= imf->notintermediate || no_intermediates;
f->intermediate |= !f->is_explicit && !f->notintermediate;
f->tried_implicit = 1; f->tried_implicit = 1;
imf = lookup_file (pat->pattern); imf = lookup_file (pat->pattern);
@ -904,7 +1028,9 @@ pattern_search (struct file *file, int archive,
dep = alloc_dep (); dep = alloc_dep ();
dep->ignore_mtime = pat->ignore_mtime; dep->ignore_mtime = pat->ignore_mtime;
dep->is_explicit = pat->is_explicit;
dep->ignore_automatic_vars = pat->ignore_automatic_vars; dep->ignore_automatic_vars = pat->ignore_automatic_vars;
dep->wait_here = pat->wait_here;
s = strcache_add (pat->name); s = strcache_add (pat->name);
if (recursions) if (recursions)
dep->name = s; dep->name = s;
@ -930,8 +1056,14 @@ pattern_search (struct file *file, int archive,
dep->next = file->deps; dep->next = file->deps;
file->deps = dep; file->deps = dep;
/* The file changed its dependencies; schedule the shuffle. */
file->was_shuffled = 0;
} }
if (!file->was_shuffled)
shuffle_deps_recursive (file->deps);
if (!tryrules[foundrule].checked_lastslash) if (!tryrules[foundrule].checked_lastslash)
{ {
/* Always allocate new storage, since STEM might be on the stack for an /* Always allocate new storage, since STEM might be on the stack for an
@ -953,11 +1085,16 @@ pattern_search (struct file *file, int archive,
file->cmds = rule->cmds; file->cmds = rule->cmds;
file->is_target = 1; file->is_target = 1;
/* Set precious flag. */ /* Set precious and notintermediate flags. */
{ {
struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]); struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]);
if (f && f->precious) if (f)
{
if (f->precious)
file->precious = 1; file->precious = 1;
if (f->notintermediate || no_intermediates)
file->notintermediate = 1;
}
} }
/* If this rule builds other targets, too, put the others into FILE's /* If this rule builds other targets, too, put the others into FILE's
@ -973,11 +1110,9 @@ pattern_search (struct file *file, int archive,
struct dep *new = alloc_dep (); struct dep *new = alloc_dep ();
/* GKM FIMXE: handle '|' here too */ /* GKM FIMXE: handle '|' here too */
memcpy (p, rule->targets[ri], p = mempcpy (p, rule->targets[ri],
rule->suffixes[ri] - rule->targets[ri] - 1); rule->suffixes[ri] - rule->targets[ri] - 1);
p += rule->suffixes[ri] - rule->targets[ri] - 1; p = mempcpy (p, file->stem, fullstemlen);
memcpy (p, file->stem, fullstemlen);
p += fullstemlen;
memcpy (p, rule->suffixes[ri], memcpy (p, rule->suffixes[ri],
rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1);
new->name = strcache_add (nm); new->name = strcache_add (nm);
@ -986,8 +1121,13 @@ pattern_search (struct file *file, int archive,
/* Set precious flag. */ /* Set precious flag. */
f = lookup_file (rule->targets[ri]); f = lookup_file (rule->targets[ri]);
if (f && f->precious) if (f)
{
if (f->precious)
new->file->precious = 1; new->file->precious = 1;
if (f->notintermediate || no_intermediates)
new->file->notintermediate = 1;
}
/* Set the is_target flag so that this file is not treated as /* Set the is_target flag so that this file is not treated as
intermediate by the pattern rule search algorithm and intermediate by the pattern rule search algorithm and
@ -1001,5 +1141,23 @@ pattern_search (struct file *file, int archive,
free (tryrules); free (tryrules);
free (deplist); free (deplist);
return rule != 0; --depth;
if (rule)
{
DBS (DB_IMPLICIT, (_("Found implicit rule '%s' for '%s'.\n"),
get_rule_defn (rule), filename));
return 1;
}
if (found_compat_rule)
{
DBS (DB_IMPLICIT, (_("Searching for a compatibility rule for '%s'.\n"),
filename));
assert (allow_compat_rules == 0);
return pattern_search (file, archive, depth, recursions, 1);
}
DBS (DB_IMPLICIT, (_("No implicit rule found for '%s'.\n"), filename));
return 0;
} }

View file

@ -1,583 +0,0 @@
/* intprops.h -- properties of integer types
Copyright (C) 2001-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Paul Eggert. */
#ifndef _GL_INTPROPS_H
#define _GL_INTPROPS_H
/* Return a value with the common real type of E and V and the value of V.
Do not evaluate E. */
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
<https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
/* The extra casts in the following macros work around compiler bugs,
e.g., in Cray C 5.0.3.0. */
/* True if the arithmetic type T is an integer type. bool counts as
an integer. */
#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
/* True if the real type T is signed. */
#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
/* Return 1 if the real expression E, after promotion, has a
signed or floating type. Do not evaluate E. */
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
/* Minimum and maximum values for integer types and expressions. */
/* The width in bits of the integer type or expression T.
Do not evaluate T.
Padding bits are not supported; this is checked at compile-time below. */
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
/* The maximum and minimum values for the integer type T. */
#define TYPE_MINIMUM(t) ((t) ~ TYPE_MAXIMUM (t))
#define TYPE_MAXIMUM(t) \
((t) (! TYPE_SIGNED (t) \
? (t) -1 \
: ((((t) 1 << (TYPE_WIDTH (t) - 2)) - 1) * 2 + 1)))
/* The maximum and minimum values for the type of the expression E,
after integer promotion. E is not evaluated. */
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH ((e) + 0) - 2)) - 1) * 2 + 1)
/* Work around OpenVMS incompatibility with C99. */
#if !defined LLONG_MAX && defined __INT64_MAX
# define LLONG_MAX __INT64_MAX
# define LLONG_MIN __INT64_MIN
#endif
/* This include file assumes that signed types are two's complement without
padding bits; the above macros have undefined behavior otherwise.
If this is a problem for you, please let us know how to fix it for your host.
This assumption is tested by the intprops-tests module. */
/* Does the __typeof__ keyword work? This could be done by
'configure', but for now it's easier to do it by hand. */
#if (2 <= __GNUC__ \
|| (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
|| (0x5110 <= __SUNPRO_C && !__STDC__))
# define _GL_HAVE___TYPEOF__ 1
#else
# define _GL_HAVE___TYPEOF__ 0
#endif
/* Return 1 if the integer type or expression T might be signed. Return 0
if it is definitely unsigned. This macro does not evaluate its argument,
and expands to an integer constant expression. */
#if _GL_HAVE___TYPEOF__
# define _GL_SIGNED_TYPE_OR_EXPR(t) TYPE_SIGNED (__typeof__ (t))
#else
# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
#endif
/* Bound on length of the string representing an unsigned integer
value representable in B bits. log10 (2.0) < 146/485. The
smallest value of B where this bound is not tight is 2621. */
#define INT_BITS_STRLEN_BOUND(b) (((b) * 146 + 484) / 485)
/* Bound on length of the string representing an integer type or expression T.
Subtract 1 for the sign bit if T is signed, and then add 1 more for
a minus sign if needed.
Because _GL_SIGNED_TYPE_OR_EXPR sometimes returns 1 when its argument is
unsigned, this macro may overestimate the true bound by one byte when
applied to unsigned types of size 2, 4, 16, ... bytes. */
#define INT_STRLEN_BOUND(t) \
(INT_BITS_STRLEN_BOUND (TYPE_WIDTH (t) - _GL_SIGNED_TYPE_OR_EXPR (t)) \
+ _GL_SIGNED_TYPE_OR_EXPR (t))
/* Bound on buffer size needed to represent an integer type or expression T,
including the terminating null. */
#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
/* Range overflow checks.
The INT_<op>_RANGE_OVERFLOW macros return 1 if the corresponding C
operators might not yield numerically correct answers due to
arithmetic overflow. They do not rely on undefined or
implementation-defined behavior. Their implementations are simple
and straightforward, but they are a bit harder to use than the
INT_<op>_OVERFLOW macros described below.
Example usage:
long int i = ...;
long int j = ...;
if (INT_MULTIPLY_RANGE_OVERFLOW (i, j, LONG_MIN, LONG_MAX))
printf ("multiply would overflow");
else
printf ("product is %ld", i * j);
Restrictions on *_RANGE_OVERFLOW macros:
These macros do not check for all possible numerical problems or
undefined or unspecified behavior: they do not check for division
by zero, for bad shift counts, or for shifting negative numbers.
These macros may evaluate their arguments zero or multiple times,
so the arguments should not have side effects. The arithmetic
arguments (including the MIN and MAX arguments) must be of the same
integer type after the usual arithmetic conversions, and the type
must have minimum value MIN and maximum MAX. Unsigned types should
use a zero MIN of the proper type.
These macros are tuned for constant MIN and MAX. For commutative
operations such as A + B, they are also tuned for constant B. */
/* Return 1 if A + B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. */
#define INT_ADD_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? (a) < (min) - (b) \
: (max) - (b) < (a))
/* Return 1 if A - B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. */
#define INT_SUBTRACT_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? (max) + (b) < (a) \
: (a) < (min) + (b))
/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
See above for restrictions. */
#define INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
((min) < 0 \
? (a) < - (max) \
: 0 < (a))
/* Return 1 if A * B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. Avoid && and || as they tickle
bugs in Sun C 5.11 2010/08/13 and other compilers; see
<https://lists.gnu.org/r/bug-gnulib/2011-05/msg00401.html>. */
#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? ((a) < 0 \
? (a) < (max) / (b) \
: (b) == -1 \
? 0 \
: (min) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a)))
/* Return 1 if A / B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. Do not check for division by zero. */
#define INT_DIVIDE_RANGE_OVERFLOW(a, b, min, max) \
((min) < 0 && (b) == -1 && (a) < - (max))
/* Return 1 if A % B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. Do not check for division by zero.
Mathematically, % should never overflow, but on x86-like hosts
INT_MIN % -1 traps, and the C standard permits this, so treat this
as an overflow too. */
#define INT_REMAINDER_RANGE_OVERFLOW(a, b, min, max) \
INT_DIVIDE_RANGE_OVERFLOW (a, b, min, max)
/* Return 1 if A << B would overflow in [MIN,MAX] arithmetic.
See above for restrictions. Here, MIN and MAX are for A only, and B need
not be of the same type as the other arguments. The C standard says that
behavior is undefined for shifts unless 0 <= B < wordwidth, and that when
A is negative then A << B has undefined behavior and A >> B has
implementation-defined behavior, but do not check these other
restrictions. */
#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
(A, B, P) work when P is non-null. */
#if 5 <= __GNUC__ && !defined __ICC
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
#elif defined __has_builtin
# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
#else
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
#endif
/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */
#ifdef __clang__
/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>. */
# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
#else
# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
#endif
/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
__builtin_mul_overflow_p and __builtin_mul_overflow_p. */
#define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
/* The _GL*_OVERFLOW macros have the same restrictions as the
*_RANGE_OVERFLOW macros, except that they do not assume that operands
(e.g., A and B) have the same type as MIN and MAX. Instead, they assume
that the result (e.g., A + B) has that type. */
#if _GL_HAS_BUILTIN_OVERFLOW_P
# define _GL_ADD_OVERFLOW(a, b, min, max) \
__builtin_add_overflow_p (a, b, (__typeof__ ((a) + (b))) 0)
# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
__builtin_sub_overflow_p (a, b, (__typeof__ ((a) - (b))) 0)
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
__builtin_mul_overflow_p (a, b, (__typeof__ ((a) * (b))) 0)
#else
# define _GL_ADD_OVERFLOW(a, b, min, max) \
((min) < 0 ? INT_ADD_RANGE_OVERFLOW (a, b, min, max) \
: (a) < 0 ? (b) <= (a) + (b) \
: (b) < 0 ? (a) <= (a) + (b) \
: (a) + (b) < (b))
# define _GL_SUBTRACT_OVERFLOW(a, b, min, max) \
((min) < 0 ? INT_SUBTRACT_RANGE_OVERFLOW (a, b, min, max) \
: (a) < 0 ? 1 \
: (b) < 0 ? (a) - (b) <= (a) \
: (a) < (b))
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
(((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
|| INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
#endif
#define _GL_DIVIDE_OVERFLOW(a, b, min, max) \
((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
: (a) < 0 ? (b) <= (a) + (b) - 1 \
: (b) < 0 && (a) + (b) <= (a))
#define _GL_REMAINDER_OVERFLOW(a, b, min, max) \
((min) < 0 ? (b) == _GL_INT_NEGATE_CONVERT (min, 1) && (a) < - (max) \
: (a) < 0 ? (a) % (b) != ((max) - (b) + 1) % (b) \
: (b) < 0 && ! _GL_UNSIGNED_NEG_MULTIPLE (a, b, max))
/* Return a nonzero value if A is a mathematical multiple of B, where
A is unsigned, B is negative, and MAX is the maximum value of A's
type. A's type must be the same as (A % B)'s type. Normally (A %
-B == 0) suffices, but things get tricky if -B would overflow. */
#define _GL_UNSIGNED_NEG_MULTIPLE(a, b, max) \
(((b) < -_GL_SIGNED_INT_MAXIMUM (b) \
? (_GL_SIGNED_INT_MAXIMUM (b) == (max) \
? (a) \
: (a) % (_GL_INT_CONVERT (a, _GL_SIGNED_INT_MAXIMUM (b)) + 1)) \
: (a) % - (b)) \
== 0)
/* Check for integer overflow, and report low order bits of answer.
The INT_<op>_OVERFLOW macros return 1 if the corresponding C operators
might not yield numerically correct answers due to arithmetic overflow.
The INT_<op>_WRAPV macros compute the low-order bits of the sum,
difference, and product of two C integers, and return 1 if these
low-order bits are not numerically correct.
These macros work correctly on all known practical hosts, and do not rely
on undefined behavior due to signed arithmetic overflow.
Example usage, assuming A and B are long int:
if (INT_MULTIPLY_OVERFLOW (a, b))
printf ("result would overflow\n");
else
printf ("result is %ld (no overflow)\n", a * b);
Example usage with WRAPV flavor:
long int result;
bool overflow = INT_MULTIPLY_WRAPV (a, b, &result);
printf ("result is %ld (%s)\n", result,
overflow ? "after overflow" : "no overflow");
Restrictions on these macros:
These macros do not check for all possible numerical problems or
undefined or unspecified behavior: they do not check for division
by zero, for bad shift counts, or for shifting negative numbers.
These macros may evaluate their arguments zero or multiple times, so the
arguments should not have side effects.
The WRAPV macros are not constant expressions. They support only
+, binary -, and *. Because the WRAPV macros convert the result,
they report overflow in different circumstances than the OVERFLOW
macros do.
These macros are tuned for their last input argument being a constant.
Return 1 if the integer expressions A * B, A - B, -A, A * B, A / B,
A % B, and A << B would overflow, respectively. */
#define INT_ADD_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_ADD_OVERFLOW)
#define INT_SUBTRACT_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_SUBTRACT_OVERFLOW)
#if _GL_HAS_BUILTIN_OVERFLOW_P
# define INT_NEGATE_OVERFLOW(a) INT_SUBTRACT_OVERFLOW (0, a)
#else
# define INT_NEGATE_OVERFLOW(a) \
INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
#endif
#define INT_MULTIPLY_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
#define INT_DIVIDE_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_DIVIDE_OVERFLOW)
#define INT_REMAINDER_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_REMAINDER_OVERFLOW)
#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
_GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
/* Return 1 if the expression A <op> B would overflow,
where OP_RESULT_OVERFLOW (A, B, MIN, MAX) does the actual test,
assuming MIN and MAX are the minimum and maximum for the result type.
Arguments should be free of side effects. */
#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
op_result_overflow (a, b, \
_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
_GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
Return 1 if the result overflows. See above for restrictions. */
#if _GL_HAS_BUILTIN_ADD_OVERFLOW
# define INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
# define INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
#else
# define INT_ADD_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
# define INT_SUBTRACT_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
#endif
#if _GL_HAS_BUILTIN_MUL_OVERFLOW
# if (9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
|| (__GNUC__ == 8 && 4 <= __GNUC_MINOR__))
# define INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
# else
/* Work around GCC bug 91450. */
# define INT_MULTIPLY_WRAPV(a, b, r) \
((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && EXPR_SIGNED (a) && EXPR_SIGNED (b) \
&& _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
? ((void) __builtin_mul_overflow (a, b, r), 1) \
: __builtin_mul_overflow (a, b, r))
# endif
#else
# define INT_MULTIPLY_WRAPV(a, b, r) \
_GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
#endif
/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
https://llvm.org/bugs/show_bug.cgi?id=25390
For now, assume all versions of GCC-like compilers generate bogus
warnings for _Generic. This matters only for compilers that
lack relevant builtins. */
#if __GNUC__
# define _GL__GENERIC_BOGUS 1
#else
# define _GL__GENERIC_BOGUS 0
#endif
/* Store the low-order bits of A <op> B into *R, where OP specifies
the operation and OVERFLOW the overflow predicate. Return 1 if the
result overflows. See above for restrictions. */
#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
(_Generic \
(*(r), \
signed char: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
signed char, SCHAR_MIN, SCHAR_MAX), \
unsigned char: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned char, 0, UCHAR_MAX), \
short int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
short int, SHRT_MIN, SHRT_MAX), \
unsigned short int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned short int, 0, USHRT_MAX), \
int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
int, INT_MIN, INT_MAX), \
unsigned int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned int, 0, UINT_MAX), \
long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX), \
unsigned long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX), \
long long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
long long int, LLONG_MIN, LLONG_MAX), \
unsigned long long int: \
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
unsigned long long int, 0, ULLONG_MAX)))
#else
/* Store the low-order bits of A <op> B into *R, where OP specifies
the operation and OVERFLOW the overflow predicate. If *R is
signed, its type is ST with bounds SMIN..SMAX; otherwise its type
is UT with bounds U..UMAX. ST and UT are narrower than int.
Return 1 if the result overflows. See above for restrictions. */
# if _GL_HAVE___TYPEOF__
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
(TYPE_SIGNED (__typeof__ (*(r))) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax))
# else
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
(overflow (a, b, smin, smax) \
? (overflow (a, b, 0, umax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \
: (overflow (a, b, 0, umax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
# endif
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
(sizeof *(r) == sizeof (signed char) \
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
signed char, SCHAR_MIN, SCHAR_MAX, \
unsigned char, UCHAR_MAX) \
: sizeof *(r) == sizeof (short int) \
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
short int, SHRT_MIN, SHRT_MAX, \
unsigned short int, USHRT_MAX) \
: sizeof *(r) == sizeof (int) \
? (EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
int, INT_MIN, INT_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
unsigned int, 0, UINT_MAX)) \
: _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
# ifdef LLONG_MAX
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
(sizeof *(r) == sizeof (long int) \
? (EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX)) \
: (EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
long long int, LLONG_MIN, LLONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
unsigned long long int, 0, ULLONG_MAX)))
# else
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
(EXPR_SIGNED (*(r)) \
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
long int, LONG_MIN, LONG_MAX) \
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
unsigned long int, 0, ULONG_MAX))
# endif
#endif
/* Store the low-order bits of A <op> B into *R, where the operation
is given by OP. Use the unsigned type UT for calculation to avoid
overflow problems. *R's type is T, with extrema TMIN and TMAX.
T must be a signed integer type. Return 1 if the result overflows. */
#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
(overflow (a, b, tmin, tmax) \
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
/* Return the low-order bits of A <op> B, where the operation is given
by OP. Use the unsigned type UT for calculation to avoid undefined
behavior on signed integer overflow, and convert the result to type T.
UT is at least as wide as T and is no narrower than unsigned int,
T is two's complement, and there is no padding or trap representations.
Assume that converting UT to T yields the low-order bits, as is
done in all known two's-complement C compilers. E.g., see:
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
According to the C standard, converting UT to T yields an
implementation-defined result or signal for values outside T's
range. However, code that works around this theoretical problem
runs afoul of a compiler bug in Oracle Studio 12.3 x86. See:
https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
As the compiler bug is real, don't try to work around the
theoretical problem. */
#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
((t) ((ut) (a) op (ut) (b)))
/* Return true if the numeric values A + B, A - B, A * B fall outside
the range TMIN..TMAX. Arguments should be integer expressions
without side effects. TMIN should be signed and nonpositive.
TMAX should be positive, and should be signed unless TMIN is zero. */
#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
((b) < 0 \
? (((tmin) \
? ((EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \
&& (a) < (tmin) - (b)) \
: (a) <= -1 - (b)) \
|| ((EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \
: (a) < 0 \
? (((tmin) \
? ((EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \
&& (b) < (tmin) - (a)) \
: (b) <= -1 - (a)) \
|| ((EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
&& (tmax) < (a) + (b))) \
: (tmax) < (b) || (tmax) - (b) < (a))
#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
(((a) < 0) == ((b) < 0) \
? ((a) < (b) \
? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
: (tmax) < (a) - (b)) \
: (a) < 0 \
? ((!EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \
|| (a) - (tmin) < (b)) \
: ((! (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
&& EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
&& (tmax) <= -1 - (b)) \
|| (tmax) + (b) < (a)))
#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
((b) < 0 \
? ((a) < 0 \
? (EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
? (a) < (tmax) / (b) \
: ((INT_NEGATE_OVERFLOW (b) \
? _GL_INT_CONVERT (b, tmax) >> (TYPE_WIDTH (b) - 1) \
: (tmax) / -(b)) \
<= -1 - (a))) \
: INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
? (EXPR_SIGNED (a) \
? 0 < (a) + (tmin) \
: 0 < (a) && -1 - (tmin) < (a) - 1) \
: (tmin) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
? (EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
: (tmin) / (a) < (b)) \
: (tmax) / (b) < (a)))
#endif /* _GL_INTPROPS_H */

2685
third_party/make/job.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Definitions for managing subprocesses in GNU Make. /* Definitions for managing subprocesses in GNU Make.
Copyright (C) 1992-2020 Free Software Foundation, Inc. Copyright (C) 1992-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,16 +12,24 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/output.h" #include "output.h"
/* Structure describing a running or dead child process. */ /* Structure describing a running or dead child process. */
#ifdef VMS
#define VMSCHILD \
char *comname; /* Temporary command file name */ \
int efn; /* Completion event flag number */ \
int cstatus; /* Completion status */ \
int vms_launch_status; /* non-zero if lib$spawn, etc failed */
#else
#define VMSCHILD #define VMSCHILD
#endif
#define CHILDBASE \ #define CHILDBASE \
char *cmd_name; /* Alloced copy of command run. */ \ char *cmd_name; /* Allocated copy of command run. */ \
char **environment; /* Environment for commands. */ \ char **environment; /* Environment for commands. */ \
VMSCHILD \ VMSCHILD \
struct output output /* Output for this child. */ struct output output /* Output for this child. */
@ -40,7 +48,6 @@ struct child
struct file *file; /* File being remade. */ struct file *file; /* File being remade. */
char *tmpdir; /* Temporary directory */
char *sh_batch_file; /* Script file for shell commands */ char *sh_batch_file; /* Script file for shell commands */
char **command_lines; /* Array of variable-expanded cmd lines. */ char **command_lines; /* Array of variable-expanded cmd lines. */
char *command_ptr; /* Ptr into command_lines[command_line]. */ char *command_ptr; /* Ptr into command_lines[command_line]. */
@ -61,28 +68,25 @@ struct child
extern struct child *children; extern struct child *children;
/* A signal handler for SIGCHLD, if needed. */ /* A signal handler for SIGCHLD, if needed. */
RETSIGTYPE child_handler (int sig); void child_handler (int sig);
int is_bourne_compatible_shell(const char *path); int is_bourne_compatible_shell(const char *path);
void new_job (struct file *file); void new_job (struct file *file);
void reap_children (int block, int err); void reap_children (int block, int err);
void start_waiting_jobs (void); void start_waiting_jobs (void);
void free_childbase (struct childbase* child);
char **construct_command_argv (char *line, char **restp, struct file *file, char **construct_command_argv (char *line, char **restp, struct file *file,
int cmd_flags, char** batch_file); int cmd_flags, char** batch_file);
pid_t child_execute_job (struct childbase *, int, char **, bool); pid_t child_execute_job (struct childbase *child, int good_stdin, char **argv);
#ifdef _AMIGA #ifdef _AMIGA
void exec_command (char **argv) NORETURN; void exec_command (char **argv) NORETURN;
#elif defined(__EMX__)
int exec_command (char **argv, char **envp);
#else #else
void exec_command (char **argv, char **envp) NORETURN; pid_t exec_command (char **argv, char **envp);
#endif #endif
void unblock_all_sigs (void); void unblock_all_sigs (void);
extern unsigned int job_slots_used; extern unsigned int job_slots_used;
extern unsigned int jobserver_tokens; extern unsigned int jobserver_tokens;
void delete_tmpdir (struct child *);

View file

@ -1,5 +1,5 @@
/* Loading dynamic objects for GNU Make. /* Loading dynamic objects for GNU Make.
Copyright (C) 2012-2020 Free Software Foundation, Inc. Copyright (C) 2012-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,22 +12,251 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#if MAKE_LOAD
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
#define SYMBOL_EXTENSION "_gmk_setup"
#include "debug.h"
#include "filedef.h"
#include "variable.h"
/* Tru64 V4.0 does not have this flag */
#ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
#endif
struct load_list
{
struct load_list *next;
const char *name;
void *dlp;
};
static struct load_list *loaded_syms = NULL;
static load_func_t
load_object (const floc *flocp, int noerror, const char *ldname,
const char *symname)
{
static void *global_dl = NULL;
load_func_t symp;
if (! global_dl)
{
global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL);
if (! global_dl)
{
const char *err = dlerror ();
OS (fatal, flocp, _("Failed to open global symbol table: %s"), err);
}
}
symp = (load_func_t) dlsym (global_dl, symname);
if (! symp)
{
struct load_list *new;
void *dlp = NULL;
/* If the path has no "/", try the current directory first. */
if (! strchr (ldname, '/')
#ifdef HAVE_DOS_PATHS
&& ! strchr (ldname, '\\')
#endif
)
dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
/* If we haven't opened it yet, try the default search path. */
if (! dlp)
dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
/* Still no? Then fail. */
if (! dlp)
{
const char *err = dlerror ();
if (noerror)
DB (DB_BASIC, ("%s\n", err));
else
OS (error, flocp, "%s", err);
return NULL;
}
DB (DB_VERBOSE, (_("Loaded shared object %s\n"), ldname));
/* Assert that the GPL license symbol is defined. */
symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
if (! symp)
OS (fatal, flocp,
_("Loaded object %s is not declared to be GPL compatible"),
ldname);
symp = (load_func_t) dlsym (dlp, symname);
if (! symp)
{
const char *err = dlerror ();
OSSS (fatal, flocp, _("Failed to load symbol %s from %s: %s"),
symname, ldname, err);
}
/* Add this symbol to a trivial lookup table. This is not efficient but
it's highly unlikely we'll be loading lots of objects, and we only
need it to look them up on unload, if we rebuild them. */
new = xmalloc (sizeof (struct load_list));
new->name = xstrdup (ldname);
new->dlp = dlp;
new->next = loaded_syms;
loaded_syms = new;
}
return symp;
}
int int
load_file (const floc *flocp, const char **ldname UNUSED, int noerror) load_file (const floc *flocp, struct file *file, int noerror)
{
const char *ldname = file->name;
size_t nmlen = strlen (ldname);
char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1);
char *symname = NULL;
const char *fp;
int r;
load_func_t symp;
/* Break the input into an object file name and a symbol name. If no symbol
name was provided, compute one from the object file name. */
fp = strchr (ldname, '(');
if (fp)
{
const char *ep;
/* There's an open paren, so see if there's a close paren: if so use
that as the symbol name. We can't have whitespace: it would have
been chopped up before this function is called. */
ep = strchr (fp+1, ')');
if (ep && ep[1] == '\0')
{
size_t l = fp - ldname;
++fp;
if (fp == ep)
OS (fatal, flocp, _("Empty symbol name for load: %s"), ldname);
/* Make a copy of the ldname part. */
memcpy (new, ldname, l);
new[l] = '\0';
ldname = new;
nmlen = l;
/* Make a copy of the symbol name part. */
symname = new + l + 1;
memcpy (symname, fp, ep - fp);
symname[ep - fp] = '\0';
}
}
/* Make sure this name is in the string cache. */
ldname = file->name = strcache_add (ldname);
/* If this object has been loaded, we're done: return -1 to ensure make does
not rebuild again. If a rebuild is allowed it was set up when this
object was initially loaded. */
file = lookup_file (ldname);
if (file && file->loaded)
return -1;
/* If we didn't find a symbol name yet, construct it from the ldname. */
if (! symname)
{
char *p = new;
fp = strrchr (ldname, '/');
#ifdef HAVE_DOS_PATHS
if (fp)
{
const char *fp2 = strchr (fp, '\\');
if (fp2 > fp)
fp = fp2;
}
else
fp = strrchr (ldname, '\\');
/* The (improbable) case of d:foo. */
if (fp && *fp && fp[1] == ':')
fp++;
#endif
if (!fp)
fp = ldname;
else
++fp;
while (isalnum ((unsigned char) *fp) || *fp == '_')
*(p++) = *(fp++);
strcpy (p, SYMBOL_EXTENSION);
symname = new;
}
DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, ldname));
/* Load it! */
symp = load_object (flocp, noerror, ldname, symname);
if (! symp)
return 0;
/* Invoke the symbol. */
r = (*symp) (flocp);
/* If the load didn't fail, add the file to the .LOADED variable. */
if (r)
do_variable_definition(flocp, ".LOADED", ldname, o_file, f_append_value, 0);
return r;
}
int
unload_file (const char *name)
{
int rc = 0;
struct load_list *d;
for (d = loaded_syms; d != NULL; d = d->next)
if (streq (d->name, name) && d->dlp)
{
DB (DB_VERBOSE, (_("Unloading shared object %s\n"), name));
rc = dlclose (d->dlp);
if (rc)
perror_with_name ("dlclose: ", d->name);
else
d->dlp = NULL;
break;
}
return rc;
}
#else
int
load_file (const floc *flocp, struct file *file UNUSED, int noerror)
{ {
if (! noerror) if (! noerror)
O (fatal, flocp, O (fatal, flocp,
_("The 'load' operation is not supported on this platform.")); _("The 'load' operation is not supported on this platform"));
return 0; return 0;
} }
void int
unload_file (const char *name UNUSED) unload_file (const char *name UNUSED)
{ {
O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported!"); O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported");
} }
#endif /* MAKE_LOAD */

View file

@ -1,5 +1,5 @@
/* API for GNU Make dynamic objects. /* API for GNU Make dynamic objects.
Copyright (C) 2013-2020 Free Software Foundation, Inc. Copyright (C) 2013-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,13 +12,13 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h" #include "filedef.h"
#include "third_party/make/variable.h" #include "variable.h"
#include "third_party/make/dep.h" #include "dep.h"
/* Allocate a buffer in our context, so we can free it. */ /* Allocate a buffer in our context, so we can free it. */
char * char *

1761
third_party/make/main.c vendored

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Miscellaneous global declarations and portability cruft for GNU Make. /* Miscellaneous global declarations and portability cruft for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,59 +12,27 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/makedev.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/stat.macros.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h"
#include "libc/mem/alloca.h"
#include "libc/mem/mem.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/stdio.h"
#include "libc/str/locale.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/consts/rlim.h"
#include "libc/sysv/consts/rlimit.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/w.h"
#include "libc/temp.h"
#include "libc/time/struct/tm.h"
#include "libc/time/time.h"
#include "third_party/gdtoa/gdtoa.h"
#include "third_party/musl/glob.h"
/* We use <config.h> instead of "config.h" so that a compilation /* We use <config.h> instead of "config.h" so that a compilation
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
(which it would do because makeint.h was found in $srcdir). */ (which it would do because makeint.h was found in $srcdir). */
#include "third_party/make/config.h" #include "config.h"
#pragma GCC diagnostic ignored "-Wredundant-decls"
#undef HAVE_CONFIG_H
#define HAVE_CONFIG_H 1
/* Specify we want GNU source code. This must be defined before any /* Some versions of GCC (e.g., 10.x) set the warn_unused_result attribute on
system headers are included. */ __builtin_alloca. This causes alloca(0) to fail and is not easily worked
around so avoid it via the preprocessor.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98055 */
#define POSIX 1 #if defined (__has_builtin)
#define _GNU_SOURCE 1 # if __has_builtin (__builtin_alloca)
# define free_alloca()
# else
# define free_alloca() alloca (0)
# endif
#else
# define free_alloca() alloca (0)
#endif
/* Disable assert() unless we're a maintainer. /* Disable assert() unless we're a maintainer.
Some asserts are compute-intensive. */ Some asserts are compute-intensive. */
@ -79,23 +47,106 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#ifdef WINDOWS32 #ifdef WINDOWS32
# define GMK_BUILDING_MAKE # define GMK_BUILDING_MAKE
#endif #endif
#include "third_party/make/gnumake.h" #include "gnumake.h"
#ifdef CRAY
/* This must happen before #include <signal.h> so
that the declaration therein is changed. */
# define signal bsdsignal
#endif
/* If we're compiling for the dmalloc debugger, turn off string inlining. */ /* If we're compiling for the dmalloc debugger, turn off string inlining. */
#if defined(HAVE_DMALLOC_H) && defined(__GNUC__) #if defined(HAVE_DMALLOC_H) && defined(__GNUC__)
# define __NO_STRING_INLINES # define __NO_STRING_INLINES
#endif #endif
#ifndef RETSIGTYPE #include <sys/types.h>
# define RETSIGTYPE void #include <sys/stat.h>
#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. */
# include <sys/timeb.h>
#endif
#if HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <time.h>
#include <errno.h>
#ifndef errno
extern int errno;
#endif
/* Define macros specifying which OS we are building for. */
#if __gnu_hurd__
# define MK_OS_HURD 1
#endif
#if __CYGWIN__
# define MK_OS_CYGWIN 1
#endif
#if defined(__MVS__)
# define MK_OS_ZOS 1
#endif
#ifdef __VMS
/* In strict ANSI mode, VMS compilers should not be defining the
VMS macro. Define it here instead of a bulk edit for the correct code.
*/
# ifndef VMS
# define VMS
# endif
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
/* Ultrix's unistd.h always defines _POSIX_VERSION, but you only get
POSIX.1 behavior with 'cc -YPOSIX', which predefines POSIX itself! */
# if defined (_POSIX_VERSION) && !defined (ultrix) && !defined (VMS)
# define POSIX 1
# endif
#endif
/* Some systems define _POSIX_VERSION but are not really POSIX.1. */
#if (defined (butterfly) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386)))
# undef POSIX
#endif
#if !defined (POSIX) && defined (_AIX) && defined (_POSIX_SOURCE)
# define POSIX 1
#endif #endif
#ifndef sigmask #ifndef sigmask
# define sigmask(sig) (1 << ((sig) - 1)) # define sigmask(sig) (1 << ((sig) - 1))
#endif #endif
#ifndef MAXPATHLEN #ifndef HAVE_SA_RESTART
# define MAXPATHLEN 1024 # define SA_RESTART 0
#endif
#ifdef HAVE_VFORK_H
# include <vfork.h>
#endif
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifndef PATH_MAX
# ifdef MAXPATHLEN
# define PATH_MAX MAXPATHLEN
# else
/* Some systems (HURD) have fully dynamic pathnames with no maximum.
Ideally we'd support this but it will take some work. */
# define PATH_MAX 4096
# endif
#endif #endif
#ifdef PATH_MAX #ifdef PATH_MAX
@ -139,6 +190,30 @@ unsigned int get_path_max (void);
# endif # endif
#endif /* STAT_MACROS_BROKEN. */ #endif /* STAT_MACROS_BROKEN. */
#ifndef S_ISREG
# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
#ifndef S_ISDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#ifdef VMS
# include <fcntl.h>
# include <types.h>
# include <unixlib.h>
# include <unixio.h>
# include <perror.h>
/* Needed to use alloca on VMS. */
# include <builtins.h>
extern int vms_use_mcr_command;
extern int vms_always_use_cmd_file;
extern int vms_gnv_shell;
extern int vms_comma_separator;
extern int vms_legacy_behavior;
extern int vms_unix_simulation;
#endif
#if !defined(__attribute__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__) #if !defined(__attribute__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__)
/* Don't use __attribute__ if it's not supported. */ /* Don't use __attribute__ if it's not supported. */
# define ATTRIBUTE(x) # define ATTRIBUTE(x)
@ -157,16 +232,26 @@ unsigned int get_path_max (void);
#define NORETURN ATTRIBUTE ((noreturn)) #define NORETURN ATTRIBUTE ((noreturn))
#if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) #if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)
# include <stdlib.h>
# include <string.h>
# define ANSI_STRING 1 # define ANSI_STRING 1
#else /* No standard headers. */ #else /* No standard headers. */
# ifdef HAVE_STRING_H # ifdef HAVE_STRING_H
# include <string.h>
# define ANSI_STRING 1 # define ANSI_STRING 1
# else
# endif # endif
# ifdef HAVE_MEMORY_H # ifdef HAVE_MEMORY_H
# include <memory.h>
# endif # endif
# ifdef HAVE_STDLIB_H # ifdef HAVE_STDLIB_H
# include <stdlib.h>
# else # else
void *malloc (int);
void *realloc (void *, int);
void free (void *);
void abort (void) NORETURN;
void exit (int) NORETURN;
# endif /* HAVE_STDLIB_H. */ # endif /* HAVE_STDLIB_H. */
#endif /* Standard headers. */ #endif /* Standard headers. */
@ -180,6 +265,7 @@ unsigned int get_path_max (void);
#endif #endif
#ifndef ANSI_STRING #ifndef ANSI_STRING
/* SCO Xenix has a buggy macro definition in <string.h>. */ /* SCO Xenix has a buggy macro definition in <string.h>. */
#undef strerror #undef strerror
#if !defined(__DECC) #if !defined(__DECC)
@ -189,6 +275,31 @@ char *strerror (int errnum);
#endif /* !ANSI_STRING. */ #endif /* !ANSI_STRING. */
#undef ANSI_STRING #undef ANSI_STRING
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if HAVE_STRINGS_H
# include <strings.h> /* Needed for strcasecmp / strncasecmp. */
#endif
#if defined _MSC_VER || defined __MINGW32__
# define MK_PRI64_PREFIX "I64"
#else
# define MK_PRI64_PREFIX "ll"
#endif
#ifndef PRIdMAX
# define PRIdMAX MK_PRI64_PREFIX "d"
#endif
#ifndef PRIuMAX
# define PRIuMAX MK_PRI64_PREFIX "u"
#endif
#ifndef SCNdMAX
# define SCNdMAX PRIdMAX
#endif
#define FILE_TIMESTAMP uintmax_t #define FILE_TIMESTAMP uintmax_t
#if !defined(HAVE_STRSIGNAL) #if !defined(HAVE_STRSIGNAL)
@ -238,13 +349,26 @@ extern mode_t umask (mode_t);
/* Handle gettext and locales. */ /* Handle gettext and locales. */
#include "third_party/make/gettext.h" #if HAVE_LOCALE_H
# include <locale.h>
#else
# define setlocale(category, locale)
#endif
#include "gettext.h"
#define _(msgid) gettext (msgid) #define _(msgid) gettext (msgid)
#define N_(msgid) gettext_noop (msgid) #define N_(msgid) gettext_noop (msgid)
#define S_(msg1,msg2,num) ngettext (msg1,msg2,num) #define S_(msg1,msg2,num) ngettext (msg1,msg2,num)
/* This is needed for getcwd() and chdir(), on some W32 systems. */
#if defined(HAVE_DIRECT_H)
# include <direct.h>
#endif
#ifdef WINDOWS32 #ifdef WINDOWS32
# include <fcntl.h>
# include <malloc.h>
# define pipe(_p) _pipe((_p), 512, O_BINARY) # define pipe(_p) _pipe((_p), 512, O_BINARY)
# define kill(_pid,_sig) w32_kill((_pid),(_sig)) # define kill(_pid,_sig) w32_kill((_pid),(_sig))
/* MSVC and Watcom C don't have ftruncate. */ /* MSVC and Watcom C don't have ftruncate. */
@ -272,14 +396,19 @@ extern int unixy_shell;
# endif # endif
/* Include only the minimal stuff from windows.h. */ /* Include only the minimal stuff from windows.h. */
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
# endif
#endif /* WINDOWS32 */ #endif /* WINDOWS32 */
/* ALL_SET() evaluates the second argument twice. */
#define ANY_SET(_v,_m) (((_v)&(_m)) != 0) #define ANY_SET(_v,_m) (((_v)&(_m)) != 0)
#define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m))) #define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m)))
#define ALL_SET(_v,_m) (((_v)&(_m)) == (_m))
/* Bitmasks for the STOPCHAR array. */
#define MAP_NUL 0x0001 #define MAP_NUL 0x0001
#define MAP_BLANK 0x0002 #define MAP_BLANK 0x0002 /* space, TAB */
#define MAP_NEWLINE 0x0004 #define MAP_NEWLINE 0x0004
#define MAP_COMMENT 0x0008 #define MAP_COMMENT 0x0008
#define MAP_SEMI 0x0010 #define MAP_SEMI 0x0010
@ -297,7 +426,11 @@ extern int unixy_shell;
/* The set of characters which are directory separators is OS-specific. */ /* The set of characters which are directory separators is OS-specific. */
#define MAP_DIRSEP 0x8000 #define MAP_DIRSEP 0x8000
#ifdef VMS
# define MAP_VMSCOMMA MAP_COMMA
#else
# define MAP_VMSCOMMA 0x0000 # define MAP_VMSCOMMA 0x0000
#endif
#define MAP_SPACE (MAP_BLANK|MAP_NEWLINE) #define MAP_SPACE (MAP_BLANK|MAP_NEWLINE)
@ -323,27 +456,58 @@ extern int unixy_shell;
# define MAP_PATHSEP MAP_SEMI # define MAP_PATHSEP MAP_SEMI
#elif PATH_SEPARATOR_CHAR == ',' #elif PATH_SEPARATOR_CHAR == ','
# define MAP_PATHSEP MAP_COMMA # define MAP_PATHSEP MAP_COMMA
#else #else
# error "Unknown PATH_SEPARATOR_CHAR" # error "Unknown PATH_SEPARATOR_CHAR"
#endif #endif
#define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m)) #define STOP_SET(_v,_m) ANY_SET(stopchar_map[(unsigned char)(_v)],(_m))
/* True if C is whitespace but not newline. */
#define ISBLANK(c) STOP_SET((c),MAP_BLANK) #define ISBLANK(c) STOP_SET((c),MAP_BLANK)
/* True if C is whitespace including newlines. */
#define ISSPACE(c) STOP_SET((c),MAP_SPACE) #define ISSPACE(c) STOP_SET((c),MAP_SPACE)
/* True if C is nul or whitespace (including newline). */
#define END_OF_TOKEN(c) STOP_SET((c),MAP_SPACE|MAP_NUL)
/* Move S past all whitespace (including newlines). */
#define NEXT_TOKEN(s) while (ISSPACE (*(s))) ++(s) #define NEXT_TOKEN(s) while (ISSPACE (*(s))) ++(s)
#define END_OF_TOKEN(s) while (! STOP_SET (*(s), MAP_SPACE|MAP_NUL)) ++(s)
/* True if C is a directory separator on the current system. */
#define ISDIRSEP(c) STOP_SET((c),MAP_DIRSEP)
/* True if S starts with a drive specifier. */
#if defined(HAVE_DOS_PATHS)
# define HAS_DRIVESPEC(_s) ((((_s)[0] >= 'a' && (_s)[0] <= 'z') \
|| ((_s)[0] >= 'A' && (_s)[0] <= 'Z')) \
&& (_s)[1] == ':')
#else
# define HAS_DRIVESPEC(_s) 0
#endif
/* We can't run setrlimit when using posix_spawn. */ /* We can't run setrlimit when using posix_spawn. */
#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && !defined(USE_POSIX_SPAWN)
# define SET_STACK_SIZE
#endif
#ifdef SET_STACK_SIZE
# include <sys/resource.h>
extern struct rlimit stack_limit; extern struct rlimit stack_limit;
#endif
#include "glob.h"
#define NILF ((floc *)0) #define NILF ((floc *)0)
/* Number of characters in a string constant. Does NOT include the \0 byte. */
#define CSTRLEN(_s) (sizeof (_s)-1) #define CSTRLEN(_s) (sizeof (_s)-1)
/* Only usable when NOT calling a macro: only use it for local functions. */
#define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s) #define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s)
/* The number of bytes needed to represent the largest integer as a string. */ /* The number of bytes needed to represent the largest signed and unsigned
#define INTSTR_LENGTH CSTRLEN ("18446744073709551616") integers as a string.
Does NOT include space for \0 so be sure to add it if needed.
Math suggested by Edward Welbourne <edward.welbourne@qt.io> */
#define INTSTR_LENGTH (53 * sizeof(uintmax_t) / 22 + 3)
#define DEFAULT_TTYNAME "true" #define DEFAULT_TTYNAME "true"
#ifdef HAVE_TTYNAME #ifdef HAVE_TTYNAME
@ -352,8 +516,19 @@ extern struct rlimit stack_limit;
# define TTYNAME(_f) DEFAULT_TTYNAME # define TTYNAME(_f) DEFAULT_TTYNAME
#endif #endif
#ifdef VMS
# define DEFAULT_TMPDIR "/sys$scratch/"
#elif defined(P_tmpdir)
# define DEFAULT_TMPDIR P_tmpdir
#else
# define DEFAULT_TMPDIR "/tmp"
#endif
struct file;
/* Specify the location of elements read from makefiles. */ /* Specify the location of elements read from makefiles. */
typedef struct typedef struct
{ {
@ -369,7 +544,7 @@ void error (const floc *flocp, size_t length, const char *fmt, ...)
ATTRIBUTE ((__format__ (__printf__, 3, 4))); ATTRIBUTE ((__format__ (__printf__, 3, 4)));
void fatal (const floc *flocp, size_t length, const char *fmt, ...) void fatal (const floc *flocp, size_t length, const char *fmt, ...)
ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4))); ATTRIBUTE ((noreturn, __format__ (__printf__, 3, 4)));
void out_of_memory () NORETURN; void out_of_memory (void) NORETURN;
/* When adding macros to this list be sure to update the value of /* When adding macros to this list be sure to update the value of
XGETTEXT_OPTIONS in the po/Makevars file. */ XGETTEXT_OPTIONS in the po/Makevars file. */
@ -387,11 +562,25 @@ void out_of_memory () NORETURN;
#define ONS(_t,_a,_f,_n,_s) _t((_a), INTSTR_LENGTH + strlen (_s), \ #define ONS(_t,_a,_f,_n,_s) _t((_a), INTSTR_LENGTH + strlen (_s), \
(_f), (_n), (_s)) (_f), (_n), (_s))
enum variable_origin;
struct variable;
void reset_makeflags (enum variable_origin origin);
struct variable *define_makeflags (int makefile);
int should_print_dir (void);
void temp_stdin_unlink (void);
void die (int) NORETURN; void die (int) NORETURN;
void pfatal_with_name (const char *) NORETURN; void pfatal_with_name (const char *) NORETURN;
void perror_with_name (const char *, const char *); void perror_with_name (const char *, const char *);
#define xstrlen(_s) ((_s)==NULL ? 0 : strlen (_s)) #define xstrlen(_s) ((_s)==NULL ? 0 : strlen (_s))
unsigned int make_toui (const char*, const char**);
char *make_lltoa (long long, char *);
char *make_ulltoa (unsigned long long, char *);
void make_seed (unsigned int);
unsigned int make_rand (void);
pid_t make_pid (void);
void *xmalloc (size_t); void *xmalloc (size_t);
void *xcalloc (size_t);
void *xrealloc (void *, size_t); void *xrealloc (void *, size_t);
char *xstrdup (const char *); char *xstrdup (const char *);
char *xstrndup (const char *, size_t); char *xstrndup (const char *, size_t);
@ -404,23 +593,30 @@ int alpha_compare (const void *, const void *);
void print_spaces (unsigned int); void print_spaces (unsigned int);
char *find_percent (char *); char *find_percent (char *);
const char *find_percent_cached (const char **); const char *find_percent_cached (const char **);
FILE *get_tmpfile (char **, const char *); const char *get_tmpdir (void);
int get_tmpfd (char **);
FILE *get_tmpfile (char **);
ssize_t writebuf (int, const void *, size_t); ssize_t writebuf (int, const void *, size_t);
ssize_t readbuf (int, void *, size_t); ssize_t readbuf (int, void *, size_t);
#ifndef HAVE_MEMRCHR
void *memrchr(const void *, int, size_t);
#endif
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
int ar_name (const char *); int ar_name (const char *);
void ar_parse_name (const char *, char **, char **); void ar_parse_name (const char *, char **, char **);
int ar_touch (const char *); int ar_touch (const char *);
time_t ar_member_date (const char *); time_t ar_member_date (const char *);
typedef long int (*ar_member_func_t) (int desc, const char *mem, int truncated, typedef intmax_t (*ar_member_func_t) (int desc, const char *mem, int truncated,
long int hdrpos, long int datapos, long int hdrpos, long int datapos,
long int size, long int date, int uid, long int size, intmax_t date, int uid,
int gid, unsigned int mode, int gid, unsigned int mode,
const void *arg); const void *arg);
long int ar_scan (const char *archive, ar_member_func_t function, const void *arg); intmax_t ar_scan (const char *archive, ar_member_func_t function,
const void *arg);
int ar_name_equal (const char *name, const char *mem, int truncated); int ar_name_equal (const char *name, const char *mem, int truncated);
#ifndef VMS #ifndef VMS
int ar_member_touch (const char *arname, const char *memname); int ar_member_touch (const char *arname, const char *memname);
@ -450,10 +646,6 @@ int gpath_search (const char *file, size_t len);
void construct_include_path (const char **arg_dirs); void construct_include_path (const char **arg_dirs);
void user_access (void);
void make_access (void);
void child_access (void);
char *strip_whitespace (const char **begpp, const char **endpp); char *strip_whitespace (const char **begpp, const char **endpp);
void show_goal_error (void); void show_goal_error (void);
@ -470,15 +662,19 @@ int guile_gmake_setup (const floc *flocp);
/* Loadable object support. Sets to the strcached name of the loaded file. */ /* Loadable object support. Sets to the strcached name of the loaded file. */
typedef int (*load_func_t)(const floc *flocp); typedef int (*load_func_t)(const floc *flocp);
int load_file (const floc *flocp, const char **filename, int noerror); int load_file (const floc *flocp, struct file *file, int noerror);
void unload_file (const char *name); int unload_file (const char *name);
/* Maintainer mode support */ /* Maintainer mode support */
#ifdef MAKE_MAINTAINER_MODE #ifdef MAKE_MAINTAINER_MODE
# define SPIN(_s) spin (_s) # define SPIN(_s) spin (_s)
void spin (const char* suffix); void spin (const char* suffix);
# define DBG(_f) dbg _f
void dbg (const char *fmt, ...);
#else #else
# define SPIN(_s) # define SPIN(_s)
/* Never put this code into Git or a release. */
# define DBG(_f) compile-error
#endif #endif
/* We omit these declarations on non-POSIX systems which define _POSIX_VERSION, /* We omit these declarations on non-POSIX systems which define _POSIX_VERSION,
@ -486,17 +682,16 @@ void spin (const char* suffix);
#if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WINDOWS32) #if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WINDOWS32)
long int atol ();
# ifndef VMS # ifndef VMS
long int lseek (); long int lseek ();
# endif # endif
# ifdef HAVE_GETCWD # ifdef HAVE_GETCWD
# if !defined(VMS) && !defined(__DECC) # if !defined(VMS) && !defined(__DECC)
char *getcwd (); char *getcwd (void);
# endif # endif
# else # else
char *getwd (); char *getwd (void);
# define getcwd(buf, len) getwd (buf) # define getcwd(buf, len) getwd (buf)
# endif # endif
@ -507,9 +702,6 @@ char *getwd ();
# define strcasecmp stricmp # define strcasecmp stricmp
# elif HAVE_STRCMPI # elif HAVE_STRCMPI
# define strcasecmp strcmpi # define strcasecmp strcmpi
# else
/* Create our own, in misc.c */
int strcasecmp (const char *s1, const char *s2);
# endif # endif
#endif #endif
@ -518,9 +710,6 @@ int strcasecmp (const char *s1, const char *s2);
# define strncasecmp strnicmp # define strncasecmp strnicmp
# elif HAVE_STRNCMPI # elif HAVE_STRNCMPI
# define strncasecmp strncmpi # define strncasecmp strncmpi
# else
/* Create our own, in misc.c */
int strncasecmp (const char *s1, const char *s2, int n);
# endif # endif
#endif #endif
@ -540,21 +729,38 @@ extern unsigned short stopchar_map[];
extern int just_print_flag, run_silent, ignore_errors_flag, keep_going_flag; extern int just_print_flag, run_silent, ignore_errors_flag, keep_going_flag;
extern int print_data_base_flag, question_flag, touch_flag, always_make_flag; extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag; extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
extern int print_version_flag, print_directory_flag, check_symlink_flag; extern int print_version_flag, check_symlink_flag;
extern int warn_undefined_variables_flag, trace_flag, posix_pedantic; extern int warn_undefined_variables_flag, posix_pedantic;
extern int not_parallel, second_expansion, clock_skew_detected; extern int not_parallel, second_expansion, clock_skew_detected;
extern int rebuilding_makefiles, one_shell, output_sync, verify_flag; extern int rebuilding_makefiles, one_shell, output_sync, verify_flag;
extern unsigned long command_count;
extern const char *default_shell; extern const char *default_shell;
/* can we run commands via 'sh -c xxx' or must we use batch files? */ /* can we run commands via 'sh -c xxx' or must we use batch files? */
extern int batch_mode_shell; extern int batch_mode_shell;
#define GNUMAKEFLAGS_NAME "GNUMAKEFLAGS"
#define MAKEFLAGS_NAME "MAKEFLAGS"
/* Resetting the command script introduction prefix character. */ /* Resetting the command script introduction prefix character. */
#define RECIPEPREFIX_NAME ".RECIPEPREFIX" #define RECIPEPREFIX_NAME ".RECIPEPREFIX"
#define RECIPEPREFIX_DEFAULT '\t' #define RECIPEPREFIX_DEFAULT '\t'
extern char cmd_prefix; extern char cmd_prefix;
extern unsigned int no_intermediates;
#if HAVE_MKFIFO
/* It seems that mkfifo() is not working correctly, or at least not the way
GNU make wants it to work, on GNU/Hurd and Cygwin so don't use it there. */
# if !defined(JOBSERVER_USE_FIFO) && !MK_OS_HURD && !MK_OS_CYGWIN
# define JOBSERVER_USE_FIFO 1
# endif
#endif
#define JOBSERVER_AUTH_OPT "jobserver-auth"
extern char *jobserver_auth;
extern unsigned int job_slots; extern unsigned int job_slots;
extern double max_load_average; extern double max_load_average;
@ -607,7 +813,14 @@ extern char *version_string, *remote_description, *make_host;
extern unsigned int commands_started; extern unsigned int commands_started;
extern int handling_fatal_signal; extern volatile sig_atomic_t handling_fatal_signal;
#ifndef MIN
#define MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
#endif
#ifndef MAX
#define MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
#endif
#define MAKE_SUCCESS 0 #define MAKE_SUCCESS 0
#define MAKE_TROUBLE 1 #define MAKE_TROUBLE 1
@ -615,6 +828,37 @@ extern int handling_fatal_signal;
/* Set up heap debugging library dmalloc. */ /* Set up heap debugging library dmalloc. */
#ifdef HAVE_DMALLOC_H
#include <dmalloc.h>
#endif
#ifndef initialize_main
# ifdef __EMX__
# define initialize_main(pargc, pargv) \
{ _wildcard(pargc, pargv); _response(pargc, pargv); }
# else
# define initialize_main(pargc, pargv)
# endif
#endif
#ifdef __EMX__
# if !defined chdir
# define chdir _chdir2
# endif
# if !defined getcwd
# define getcwd _getcwd2
# endif
/* NO_CHDIR2 causes make not to use _chdir2() and _getcwd2() instead of
chdir() and getcwd(). This avoids some error messages for the
make testsuite but restricts the drive letter support. */
# ifdef NO_CHDIR2
# warning NO_CHDIR2: usage of drive letters restricted
# undef chdir
# undef getcwd
# endif
#endif
#ifndef initialize_main #ifndef initialize_main
# define initialize_main(pargc, pargv) # define initialize_main(pargc, pargv)
#endif #endif

View file

@ -1,5 +1,5 @@
/* Miscellaneous generic support functions for GNU Make. /* Miscellaneous generic support functions for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,15 +12,97 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h" #include "filedef.h"
#include "third_party/make/dep.h" #include "dep.h"
#include "third_party/make/debug.h" #include "os.h"
#include "libc/calls/calls.h" #include "debug.h"
/* GNU make no longer supports pre-ANSI89 environments. */ #include <assert.h>
#include <stdarg.h>
#ifdef WINDOWS32
# include <windows.h>
# include <io.h>
#endif
#ifdef __EMX__
# define INCL_DOS
# include <os2.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
unsigned int
make_toui (const char *str, const char **error)
{
char *end;
unsigned long val = strtoul (str, &end, 10);
if (error)
{
if (str[0] == '\0')
*error = "Missing value";
else if (*end != '\0')
*error = "Invalid value";
else
*error = NULL;
}
return val;
}
/* Convert val into a string, written to buf. buf must be large enough
to hold the largest possible value, plus a nul byte. Returns buf.
We can't use standard PRI* here: those are based on intNN_t types. */
char *
make_lltoa (long long val, char *buf)
{
sprintf (buf, "%" MK_PRI64_PREFIX "d", val);
return buf;
}
char *
make_ulltoa (unsigned long long val, char *buf)
{
sprintf (buf, "%" MK_PRI64_PREFIX "u", val);
return buf;
}
/* Simple random number generator, for use with shuffle.
This doesn't need to be truly random, just pretty random. Use our own
implementation rather than relying on the C runtime's rand() so we always
get the same results for a given seed, regardless of C runtime. */
static unsigned int mk_state = 0;
void
make_seed (unsigned int seed)
{
mk_state = seed;
}
unsigned int
make_rand ()
{
/* mk_state must never be 0. */
if (mk_state == 0)
mk_state = (unsigned int)(time (NULL) ^ make_pid ()) + 1;
/* A simple xorshift RNG. */
mk_state ^= mk_state << 13;
mk_state ^= mk_state >> 17;
mk_state ^= mk_state << 5;
return mk_state;
}
/* Compare strings *S1 and *S2. /* Compare strings *S1 and *S2.
Return negative if the first is less, positive if it is greater, Return negative if the first is less, positive if it is greater,
@ -81,7 +163,7 @@ collapse_continuations (char *line)
if (i & 1) if (i & 1)
{ {
/* Backslash/newline handling: /* Backslash/newline handling:
In traditional GNU make all trailing whitespace, consecutive In traditional GNU Make all trailing whitespace, consecutive
backslash/newlines, and any leading non-newline whitespace on the backslash/newlines, and any leading non-newline whitespace on the
next line is reduced to a single space. next line is reduced to a single space.
In POSIX, each backslash/newline and is replaced by a space. */ In POSIX, each backslash/newline and is replaced by a space. */
@ -162,6 +244,85 @@ concat (unsigned int num, ...)
} }
#ifndef HAVE_UNISTD_H
pid_t getpid ();
#endif
pid_t make_pid ()
{
return getpid ();
}
/* Like malloc but get fatal error if memory is exhausted. */
/* Don't bother if we're using dmalloc; it provides these for us. */
#ifndef HAVE_DMALLOC_H
#undef xmalloc
#undef xcalloc
#undef xrealloc
#undef xstrdup
void *
xmalloc (size_t size)
{
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = malloc (size ? size : 1);
if (result == 0)
out_of_memory ();
return result;
}
void *
xcalloc (size_t size)
{
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = calloc (size ? size : 1, 1);
if (result == 0)
out_of_memory ();
return result;
}
void *
xrealloc (void *ptr, size_t size)
{
void *result;
/* Some older implementations of realloc() don't conform to ISO. */
if (! size)
size = 1;
result = ptr ? realloc (ptr, size) : malloc (size);
if (result == 0)
out_of_memory ();
return result;
}
char *
xstrdup (const char *ptr)
{
char *result;
#ifdef HAVE_STRDUP
result = strdup (ptr);
#else
result = malloc (strlen (ptr) + 1);
#endif
if (result == 0)
out_of_memory ();
#ifdef HAVE_STRDUP
return result;
#else
return strcpy (result, ptr);
#endif
}
#endif /* HAVE_DMALLOC_H */
char * char *
xstrndup (const char *str, size_t length) xstrndup (const char *str, size_t length)
{ {
@ -181,6 +342,29 @@ xstrndup (const char *str, size_t length)
return result; return result;
} }
#ifndef HAVE_MEMRCHR
void *
memrchr(const void* str, int ch, size_t len)
{
const char* sp = str;
const char* cp = sp;
if (len == 0)
return NULL;
cp += len - 1;
while (cp[0] != ch)
{
if (cp == sp)
return NULL;
--cp;
}
return (void*)cp;
}
#endif
/* Limited INDEX: /* Limited INDEX:
@ -204,7 +388,8 @@ lindex (const char *s, const char *limit, int c)
char * char *
end_of_token (const char *s) end_of_token (const char *s)
{ {
END_OF_TOKEN (s); while (! END_OF_TOKEN (*s))
++s;
return (char *)s; return (char *)s;
} }
@ -340,11 +525,31 @@ spin (const char* type)
{ {
fprintf (stderr, "SPIN on %s\n", filenm); fprintf (stderr, "SPIN on %s\n", filenm);
do do
#ifdef WINDOWS32
Sleep (1000);
#else
sleep (1); sleep (1);
#endif
while (stat (filenm, &dummy) == 0); while (stat (filenm, &dummy) == 0);
} }
} }
void
dbg (const char *fmt, ...)
{
FILE *fp = fopen ("/tmp/gmkdebug.log", "a+");
va_list args;
char buf[4096];
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
fprintf(fp, "%u: %s\n", (unsigned) make_pid (), buf);
fflush (fp);
fclose (fp);
}
#endif #endif
@ -359,283 +564,314 @@ char *mktemp (char *template);
# endif # endif
#endif #endif
FILE * #ifndef HAVE_UMASK
get_tmpfile (char **name, const char *template) mode_t
umask (mode_t mask)
{ {
FILE *file; return 0;
#ifdef HAVE_FDOPEN }
int fd;
#endif #endif
#ifdef VMS
# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
#else
# define DEFAULT_TMPFILE "GmXXXXXX"
#endif
const char *
get_tmpdir ()
{
static const char *tmpdir = NULL;
if (!tmpdir)
{
#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
# define TMP_EXTRAS "TMP", "TEMP",
#else
# define TMP_EXTRAS
#endif
const char *tlist[] = { "MAKE_TMPDIR", "TMPDIR", TMP_EXTRAS NULL };
const char **tp;
unsigned int found = 0;
for (tp = tlist; *tp; ++tp)
if ((tmpdir = getenv (*tp)) && *tmpdir != '\0')
{
struct stat st;
int r;
found = 1;
EINTRLOOP(r, stat (tmpdir, &st));
if (r < 0)
OSSS (error, NILF,
_("%s value %s: %s"), *tp, tmpdir, strerror (errno));
else if (! S_ISDIR (st.st_mode))
OSS (error, NILF,
_("%s value %s: not a directory"), *tp, tmpdir);
else
return tmpdir;
}
tmpdir = DEFAULT_TMPDIR;
if (found)
OS (error, NILF, _("using default temporary directory '%s'"), tmpdir);
}
return tmpdir;
}
static char *
get_tmptemplate ()
{
const char *tmpdir = get_tmpdir ();
char *template;
char *cp;
template = xmalloc (strlen (tmpdir) + CSTRLEN (DEFAULT_TMPFILE) + 2);
cp = stpcpy (template, tmpdir);
#if !defined VMS
/* It's not possible for tmpdir to be empty. */
if (! ISDIRSEP (cp[-1]))
*(cp++) = '/';
#endif
strcpy (cp, DEFAULT_TMPFILE);
return template;
}
#if !HAVE_MKSTEMP || !HAVE_FDOPEN
/* Generate a temporary filename. This is not safe as another program could
snipe our filename after we've generated it: use this only on systems
without more secure alternatives. */
static char *
get_tmppath ()
{
char *path;
# ifdef HAVE_MKTEMP
path = get_tmptemplate ();
if (*mktemp (path) == '\0')
{
OSS (error, NILF,
_("cannot generate temp path from %s: %s"), path, strerror (errno));
return NULL;
}
# else
path = xmalloc (L_tmpnam + 1);
if (tmpnam (path) == NULL)
{
OS (error, NILF,
_("cannot generate temp name: %s"), strerror (errno));
return NULL;
}
# endif
return path;
}
#endif
/* Generate a temporary file and return an fd for it. If name is NULL then
the temp file is anonymous and will be deleted when the process exits. If
name is not null then *name will point to an allocated buffer, or set to
NULL on failure. */
int
get_tmpfd (char **name)
{
int fd = -1;
char *tmpnm;
mode_t mask;
if (name)
*name = NULL;
else
{
/* If there's an os-specific way to get an anonymous temp file use it. */
fd = os_anontmp ();
if (fd >= 0)
return fd;
}
/* Preserve the current umask, and set a restrictive one for temp files.
Only really needed for mkstemp() but won't hurt for the open method. */
mask = umask (0077);
#if defined(HAVE_MKSTEMP)
tmpnm = get_tmptemplate ();
/* It's safest to use mkstemp(), if we can. */
EINTRLOOP (fd, mkstemp (tmpnm));
#else
tmpnm = get_tmppath ();
if (!tmpnm)
return -1;
/* Can't use mkstemp(), but try to guard against a race condition. */
EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600));
#endif
if (fd < 0)
{
OSS (error, NILF,
_("cannot create temporary file %s: %s"), tmpnm, strerror (errno));
free (tmpnm);
return -1;
}
if (name)
*name = tmpnm;
else
{
int r;
EINTRLOOP (r, unlink (tmpnm));
if (r < 0)
OSS (error, NILF,
_("cannot unlink temporary file %s: %s"), tmpnm, strerror (errno));
free (tmpnm);
}
umask (mask);
return fd;
}
/* Return a FILE* for a temporary file, opened in the safest way possible.
Set name to point to an allocated buffer containing the name of the file,
or NULL on failure. Note, name cannot be NULL! */
FILE *
get_tmpfile (char **name)
{
/* Be consistent with tmpfile, which opens as if by "wb+". */
const char *tmpfile_mode = "wb+";
FILE *file;
#if defined(HAVE_FDOPEN)
int fd;
assert (name);
fd = get_tmpfd (name);
if (fd < 0)
return NULL;
assert (*name);
ENULLLOOP (file, fdopen (fd, tmpfile_mode));
if (file == NULL)
OSS (error, NILF,
_("fdopen: temporary file %s: %s"), *name, strerror (errno));
#else
/* Preserve the current umask, and set a restrictive one for temp files. */ /* Preserve the current umask, and set a restrictive one for temp files. */
mode_t mask = umask (0077); mode_t mask = umask (0077);
#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP) assert (name);
# define TEMPLATE_LEN strlen (template) *name = get_tmppath ();
#else if (!*name)
# define TEMPLATE_LEN L_tmpnam return NULL;
#endif
*name = xmalloc (TEMPLATE_LEN + 1);
strcpy (*name, template);
#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN) /* Although this fopen is insecure, it is executed only on non-fdopen
/* It's safest to use mkstemp(), if we can. */ platforms, which should be a rarity nowadays. */
EINTRLOOP (fd, mkstemp (*name));
if (fd == -1)
file = NULL;
else
file = fdopen (fd, "w");
#else
# ifdef HAVE_MKTEMP
(void) mktemp (*name);
# else
(void) tmpnam (*name);
# endif
# ifdef HAVE_FDOPEN ENULLLOOP (file, fopen (*name, tmpfile_mode));
/* Can't use mkstemp(), but guard against a race condition. */ if (file == NULL)
EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600)); {
if (fd == -1) OSS (error, NILF,
return 0; _("fopen: temporary file %s: %s"), *name, strerror (errno));
file = fdopen (fd, "w"); free (*name);
# else *name = NULL;
/* Not secure, but what can we do? */ }
file = fopen (*name, "w");
# endif
#endif
umask (mask); umask (mask);
#endif
return file; return file;
} }
#ifdef GETLOADAVG_PRIVILEGED
#ifdef POSIX #if HAVE_TTYNAME && defined(__EMX__)
/* OS/2 kLIBC has a declaration for ttyname(), so configure finds it.
/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid But, it is not implemented! Roll our own. */
functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2, char *ttyname (int fd)
for example) which claim to be POSIX.1 also have the BSD setreuid and
setregid functions, but they don't work as in BSD and only the POSIX.1
way works. */
#undef HAVE_SETREUID
#undef HAVE_SETREGID
#else /* Not POSIX. */
/* Some POSIX.1 systems have the seteuid and setegid functions. In a
POSIX-like system, they are the best thing to use. However, some
non-POSIX systems have them too but they do not work in the POSIX style
and we must use setreuid and setregid instead. */
#undef HAVE_SETEUID
#undef HAVE_SETEGID
#endif /* POSIX. */
/* Keep track of the user and group IDs for user- and make- access. */
static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
#define access_inited (user_uid != -1)
static enum { make, user } current_access;
/* Under -d, write a message describing the current IDs. */
static void
log_access (const char *flavor)
{ {
if (! ISDB (DB_JOBS)) ULONG type;
return; ULONG attr;
ULONG rc;
/* All the other debugging messages go to stdout, rc = DosQueryHType (fd, &type, &attr);
but we write this one to stderr because it might be if (rc)
run in a child fork whose stdout is piped. */ {
errno = EBADF;
fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"), return NULL;
flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
(unsigned long) getegid (), (unsigned long) getgid ());
fflush (stderr);
} }
if (type == HANDTYPE_DEVICE)
static void
init_access (void)
{ {
user_uid = getuid (); if (attr & 3) /* 1 = KBD$, 2 = SCREEN$ */
user_gid = getgid (); return (char *) "/dev/con";
make_uid = geteuid (); if (attr & 4) /* 4 = NUL */
make_gid = getegid (); return (char *) "/dev/nul";
/* Do these ever fail? */ if (attr & 8) /* 8 = CLOCK$ */
if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1) return (char *) "/dev/clock$";
pfatal_with_name ("get{e}[gu]id");
log_access (_("Initialized access"));
current_access = make;
} }
#endif /* GETLOADAVG_PRIVILEGED */ errno = ENOTTY;
return NULL;
}
#endif
/* Give the process appropriate permissions for access to #if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
user data (i.e., to stat files, or to spawn a child process). */ /* If we don't have strcasecmp() (from POSIX), or anything that can substitute
void for it, define our own version. */
user_access (void)
int
strcasecmp (const char *s1, const char *s2)
{ {
#ifdef GETLOADAVG_PRIVILEGED while (1)
{
int c1 = (unsigned char) *(s1++);
int c2 = (unsigned char) *(s2++);
if (!access_inited) if (isalpha (c1))
init_access (); c1 = tolower (c1);
if (isalpha (c2))
c2 = tolower (c2);
if (current_access == user) if (c1 != '\0' && c1 == c2)
return; continue;
/* We are in "make access" mode. This means that the effective user and return (c1 - c2);
group IDs are those of make (if it was installed setuid or setgid). }
We now want to set the effective user and group IDs to the real IDs, }
which are the IDs of the process that exec'd make. */
#ifdef HAVE_SETEUID
/* Modern systems have the seteuid/setegid calls which set only the
effective IDs, which is ideal. */
if (seteuid (user_uid) < 0)
pfatal_with_name ("user_access: seteuid");
#else /* Not HAVE_SETEUID. */
#ifndef HAVE_SETREUID
/* System V has only the setuid/setgid calls to set user/group IDs.
There is an effective ID, which can be set by setuid/setgid.
It can be set (unless you are root) only to either what it already is
(returned by geteuid/getegid, now in make_uid/make_gid),
the real ID (return by getuid/getgid, now in user_uid/user_gid),
or the saved set ID (what the effective ID was before this set-ID
executable (make) was exec'd). */
if (setuid (user_uid) < 0)
pfatal_with_name ("user_access: setuid");
#else /* HAVE_SETREUID. */
/* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
They may be set to themselves or each other. So you have two alternatives
at any one time. If you use setuid/setgid, the effective will be set to
the real, leaving only one alternative. Using setreuid/setregid, however,
you can toggle between your two alternatives by swapping the values in a
single setreuid or setregid call. */
if (setreuid (make_uid, user_uid) < 0)
pfatal_with_name ("user_access: setreuid");
#endif /* Not HAVE_SETREUID. */
#endif /* HAVE_SETEUID. */
#ifdef HAVE_SETEGID
if (setegid (user_gid) < 0)
pfatal_with_name ("user_access: setegid");
#else
#ifndef HAVE_SETREGID
if (setgid (user_gid) < 0)
pfatal_with_name ("user_access: setgid");
#else
if (setregid (make_gid, user_gid) < 0)
pfatal_with_name ("user_access: setregid");
#endif
#endif #endif
current_access = user; #if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
/* If we don't have strncasecmp() (from POSIX), or anything that can
substitute for it, define our own version. */
log_access (_("User access")); int
strncasecmp (const char *s1, const char *s2, size_t n)
{
while (n-- > 0)
{
int c1 = (unsigned char) *(s1++);
int c2 = (unsigned char) *(s2++);
#endif /* GETLOADAVG_PRIVILEGED */ if (isalpha (c1))
c1 = tolower (c1);
if (isalpha (c2))
c2 = tolower (c2);
if (c1 != '\0' && c1 == c2)
continue;
return (c1 - c2);
} }
/* Give the process appropriate permissions for access to return 0;
make data (i.e., the load average). */
void
make_access (void)
{
#ifdef GETLOADAVG_PRIVILEGED
if (!access_inited)
init_access ();
if (current_access == make)
return;
/* See comments in user_access, above. */
#ifdef HAVE_SETEUID
if (seteuid (make_uid) < 0)
pfatal_with_name ("make_access: seteuid");
#else
#ifndef HAVE_SETREUID
if (setuid (make_uid) < 0)
pfatal_with_name ("make_access: setuid");
#else
if (setreuid (user_uid, make_uid) < 0)
pfatal_with_name ("make_access: setreuid");
#endif
#endif
#ifdef HAVE_SETEGID
if (setegid (make_gid) < 0)
pfatal_with_name ("make_access: setegid");
#else
#ifndef HAVE_SETREGID
if (setgid (make_gid) < 0)
pfatal_with_name ("make_access: setgid");
#else
if (setregid (user_gid, make_gid) < 0)
pfatal_with_name ("make_access: setregid");
#endif
#endif
current_access = make;
log_access (_("Make access"));
#endif /* GETLOADAVG_PRIVILEGED */
} }
/* Give the process appropriate permissions for a child process.
This is like user_access, but you can't get back to make_access. */
void
child_access (void)
{
#ifdef GETLOADAVG_PRIVILEGED
if (!access_inited)
abort ();
/* Set both the real and effective UID and GID to the user's.
They cannot be changed back to make's. */
#ifndef HAVE_SETREUID
if (setuid (user_uid) < 0)
pfatal_with_name ("child_access: setuid");
#else
if (setreuid (user_uid, user_uid) < 0)
pfatal_with_name ("child_access: setreuid");
#endif #endif
#ifndef HAVE_SETREGID
if (setgid (user_gid) < 0)
pfatal_with_name ("child_access: setgid");
#else
if (setregid (user_gid, user_gid) < 0)
pfatal_with_name ("child_access: setregid");
#endif
log_access (_("Child access"));
#endif /* GETLOADAVG_PRIVILEGED */
}
#ifdef NEED_GET_PATH_MAX #ifdef NEED_GET_PATH_MAX
unsigned int unsigned int
@ -645,13 +881,163 @@ get_path_max (void)
if (value == 0) if (value == 0)
{ {
long int x = pathconf ("/", _PC_PATH_MAX); long x = pathconf ("/", _PC_PATH_MAX);
if (x > 0) if (x > 0)
value = x; value = (unsigned int) x;
else else
return MAXPATHLEN; value = PATH_MAX;
} }
return value; return value;
} }
#endif #endif
#if !HAVE_MEMPCPY
void *
mempcpy (void *dest, const void *src, size_t n)
{
return (char *) memcpy (dest, src, n) + n;
}
#endif
#if !HAVE_STPCPY
char *
stpcpy (char *dest, const char *src)
{
char *d = dest;
const char *s = src;
do
*d++ = *s;
while (*s++ != '\0');
return d - 1;
}
#endif
#if !HAVE_STRTOLL
# undef UNSIGNED
# undef USE_NUMBER_GROUPING
# undef USE_WIDE_CHAR
# define QUAD 1
# include <strtol.c>
#endif
#if !HAVE_STRERROR
char *
strerror (int errnum)
{
static char msg[256];
#define SETMSG(_e, _m) case _e: strcpy(msg, _m); break
switch (errnum)
{
#ifdef EPERM
SETMSG (EPERM , "Operation not permitted");
#endif
#ifdef ENOENT
SETMSG (ENOENT , "No such file or directory");
#endif
#ifdef ESRCH
SETMSG (ESRCH , "No such process");
#endif
#ifdef EINTR
SETMSG (EINTR , "Interrupted system call");
#endif
#ifdef EIO
SETMSG (EIO , "I/O error");
#endif
#ifdef ENXIO
SETMSG (ENXIO , "No such device or address");
#endif
#ifdef E2BIG
SETMSG (E2BIG , "Argument list too long");
#endif
#ifdef ENOEXEC
SETMSG (ENOEXEC, "Exec format error");
#endif
#ifdef EBADF
SETMSG (EBADF , "Bad file number");
#endif
#ifdef ECHILD
SETMSG (ECHILD , "No child processes");
#endif
#ifdef EAGAIN
SETMSG (EAGAIN , "Try again");
#endif
#ifdef ENOMEM
SETMSG (ENOMEM , "Out of memory");
#endif
#ifdef EACCES
SETMSG (EACCES , "Permission denied");
#endif
#ifdef EFAULT
SETMSG (EFAULT , "Bad address");
#endif
#ifdef ENOTBLK
SETMSG (ENOTBLK, "Block device required");
#endif
#ifdef EBUSY
SETMSG (EBUSY , "Device or resource busy");
#endif
#ifdef EEXIST
SETMSG (EEXIST , "File exists");
#endif
#ifdef EXDEV
SETMSG (EXDEV , "Cross-device link");
#endif
#ifdef ENODEV
SETMSG (ENODEV , "No such device");
#endif
#ifdef ENOTDIR
SETMSG (ENOTDIR, "Not a directory");
#endif
#ifdef EISDIR
SETMSG (EISDIR , "Is a directory");
#endif
#ifdef EINVAL
SETMSG (EINVAL , "Invalid argument");
#endif
#ifdef ENFILE
SETMSG (ENFILE , "File table overflow");
#endif
#ifdef EMFILE
SETMSG (EMFILE , "Too many open files");
#endif
#ifdef ENOTTY
SETMSG (ENOTTY , "Not a typewriter");
#endif
#ifdef ETXTBSY
SETMSG (ETXTBSY, "Text file busy");
#endif
#ifdef EFBIG
SETMSG (EFBIG , "File too large");
#endif
#ifdef ENOSPC
SETMSG (ENOSPC , "No space left on device");
#endif
#ifdef ESPIPE
SETMSG (ESPIPE , "Illegal seek");
#endif
#ifdef EROFS
SETMSG (EROFS , "Read-only file system");
#endif
#ifdef EMLINK
SETMSG (EMLINK , "Too many links");
#endif
#ifdef EPIPE
SETMSG (EPIPE , "Broken pipe");
#endif
#ifdef EDOM
SETMSG (EDOM , "Math argument out of domain of func");
#endif
#ifdef ERANGE
SETMSG (ERANGE , "Math result not representable");
#endif
default: sprintf (msg, "Unknown error %d", errnum); break;
}
return msg;
}
#endif

37
third_party/make/mkconfig.h vendored Normal file
View file

@ -0,0 +1,37 @@
/* src/mkconfig.h. Generated from mkconfig.h.in by configure. */
/* Autoconf values for use on non-POSIX systems.
Copyright (C) 2022-2023 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
/* Name of package */
#define PACKAGE "make"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "bug-make@gnu.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "GNU Make"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "GNU Make 4.4.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "make"
/* Define to the home page for this package. */
#define PACKAGE_URL "https://www.gnu.org/software/make/"
/* Define to the version of this package. */
#define PACKAGE_VERSION "4.4.1"

65
third_party/make/mkcustom.h vendored Normal file
View file

@ -0,0 +1,65 @@
/* Miscellaneous global declarations and portability cruft for GNU Make.
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
/*
This file is included at the end of config.h
That means it's included _everywhere_ as the first thing,
INCLUDING content imported from gnulib. BE AWARE!!
*/
#undef HAVE_CONFIG_H
#define HAVE_CONFIG_H 1
/* Specify we want GNU source code. This must be defined before any
system headers are included. */
#define _GNU_SOURCE 1
/* AIX requires this to be the first thing in the file. */
#if HAVE_ALLOCA_H
# include <alloca.h>
#else
# ifdef _AIX
#pragma alloca
# else
# if !defined(__GNUC__) && !defined(WINDOWS32)
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#endif
/* Declare function prototypes for src/misc.c functions if needed. */
#include <stddef.h>
#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
int strcasecmp (const char *s1, const char *s2);
#endif
#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
int strncasecmp (const char *s1, const char *s2, size_t n);
#endif
#if !HAVE_MEMPCPY
void *mempcpy (void *dest, const void *src, size_t n);
#endif
#if !HAVE_STPCPY
char *stpcpy (char *dest, const char *src);
#endif

101
third_party/make/os.h vendored
View file

@ -1,5 +1,5 @@
/* Declarations for operating system interfaces for GNU Make. /* Declarations for operating system interfaces for GNU Make.
Copyright (C) 2016-2020 Free Software Foundation, Inc. Copyright (C) 2016-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,8 +12,35 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#define IO_UNKNOWN 0x0001
#define IO_COMBINED_OUTERR 0x0002
#define IO_STDIN_OK 0x0004
#define IO_STDOUT_OK 0x0008
#define IO_STDERR_OK 0x0010
#if defined(VMS) || defined(_AMIGA) || defined(__MSDOS__)
# define check_io_state() (IO_STDIN_OK|IO_STDOUT_OK|IO_STDERR_OK)
# define fd_inherit(_i) (0)
# define fd_noinherit(_i) (0)
# define fd_set_append(_i) (void)(0)
# define os_anontmp() (-1)
#else
/* Determine the state of stdin/stdout/stderr. */
unsigned int check_io_state (void);
/* Set a file descriptor to close/not close in a subprocess. */
void fd_inherit (int);
void fd_noinherit (int);
/* If the file descriptor is for a file put it into append mode. */
void fd_set_append (int);
/* Return a file descriptor for a new anonymous temp file, or -1. */
int os_anontmp (void);
#endif
/* This section provides OS-specific functions to support the jobserver. */ /* This section provides OS-specific functions to support the jobserver. */
@ -22,19 +49,26 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
/* Returns 1 if the jobserver is enabled, else 0. */ /* Returns 1 if the jobserver is enabled, else 0. */
unsigned int jobserver_enabled (void); unsigned int jobserver_enabled (void);
/* Called in the master instance to set up the jobserver initially. */ /* Called in the parent make to set up the jobserver initially. */
unsigned int jobserver_setup (int job_slots); unsigned int jobserver_setup (int job_slots, const char *style);
/* Called in a child instance to connect to the jobserver. */ /* Called in a child instance to connect to the jobserver.
Return 1 if we got a valid auth, else 0. */
unsigned int jobserver_parse_auth (const char* auth); unsigned int jobserver_parse_auth (const char* auth);
/* Returns an allocated buffer used to pass to child instances. */ /* Returns an allocated buffer used to pass to child instances. */
char *jobserver_get_auth (void); char *jobserver_get_auth (void);
/* Clear this instance's jobserver configuration. */ /* Returns a pointer to a static string used to indicate that the child
cannot access the jobserver, or NULL if it always can. */
const char *jobserver_get_invalid_auth (void);
/* Clear this instance's jobserver configuration.
This method might be invoked from a signal handler. */
void jobserver_clear (void); void jobserver_clear (void);
/* Recover all the jobserver tokens and return the number we got. */ /* Recover all the jobserver tokens and return the number we got.
Will also run jobserver_clear() as a side-effect. */
unsigned int jobserver_acquire_all (void); unsigned int jobserver_acquire_all (void);
/* Release a jobserver token. If it fails and is_fatal is 1, fatal. */ /* Release a jobserver token. If it fails and is_fatal is 1, fatal. */
@ -62,9 +96,10 @@ unsigned int jobserver_acquire (int timeout);
#else #else
#define jobserver_enabled() (0) #define jobserver_enabled() (0)
#define jobserver_setup(_slots) (0) #define jobserver_setup(_slots, _style) (0)
#define jobserver_parse_auth(_auth) (0) #define jobserver_parse_auth(_auth) (0)
#define jobserver_get_auth() (NULL) #define jobserver_get_auth() (NULL)
#define jobserver_get_invalid_auth() (NULL)
#define jobserver_clear() (void)(0) #define jobserver_clear() (void)(0)
#define jobserver_release(_fatal) (void)(0) #define jobserver_release(_fatal) (void)(0)
#define jobserver_acquire_all() (0) #define jobserver_acquire_all() (0)
@ -74,7 +109,46 @@ unsigned int jobserver_acquire (int timeout);
#define jobserver_pre_acquire() (void)(0) #define jobserver_pre_acquire() (void)(0)
#define jobserver_acquire(_tmout) (0) #define jobserver_acquire(_tmout) (0)
#endif #endif /* MAKE_JOBSERVER */
#ifndef NO_OUTPUT_SYNC
/* Returns 1 if output sync is enabled, else 0. */
unsigned int osync_enabled (void);
/* Called in the parent make to set up output sync initially. */
void osync_setup (void);
/* Returns an allocated buffer containing output sync info to pass to child
instances, or NULL if not needed. */
char *osync_get_mutex (void);
/* Called in a child instance to obtain info on the output sync mutex.
Return 1 if we got a valid mutex, else 0. */
unsigned int osync_parse_mutex (const char *mutex);
/* Clean up this instance's output sync facilities.
This method might be invoked from a signal handler. */
void osync_clear (void);
/* Acquire the output sync lock. This will wait until available.
Returns 0 if there was an error getting the semaphore. */
unsigned int osync_acquire (void);
/* Release the output sync lock. */
void osync_release (void);
#else
#define osync_enabled() (0)
#define osync_setup() (void)(0)
#define osync_get_mutex() (0)
#define osync_parse_mutex(_s) (0)
#define osync_clear() (void)(0)
#define osync_acquire() (1)
#define osync_release() (void)(0)
#endif /* NO_OUTPUT_SYNC */
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */ /* Create a "bad" file descriptor for stdin when parallel jobs are run. */
#if defined(VMS) || defined(WINDOWS32) || defined(_AMIGA) || defined(__MSDOS__) #if defined(VMS) || defined(WINDOWS32) || defined(_AMIGA) || defined(__MSDOS__)
@ -82,12 +156,3 @@ unsigned int jobserver_acquire (int timeout);
#else #else
int get_bad_stdin (void); int get_bad_stdin (void);
#endif #endif
/* Set a file descriptor to close/not close in a subprocess. */
#if defined(VMS) || defined(_AMIGA) || defined(__MSDOS__)
# define fd_inherit(_i) 0
# define fd_noinherit(_i) 0
#else
void fd_inherit (int);
void fd_noinherit (int);
#endif

View file

@ -1,5 +1,5 @@
/* Output to stdout / stderr for GNU make /* Output to stdout / stderr for GNU Make
Copyright (C) 2013-2020 Free Software Foundation, Inc. Copyright (C) 2013-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,15 +12,27 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/os.h" #include "os.h"
#include "third_party/make/output.h" #include "output.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/struct/flock.h"
/* GNU make no longer supports pre-ANSI89 environments. */ /* GNU Make no longer supports pre-ANSI89 environments. */
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
struct output *output_context = NULL; struct output *output_context = NULL;
unsigned int stdio_traced = 0; unsigned int stdio_traced = 0;
@ -29,31 +41,29 @@ unsigned int stdio_traced = 0;
#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0) #define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
#ifdef HAVE_FCNTL_H
# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
#else
# define STREAM_OK(_s) 1
#endif
/* Write a string to the current STDOUT or STDERR. */ /* Write a string to the current STDOUT or STDERR. */
static void static void
_outputs (struct output *out, int is_err, const char *msg) _outputs (struct output *out, int is_err, const char *msg)
{ {
if (! out || ! out->syncout) FILE *f;
{
FILE *f = is_err ? stderr : stdout; if (out && out->syncout)
fputs (msg, f);
fflush (f);
}
else
{ {
int fd = is_err ? out->err : out->out; int fd = is_err ? out->err : out->out;
if (fd != OUTPUT_NONE)
{
size_t len = strlen (msg); size_t len = strlen (msg);
int r; int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END)); EINTRLOOP (r, lseek (fd, 0, SEEK_END));
writebuf (fd, msg, len); writebuf (fd, msg, len);
return;
} }
} }
f = is_err ? stderr : stdout;
fputs (msg, f);
fflush (f);
}
/* Write a message indicating that we've just entered or /* Write a message indicating that we've just entered or
left (according to ENTERING) the current directory. */ left (according to ENTERING) the current directory. */
@ -125,73 +135,10 @@ log_working_directory (int entering)
return 1; return 1;
} }
/* Set a file descriptor to be in O_APPEND mode.
If it fails, just ignore it. */
static void
set_append_mode (int fd)
{
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
int flags = fcntl (fd, F_GETFL, 0);
if (flags >= 0)
{
int r;
EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND));
}
#endif
}
#ifndef NO_OUTPUT_SYNC #ifndef NO_OUTPUT_SYNC
/* Semaphore for use in -j mode with output_sync. */
static sync_handle_t sync_handle = -1;
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
/* Set up the sync handle. Disables output_sync on error. */
static int
sync_init (void)
{
int combined_output = 0;
#ifdef WINDOWS32
if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
|| (sync_handle = create_mutex ()) == -1)
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
else
{
combined_output = same_stream (stdout, stderr);
prepare_mutex_handle_string (sync_handle);
}
#else
if (STREAM_OK (stdout))
{
struct stat stbuf_o, stbuf_e;
sync_handle = fileno (stdout);
combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
&& fstat (fileno (stderr), &stbuf_e) == 0
&& stbuf_o.st_dev == stbuf_e.st_dev
&& stbuf_o.st_ino == stbuf_e.st_ino);
}
else if (STREAM_OK (stderr))
sync_handle = fileno (stderr);
else
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
#endif
return combined_output;
}
/* Support routine for output_sync() */ /* Support routine for output_sync() */
static void static void
pump_from_tmp (int from, FILE *to) pump_from_tmp (int from, FILE *to)
@ -232,55 +179,13 @@ pump_from_tmp (int from, FILE *to)
#endif #endif
} }
/* Obtain the lock for writing output. */ /* Returns a file descriptor to a temporary file, that will be automatically
static void * deleted on exit. */
acquire_semaphore (void)
{
static struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
return &fl;
perror ("fcntl()");
return NULL;
}
/* Release the lock for writing output. */
static void
release_semaphore (void *sem)
{
struct flock *flp = (struct flock *)sem;
flp->l_type = F_UNLCK;
if (fcntl (sync_handle, F_SETLKW, flp) == -1)
perror ("fcntl()");
}
/* Returns a file descriptor to a temporary file. The file is automatically
closed/deleted on exit. Don't use a FILE* stream. */
int int
output_tmpfd (void) output_tmpfd (void)
{ {
mode_t mask = umask (0077); int fd = get_tmpfd (NULL);
int fd = -1; fd_set_append (fd);
FILE *tfile = tmpfile ();
if (! tfile)
pfatal_with_name ("tmpfile");
/* Create a duplicate so we can close the stream. */
fd = dup (fileno (tfile));
if (fd < 0)
pfatal_with_name ("dup");
fclose (tfile);
set_append_mode (fd);
umask (mask);
return fd; return fd;
} }
@ -291,13 +196,25 @@ output_tmpfd (void)
static void static void
setup_tmpfile (struct output *out) setup_tmpfile (struct output *out)
{ {
/* Is make's stdout going to the same place as stderr? */ static unsigned int in_setup = 0;
static int combined_output = -1; unsigned int io_state;
if (combined_output < 0) /* If something fails during setup we might recurse back into this function
combined_output = sync_init (); while writing errors. Make sure we don't do so infinitely. */
if (in_setup)
return;
in_setup = 1;
if (STREAM_OK (stdout)) io_state = check_io_state ();
if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK))
{
/* This is probably useless since stdout/stderr aren't working. */
perror_with_name ("output-sync suppressed: ", "stderr");
goto error;
}
if (ANY_SET (io_state, IO_STDOUT_OK))
{ {
int fd = output_tmpfd (); int fd = output_tmpfd ();
if (fd < 0) if (fd < 0)
@ -306,9 +223,9 @@ setup_tmpfile (struct output *out)
out->out = fd; out->out = fd;
} }
if (STREAM_OK (stderr)) if (ANY_SET (io_state, IO_STDERR_OK))
{ {
if (out->out != OUTPUT_NONE && combined_output) if (out->out != OUTPUT_NONE && ANY_SET (io_state, IO_COMBINED_OUTERR))
out->err = out->out; out->err = out->out;
else else
{ {
@ -320,12 +237,18 @@ setup_tmpfile (struct output *out)
} }
} }
in_setup = 0;
return; return;
/* If we failed to create a temp file, disable output sync going forward. */ /* If we failed to create a temp file, disable output sync going forward. */
error: error:
O (error, NILF,
_("cannot open output-sync lock file, suppressing output-sync."));
output_close (out); output_close (out);
output_sync = OUTPUT_SYNC_NONE; output_sync = OUTPUT_SYNC_NONE;
osync_clear ();
in_setup = 0;
} }
/* Synchronize the output of jobs in -j mode to keep the results of /* Synchronize the output of jobs in -j mode to keep the results of
@ -336,6 +259,8 @@ setup_tmpfile (struct output *out)
void void
output_dump (struct output *out) output_dump (struct output *out)
{ {
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
int outfd_not_empty = FD_NOT_EMPTY (out->out); int outfd_not_empty = FD_NOT_EMPTY (out->out);
int errfd_not_empty = FD_NOT_EMPTY (out->err); int errfd_not_empty = FD_NOT_EMPTY (out->err);
@ -346,10 +271,16 @@ output_dump (struct output *out)
/* Try to acquire the semaphore. If it fails, dump the output /* Try to acquire the semaphore. If it fails, dump the output
unsynchronized; still better than silently discarding it. unsynchronized; still better than silently discarding it.
We want to keep this lock for as little time as possible. */ We want to keep this lock for as little time as possible. */
void *sem = acquire_semaphore (); if (!osync_acquire ())
{
O (error, NILF,
_("warning: Cannot acquire output lock, disabling output sync."));
osync_clear ();
}
/* Log the working directory for this dump. */ /* Log the working directory for this dump. */
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
if (output_sync != OUTPUT_SYNC_RECURSE && should_print_dir ())
traced = log_working_directory (1); traced = log_working_directory (1);
if (outfd_not_empty) if (outfd_not_empty)
@ -361,8 +292,7 @@ output_dump (struct output *out)
log_working_directory (0); log_working_directory (0);
/* Exit the critical section. */ /* Exit the critical section. */
if (sem) osync_release ();
release_semaphore (sem);
/* Truncate and reset the output, in case we use it again. */ /* Truncate and reset the output, in case we use it again. */
if (out->out != OUTPUT_NONE) if (out->out != OUTPUT_NONE)
@ -382,53 +312,6 @@ output_dump (struct output *out)
#endif /* NO_OUTPUT_SYNC */ #endif /* NO_OUTPUT_SYNC */
/* This code is stolen from gnulib.
If/when we abandon the requirement to work with K&R compilers, we can
remove this (and perhaps other parts of GNU make!) and migrate to using
gnulib directly.
This is called only through atexit(), which means die() has already been
invoked. So, call exit() here directly. Apparently that works...?
*/
/* Close standard output, exiting with status 'exit_failure' on failure.
If a program writes *anything* to stdout, that program should close
stdout and make sure that it succeeds before exiting. Otherwise,
suppose that you go to the extreme of checking the return status
of every function that does an explicit write to stdout. The last
printf can succeed in writing to the internal stream buffer, and yet
the fclose(stdout) could still fail (due e.g., to a disk full error)
when it tries to write out that buffered data. Thus, you would be
left with an incomplete output file and the offending program would
exit successfully. Even calling fflush is not always sufficient,
since some file systems (NFS and CODA) buffer written/flushed data
until an actual close call.
Besides, it's wasteful to check the return value from every call
that writes to stdout -- just let the internal stream state record
the failure. That's what the ferror test is checking below.
It's important to detect such failures and exit nonzero because many
tools (most notably 'make' and other build-management systems) depend
on being able to detect failure in other tools via their exit status. */
static void
close_stdout (void)
{
int prev_fail = ferror (stdout);
int fclose_fail = fclose (stdout);
if (prev_fail || fclose_fail)
{
if (fclose_fail)
perror_with_name (_("write error: stdout"), "");
else
O (error, NILF, _("write error: stdout"));
exit (MAKE_TROUBLE);
}
}
void void
output_init (struct output *out) output_init (struct output *out)
{ {
@ -439,28 +322,10 @@ output_init (struct output *out)
return; return;
} }
/* Configure this instance of make. Be sure stdout is line-buffered. */ /* Force stdout/stderr into append mode (if they are files) to ensure
parallel jobs won't lose output due to overlapping writes. */
#ifdef HAVE_SETVBUF fd_set_append (fileno (stdout));
# ifdef SETVBUF_REVERSED fd_set_append (fileno (stderr));
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
# else /* setvbuf not reversed. */
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
# endif /* setvbuf reversed. */
#elif HAVE_SETLINEBUF
setlinebuf (stdout);
#endif /* setlinebuf missing. */
/* Force stdout/stderr into append mode. This ensures parallel jobs won't
lose output due to overlapping writes. */
set_append_mode (fileno (stdout));
set_append_mode (fileno (stderr));
#ifdef HAVE_ATEXIT
if (STREAM_OK (stdout))
atexit (close_stdout);
#endif
} }
void void
@ -499,7 +364,7 @@ output_start (void)
/* If we're not syncing this output per-line or per-target, make sure we emit /* If we're not syncing this output per-line or per-target, make sure we emit
the "Entering..." message where appropriate. */ the "Entering..." message where appropriate. */
if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE) if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
if (! stdio_traced && print_directory_flag) if (! stdio_traced && should_print_dir ())
stdio_traced = log_working_directory (1); stdio_traced = log_working_directory (1);
} }
@ -542,10 +407,11 @@ void
message (int prefix, size_t len, const char *fmt, ...) message (int prefix, size_t len, const char *fmt, ...)
{ {
va_list args; va_list args;
char *start;
char *p; char *p;
len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1; len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
p = get_buffer (len); start = p = get_buffer (len);
if (prefix) if (prefix)
{ {
@ -562,8 +428,8 @@ message (int prefix, size_t len, const char *fmt, ...)
strcat (p, "\n"); strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0'); assert (start[len-1] == '\0');
outputs (0, fmtbuf.buffer); outputs (0, start);
} }
/* Print an error message. */ /* Print an error message. */
@ -572,12 +438,13 @@ void
error (const floc *flocp, size_t len, const char *fmt, ...) error (const floc *flocp, size_t len, const char *fmt, ...)
{ {
va_list args; va_list args;
char *start;
char *p; char *p;
len += (strlen (fmt) + strlen (program) len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 4 + 1 + 1); + INTSTR_LENGTH + 4 + 1 + 1);
p = get_buffer (len); start = p = get_buffer (len);
if (flocp && flocp->filenm) if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset); sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
@ -593,8 +460,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...)
strcat (p, "\n"); strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0'); assert (start[len-1] == '\0');
outputs (1, fmtbuf.buffer); outputs (1, start);
} }
/* Print an error message and exit. */ /* Print an error message and exit. */
@ -604,12 +471,13 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
{ {
va_list args; va_list args;
const char *stop = _(". Stop.\n"); const char *stop = _(". Stop.\n");
char *start;
char *p; char *p;
len += (strlen (fmt) + strlen (program) len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0) + (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 8 + strlen (stop) + 1); + INTSTR_LENGTH + 8 + strlen (stop) + 1);
p = get_buffer (len); start = p = get_buffer (len);
if (flocp && flocp->filenm) if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset); sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
@ -625,8 +493,8 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
strcat (p, stop); strcat (p, stop);
assert (fmtbuf.buffer[len-1] == '\0'); assert (start[len-1] == '\0');
outputs (1, fmtbuf.buffer); outputs (1, start);
die (MAKE_FAILURE); die (MAKE_FAILURE);
} }

View file

@ -1,5 +1,5 @@
/* Output to stdout / stderr for GNU make /* Output to stdout / stderr for GNU Make
Copyright (C) 2013-2020 Free Software Foundation, Inc. Copyright (C) 2013-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,7 +12,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
struct output struct output
{ {
@ -50,51 +50,9 @@ void output_start (void);
/* Show a message on stdout or stderr. Will start the output if needed. */ /* Show a message on stdout or stderr. Will start the output if needed. */
void outputs (int is_err, const char *msg); void outputs (int is_err, const char *msg);
#ifdef NO_OUTPUT_SYNC #if defined(NO_OUTPUT_SYNC)
# define RECORD_SYNC_MUTEX(m) \ # define output_dump(_o) (void)(0)
O (error, NILF, \
_("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build."));
#else #else
int output_tmpfd (void);
/* Dump any child output content to stdout, and reset it. */ /* Dump any child output content to stdout, and reset it. */
void output_dump (struct output *out); void output_dump (struct output *out);
# ifdef WINDOWS32
/* For emulations in w32/compat/posixfcn.c. */
# define F_GETFD 1
# define F_SETLKW 2
/* Implementation note: None of the values of l_type below can be zero
-- they are compared with a static instance of the struct, so zero
means unknown/invalid, see w32/compat/posixfcn.c. */
# define F_WRLCK 1
# define F_UNLCK 2
struct flock
{
short l_type;
short l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
/* This type is actually a HANDLE, but we want to avoid including
windows.h as much as possible. */
typedef intptr_t sync_handle_t;
/* Public functions emulated/provided in posixfcn.c. */
int fcntl (intptr_t fd, int cmd, ...);
intptr_t create_mutex (void);
int same_stream (FILE *f1, FILE *f2);
# define RECORD_SYNC_MUTEX(m) record_sync_mutex(m)
void record_sync_mutex (const char *str);
void prepare_mutex_handle_string (intptr_t hdl);
# else /* !WINDOWS32 */
typedef int sync_handle_t; /* file descriptor */
# define RECORD_SYNC_MUTEX(m) (void)(m)
#endif #endif
#endif /* !NO_OUTPUT_SYNC */

View file

@ -1,5 +1,5 @@
/* POSIX-based operating system interface for GNU Make. /* POSIX-based operating system interface for GNU Make.
Copyright (C) 2016-2020 Free Software Foundation, Inc. Copyright (C) 2016-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,24 +12,77 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "libc/dce.h"
/**/ #include "makeint.h"
#include "libc/sock/select.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "third_party/make/config.h"
#include "third_party/make/debug.h"
#include "third_party/make/job.h"
#include "third_party/make/os.h"
#ifdef MAKE_JOBSERVER #include <stdio.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
#elif defined(HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if MK_OS_ZOS
/* FIXME: HAVE_PSELECT path hangs on z/OS */
#undef HAVE_PSELECT
#endif
#if !defined(FD_OK)
# define FD_OK(_f) 1
#endif
#if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H)
# include <sys/select.h>
#endif
#include "debug.h"
#include "job.h"
#include "os.h"
#define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
unsigned int
check_io_state ()
{
static unsigned int state = IO_UNKNOWN;
/* We only need to compute this once per process. */
if (state != IO_UNKNOWN)
return state;
if (STREAM_OK (stdin))
state |= IO_STDIN_OK;
if (STREAM_OK (stdout))
state |= IO_STDOUT_OK;
if (STREAM_OK (stderr))
state |= IO_STDERR_OK;
if (ALL_SET (state, IO_STDOUT_OK|IO_STDERR_OK))
{
struct stat stbuf_o, stbuf_e;
if (fstat (fileno (stdout), &stbuf_o) == 0
&& fstat (fileno (stderr), &stbuf_e) == 0
&& stbuf_o.st_dev == stbuf_e.st_dev
&& stbuf_o.st_ino == stbuf_e.st_ino)
state |= IO_COMBINED_OUTERR;
}
return state;
}
#if defined(MAKE_JOBSERVER)
#define FIFO_PREFIX "fifo:"
/* This section provides OS-specific functions to support the jobserver. */ /* This section provides OS-specific functions to support the jobserver. */
/* True if this is the root make instance. */
static unsigned char job_root = 0;
/* These track the state of the jobserver pipe. Passed to child instances. */ /* These track the state of the jobserver pipe. Passed to child instances. */
static int job_fds[2] = { -1, -1 }; static int job_fds[2] = { -1, -1 };
@ -41,79 +94,197 @@ static int job_rfd = -1;
/* Token written to the pipe (could be any character...) */ /* Token written to the pipe (could be any character...) */
static char token = '+'; static char token = '+';
static int make_job_rfd(void) { /* The type of jobserver we're using. */
enum js_type
{
js_none = 0, /* No jobserver. */
js_pipe, /* Use a simple pipe as the jobserver. */
js_fifo /* Use a named pipe as the jobserver. */
};
static enum js_type js_type = js_none;
/* The name of the named pipe (if used). */
static char *fifo_name = NULL;
static int
make_job_rfd ()
{
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
/* Pretend we succeeded. */ /* Pretend we succeeded. */
return 0; return 0;
#else #else
EINTRLOOP (job_rfd, dup (job_fds[0])); EINTRLOOP (job_rfd, dup (job_fds[0]));
if (job_rfd >= 0) fd_noinherit(job_rfd); if (job_rfd >= 0)
fd_noinherit (job_rfd);
return job_rfd; return job_rfd;
#endif #endif
} }
static void set_blocking(int fd, int blocking) { static void
set_blocking (int fd, int blocking)
{
/* If we're not using pselect() don't change the blocking. */ /* If we're not using pselect() don't change the blocking. */
#ifdef HAVE_PSELECT #ifdef HAVE_PSELECT
int flags; int flags;
EINTRLOOP (flags, fcntl (fd, F_GETFL)); EINTRLOOP (flags, fcntl (fd, F_GETFL));
if (flags >= 0) { if (flags >= 0)
{
int r; int r;
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
EINTRLOOP (r, fcntl (fd, F_SETFL, flags)); EINTRLOOP (r, fcntl (fd, F_SETFL, flags));
if (r < 0) pfatal_with_name("fcntl(O_NONBLOCK)"); if (r < 0)
pfatal_with_name ("fcntl(O_NONBLOCK)");
} }
#else
(void) fd;
(void) blocking;
#endif #endif
} }
unsigned int jobserver_setup(int slots) { unsigned int
jobserver_setup (int slots, const char *style)
{
int r; int r;
#if JOBSERVER_USE_FIFO
if (!style || strcmp (style, "fifo") == 0)
{
/* Unfortunately glibc warns about uses of mktemp even though we aren't
using it in dangerous way here. So avoid this by generating our own
temporary file name. */
# define FNAME_PREFIX "GMfifo"
const char *tmpdir = get_tmpdir ();
fifo_name = xmalloc (strlen (tmpdir) + CSTRLEN (FNAME_PREFIX)
+ INTSTR_LENGTH + 2);
sprintf (fifo_name, "%s/" FNAME_PREFIX "%" MK_PRI64_PREFIX "d",
tmpdir, (long long)make_pid ());
EINTRLOOP (r, mkfifo (fifo_name, 0600));
if (r < 0)
{
perror_with_name("jobserver mkfifo: ", fifo_name);
free (fifo_name);
fifo_name = NULL;
}
else
{
/* We have to open the read side in non-blocking mode, else it will
hang until the write side is open. */
EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY|O_NONBLOCK));
if (job_fds[0] < 0)
OSS (fatal, NILF, _("cannot open jobserver %s: %s"),
fifo_name, strerror (errno));
EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
if (job_fds[0] < 0)
OSS (fatal, NILF, _("cannot open jobserver %s: %s"),
fifo_name, strerror (errno));
js_type = js_fifo;
}
}
#endif
if (js_type == js_none)
{
if (style && strcmp (style, "pipe") != 0)
OS (fatal, NILF, _("unknown jobserver auth style '%s'"), style);
EINTRLOOP (r, pipe (job_fds)); EINTRLOOP (r, pipe (job_fds));
if (r < 0) pfatal_with_name(_("creating jobs pipe")); if (r < 0)
pfatal_with_name (_("creating jobs pipe"));
js_type = js_pipe;
}
/* By default we don't send the job pipe FDs to our children. /* By default we don't send the job pipe FDs to our children.
See jobserver_pre_child() and jobserver_post_child(). */ See jobserver_pre_child() and jobserver_post_child(). */
fd_noinherit (job_fds[0]); fd_noinherit (job_fds[0]);
fd_noinherit (job_fds[1]); fd_noinherit (job_fds[1]);
if (make_job_rfd() < 0) pfatal_with_name(_("duping jobs pipe")); if (make_job_rfd () < 0)
pfatal_with_name (_("duping jobs pipe"));
while (slots--) { while (slots--)
{
EINTRLOOP (r, write (job_fds[1], &token, 1)); EINTRLOOP (r, write (job_fds[1], &token, 1));
if (r != 1) pfatal_with_name(_("init jobserver pipe")); if (r != 1)
pfatal_with_name (_("init jobserver pipe"));
} }
/* When using pselect() we want the read to be non-blocking. */ /* When using pselect() we want the read to be non-blocking. */
set_blocking (job_fds[0], 0); set_blocking (job_fds[0], 0);
job_root = 1;
return 1; return 1;
} }
unsigned int jobserver_parse_auth(const char *auth) { unsigned int
jobserver_parse_auth (const char *auth)
{
int rfd, wfd;
/* Given the command-line parameter, parse it. */ /* Given the command-line parameter, parse it. */
if (sscanf(auth, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
OS(fatal, NILF, _("internal error: invalid --jobserver-auth string '%s'"),
auth);
DB(DB_JOBS, (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1])); /* First see if we're using a named pipe. */
if (strncmp (auth, FIFO_PREFIX, CSTRLEN (FIFO_PREFIX)) == 0)
{
fifo_name = xstrdup (auth + CSTRLEN (FIFO_PREFIX));
#ifdef HAVE_FCNTL_H EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY));
#define FD_OK(_f) (fcntl((_f), F_GETFD) != -1) if (job_fds[0] < 0)
#else {
#define FD_OK(_f) 1 OSS (error, NILF,
#endif _("cannot open jobserver %s: %s"), fifo_name, strerror (errno));
return 0;
}
/* Make sure our pipeline is valid, and (possibly) create a duplicate pipe, EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY));
that will be closed in the SIGCHLD handler. If this fails with EBADF, if (job_fds[1] < 0)
the parent has closed the pipe on us because it didn't think we were a {
submake. If so, warn and default to -j1. */ OSS (error, NILF,
_("cannot open jobserver %s: %s"), fifo_name, strerror (errno));
return 0;
}
js_type = js_fifo;
}
/* If not, it must be a simple pipe. */
else if (sscanf (auth, "%d,%d", &rfd, &wfd) == 2)
{
/* The parent overrode our FDs because we aren't a recursive make. */
if (rfd == -2 || wfd == -2)
return 0;
if (!FD_OK(job_fds[0]) || !FD_OK(job_fds[1]) || make_job_rfd() < 0) { /* Make sure our pipeline is valid. */
if (errno != EBADF) pfatal_with_name(_("jobserver pipeline")); if (!FD_OK (rfd) || !FD_OK (wfd))
return 0;
job_fds[0] = job_fds[1] = -1; job_fds[0] = rfd;
job_fds[1] = wfd;
js_type = js_pipe;
}
/* Who knows what it is? */
else
{
OS (error, NILF, _("invalid --jobserver-auth string '%s'"), auth);
return 0;
}
/* Create a duplicate pipe, if needed, that will be closed in the SIGCHLD
handler. If this fails with EBADF, the parent closed the pipe on us as
it didn't think we were a submake. If so, warn and default to -j1. */
if (make_job_rfd () < 0)
{
if (errno != EBADF)
pfatal_with_name ("jobserver readfd");
jobserver_clear ();
return 0; return 0;
} }
@ -121,37 +292,96 @@ unsigned int jobserver_parse_auth(const char *auth) {
/* When using pselect() we want the read to be non-blocking. */ /* When using pselect() we want the read to be non-blocking. */
set_blocking (job_fds[0], 0); set_blocking (job_fds[0], 0);
/* By default we don't send the job pipe FDs to our children.
See jobserver_pre_child() and jobserver_post_child(). */
fd_noinherit (job_fds[0]);
fd_noinherit (job_fds[1]);
return 1; return 1;
} }
char *jobserver_get_auth(void) { char *
char *auth = xmalloc((INTSTR_LENGTH * 2) + 2); jobserver_get_auth ()
{
char *auth;
if (js_type == js_fifo) {
auth = xmalloc (strlen (fifo_name) + CSTRLEN (FIFO_PREFIX) + 1);
sprintf (auth, FIFO_PREFIX "%s", fifo_name);
} else {
auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
sprintf (auth, "%d,%d", job_fds[0], job_fds[1]); sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
}
return auth; return auth;
} }
unsigned int jobserver_enabled(void) { const char *
return job_fds[0] >= 0; jobserver_get_invalid_auth ()
{
/* If we're using a named pipe we don't need to invalidate the jobserver. */
if (js_type == js_fifo) {
return NULL;
} }
void jobserver_clear(void) { /* It's not really great that we are assuming the command line option
if (job_fds[0] >= 0) close(job_fds[0]); here but other alternatives are also gross. */
if (job_fds[1] >= 0) close(job_fds[1]); return " --" JOBSERVER_AUTH_OPT "=-2,-2";
if (job_rfd >= 0) close(job_rfd); }
unsigned int
jobserver_enabled ()
{
return js_type != js_none;
}
void
jobserver_clear ()
{
if (job_fds[0] >= 0)
close (job_fds[0]);
if (job_fds[1] >= 0)
close (job_fds[1]);
if (job_rfd >= 0)
close (job_rfd);
job_fds[0] = job_fds[1] = job_rfd = -1; job_fds[0] = job_fds[1] = job_rfd = -1;
if (fifo_name)
{
if (job_root)
{
int r;
EINTRLOOP (r, unlink (fifo_name));
} }
void jobserver_release(int is_fatal) { if (!handling_fatal_signal)
{
free (fifo_name);
fifo_name = NULL;
}
}
js_type = js_none;
}
void
jobserver_release (int is_fatal)
{
int r; int r;
EINTRLOOP (r, write (job_fds[1], &token, 1)); EINTRLOOP (r, write (job_fds[1], &token, 1));
if (r != 1) { if (r != 1)
if (is_fatal) pfatal_with_name(_("write jobserver")); {
if (is_fatal)
pfatal_with_name (_("write jobserver"));
perror_with_name ("write", ""); perror_with_name ("write", "");
} }
} }
unsigned int jobserver_acquire_all(void) { unsigned int
jobserver_acquire_all ()
{
int r;
unsigned int tokens = 0; unsigned int tokens = 0;
/* Use blocking reads to wait for all outstanding jobs. */ /* Use blocking reads to wait for all outstanding jobs. */
@ -161,39 +391,57 @@ unsigned int jobserver_acquire_all(void) {
close (job_fds[1]); close (job_fds[1]);
job_fds[1] = -1; job_fds[1] = -1;
while (1) { while (1)
{
char intake; char intake;
int r;
EINTRLOOP (r, read (job_fds[0], &intake, 1)); EINTRLOOP (r, read (job_fds[0], &intake, 1));
if (r != 1) return tokens; if (r != 1)
break;
++tokens; ++tokens;
} }
DB (DB_JOBS, ("Acquired all %u jobserver tokens.\n", tokens));
jobserver_clear ();
return tokens;
} }
/* Prepare the jobserver to start a child process. */ /* Prepare the jobserver to start a child process. */
void jobserver_pre_child(int recursive) { void
if (recursive && job_fds[0] >= 0) { jobserver_pre_child (int recursive)
{
if (recursive && js_type == js_pipe)
{
fd_inherit (job_fds[0]); fd_inherit (job_fds[0]);
fd_inherit (job_fds[1]); fd_inherit (job_fds[1]);
} }
} }
/* Reconfigure the jobserver after starting a child process. */ /* Reconfigure the jobserver after starting a child process. */
void jobserver_post_child(int recursive) { void
if (recursive && job_fds[0] >= 0) { jobserver_post_child (int recursive)
{
if (recursive && js_type == js_pipe)
{
fd_noinherit (job_fds[0]); fd_noinherit (job_fds[0]);
fd_noinherit (job_fds[1]); fd_noinherit (job_fds[1]);
} }
} }
void jobserver_signal(void) { void
if (job_rfd >= 0) { jobserver_signal ()
{
if (job_rfd >= 0)
{
close (job_rfd); close (job_rfd);
job_rfd = -1; job_rfd = -1;
} }
} }
void jobserver_pre_acquire(void) { void
jobserver_pre_acquire ()
{
/* Make sure we have a dup'd FD. */ /* Make sure we have a dup'd FD. */
if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0) if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0)
pfatal_with_name (_("duping jobs pipe")); pfatal_with_name (_("duping jobs pipe"));
@ -208,21 +456,25 @@ void jobserver_pre_acquire(void) {
and only unblocked (atomically) within the pselect() call, so we can and only unblocked (atomically) within the pselect() call, so we can
never miss a SIGCHLD. never miss a SIGCHLD.
*/ */
unsigned int jobserver_acquire(int timeout) { unsigned int
jobserver_acquire (int timeout)
{
struct timespec spec; struct timespec spec;
struct timespec *specp = NULL; struct timespec *specp = NULL;
sigset_t empty; sigset_t empty;
sigemptyset (&empty); sigemptyset (&empty);
if (timeout) { if (timeout)
{
/* Alarm after one second (is this too granular?) */ /* Alarm after one second (is this too granular?) */
spec.tv_sec = 1; spec.tv_sec = 1;
spec.tv_nsec = 0; spec.tv_nsec = 0;
specp = &spec; specp = &spec;
} }
while (1) { while (1)
{
fd_set readfds; fd_set readfds;
int r; int r;
char intake; char intake;
@ -232,31 +484,38 @@ unsigned int jobserver_acquire(int timeout) {
r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty); r = pselect (job_fds[0]+1, &readfds, NULL, NULL, specp, &empty);
if (r < 0) if (r < 0)
switch (errno)
{ {
if (errno == EINTR) case EINTR:
/* SIGCHLD will show up as an EINTR. */ /* SIGCHLD will show up as an EINTR. */
return 0; return 0;
if (errno == EBADF)
case EBADF:
/* Someone closed the jobs pipe. /* Someone closed the jobs pipe.
That shouldn't happen but if it does we're done. */ That shouldn't happen but if it does we're done. */
O (fatal, NILF, _("job server shut down")); O (fatal, NILF, _("job server shut down"));
default:
pfatal_with_name (_("pselect jobs pipe")); pfatal_with_name (_("pselect jobs pipe"));
} }
if (r == 0) /* Timeout. */ if (r == 0)
/* Timeout. */
return 0; return 0;
/* The read FD is ready: read it! This is non-blocking. */ /* The read FD is ready: read it! This is non-blocking. */
EINTRLOOP (r, read (job_fds[0], &intake, 1)); EINTRLOOP (r, read (job_fds[0], &intake, 1));
if (r < 0) { if (r < 0)
{
/* Someone sniped our token! Try again. */ /* Someone sniped our token! Try again. */
if (errno == EAGAIN) continue; if (errno == EAGAIN)
continue;
pfatal_with_name (_("read jobs pipe")); pfatal_with_name (_("read jobs pipe"));
} }
/* read() should never return 0: only the master make can reap all the /* read() should never return 0: only the parent make can reap all the
tokens and close the write side...?? */ tokens and close the write side...?? */
return r > 0; return r > 0;
} }
@ -288,37 +547,52 @@ unsigned int jobserver_acquire(int timeout) {
during the section mentioned above, the read(2) will be invoked with an during the section mentioned above, the read(2) will be invoked with an
invalid FD and will return immediately with EBADF. */ invalid FD and will return immediately with EBADF. */
static RETSIGTYPE job_noop(int sig UNUSED) { static void
job_noop (int sig UNUSED)
{
} }
/* Set the child handler action flags to FLAGS. */ /* Set the child handler action flags to FLAGS. */
static void set_child_handler_action_flags(int set_handler, int set_alarm) { static void
set_child_handler_action_flags (int set_handler, int set_alarm)
{
struct sigaction sa; struct sigaction sa;
#ifdef __EMX__
/* The child handler must be turned off here. */
signal (SIGCHLD, SIG_DFL);
#endif
memset (&sa, '\0', sizeof sa); memset (&sa, '\0', sizeof sa);
sa.sa_handler = child_handler; sa.sa_handler = child_handler;
sa.sa_flags = set_handler ? 0 : SA_RESTART; sa.sa_flags = set_handler ? 0 : SA_RESTART;
#if defined SIGCHLD #if defined SIGCHLD
if (sigaction(SIGCHLD, &sa, NULL) < 0) pfatal_with_name("sigaction: SIGCHLD"); if (sigaction (SIGCHLD, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGCHLD");
#endif #endif
#if defined SIGCLD && SIGCLD != SIGCHLD #if defined SIGCLD && SIGCLD != SIGCHLD
if (sigaction(SIGCLD, &sa, NULL) < 0) pfatal_with_name("sigaction: SIGCLD"); if (sigaction (SIGCLD, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGCLD");
#endif #endif
#if defined SIGALRM #if defined SIGALRM
if (set_alarm) { if (set_alarm)
{
/* If we're about to enter the read(), set an alarm to wake up in a /* If we're about to enter the read(), set an alarm to wake up in a
second so we can check if the load has dropped and we can start more second so we can check if the load has dropped and we can start more
work. On the way out, turn off the alarm and set SIG_DFL. */ work. On the way out, turn off the alarm and set SIG_DFL. */
if (set_handler) { if (set_handler)
{
sa.sa_handler = job_noop; sa.sa_handler = job_noop;
sa.sa_flags = 0; sa.sa_flags = 0;
if (sigaction (SIGALRM, &sa, NULL) < 0) if (sigaction (SIGALRM, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGALRM"); pfatal_with_name ("sigaction: SIGALRM");
alarm (1); alarm (1);
} else { }
else
{
alarm (0); alarm (0);
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
sa.sa_flags = 0; sa.sa_flags = 0;
@ -329,7 +603,9 @@ static void set_child_handler_action_flags(int set_handler, int set_alarm) {
#endif #endif
} }
unsigned int jobserver_acquire(int timeout) { unsigned int
jobserver_acquire (int timeout)
{
char intake; char intake;
int got_token; int got_token;
int saved_errno; int saved_errno;
@ -342,15 +618,18 @@ unsigned int jobserver_acquire(int timeout) {
set_child_handler_action_flags (0, timeout); set_child_handler_action_flags (0, timeout);
if (got_token == 1) return 1; if (got_token == 1)
return 1;
/* If the error _wasn't_ expected (EINTR or EBADF), fatal. Otherwise, /* If the error _wasn't_ expected (EINTR or EBADF), fatal. Otherwise,
go back and reap_children(), and try again. */ go back and reap_children(), and try again. */
errno = saved_errno; errno = saved_errno;
if (errno != EINTR && errno != EBADF) pfatal_with_name(_("read jobs pipe")); if (errno != EINTR && errno != EBADF && errno != EAGAIN)
pfatal_with_name (_("read jobs pipe"));
if (errno == EBADF) DB(DB_JOBS, ("Read returned EBADF.\n")); if (errno == EBADF)
DB (DB_JOBS, ("Read returned EBADF.\n"));
return 0; return 0;
} }
@ -359,19 +638,144 @@ unsigned int jobserver_acquire(int timeout) {
#endif /* MAKE_JOBSERVER */ #endif /* MAKE_JOBSERVER */
#if !defined(NO_OUTPUT_SYNC)
#define MUTEX_PREFIX "fnm:"
static int osync_handle = -1;
static char *osync_tmpfile = NULL;
static unsigned int sync_root = 0;
unsigned int
osync_enabled ()
{
return osync_handle >= 0;
}
void
osync_setup ()
{
osync_handle = get_tmpfd (&osync_tmpfile);
fd_noinherit (osync_handle);
sync_root = 1;
}
char *
osync_get_mutex ()
{
char *mutex = NULL;
if (osync_enabled ())
{
/* Prepare the mutex handle string for our children. */
mutex = xmalloc (strlen (osync_tmpfile) + CSTRLEN (MUTEX_PREFIX) + 1);
sprintf (mutex, MUTEX_PREFIX "%s", osync_tmpfile);
}
return mutex;
}
unsigned int
osync_parse_mutex (const char *mutex)
{
if (strncmp (mutex, MUTEX_PREFIX, CSTRLEN (MUTEX_PREFIX)) != 0)
{
OS (error, NILF, _("invalid --sync-mutex string '%s'"), mutex);
return 0;
}
free (osync_tmpfile);
osync_tmpfile = xstrdup (mutex + CSTRLEN (MUTEX_PREFIX));
EINTRLOOP (osync_handle, open (osync_tmpfile, O_WRONLY));
if (osync_handle < 0)
OSS (fatal, NILF, _("cannot open output sync mutex %s: %s"),
osync_tmpfile, strerror (errno));
fd_noinherit (osync_handle);
return 1;
}
void
osync_clear ()
{
if (osync_handle >= 0)
{
close (osync_handle);
osync_handle = -1;
}
if (sync_root && osync_tmpfile)
{
int r;
EINTRLOOP (r, unlink (osync_tmpfile));
free (osync_tmpfile);
osync_tmpfile = NULL;
}
}
unsigned int
osync_acquire ()
{
if (osync_enabled())
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
/* We don't want to keep waiting on EINTR. */
if (fcntl (osync_handle, F_SETLKW, &fl) == -1)
{
perror ("fcntl()");
return 0;
}
}
return 1;
}
void
osync_release ()
{
if (osync_enabled())
{
struct flock fl;
fl.l_type = F_UNLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
/* We don't want to keep waiting on EINTR. */
if (fcntl (osync_handle, F_SETLKW, &fl) == -1)
perror ("fcntl()");
}
}
#endif
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */ /* Create a "bad" file descriptor for stdin when parallel jobs are run. */
int get_bad_stdin(void) { int
get_bad_stdin ()
{
static int bad_stdin = -1; static int bad_stdin = -1;
/* Set up a bad standard input that reads from a broken pipe. */ /* Set up a bad standard input that reads from a broken pipe. */
if (bad_stdin == -1) { if (bad_stdin == -1)
{
/* Make a file descriptor that is the read end of a broken pipe. /* Make a file descriptor that is the read end of a broken pipe.
This will be used for some children's standard inputs. */ This will be used for some children's standard inputs. */
int pd[2]; int pd[2];
if (pipe(pd) == 0) { if (pipe (pd) == 0)
{
/* Close the write side. */ /* Close the write side. */
(void)close(pd[1]); close (pd[1]);
/* Save the read side. */ /* Save the read side. */
bad_stdin = pd[0]; bad_stdin = pd[0];
@ -390,29 +794,105 @@ int get_bad_stdin(void) {
#if !defined(F_SETFD) || !defined(F_GETFD) #if !defined(F_SETFD) || !defined(F_GETFD)
void fd_inherit (int fd) {} void fd_inherit (int fd) {}
void fd_noinherit (int fd) {} void fd_noinherit (int fd) {}
#else #else
# ifndef FD_CLOEXEC # ifndef FD_CLOEXEC
# define FD_CLOEXEC 1 # define FD_CLOEXEC 1
# endif # endif
void fd_inherit(int fd) { void
fd_inherit (int fd)
{
int flags; int flags;
EINTRLOOP (flags, fcntl (fd, F_GETFD)); EINTRLOOP (flags, fcntl (fd, F_GETFD));
if (flags >= 0) { if (flags >= 0)
{
int r; int r;
flags &= ~FD_CLOEXEC; flags &= ~FD_CLOEXEC;
EINTRLOOP (r, fcntl (fd, F_SETFD, flags)); EINTRLOOP (r, fcntl (fd, F_SETFD, flags));
} }
} }
void fd_noinherit(int fd) { void
fd_noinherit (int fd)
{
int flags; int flags;
EINTRLOOP (flags, fcntl(fd, F_GETFD)); EINTRLOOP (flags, fcntl(fd, F_GETFD));
if (flags >= 0) { if (flags >= 0)
{
int r; int r;
flags |= FD_CLOEXEC; flags |= FD_CLOEXEC;
EINTRLOOP (r, fcntl(fd, F_SETFD, flags)); EINTRLOOP (r, fcntl(fd, F_SETFD, flags));
} }
} }
#endif #endif
/* Set a file descriptor referring to a regular file to be in O_APPEND mode.
If it fails, just ignore it. */
void
fd_set_append (int fd)
{
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
struct stat stbuf;
int flags;
if (fstat (fd, &stbuf) == 0 && S_ISREG (stbuf.st_mode))
{
flags = fcntl (fd, F_GETFL, 0);
if (flags >= 0)
{
int r;
EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND));
}
}
#endif
}
/* Return a file descriptor for a new anonymous temp file, or -1. */
int
os_anontmp ()
{
const char *tdir = get_tmpdir ();
int fd = -1;
if (IsLinux ())
{
static unsigned int tmpfile_works = 1;
if (tmpfile_works)
{
EINTRLOOP (fd, open (tdir, O_RDWR | O_TMPFILE | O_EXCL, 0600));
if (fd >= 0)
return fd;
DB (DB_BASIC, (_("Cannot open '%s' with O_TMPFILE: %s.\n"),
tdir, strerror (errno)));
tmpfile_works = 0;
}
}
#if HAVE_DUP
/* If we can dup and we are creating temp files in the default location then
try tmpfile() + dup() + fclose() to avoid ever having a named file. */
if (streq (tdir, DEFAULT_TMPDIR))
{
mode_t mask = umask (0077);
FILE *tfile;
ENULLLOOP (tfile, tmpfile ());
if (!tfile)
{
OS (error, NILF, "tmpfile: %s", strerror (errno));
return -1;
}
umask (mask);
EINTRLOOP (fd, dup (fileno (tfile)));
if (fd < 0)
OS (error, NILF, "dup: %s", strerror (errno));
fclose (tfile);
}
#endif
return fd;
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Basic dependency engine for GNU Make. /* Basic dependency engine for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,16 +12,39 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "filedef.h"
#include "job.h"
#include "commands.h"
#include "dep.h"
#include "variable.h"
#include "debug.h"
#include <assert.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
#include <sys/file.h>
#endif
#ifdef VMS
#include <starlet.h>
#endif
#ifdef WINDOWS32
#include <windows.h>
#include <io.h>
#include <sys/stat.h>
#if defined(_MSC_VER) && _MSC_VER > 1200
/* VC7 or later supports _stat64 to access 64-bit file size. */
#define STAT _stat64
#else
#define STAT stat
#endif
#endif
#include "third_party/make/makeint.inc"
#include "third_party/make/filedef.h"
#include "third_party/make/job.h"
#include "third_party/make/commands.h"
#include "third_party/make/dep.h"
#include "third_party/make/variable.h"
#include "libc/runtime/runtime.h"
#include "third_party/make/debug.h"
/* The test for circular dependencies is based on the 'updating' bit in /* The test for circular dependencies is based on the 'updating' bit in
'struct file'. However, double colon targets have separate 'struct 'struct file'. However, double colon targets have separate 'struct
@ -56,8 +79,27 @@ static FILE_TIMESTAMP name_mtime (const char *name);
static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr); static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
/* Remake all the goals in the 'struct dep' chain GOALS. Return -1 if nothing static void
was done, 0 if all goals were updated successfully, or 1 if a goal failed. check_also_make (const struct file *file)
{
struct dep *ad;
FILE_TIMESTAMP mtime = file->last_mtime;
if (mtime == UNKNOWN_MTIME)
mtime = name_mtime (file->name);
/* If we updated the file, check its also-make files. */
if (is_ordinary_mtime (mtime) && mtime > file->mtime_before_update)
for (ad = file->also_make; ad; ad = ad->next)
if (ad->file->last_mtime == NONEXISTENT_MTIME)
OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
_("warning: pattern recipe did not update peer target '%s'."),
ad->file->name);
}
/* Remake all the goals in the 'struct dep' chain GOALS. Return update_status
representing the totality of the status of the goals.
If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q, If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q,
and -n should be disabled for them unless they were also command-line and -n should be disabled for them unless they were also command-line
@ -67,12 +109,13 @@ static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
enum update_status enum update_status
update_goal_chain (struct goaldep *goaldeps) update_goal_chain (struct goaldep *goaldeps)
{ {
unsigned long last_cmd_count = 0;
int t = touch_flag, q = question_flag, n = just_print_flag; int t = touch_flag, q = question_flag, n = just_print_flag;
enum update_status status = us_none; enum update_status status = us_none;
/* Duplicate the chain so we can remove things from it. */ /* Duplicate the chain so we can remove things from it. */
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
struct dep *goals = copy_dep_chain ((struct dep *)goaldeps); struct dep *goals = goals_orig;
goal_list = rebuilding_makefiles ? goaldeps : NULL; goal_list = rebuilding_makefiles ? goaldeps : NULL;
@ -86,24 +129,29 @@ update_goal_chain (struct goaldep *goaldeps)
while (goals != 0) while (goals != 0)
{ {
struct dep *g, *lastgoal; struct dep *gu, *g, *lastgoal;
/* Start jobs that are waiting for the load to go down. */ /* Start jobs that are waiting for the load to go down. */
start_waiting_jobs (); start_waiting_jobs ();
/* Wait for a child to die. */ /* Check for exited children. If no children have finished since the
last time we looked, then block until one exits. If some have
exited don't block, so we can possibly do more work. */
reap_children (1, 0); reap_children (last_cmd_count == command_count, 0);
last_cmd_count = command_count;
lastgoal = 0; lastgoal = 0;
g = goals; gu = goals;
while (g != 0) while (gu != 0)
{ {
/* Iterate over all double-colon entries for this file. */ /* Iterate over all double-colon entries for this file. */
struct file *file; struct file *file;
int stop = 0, any_not_updated = 0; int stop = 0, any_not_updated = 0;
g = gu->shuf ? gu->shuf : gu;
goal_dep = g; goal_dep = g;
for (file = g->file->double_colon ? g->file->double_colon : g->file; for (file = g->file->double_colon ? g->file->double_colon : g->file;
@ -163,8 +211,7 @@ update_goal_chain (struct goaldep *goaldeps)
FILE_TIMESTAMP mtime = MTIME (file); FILE_TIMESTAMP mtime = MTIME (file);
check_renamed (file); check_renamed (file);
if (file->updated && g->changed && if (file->updated && mtime != file->mtime_before_update)
mtime != file->mtime_before_update)
{ {
/* Updating was done. If this is a makefile and /* Updating was done. If this is a makefile and
just_print_flag or question_flag is set (meaning just_print_flag or question_flag is set (meaning
@ -214,31 +261,30 @@ update_goal_chain (struct goaldep *goaldeps)
/* This goal is finished. Remove it from the chain. */ /* This goal is finished. Remove it from the chain. */
if (lastgoal == 0) if (lastgoal == 0)
goals = g->next; goals = gu->next;
else else
lastgoal->next = g->next; lastgoal->next = gu->next;
/* Free the storage. */ gu = lastgoal == 0 ? goals : lastgoal->next;
free (g);
g = lastgoal == 0 ? goals : lastgoal->next;
if (stop) if (stop)
break; break;
} }
else else
{ {
lastgoal = g; lastgoal = gu;
g = g->next; gu = gu->next;
} }
} }
/* If we reached the end of the dependency graph update CONSIDERED /* If we reached the end of the dependency graph update CONSIDERED
for the next pass. */ for the next pass. */
if (g == 0) if (gu == 0)
++considered; ++considered;
} }
free_dep_chain (goals_orig);
if (rebuilding_makefiles) if (rebuilding_makefiles)
{ {
touch_flag = t; touch_flag = t;
@ -266,7 +312,7 @@ show_goal_error (void)
if (goal->error) if (goal->error)
{ {
OSS (error, &goal->floc, "%s: %s", OSS (error, &goal->floc, "%s: %s",
goal->file->name, strerror ((int)goal->error)); goal->file->name, strerror (goal->error));
goal->error = 0; goal->error = 0;
} }
return; return;
@ -322,8 +368,7 @@ update_file (struct file *file, unsigned int depth)
check_renamed (f); check_renamed (f);
/* Clean up any alloca() used during the update. */ /* Clean up any alloca() used during the update. */
void *volatile wat = alloca (0); free_alloca ();
(void)wat;
/* If we got an error, don't bother with double_colon etc. */ /* If we got an error, don't bother with double_colon etc. */
if (new && !keep_going_flag) if (new && !keep_going_flag)
@ -395,7 +440,7 @@ complain (struct file *file)
} }
/* Consider a single 'struct file' and update it as appropriate. /* Consider a single 'struct file' and update it as appropriate.
Return 0 on success, or non-0 on failure. */ Return an update_status value; use us_success if we aren't sure yet. */
static enum update_status static enum update_status
update_file_1 (struct file *file, unsigned int depth) update_file_1 (struct file *file, unsigned int depth)
@ -404,7 +449,7 @@ update_file_1 (struct file *file, unsigned int depth)
FILE_TIMESTAMP this_mtime; FILE_TIMESTAMP this_mtime;
int noexist, must_make, deps_changed; int noexist, must_make, deps_changed;
struct file *ofile; struct file *ofile;
struct dep *d, *ad; struct dep *du, *d, *ad;
struct dep amake; struct dep amake;
int running = 0; int running = 0;
@ -428,7 +473,7 @@ update_file_1 (struct file *file, unsigned int depth)
} }
DBF (DB_VERBOSE, _("File '%s' was considered already.\n")); DBF (DB_VERBOSE, _("File '%s' was considered already.\n"));
return 0; return us_success;
} }
switch (file->command_state) switch (file->command_state)
@ -438,7 +483,7 @@ update_file_1 (struct file *file, unsigned int depth)
break; break;
case cs_running: case cs_running:
DBF (DB_VERBOSE, _("Still updating file '%s'.\n")); DBF (DB_VERBOSE, _("Still updating file '%s'.\n"));
return 0; return us_success;
case cs_finished: case cs_finished:
DBF (DB_VERBOSE, _("Finished updating file '%s'.\n")); DBF (DB_VERBOSE, _("Finished updating file '%s'.\n"));
return file->update_status; return file->update_status;
@ -450,8 +495,6 @@ update_file_1 (struct file *file, unsigned int depth)
fail. */ fail. */
file->no_diag = file->dontcare; file->no_diag = file->dontcare;
++depth;
/* Notice recursive update of the same file. */ /* Notice recursive update of the same file. */
start_updating (file); start_updating (file);
@ -459,6 +502,9 @@ update_file_1 (struct file *file, unsigned int depth)
remember this one to turn off updating. */ remember this one to turn off updating. */
ofile = file; ofile = file;
/* Increase the depth for reporting how we build the file. */
++depth;
/* Looking at the file's modtime beforehand allows the possibility /* Looking at the file's modtime beforehand allows the possibility
that its name may be changed by a VPATH search, and thus it may that its name may be changed by a VPATH search, and thus it may
not need an implicit rule. If this were not done, the file not need an implicit rule. If this were not done, the file
@ -470,8 +516,7 @@ update_file_1 (struct file *file, unsigned int depth)
noexist = this_mtime == NONEXISTENT_MTIME; noexist = this_mtime == NONEXISTENT_MTIME;
if (noexist) if (noexist)
DBF (DB_BASIC, _("File '%s' does not exist.\n")); DBF (DB_BASIC, _("File '%s' does not exist.\n"));
else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX else if (is_ordinary_mtime (this_mtime) && file->low_resolution_time)
&& file->low_resolution_time)
{ {
/* Avoid spurious rebuilds due to low resolution time stamps. */ /* Avoid spurious rebuilds due to low resolution time stamps. */
int ns = FILE_TIMESTAMP_NS (this_mtime); int ns = FILE_TIMESTAMP_NS (this_mtime);
@ -482,17 +527,34 @@ update_file_1 (struct file *file, unsigned int depth)
this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns; this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
} }
/* If any also_make target doesn't exist, we must remake this one too.
If they do exist choose the oldest mtime so they will rebuild. */
for (ad = file->also_make; ad && !noexist; ad = ad->next)
{
struct file *adfile = ad->file;
FILE_TIMESTAMP fmtime = file_mtime (adfile);
noexist = fmtime == NONEXISTENT_MTIME;
if (noexist)
{
check_renamed (adfile);
DBS (DB_BASIC,
(_("Grouped target peer '%s' of file '%s' does not exist.\n"),
adfile->name, file->name));
}
else if (fmtime < this_mtime)
this_mtime = fmtime;
}
must_make = noexist; must_make = noexist;
/* If file was specified as a target with no commands, /* If file was specified as a target with no commands, come up with some
come up with some default commands. */ default commands. This may also add more also_make files. */
if (!file->phony && file->cmds == 0 && !file->tried_implicit) if (!file->phony && file->cmds == 0 && !file->tried_implicit)
{ {
if (try_implicit_rule (file, depth)) try_implicit_rule (file, depth);
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
else
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
file->tried_implicit = 1; file->tried_implicit = 1;
} }
if (file->cmds == 0 && !file->is_target if (file->cmds == 0 && !file->is_target
@ -514,17 +576,28 @@ update_file_1 (struct file *file, unsigned int depth)
{ {
struct dep *lastd = 0; struct dep *lastd = 0;
/* Perform second expansion and enter each dependency name as a file.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. */
if (second_expansion)
expand_deps (ad->file);
/* Find the deps we're scanning */ /* Find the deps we're scanning */
d = ad->file->deps; du = ad->file->deps;
ad = ad->next; ad = ad->next;
while (d) while (du)
{ {
enum update_status new; enum update_status new;
FILE_TIMESTAMP mtime; FILE_TIMESTAMP mtime;
int maybe_make; int maybe_make;
int dontcare = 0; int dontcare = 0;
d = du->shuf ? du->shuf : du;
if (d->wait_here && running)
break;
check_renamed (d->file); check_renamed (d->file);
mtime = file_mtime (d->file); mtime = file_mtime (d->file);
@ -534,14 +607,16 @@ update_file_1 (struct file *file, unsigned int depth)
{ {
OSS (error, NILF, _("Circular %s <- %s dependency dropped."), OSS (error, NILF, _("Circular %s <- %s dependency dropped."),
file->name, d->file->name); file->name, d->file->name);
/* We cannot free D here because our the caller will still have /* We cannot free D here because our the caller will still have
a reference to it when we were called recursively via a reference to it when we were called recursively via
check_dep below. */ check_dep below. */
if (lastd == 0) if (lastd == 0)
file->deps = d->next; file->deps = du->next;
else else
lastd->next = d->next; lastd->next = du->next;
d = d->next;
du = du->next;
continue; continue;
} }
@ -590,8 +665,8 @@ update_file_1 (struct file *file, unsigned int depth)
d->changed = ((file_mtime (d->file) != mtime) d->changed = ((file_mtime (d->file) != mtime)
|| (mtime == NONEXISTENT_MTIME)); || (mtime == NONEXISTENT_MTIME));
lastd = d; lastd = du;
d = d->next; du = du->next;
} }
} }
@ -600,7 +675,13 @@ update_file_1 (struct file *file, unsigned int depth)
if (must_make || always_make_flag) if (must_make || always_make_flag)
{ {
for (d = file->deps; d != 0; d = d->next) for (du = file->deps; du != 0; du = du->next)
{
d = du->shuf ? du->shuf : du;
if (d->wait_here && running)
break;
if (d->file->intermediate) if (d->file->intermediate)
{ {
enum update_status new; enum update_status new;
@ -653,20 +734,23 @@ update_file_1 (struct file *file, unsigned int depth)
|| file_mtime (d->file) != mtime); || file_mtime (d->file) != mtime);
} }
} }
}
finish_updating (file); finish_updating (file);
finish_updating (ofile); finish_updating (ofile);
DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n")); /* We've decided what we need to do to build the file. */
--depth;
if (running) if (running)
{ {
set_command_state (file, cs_deps_running); set_command_state (file, cs_deps_running);
--depth;
DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n")); DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n"));
return 0; return us_success;
} }
DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n"));
/* If any dependency failed, give up now. */ /* If any dependency failed, give up now. */
if (dep_status) if (dep_status)
@ -675,8 +759,6 @@ update_file_1 (struct file *file, unsigned int depth)
file->update_status = dep_status == us_none ? us_failed : dep_status; file->update_status = dep_status == us_none ? us_failed : dep_status;
notice_finished_file (file); notice_finished_file (file);
--depth;
DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n")); DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n"));
if (depth == 0 && keep_going_flag if (depth == 0 && keep_going_flag
@ -751,16 +833,13 @@ update_file_1 (struct file *file, unsigned int depth)
if (fmt) if (fmt)
{ {
print_spaces (depth); print_spaces (depth+1);
printf (fmt, dep_name (d), file->name); printf (fmt, dep_name (d), file->name);
fflush (stdout); fflush (stdout);
} }
} }
} }
/* Here depth returns to the value it had when we were called. */
depth--;
if (file->double_colon && file->deps == 0) if (file->double_colon && file->deps == 0)
{ {
must_make = 1; must_make = 1;
@ -792,6 +871,11 @@ update_file_1 (struct file *file, unsigned int depth)
fflush (stdout); fflush (stdout);
} }
/* Since make has not created this file, make should not remove it,
even if the file is intermediate. */
if (!file->notintermediate && no_intermediates == 0)
file->secondary = 1;
notice_finished_file (file); notice_finished_file (file);
/* Since we don't need to remake the file, convert it to use the /* Since we don't need to remake the file, convert it to use the
@ -804,7 +888,7 @@ update_file_1 (struct file *file, unsigned int depth)
file = file->prev; file = file->prev;
} }
return 0; return us_success;
} }
DBF (DB_BASIC, _("Must remake target '%s'.\n")); DBF (DB_BASIC, _("Must remake target '%s'.\n"));
@ -823,7 +907,7 @@ update_file_1 (struct file *file, unsigned int depth)
if (file->command_state != cs_finished) if (file->command_state != cs_finished)
{ {
DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n")); DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n"));
return 0; return us_success;
} }
switch (file->update_status) switch (file->update_status)
@ -876,7 +960,7 @@ notice_finished_file (struct file *file)
we don't want to do the touching. */ we don't want to do the touching. */
unsigned int i; unsigned int i;
for (i = 0; i < file->cmds->ncommand_lines; ++i) for (i = 0; i < file->cmds->ncommand_lines; ++i)
if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE)) if (NONE_SET (file->cmds->lines_flags[i], COMMANDS_RECURSE))
goto have_nonrecursing; goto have_nonrecursing;
} }
else else
@ -917,7 +1001,7 @@ notice_finished_file (struct file *file)
if ((question_flag || just_print_flag || touch_flag) && file->cmds) if ((question_flag || just_print_flag || touch_flag) && file->cmds)
{ {
for (i = file->cmds->ncommand_lines; i > 0; --i) for (i = file->cmds->ncommand_lines; i > 0; --i)
if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE)) if (NONE_SET (file->cmds->lines_flags[i-1], COMMANDS_RECURSE))
break; break;
} }
@ -958,6 +1042,7 @@ notice_finished_file (struct file *file)
} }
if (ran && file->update_status != us_none) if (ran && file->update_status != us_none)
{
/* We actually tried to update FILE, which has /* We actually tried to update FILE, which has
updated its also_make's as well (if it worked). updated its also_make's as well (if it worked).
If it didn't work, it wouldn't work again for them. If it didn't work, it wouldn't work again for them.
@ -975,6 +1060,12 @@ notice_finished_file (struct file *file)
never be done because the target is already updated. */ never be done because the target is already updated. */
f_mtime (d->file, 0); f_mtime (d->file, 0);
} }
/* If the target was created by an implicit rule, and it was updated,
warn about any of its also_make targets that don't exist. */
if (file->tried_implicit && file->also_make)
check_also_make (file);
}
else if (file->update_status == us_none) else if (file->update_status == us_none)
/* Nothing was done for FILE, but it needed nothing done. /* Nothing was done for FILE, but it needed nothing done.
So mark it now as "succeeded". */ So mark it now as "succeeded". */
@ -995,7 +1086,6 @@ check_dep (struct file *file, unsigned int depth,
struct dep *d; struct dep *d;
enum update_status dep_status = us_success; enum update_status dep_status = us_success;
++depth;
start_updating (file); start_updating (file);
/* We might change file if we find a different one via vpath; /* We might change file if we find a different one via vpath;
@ -1021,10 +1111,7 @@ check_dep (struct file *file, unsigned int depth,
if (!file->phony && file->cmds == 0 && !file->tried_implicit) if (!file->phony && file->cmds == 0 && !file->tried_implicit)
{ {
if (try_implicit_rule (file, depth)) try_implicit_rule (file, depth);
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
else
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
file->tried_implicit = 1; file->tried_implicit = 1;
} }
if (file->cmds == 0 && !file->is_target if (file->cmds == 0 && !file->is_target
@ -1063,6 +1150,12 @@ check_dep (struct file *file, unsigned int depth,
} }
ld = 0; ld = 0;
/* Perform second expansion and enter each dependency name as a file.
We only need to do this if second_expansion has been defined; if it
hasn't then all deps were expanded as the makefile was read in. */
if (second_expansion)
expand_deps (file);
d = file->deps; d = file->deps;
while (d != 0) while (d != 0)
{ {
@ -1090,7 +1183,7 @@ check_dep (struct file *file, unsigned int depth,
d->file->parent = file; d->file->parent = file;
maybe_make = *must_make_ptr; maybe_make = *must_make_ptr;
new = check_dep (d->file, depth, this_mtime, &maybe_make); new = check_dep (d->file, depth+1, this_mtime, &maybe_make);
if (new > dep_status) if (new > dep_status)
dep_status = new; dep_status = new;
@ -1249,7 +1342,7 @@ f_mtime (struct file *file, int search)
if (ar_name (file->name)) if (ar_name (file->name))
{ {
/* This file is an archive-member reference. */ /* This file is an archive-member reference. */
FILE_TIMESTAMP memmtime;
char *arname, *memname; char *arname, *memname;
struct file *arfile; struct file *arfile;
time_t member_date; time_t member_date;
@ -1257,6 +1350,9 @@ f_mtime (struct file *file, int search)
/* Find the archive's name. */ /* Find the archive's name. */
ar_parse_name (file->name, &arname, &memname); ar_parse_name (file->name, &arname, &memname);
/* Find the mtime of the member file (it might not exist). */
memmtime = name_mtime (memname);
/* Find the modification time of the archive itself. /* Find the modification time of the archive itself.
Also allow for its name to be changed via VPATH search. */ Also allow for its name to be changed via VPATH search. */
arfile = lookup_file (arname); arfile = lookup_file (arname);
@ -1300,9 +1396,16 @@ f_mtime (struct file *file, int search)
return NONEXISTENT_MTIME; return NONEXISTENT_MTIME;
member_date = ar_member_date (file->hname); member_date = ar_member_date (file->hname);
mtime = (member_date == (time_t) -1
? NONEXISTENT_MTIME if (member_date == (time_t) -1
: file_timestamp_cons (file->hname, member_date, 0)); || (memmtime != NONEXISTENT_MTIME
&& (time_t) FILE_TIMESTAMP_S (memmtime) > member_date))
/* If the member file exists and is newer than the member in the
archive, pretend it's nonexistent. This means the member file was
updated but not added to the archive yet. */
mtime = NONEXISTENT_MTIME;
else
mtime = file_timestamp_cons (file->hname, member_date, 0);
} }
else else
#endif #endif
@ -1328,7 +1431,13 @@ f_mtime (struct file *file, int search)
/* If we found it in VPATH, see if it's in GPATH too; if so, /* If we found it in VPATH, see if it's in GPATH too; if so,
change the name right now; if not, defer until after the change the name right now; if not, defer until after the
dependencies are updated. */ dependencies are updated. */
#ifndef VMS
name_len = strlen (name) - strlen (file->name) - 1; name_len = strlen (name) - strlen (file->name) - 1;
#else
name_len = strlen (name) - strlen (file->name);
if (name[name_len - 1] == '/')
name_len--;
#endif
if (gpath_search (name, name_len)) if (gpath_search (name, name_len))
{ {
rename_file (file, name); rename_file (file, name);
@ -1386,7 +1495,7 @@ f_mtime (struct file *file, int search)
/ 1e9)); / 1e9));
char from_now_string[100]; char from_now_string[100];
if (from_now >= 99 && from_now <= ULONG_MAX) if (from_now >= 100.0 && from_now < (double) ULONG_MAX)
sprintf (from_now_string, "%lu", (unsigned long) from_now); sprintf (from_now_string, "%lu", (unsigned long) from_now);
else else
sprintf (from_now_string, "%.2g", from_now); sprintf (from_now_string, "%.2g", from_now);
@ -1438,12 +1547,16 @@ static FILE_TIMESTAMP
name_mtime (const char *name) name_mtime (const char *name)
{ {
FILE_TIMESTAMP mtime; FILE_TIMESTAMP mtime;
#if defined(WINDOWS32)
struct STAT st;
#else
struct stat st; struct stat st;
#endif
int e; int e;
#if defined(WINDOWS32) #if defined(WINDOWS32)
{ {
char tem[MAXPATHLEN], *tstart, *tend; char tem[MAX_PATH+1], *tstart, *tend;
const char *p = name + strlen (name); const char *p = name + strlen (name);
/* Remove any trailing slashes and "."/"..". MS-Windows stat /* Remove any trailing slashes and "."/"..". MS-Windows stat
@ -1461,7 +1574,7 @@ name_mtime (const char *name)
tend--; tend--;
if (*tend == '.' && tend > tstart) if (*tend == '.' && tend > tstart)
tend--; tend--;
for ( ; tend > tstart && (*tend == '/' || *tend == '\\'); tend--) for ( ; tend > tstart && ISDIRSEP (*tend); tend--)
*tend = '\0'; *tend = '\0';
} }
else else
@ -1470,7 +1583,11 @@ name_mtime (const char *name)
tend = &tem[0]; tend = &tem[0];
} }
#if defined(WINDOWS32)
e = STAT (tem, &st);
#else
e = stat (tem, &st); e = stat (tem, &st);
#endif
if (e == 0 && !_S_ISDIR (st.st_mode) && tend < tem + (p - name - 1)) if (e == 0 && !_S_ISDIR (st.st_mode) && tend < tem + (p - name - 1))
{ {
errno = ENOTDIR; errno = ENOTDIR;
@ -1535,7 +1652,7 @@ name_mtime (const char *name)
mtime = ltime; mtime = ltime;
/* Set up to check the file pointed to by this link. */ /* Set up to check the file pointed to by this link. */
EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX)); EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX - 1));
if (llen < 0) if (llen < 0)
{ {
/* Eh? Just take what we have. */ /* Eh? Just take what we have. */
@ -1572,7 +1689,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
{ {
static const char *dirs[] = static const char *dirs[] =
{ {
#if !defined(_AMIGA) && !defined(__COSMOPOLITAN__) #ifndef _AMIGA
"/lib", "/lib",
"/usr/lib", "/usr/lib",
#endif #endif
@ -1583,7 +1700,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
*/ */
#define LIBDIR "." #define LIBDIR "."
#endif #endif
LIBDIR, /* Defined by configuration. */ // LIBDIR, /* Defined by configuration. */
0 0
}; };
@ -1618,7 +1735,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
static size_t buflen = 0; static size_t buflen = 0;
static size_t libdir_maxlen = 0; static size_t libdir_maxlen = 0;
static unsigned int std_dirs = 0; static unsigned int std_dirs = 0;
char *libbuf = variable_expand (""); char *libbuf;
/* Expand the pattern using LIB as a replacement. */ /* Expand the pattern using LIB as a replacement. */
{ {
@ -1635,10 +1752,12 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
p[len] = c; p[len] = c;
continue; continue;
} }
p4 = variable_buffer_output (libbuf, p, p3-p); p4 = variable_buffer_output (variable_buffer, p, p3-p);
p4 = variable_buffer_output (p4, lib, liblen); p4 = variable_buffer_output (p4, lib, liblen);
p4 = variable_buffer_output (p4, p3+1, len - (p3-p)); p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
p[len] = c; p[len] = c;
libbuf = variable_buffer;
} }
/* Look first for 'libNAME.a' in the current directory. */ /* Look first for 'libNAME.a' in the current directory. */

297
third_party/make/remote-cstms.c vendored Normal file
View file

@ -0,0 +1,297 @@
/* GNU Make remote job exportation interface to the Customs daemon.
THIS CODE IS NOT SUPPORTED BY THE GNU PROJECT.
Please do not send bug reports or questions about it to
the Make maintainers.
Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "filedef.h"
#include "job.h"
#include "commands.h"
#include "debug.h"
#if HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <netdb.h>
#include "customs.h"
char *remote_description = "Customs";
/* File name of the Customs 'export' client command.
A full path name can be used to avoid some path-searching overhead. */
#define EXPORT_COMMAND "/usr/local/bin/export"
/* ExportPermit gotten by start_remote_job_p, and used by start_remote_job. */
static ExportPermit permit;
/* Normalized path name of the current directory. */
static char *normalized_cwd;
/* Call once at startup even if no commands are run. */
void
remote_setup (void)
{
}
/* Called before exit. */
void
remote_cleanup (void)
{
}
/* Return nonzero if the next job should be done remotely. */
int
start_remote_job_p (int first_p)
{
static int inited = 0;
int status;
int njobs;
if (!inited)
{
/* Allow the user to turn off job exportation (useful while he is
debugging Customs, for example). */
if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0)
{
inited = -1;
return 0;
}
if (ISDB (DB_JOBS))
Rpc_Debug (1);
/* Ping the daemon once to see if it is there. */
inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1;
if (starting_directory == 0)
/* main couldn't figure it out. */
inited = -1;
else
{
/* Normalize the current directory path name to something
that should work on all machines exported to. */
normalized_cwd = xmalloc (GET_PATH_MAX);
strcpy (normalized_cwd, starting_directory);
if (Customs_NormPath (normalized_cwd, GET_PATH_MAX) < 0)
/* Path normalization failure means using Customs
won't work, but it's not really an error. */
inited = -1;
}
}
if (inited < 0)
return 0;
njobs = job_slots_used;
if (!first_p)
njobs -= 1; /* correction for being called from reap_children() */
/* the first job should run locally, or, if the -l flag is given, we use
that as clue as to how many local jobs should be scheduled locally */
if (max_load_average < 0 && njobs == 0 || njobs < max_load_average)
return 0;
status = Customs_Host (EXPORT_SAME, &permit);
if (status != RPC_SUCCESS)
{
DB (DB_JOBS, (_("Customs won't export: %s\n"),
Rpc_ErrorMessage (status)));
return 0;
}
return !CUSTOMS_FAIL (&permit.addr);
}
/* Start a remote job running the command in ARGV, with environment from
ENVP. It gets standard input from STDIN_FD. On failure, return
nonzero. On success, return zero, and set *USED_STDIN to nonzero if it
will actually use STDIN_FD, zero if not, set *ID_PTR to a unique
identification, and set *IS_REMOTE to nonzero if the job is remote, zero
if it is local (meaning *ID_PTR is a process ID). */
int
start_remote_job (char **argv, char **envp, int stdin_fd,
int *is_remote, pid_t *id_ptr, int *used_stdin)
{
char waybill[MAX_DATA_SIZE], msg[128];
struct hostent *host;
struct timeval timeout;
struct sockaddr_in sin;
int len;
int retsock, retport, sock;
Rpc_Stat status;
pid_t pid;
/* Create the return socket. */
retsock = Rpc_UdpCreate (True, 0);
if (retsock < 0)
{
O (error, NILF, "exporting: Couldn't create return socket.");
return 1;
}
/* Get the return socket's port number. */
len = sizeof (sin);
if (getsockname (retsock, (struct sockaddr *) &sin, &len) < 0)
{
(void) close (retsock);
perror_with_name ("exporting: ", "getsockname");
return 1;
}
retport = sin.sin_port;
/* Create the TCP socket for talking to the remote child. */
sock = Rpc_TcpCreate (False, 0);
/* Create a WayBill to give to the server. */
len = Customs_MakeWayBill (&permit, normalized_cwd, argv[0], argv,
envp, retport, waybill);
/* Modify the waybill for the child's uid/gid. */
{
WayBill *wb = (WayBill *) waybill;
wb->ruid = wb->euid;
wb->rgid = wb->egid;
}
/* Send the request to the server, timing out in 20 seconds. */
timeout.tv_usec = 0;
timeout.tv_sec = 20;
sin.sin_family = AF_INET;
sin.sin_port = htons (Customs_Port ());
sin.sin_addr = permit.addr;
status = Rpc_Call (sock, &sin, (Rpc_Proc) CUSTOMS_IMPORT,
len, (Rpc_Opaque) waybill,
sizeof (msg), (Rpc_Opaque) msg,
1, &timeout);
host = gethostbyaddr ((char *)&permit.addr, sizeof(permit.addr), AF_INET);
{
const char *hnm = host ? host->h_name : inet_ntoa (permit.addr);
size_t hlen = strlen (hnm);
if (status != RPC_SUCCESS)
{
const char *err = Rpc_ErrorMessage (status);
(void) close (retsock);
(void) close (sock);
error (NILF, hlen + strlen (err),
"exporting to %s: %s", hnm, err);
return 1;
}
else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0')
{
(void) close (retsock);
(void) close (sock);
error (NILF, hlen + strlen (msg), "exporting to %s: %s", hnm, msg);
return 1;
}
else
{
error (NILF, hlen + INTSTR_LENGTH,
"*** exported to %s (id %u)", hnm, permit.id);
}
fflush (stdout);
fflush (stderr);
}
pid = vfork ();
if (pid < 0)
{
/* The fork failed! */
perror_with_name ("fork", "");
return 1;
}
else if (pid == 0)
{
/* Child side. Run 'export' to handle the connection. */
static char sock_buf[INTSTR_LENGTH], retsock_buf[INTSTR_LENGTH];
static char id_buf[INTSTR_LENGTH];
static char *new_argv[6] =
{ EXPORT_COMMAND, "-id", sock_buf, retsock_buf, id_buf, 0 };
/* Set up the arguments. */
(void) sprintf (sock_buf, "%d", sock);
(void) sprintf (retsock_buf, "%d", retsock);
(void) sprintf (id_buf, "%x", permit.id);
/* Get the right stdin. */
if (stdin_fd != 0)
(void) dup2 (stdin_fd, 0);
/* Unblock signals in the child. */
unblock_all_sigs ();
/* Run the command. */
exec_command (new_argv, envp);
}
/* Parent side. Return the 'export' process's ID. */
(void) close (retsock);
(void) close (sock);
*is_remote = 0;
*id_ptr = pid;
*used_stdin = 1;
return 0;
}
/* Get the status of a dead remote child. Block waiting for one to die
if BLOCK is nonzero. Set *EXIT_CODE_PTR to the exit status, *SIGNAL_PTR
to the termination signal or zero if it exited normally, and *COREDUMP_PTR
nonzero if it dumped core. Return the ID of the child that died,
0 if we would have to block and !BLOCK, or < 0 if there were none. */
int
remote_status (int *exit_code_ptr, int *signal_ptr, int *coredump_ptr,
int block)
{
return -1;
}
/* Block asynchronous notification of remote child death.
If this notification is done by raising the child termination
signal, do not block that signal. */
void
block_remote_children (void)
{
return;
}
/* Restore asynchronous notification of remote child death.
If this is done by raising the child termination signal,
do not unblock that signal. */
void
unblock_remote_children (void)
{
return;
}
/* Send signal SIG to child ID. Return 0 if successful, -1 if not. */
int
remote_kill (pid_t id, int sig)
{
return -1;
}

View file

@ -1,5 +1,5 @@
/* Template for the remote job exportation interface to GNU Make. /* Template for the remote job exportation interface to GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,12 +12,12 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h" #include "filedef.h"
#include "third_party/make/job.h" #include "job.h"
#include "third_party/make/commands.h" #include "commands.h"
char *remote_description = 0; char *remote_description = 0;

View file

@ -1,5 +1,5 @@
/* Pattern and suffix rule internals for GNU Make. /* Pattern and suffix rule internals for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,16 +12,18 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h"
#include "third_party/make/dep.h" #include <assert.h>
#include "third_party/make/job.h"
#include "third_party/make/commands.h" #include "filedef.h"
#include "third_party/make/variable.h" #include "dep.h"
#include "libc/runtime/runtime.h" #include "job.h"
#include "third_party/make/rule.h" #include "commands.h"
#include "variable.h"
#include "rule.h"
static void freerule (struct rule *rule, struct rule *lastrule); static void freerule (struct rule *rule, struct rule *lastrule);
@ -57,6 +59,63 @@ struct file *suffix_file;
/* Maximum length of a suffix. */ /* Maximum length of a suffix. */
static size_t maxsuffix; static size_t maxsuffix;
/* Return the rule definition: space separated rule targets, followed by
either a colon or two colons in the case of a terminal rule, followed by
space separated rule prerequisites, followed by a pipe, followed by
order-only prerequisites, if present. */
const char *
get_rule_defn (struct rule *r)
{
if (r->_defn == NULL)
{
size_t len = 8; /* Reserve for ":: ", " | ", and nul. */
unsigned int k;
char *p;
const char *sep = "";
const struct dep *dep, *ood = 0;
for (k = 0; k < r->num; ++k)
len += r->lens[k] + 1;
for (dep = r->deps; dep; dep = dep->next)
len += strlen (dep_name (dep)) + (dep->wait_here ? CSTRLEN (" .WAIT") : 0) + 1;
p = r->_defn = xmalloc (len);
for (k = 0; k < r->num; ++k, sep = " ")
p = mempcpy (mempcpy (p, sep, strlen (sep)), r->targets[k], r->lens[k]);
*p++ = ':';
if (r->terminal)
*p++ = ':';
/* Copy all normal dependencies; note any order-only deps. */
for (dep = r->deps; dep; dep = dep->next)
if (dep->ignore_mtime == 0)
{
if (dep->wait_here)
p = mempcpy (p, " .WAIT", CSTRLEN (" .WAIT"));
p = mempcpy (mempcpy (p, " ", 1), dep_name (dep),
strlen (dep_name (dep)));
}
else if (ood == 0)
ood = dep;
/* Copy order-only deps, if we have any. */
for (sep = " | "; ood; ood = ood->next, sep = " ")
if (ood->ignore_mtime)
{
p = mempcpy (p, sep, strlen (sep));
if (ood->wait_here)
p = mempcpy (p, ".WAIT ", CSTRLEN (".WAIT "));
p = mempcpy (p, dep_name (ood), strlen (dep_name (ood)));
}
*p = '\0';
}
return r->_defn;
}
/* Compute the maximum dependency length and maximum number of dependencies of /* Compute the maximum dependency length and maximum number of dependencies of
all implicit rules. Also sets the subdir flag for a rule when appropriate, all implicit rules. Also sets the subdir flag for a rule when appropriate,
@ -78,7 +137,18 @@ snap_implicit_rules (void)
for (dep = prereqs; dep; dep = dep->next) for (dep = prereqs; dep; dep = dep->next)
{ {
size_t l = strlen (dep_name (dep)); const char *d = dep_name (dep);
size_t l = strlen (d);
if (dep->need_2nd_expansion)
/* When pattern_search allocates a buffer, allow 5 bytes per each % to
substitute each % with $(*F) while avoiding realloc. */
while ((d = strchr (d, '%')) != 0)
{
l += 4;
++d;
}
if (l > max_pattern_dep_length) if (l > max_pattern_dep_length)
max_pattern_dep_length = l; max_pattern_dep_length = l;
++pre_deps; ++pre_deps;
@ -101,8 +171,16 @@ snap_implicit_rules (void)
const char *dname = dep_name (dep); const char *dname = dep_name (dep);
size_t len = strlen (dname); size_t len = strlen (dname);
#ifdef VMS
const char *p = strrchr (dname, ']');
const char *p2;
if (p == 0)
p = strrchr (dname, ':');
p2 = p ? strchr (p, '%') : 0;
#else
const char *p = strrchr (dname, '/'); const char *p = strrchr (dname, '/');
const char *p2 = p ? strchr (p, '%') : 0; const char *p2 = p ? strchr (p, '%') : 0;
#endif
ndeps++; ndeps++;
if (len > max_pattern_dep_length) if (len > max_pattern_dep_length)
@ -172,7 +250,11 @@ convert_suffix_rule (const char *target, const char *source,
{ {
/* Special case: TARGET being nil means we are defining a '.X.a' suffix /* Special case: TARGET being nil means we are defining a '.X.a' suffix
rule; the target pattern is always '(%.o)'. */ rule; the target pattern is always '(%.o)'. */
#ifdef VMS
*names = strcache_add_len ("(%.obj)", 7);
#else
*names = strcache_add_len ("(%.o)", 5); *names = strcache_add_len ("(%.o)", 5);
#endif
*percents = *names + 1; *percents = *names + 1;
} }
else else
@ -264,7 +346,7 @@ convert_to_pattern (void)
/* POSIX says that suffix rules can't have prerequisites. /* POSIX says that suffix rules can't have prerequisites.
In POSIX mode, don't make this a suffix rule. Previous versions In POSIX mode, don't make this a suffix rule. Previous versions
of GNU make did treat this as a suffix rule and ignored the of GNU Make did treat this as a suffix rule and ignored the
prerequisites, which is bad. In the future we'll do the same as prerequisites, which is bad. In the future we'll do the same as
POSIX, but for now preserve the old behavior and warn about it. */ POSIX, but for now preserve the old behavior and warn about it. */
if (f->deps != 0) if (f->deps != 0)
@ -384,6 +466,7 @@ install_pattern_rule (struct pspec *p, int terminal)
r->targets = xmalloc (sizeof (const char *)); r->targets = xmalloc (sizeof (const char *));
r->suffixes = xmalloc (sizeof (const char *)); r->suffixes = xmalloc (sizeof (const char *));
r->lens = xmalloc (sizeof (unsigned int)); r->lens = xmalloc (sizeof (unsigned int));
r->_defn = NULL;
r->lens[0] = (unsigned int) strlen (p->target); r->lens[0] = (unsigned int) strlen (p->target);
r->targets[0] = p->target; r->targets[0] = p->target;
@ -425,6 +508,7 @@ freerule (struct rule *rule, struct rule *lastrule)
free ((void *)rule->targets); free ((void *)rule->targets);
free ((void *)rule->suffixes); free ((void *)rule->suffixes);
free (rule->lens); free (rule->lens);
free ((void *) rule->_defn);
/* We can't free the storage for the commands because there /* We can't free the storage for the commands because there
are ways that they could be in more than one place: are ways that they could be in more than one place:
@ -474,6 +558,7 @@ create_pattern_rule (const char **targets, const char **target_percents,
r->targets = targets; r->targets = targets;
r->suffixes = target_percents; r->suffixes = target_percents;
r->lens = xmalloc (n * sizeof (unsigned int)); r->lens = xmalloc (n * sizeof (unsigned int));
r->_defn = NULL;
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
{ {
@ -491,17 +576,8 @@ create_pattern_rule (const char **targets, const char **target_percents,
static void /* Useful to call from gdb. */ static void /* Useful to call from gdb. */
print_rule (struct rule *r) print_rule (struct rule *r)
{ {
unsigned int i; fputs (get_rule_defn (r), stdout);
putchar ('\n');
for (i = 0; i < r->num; ++i)
{
fputs (r->targets[i], stdout);
putchar ((i + 1 == r->num) ? ':' : ' ');
}
if (r->terminal)
putchar (':');
print_prereqs (r->deps);
if (r->cmds != 0) if (r->cmds != 0)
print_commands (r->cmds); print_commands (r->cmds);

View file

@ -1,5 +1,5 @@
/* Definitions for using pattern rules in GNU Make. /* Definitions for using pattern rules in GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,7 +12,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
/* Structure used for pattern (implicit) rules. */ /* Structure used for pattern (implicit) rules. */
@ -25,6 +25,7 @@ struct rule
const char **suffixes; /* Suffixes (after '%') of each target. */ const char **suffixes; /* Suffixes (after '%') of each target. */
struct dep *deps; /* Dependencies of the rule. */ struct dep *deps; /* Dependencies of the rule. */
struct commands *cmds; /* Commands to execute. */ struct commands *cmds; /* Commands to execute. */
char *_defn; /* Definition of the rule. */
unsigned short num; /* Number of targets. */ unsigned short num; /* Number of targets. */
char terminal; /* If terminal (double-colon). */ char terminal; /* If terminal (double-colon). */
char in_use; /* If in use by a parent pattern_search. */ char in_use; /* If in use by a parent pattern_search. */
@ -54,4 +55,5 @@ void install_pattern_rule (struct pspec *p, int terminal);
void create_pattern_rule (const char **targets, const char **target_percents, void create_pattern_rule (const char **targets, const char **target_percents,
unsigned short num, int terminal, struct dep *deps, unsigned short num, int terminal, struct dep *deps,
struct commands *commands, int override); struct commands *commands, int override);
const char *get_rule_defn (struct rule *rule);
void print_rule_data_base (void); void print_rule_data_base (void);

237
third_party/make/shuffle.c vendored Normal file
View file

@ -0,0 +1,237 @@
/* Provide prerequisite shuffle support.
Copyright (C) 2022-2023 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "shuffle.h"
#include "filedef.h"
#include "dep.h"
/* Supported shuffle modes. */
static void random_shuffle_array (void ** a, size_t len);
static void reverse_shuffle_array (void ** a, size_t len);
static void identity_shuffle_array (void ** a, size_t len);
/* The way goals and rules are shuffled during update. */
enum shuffle_mode
{
/* No shuffle data is populated or used. */
sm_none,
/* Random within dependency list. */
sm_random,
/* Inverse order. */
sm_reverse,
/* identity order. Differs from SM_NONE by explicitly populating
the traversal order. */
sm_identity,
};
/* Shuffle configuration. */
static struct
{
enum shuffle_mode mode;
unsigned int seed;
void (*shuffler) (void **a, size_t len);
char strval[INTSTR_LENGTH + 1];
} config = { sm_none, 0, NULL, "" };
/* Return string value of --shuffle= option passed.
If none was passed or --shuffle=none was used function
returns NULL. */
const char *
shuffle_get_mode ()
{
return config.strval[0] == '\0' ? NULL : config.strval;
}
void
shuffle_set_mode (const char *cmdarg)
{
/* Parse supported '--shuffle' mode. */
if (strcasecmp (cmdarg, "reverse") == 0)
{
config.mode = sm_reverse;
config.shuffler = reverse_shuffle_array;
strcpy (config.strval, "reverse");
}
else if (strcasecmp (cmdarg, "identity") == 0)
{
config.mode = sm_identity;
config.shuffler = identity_shuffle_array;
strcpy (config.strval, "identity");
}
else if (strcasecmp (cmdarg, "none") == 0)
{
config.mode = sm_none;
config.shuffler = NULL;
config.strval[0] = '\0';
}
else
{
if (strcasecmp (cmdarg, "random") == 0)
config.seed = make_rand ();
else
{
/* Assume explicit seed. */
const char *err;
config.seed = make_toui (cmdarg, &err);
if (err)
OSS (fatal, NILF, _("invalid shuffle mode: %s: '%s'"), err, cmdarg);
}
config.mode = sm_random;
config.shuffler = random_shuffle_array;
sprintf (config.strval, "%u", config.seed);
}
}
/* Shuffle array elements using RAND(). */
static void
random_shuffle_array (void **a, size_t len)
{
size_t i;
for (i = 0; i < len; i++)
{
void *t;
/* Pick random element and swap. */
unsigned int j = make_rand () % len;
if (i == j)
continue;
/* Swap. */
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
/* Shuffle array elements using reverse order. */
static void
reverse_shuffle_array (void **a, size_t len)
{
size_t i;
for (i = 0; i < len / 2; i++)
{
void *t;
/* Pick mirror and swap. */
size_t j = len - 1 - i;
/* Swap. */
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
/* Shuffle array elements using identity order. */
static void
identity_shuffle_array (void **a UNUSED, size_t len UNUSED)
{
/* No-op! */
}
/* Shuffle list of dependencies by populating '->shuf'
field in each 'struct dep'. */
static void
shuffle_deps (struct dep *deps)
{
size_t ndeps = 0;
struct dep *dep;
void **da;
void **dp;
for (dep = deps; dep; dep = dep->next)
{
/* Do not reshuffle prerequisites if any .WAIT is present. */
if (dep->wait_here)
return;
ndeps++;
}
if (ndeps == 0)
return;
/* Allocate array of all deps, store, shuffle, write back. */
da = xmalloc (sizeof (struct dep *) * ndeps);
/* Store locally. */
for (dep = deps, dp = da; dep; dep = dep->next, dp++)
*dp = dep;
/* Shuffle. */
config.shuffler (da, ndeps);
/* Write back. */
for (dep = deps, dp = da; dep; dep = dep->next, dp++)
dep->shuf = *dp;
free (da);
}
/* Shuffle 'deps' of each 'file' recursively. */
static void
shuffle_file_deps_recursive (struct file *f)
{
struct dep *dep;
/* Implicit rules do not always provide any depends. */
if (!f)
return;
/* Avoid repeated shuffles and loops. */
if (f->was_shuffled)
return;
f->was_shuffled = 1;
shuffle_deps (f->deps);
/* Shuffle dependencies. */
for (dep = f->deps; dep; dep = dep->next)
shuffle_file_deps_recursive (dep->file);
}
/* Shuffle goal dependencies first, then shuffle dependency list
of each file reachable from goaldep recursively. Used by
--shuffle flag to introduce artificial non-determinism in build
order. .*/
void
shuffle_deps_recursive (struct dep *deps)
{
struct dep *dep;
/* Exit early if shuffling was not requested. */
if (config.mode == sm_none)
return;
/* Do not reshuffle prerequisites if .NOTPARALLEL was specified. */
if (not_parallel)
return;
/* Set specific seed at the top level of recursion. */
if (config.mode == sm_random)
make_seed (config.seed);
shuffle_deps (deps);
/* Shuffle dependencies. */
for (dep = deps; dep; dep = dep->next)
shuffle_file_deps_recursive (dep->file);
}

26
third_party/make/shuffle.h vendored Normal file
View file

@ -0,0 +1,26 @@
/* Declarations for target shuffling support.
Copyright (C) 2022-2022 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
struct dep;
struct goaldep;
void shuffle_set_mode (const char *cmdarg);
const char *shuffle_get_mode (void);
void shuffle_deps_recursive (struct dep* g);
#define shuffle_goaldeps_recursive(_g) do{ \
shuffle_deps_recursive ((struct dep *)_g); \
} while(0)

254
third_party/make/signame.c vendored Normal file
View file

@ -0,0 +1,254 @@
/* Convert between signal names and numbers.
Copyright (C) 1990-2023 Free Software Foundation, Inc.
This file is part of GNU Make.
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
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>. */
#include "makeint.h"
/* If the system provides strsignal, we don't need it. */
#if !HAVE_STRSIGNAL
/* If the system provides sys_siglist, we'll use that.
Otherwise create our own.
*/
#if !HAVE_DECL_SYS_SIGLIST
/* Some systems do not define NSIG in <signal.h>. */
#ifndef NSIG
#ifdef _NSIG
#define NSIG _NSIG
#else
#define NSIG 32
#endif
#endif
/* There is too much variation in Sys V signal numbers and names, so
we must initialize them at runtime. */
static const char *undoc;
static const char *sys_siglist[NSIG];
/* Table of abbreviations for signals. Note: A given number can
appear more than once with different abbreviations. */
#define SIG_TABLE_SIZE (NSIG*2)
typedef struct
{
int number;
const char *abbrev;
} num_abbrev;
static num_abbrev sig_table[SIG_TABLE_SIZE];
/* Number of elements of sig_table used. */
static int sig_table_nelts = 0;
/* Enter signal number NUMBER into the tables with ABBREV and NAME. */
static void
init_sig (int number, const char *abbrev, const char *name)
{
/* If this value is ever greater than NSIG it seems like it'd be a bug in
the system headers, but... better safe than sorry. We know, for
example, that this isn't always true on VMS. */
if (number >= 0 && number < NSIG)
sys_siglist[number] = name;
if (sig_table_nelts < SIG_TABLE_SIZE)
{
sig_table[sig_table_nelts].number = number;
sig_table[sig_table_nelts++].abbrev = abbrev;
}
}
static int
signame_init (void)
{
int i;
undoc = xstrdup (_("unknown signal"));
/* Initialize signal names. */
for (i = 0; i < NSIG; i++)
sys_siglist[i] = undoc;
/* Initialize signal names. */
#if defined (SIGHUP)
init_sig (SIGHUP, "HUP", _("Hangup"));
#endif
#if defined (SIGINT)
init_sig (SIGINT, "INT", _("Interrupt"));
#endif
#if defined (SIGQUIT)
init_sig (SIGQUIT, "QUIT", _("Quit"));
#endif
#if defined (SIGILL)
init_sig (SIGILL, "ILL", _("Illegal Instruction"));
#endif
#if defined (SIGTRAP)
init_sig (SIGTRAP, "TRAP", _("Trace/breakpoint trap"));
#endif
/* If SIGIOT == SIGABRT, we want to print it as SIGABRT because
SIGABRT is in ANSI and POSIX.1 and SIGIOT isn't. */
#if defined (SIGABRT)
init_sig (SIGABRT, "ABRT", _("Aborted"));
#endif
#if defined (SIGIOT)
init_sig (SIGIOT, "IOT", _("IOT trap"));
#endif
#if defined (SIGEMT)
init_sig (SIGEMT, "EMT", _("EMT trap"));
#endif
#if defined (SIGFPE)
init_sig (SIGFPE, "FPE", _("Floating point exception"));
#endif
#if defined (SIGKILL)
init_sig (SIGKILL, "KILL", _("Killed"));
#endif
#if defined (SIGBUS)
init_sig (SIGBUS, "BUS", _("Bus error"));
#endif
#if defined (SIGSEGV)
init_sig (SIGSEGV, "SEGV", _("Segmentation fault"));
#endif
#if defined (SIGSYS)
init_sig (SIGSYS, "SYS", _("Bad system call"));
#endif
#if defined (SIGPIPE)
init_sig (SIGPIPE, "PIPE", _("Broken pipe"));
#endif
#if defined (SIGALRM)
init_sig (SIGALRM, "ALRM", _("Alarm clock"));
#endif
#if defined (SIGTERM)
init_sig (SIGTERM, "TERM", _("Terminated"));
#endif
#if defined (SIGUSR1)
init_sig (SIGUSR1, "USR1", _("User defined signal 1"));
#endif
#if defined (SIGUSR2)
init_sig (SIGUSR2, "USR2", _("User defined signal 2"));
#endif
/* If SIGCLD == SIGCHLD, we want to print it as SIGCHLD because that
is what is in POSIX.1. */
#if defined (SIGCHLD)
init_sig (SIGCHLD, "CHLD", _("Child exited"));
#endif
#if defined (SIGCLD)
init_sig (SIGCLD, "CLD", _("Child exited"));
#endif
#if defined (SIGPWR)
init_sig (SIGPWR, "PWR", _("Power failure"));
#endif
#if defined (SIGTSTP)
init_sig (SIGTSTP, "TSTP", _("Stopped"));
#endif
#if defined (SIGTTIN)
init_sig (SIGTTIN, "TTIN", _("Stopped (tty input)"));
#endif
#if defined (SIGTTOU)
init_sig (SIGTTOU, "TTOU", _("Stopped (tty output)"));
#endif
#if defined (SIGSTOP)
init_sig (SIGSTOP, "STOP", _("Stopped (signal)"));
#endif
#if defined (SIGXCPU)
init_sig (SIGXCPU, "XCPU", _("CPU time limit exceeded"));
#endif
#if defined (SIGXFSZ)
init_sig (SIGXFSZ, "XFSZ", _("File size limit exceeded"));
#endif
#if defined (SIGVTALRM)
init_sig (SIGVTALRM, "VTALRM", _("Virtual timer expired"));
#endif
#if defined (SIGPROF)
init_sig (SIGPROF, "PROF", _("Profiling timer expired"));
#endif
#if defined (SIGWINCH)
/* "Window size changed" might be more accurate, but even if that
is all that it means now, perhaps in the future it will be
extended to cover other kinds of window changes. */
init_sig (SIGWINCH, "WINCH", _("Window changed"));
#endif
#if defined (SIGCONT)
init_sig (SIGCONT, "CONT", _("Continued"));
#endif
#if defined (SIGURG)
init_sig (SIGURG, "URG", _("Urgent I/O condition"));
#endif
#if defined (SIGIO)
/* "I/O pending" has also been suggested. A disadvantage is that signal
only happens when the process has asked for it, not every time I/O is
pending. Another disadvantage is the confusion from giving it a
different name than under Unix. */
init_sig (SIGIO, "IO", _("I/O possible"));
#endif
#if defined (SIGWIND)
init_sig (SIGWIND, "WIND", _("SIGWIND"));
#endif
#if defined (SIGPHONE)
init_sig (SIGPHONE, "PHONE", _("SIGPHONE"));
#endif
#if defined (SIGPOLL)
init_sig (SIGPOLL, "POLL", _("I/O possible"));
#endif
#if defined (SIGLOST)
init_sig (SIGLOST, "LOST", _("Resource lost"));
#endif
#if defined (SIGDANGER)
init_sig (SIGDANGER, "DANGER", _("Danger signal"));
#endif
#if defined (SIGINFO)
init_sig (SIGINFO, "INFO", _("Information request"));
#endif
#if defined (SIGNOFP)
init_sig (SIGNOFP, "NOFP", _("Floating point co-processor not available"));
#endif
return 1;
}
#endif /* HAVE_DECL_SYS_SIGLIST */
char *
strsignal (int sig)
{
static char buf[] = "Signal 12345678901234567890";
#if ! HAVE_DECL_SYS_SIGLIST
# if HAVE_DECL__SYS_SIGLIST
# define sys_siglist _sys_siglist
# elif HAVE_DECL___SYS_SIGLIST
# define sys_siglist __sys_siglist
# else
static int sig_initted = 0;
if (!sig_initted)
sig_initted = signame_init ();
# endif
#endif
if (sig > 0 && sig < NSIG)
return (char *) sys_siglist[sig];
sprintf (buf, "Signal %d", sig);
return buf;
}
#endif /* HAVE_STRSIGNAL */

View file

@ -1,119 +0,0 @@
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
/* A substitute for POSIX 2008 <stddef.h>, for platforms that have issues.
Copyright (C) 2009-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>. */
/* Written by Eric Blake. */
/*
* POSIX 2008 <stddef.h> for platforms that have issues.
* <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stddef.h.html>
*/
#if __GNUC__ >= 3
#pragma GCC system_header
#endif
#if defined __need_wchar_t || defined __need_size_t \
|| defined __need_ptrdiff_t || defined __need_NULL \
|| defined __need_wint_t
/* Special invocation convention inside gcc header files. In
particular, gcc provides a version of <stddef.h> that blindly
redefines NULL even when __need_wint_t was defined, even though
wint_t is not normally provided by <stddef.h>. Hence, we must
remember if special invocation has ever been used to obtain wint_t,
in which case we need to clean up NULL yet again. */
# if !(defined _GL_STDDEF_H && defined _GL_STDDEF_WINT_T)
# ifdef __need_wint_t
# define _GL_STDDEF_WINT_T
# endif
# endif
#else
/* Normal invocation convention. */
# ifndef _GL_STDDEF_H
/* The include_next requires a split double-inclusion guard. */
/* On NetBSD 5.0, the definition of NULL lacks proper parentheses. */
# if (0 \
&& (!defined _GL_STDDEF_H || defined _GL_STDDEF_WINT_T))
# undef NULL
# ifdef __cplusplus
/* ISO C++ says that the macro NULL must expand to an integer constant
expression, hence '((void *) 0)' is not allowed in C++. */
# if __GNUG__ >= 3
/* GNU C++ has a __null macro that behaves like an integer ('int' or
'long') but has the same size as a pointer. Use that, to avoid
warnings. */
# define NULL __null
# else
# define NULL 0L
# endif
# else
# define NULL ((void *) 0)
# endif
# endif
# ifndef _GL_STDDEF_H
# define _GL_STDDEF_H
/* Some platforms lack wchar_t. */
#if !1
# define wchar_t int
#endif
/* Some platforms lack max_align_t. The check for _GCC_MAX_ALIGN_T is
a hack in case the configure-time test was done with g++ even though
we are currently compiling with gcc.
On MSVC, max_align_t is defined only in C++ mode, after <cstddef> was
included. Its definition is good since it has an alignment of 8 (on x86
and x86_64). */
#if defined _MSC_VER && defined __cplusplus
#else
# if ! (0 || defined _GCC_MAX_ALIGN_T)
# if !GNULIB_defined_max_align_t
/* On the x86, the maximum storage alignment of double, long, etc. is 4,
but GCC's C11 ABI for x86 says that max_align_t has an alignment of 8,
and the C11 standard allows this. Work around this problem by
using __alignof__ (which returns 8 for double) rather than _Alignof
(which returns 4), and align each union member accordingly. */
# ifdef __GNUC__
# define _GL_STDDEF_ALIGNAS(type) \
__attribute__ ((__aligned__ (__alignof__ (type))))
# else
# define _GL_STDDEF_ALIGNAS(type) /* */
# endif
typedef union
{
char *__p _GL_STDDEF_ALIGNAS (char *);
double __d _GL_STDDEF_ALIGNAS (double);
long double __ld _GL_STDDEF_ALIGNAS (long double);
long int __i _GL_STDDEF_ALIGNAS (long int);
} rpl_max_align_t;
# define max_align_t rpl_max_align_t
# define GNULIB_defined_max_align_t 1
# endif
# endif
#endif
# endif /* _GL_STDDEF_H */
# endif /* _GL_STDDEF_H */
#endif /* __need_XXX */

View file

@ -1,735 +0,0 @@
/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
/* Copyright (C) 2001-2002, 2004-2020 Free Software Foundation, Inc.
Written by Paul Eggert, Bruno Haible, Sam Steingold, Peter Burwood.
This file is part of gnulib.
This program 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 Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <https://www.gnu.org/licenses/>. */
/*
* ISO C 99 <stdint.h> for platforms that lack it.
* <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdint.h.html>
*/
#ifndef _GL_STDINT_H
#if __GNUC__ >= 3
#pragma GCC system_header
#endif
/* When including a system file that in turn includes <inttypes.h>,
use the system <inttypes.h>, not our substitute. This avoids
problems with (for example) VMS, whose <sys/bitypes.h> includes
<inttypes.h>. */
#define _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
/* On Android (Bionic libc), <sys/types.h> includes this file before
having defined 'time_t'. Therefore in this case avoid including
other system header files; just include the system's <stdint.h>.
Ideally we should test __BIONIC__ here, but it is only defined after
<sys/cdefs.h> has been included; hence test __ANDROID__ instead. */
#if defined __ANDROID__ && defined _GL_INCLUDING_SYS_TYPES_H
#else
/* Get those types that are already defined in other system include
files, so that we can "#define int8_t signed char" below without
worrying about a later system include file containing a "typedef
signed char int8_t;" that will get messed up by our macro. Our
macros should all be consistent with the system versions, except
for the "fast" types and macros, which we recommend against using
in public interfaces due to compiler differences. */
#if 1
# if defined __sgi && ! defined __c99
/* Bypass IRIX's <stdint.h> if in C89 mode, since it merely annoys users
with "This header file is to be used only for c99 mode compilations"
diagnostics. */
# define __STDINT_H__
# endif
/* Some pre-C++11 <stdint.h> implementations need this. */
# ifdef __cplusplus
# ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS 1
# endif
# ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS 1
# endif
# endif
/* Other systems may have an incomplete or buggy <stdint.h>.
in <inttypes.h> would reinclude us, skipping our contents because
_GL_STDINT_H is defined.
The include_next requires a split double-inclusion guard. */
#endif
#if ! defined _GL_STDINT_H && ! defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H
#define _GL_STDINT_H
/* Get SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, INT_MIN, INT_MAX,
LONG_MIN, LONG_MAX, ULONG_MAX, _GL_INTEGER_WIDTH. */
/* Override WINT_MIN and WINT_MAX if gnulib's <wchar.h> or <wctype.h> overrides
wint_t. */
#if 0
# undef WINT_MIN
# undef WINT_MAX
# define WINT_MIN 0x0U
# define WINT_MAX 0xffffffffU
#endif
#if ! 0
/* <sys/types.h> defines some of the stdint.h types as well, on glibc,
IRIX 6.5, and OpenBSD 3.8 (via <machine/types.h>).
AIX 5.2 <sys/types.h> isn't needed and causes troubles.
Mac OS X 10.4.6 <sys/types.h> includes <stdint.h> (which is us), but
relies on the system <stdint.h> definitions, so include
<sys/types.h> after <stdint.h>. */
# if 1 && ! defined _AIX
# endif
# if 1
/* In OpenBSD 3.8, <inttypes.h> includes <machine/types.h>, which defines
int{8,16,32,64}_t, uint{8,16,32,64}_t and __BIT_TYPES_DEFINED__.
<inttypes.h> also defines intptr_t and uintptr_t. */
# elif 0
/* Solaris 7 <sys/inttypes.h> has the types except the *_fast*_t types, and
the macros except for *_FAST*_*, INTPTR_MIN, PTRDIFF_MIN, PTRDIFF_MAX. */
# endif
# if 0 && ! defined __BIT_TYPES_DEFINED__
/* Linux libc4 >= 4.6.7 and libc5 have a <sys/bitypes.h> that defines
int{8,16,32,64}_t and __BIT_TYPES_DEFINED__. In libc5 >= 5.2.2 it is
included by <sys/types.h>. */
# endif
# undef _GL_JUST_INCLUDE_SYSTEM_INTTYPES_H
/* Minimum and maximum values for an integer type under the usual assumption.
Return an unspecified value if BITS == 0, adding a check to pacify
picky compilers. */
/* These are separate macros, because if you try to merge these macros into
a single one, HP-UX cc rejects the resulting expression in constant
expressions. */
# define _STDINT_UNSIGNED_MIN(bits, zero) \
(zero)
# define _STDINT_SIGNED_MIN(bits, zero) \
(~ _STDINT_MAX (1, bits, zero))
# define _STDINT_MAX(signed, bits, zero) \
(((((zero) + 1) << ((bits) ? (bits) - 1 - (signed) : 0)) - 1) * 2 + 1)
#if !GNULIB_defined_stdint_types
/* 7.18.1.1. Exact-width integer types */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. */
# undef int8_t
# undef uint8_t
typedef signed char gl_int8_t;
typedef unsigned char gl_uint8_t;
# define int8_t gl_int8_t
# define uint8_t gl_uint8_t
# undef int16_t
# undef uint16_t
typedef short int gl_int16_t;
typedef unsigned short int gl_uint16_t;
# define int16_t gl_int16_t
# define uint16_t gl_uint16_t
# undef int32_t
# undef uint32_t
typedef int gl_int32_t;
typedef unsigned int gl_uint32_t;
# define int32_t gl_int32_t
# define uint32_t gl_uint32_t
/* If the system defines INT64_MAX, assume int64_t works. That way,
if the underlying platform defines int64_t to be a 64-bit long long
int, the code below won't mistakenly define it to be a 64-bit long
int, which would mess up C++ name mangling. We must use #ifdef
rather than #if, to avoid an error with HP-UX 10.20 cc. */
# ifdef INT64_MAX
# define GL_INT64_T
# else
/* Do not undefine int64_t if gnulib is not being used with 64-bit
types, since otherwise it breaks platforms like Tandem/NSK. */
# if LONG_MAX >> 31 >> 31 == 1
# undef int64_t
typedef long int gl_int64_t;
# define int64_t gl_int64_t
# define GL_INT64_T
# elif defined _MSC_VER
# undef int64_t
typedef __int64 gl_int64_t;
# define int64_t gl_int64_t
# define GL_INT64_T
# else
# undef int64_t
typedef long long int gl_int64_t;
# define int64_t gl_int64_t
# define GL_INT64_T
# endif
# endif
# ifdef UINT64_MAX
# define GL_UINT64_T
# else
# if ULONG_MAX >> 31 >> 31 >> 1 == 1
# undef uint64_t
typedef unsigned long int gl_uint64_t;
# define uint64_t gl_uint64_t
# define GL_UINT64_T
# elif defined _MSC_VER
# undef uint64_t
typedef unsigned __int64 gl_uint64_t;
# define uint64_t gl_uint64_t
# define GL_UINT64_T
# else
# undef uint64_t
typedef unsigned long long int gl_uint64_t;
# define uint64_t gl_uint64_t
# define GL_UINT64_T
# endif
# endif
/* Avoid collision with Solaris 2.5.1 <pthread.h> etc. */
# define _UINT8_T
# define _UINT32_T
# define _UINT64_T
/* 7.18.1.2. Minimum-width integer types */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types
are the same as the corresponding N_t types. */
# undef int_least8_t
# undef uint_least8_t
# undef int_least16_t
# undef uint_least16_t
# undef int_least32_t
# undef uint_least32_t
# undef int_least64_t
# undef uint_least64_t
# define int_least8_t int8_t
# define uint_least8_t uint8_t
# define int_least16_t int16_t
# define uint_least16_t uint16_t
# define int_least32_t int32_t
# define uint_least32_t uint32_t
# ifdef GL_INT64_T
# define int_least64_t int64_t
# endif
# ifdef GL_UINT64_T
# define uint_least64_t uint64_t
# endif
/* 7.18.1.3. Fastest minimum-width integer types */
/* Note: Other <stdint.h> substitutes may define these types differently.
It is not recommended to use these types in public header files. */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types
are taken from the same list of types. The following code normally
uses types consistent with glibc, as that lessens the chance of
incompatibility with older GNU hosts. */
# undef int_fast8_t
# undef uint_fast8_t
# undef int_fast16_t
# undef uint_fast16_t
# undef int_fast32_t
# undef uint_fast32_t
# undef int_fast64_t
# undef uint_fast64_t
typedef signed char gl_int_fast8_t;
typedef unsigned char gl_uint_fast8_t;
# ifdef __sun
/* Define types compatible with SunOS 5.10, so that code compiled under
earlier SunOS versions works with code compiled under SunOS 5.10. */
typedef int gl_int_fast32_t;
typedef unsigned int gl_uint_fast32_t;
# else
typedef long int gl_int_fast32_t;
typedef unsigned long int gl_uint_fast32_t;
# endif
typedef gl_int_fast32_t gl_int_fast16_t;
typedef gl_uint_fast32_t gl_uint_fast16_t;
# define int_fast8_t gl_int_fast8_t
# define uint_fast8_t gl_uint_fast8_t
# define int_fast16_t gl_int_fast16_t
# define uint_fast16_t gl_uint_fast16_t
# define int_fast32_t gl_int_fast32_t
# define uint_fast32_t gl_uint_fast32_t
# ifdef GL_INT64_T
# define int_fast64_t int64_t
# endif
# ifdef GL_UINT64_T
# define uint_fast64_t uint64_t
# endif
/* 7.18.1.4. Integer types capable of holding object pointers */
/* kLIBC's <stdint.h> defines _INTPTR_T_DECLARED and needs its own
definitions of intptr_t and uintptr_t (which use int and unsigned)
to avoid clashes with declarations of system functions like sbrk.
Similarly, mingw 5.22 <crtdefs.h> defines _INTPTR_T_DEFINED and
_UINTPTR_T_DEFINED and needs its own definitions of intptr_t and
uintptr_t to avoid conflicting declarations of system functions like
_findclose in <io.h>. */
# if !((defined __KLIBC__ && defined _INTPTR_T_DECLARED) \
|| (defined __MINGW32__ && defined _INTPTR_T_DEFINED && defined _UINTPTR_T_DEFINED))
# undef intptr_t
# undef uintptr_t
# ifdef _WIN64
typedef long long int gl_intptr_t;
typedef unsigned long long int gl_uintptr_t;
# else
typedef long int gl_intptr_t;
typedef unsigned long int gl_uintptr_t;
# endif
# define intptr_t gl_intptr_t
# define uintptr_t gl_uintptr_t
# endif
/* 7.18.1.5. Greatest-width integer types */
/* Note: These types are compiler dependent. It may be unwise to use them in
public header files. */
/* If the system defines INTMAX_MAX, assume that intmax_t works, and
similarly for UINTMAX_MAX and uintmax_t. This avoids problems with
assuming one type where another is used by the system. */
# ifndef INTMAX_MAX
# undef INTMAX_C
# undef intmax_t
# if LONG_MAX >> 30 == 1
typedef long long int gl_intmax_t;
# define intmax_t gl_intmax_t
# elif defined GL_INT64_T
# define intmax_t int64_t
# else
typedef long int gl_intmax_t;
# define intmax_t gl_intmax_t
# endif
# endif
# ifndef UINTMAX_MAX
# undef UINTMAX_C
# undef uintmax_t
# if ULONG_MAX >> 31 == 1
typedef unsigned long long int gl_uintmax_t;
# define uintmax_t gl_uintmax_t
# elif defined GL_UINT64_T
# define uintmax_t uint64_t
# else
typedef unsigned long int gl_uintmax_t;
# define uintmax_t gl_uintmax_t
# endif
# endif
/* Verify that intmax_t and uintmax_t have the same size. Too much code
breaks if this is not the case. If this check fails, the reason is likely
to be found in the autoconf macros. */
typedef int _verify_intmax_size[sizeof (intmax_t) == sizeof (uintmax_t)
? 1 : -1];
# define GNULIB_defined_stdint_types 1
# endif /* !GNULIB_defined_stdint_types */
/* 7.18.2. Limits of specified-width integer types */
/* 7.18.2.1. Limits of exact-width integer types */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. */
# undef INT8_MIN
# undef INT8_MAX
# undef UINT8_MAX
# define INT8_MIN (~ INT8_MAX)
# define INT8_MAX 127
# define UINT8_MAX 255
# undef INT16_MIN
# undef INT16_MAX
# undef UINT16_MAX
# define INT16_MIN (~ INT16_MAX)
# define INT16_MAX 32767
# define UINT16_MAX 65535
# undef INT32_MIN
# undef INT32_MAX
# undef UINT32_MAX
# define INT32_MIN (~ INT32_MAX)
# define INT32_MAX 2147483647
# define UINT32_MAX 4294967295U
# if defined GL_INT64_T && ! defined INT64_MAX
/* Prefer (- INTMAX_C (1) << 63) over (~ INT64_MAX) because SunPRO C 5.0
evaluates the latter incorrectly in preprocessor expressions. */
# define INT64_MIN (- INTMAX_C (1) << 63)
# define INT64_MAX INTMAX_C (9223372036854775807)
# endif
# if defined GL_UINT64_T && ! defined UINT64_MAX
# define UINT64_MAX UINTMAX_C (18446744073709551615)
# endif
/* 7.18.2.2. Limits of minimum-width integer types */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. Therefore the leastN_t types
are the same as the corresponding N_t types. */
# undef INT_LEAST8_MIN
# undef INT_LEAST8_MAX
# undef UINT_LEAST8_MAX
# define INT_LEAST8_MIN INT8_MIN
# define INT_LEAST8_MAX INT8_MAX
# define UINT_LEAST8_MAX UINT8_MAX
# undef INT_LEAST16_MIN
# undef INT_LEAST16_MAX
# undef UINT_LEAST16_MAX
# define INT_LEAST16_MIN INT16_MIN
# define INT_LEAST16_MAX INT16_MAX
# define UINT_LEAST16_MAX UINT16_MAX
# undef INT_LEAST32_MIN
# undef INT_LEAST32_MAX
# undef UINT_LEAST32_MAX
# define INT_LEAST32_MIN INT32_MIN
# define INT_LEAST32_MAX INT32_MAX
# define UINT_LEAST32_MAX UINT32_MAX
# undef INT_LEAST64_MIN
# undef INT_LEAST64_MAX
# ifdef GL_INT64_T
# define INT_LEAST64_MIN INT64_MIN
# define INT_LEAST64_MAX INT64_MAX
# endif
# undef UINT_LEAST64_MAX
# ifdef GL_UINT64_T
# define UINT_LEAST64_MAX UINT64_MAX
# endif
/* 7.18.2.3. Limits of fastest minimum-width integer types */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits. Therefore the fastN_t types
are taken from the same list of types. */
# undef INT_FAST8_MIN
# undef INT_FAST8_MAX
# undef UINT_FAST8_MAX
# define INT_FAST8_MIN SCHAR_MIN
# define INT_FAST8_MAX SCHAR_MAX
# define UINT_FAST8_MAX UCHAR_MAX
# undef INT_FAST16_MIN
# undef INT_FAST16_MAX
# undef UINT_FAST16_MAX
# define INT_FAST16_MIN INT_FAST32_MIN
# define INT_FAST16_MAX INT_FAST32_MAX
# define UINT_FAST16_MAX UINT_FAST32_MAX
# undef INT_FAST32_MIN
# undef INT_FAST32_MAX
# undef UINT_FAST32_MAX
# ifdef __sun
# define INT_FAST32_MIN INT_MIN
# define INT_FAST32_MAX INT_MAX
# define UINT_FAST32_MAX UINT_MAX
# else
# define INT_FAST32_MIN LONG_MIN
# define INT_FAST32_MAX LONG_MAX
# define UINT_FAST32_MAX ULONG_MAX
# endif
# undef INT_FAST64_MIN
# undef INT_FAST64_MAX
# ifdef GL_INT64_T
# define INT_FAST64_MIN INT64_MIN
# define INT_FAST64_MAX INT64_MAX
# endif
# undef UINT_FAST64_MAX
# ifdef GL_UINT64_T
# define UINT_FAST64_MAX UINT64_MAX
# endif
/* 7.18.2.4. Limits of integer types capable of holding object pointers */
# undef INTPTR_MIN
# undef INTPTR_MAX
# undef UINTPTR_MAX
# ifdef _WIN64
# define INTPTR_MIN LLONG_MIN
# define INTPTR_MAX LLONG_MAX
# define UINTPTR_MAX ULLONG_MAX
# else
# define INTPTR_MIN LONG_MIN
# define INTPTR_MAX LONG_MAX
# define UINTPTR_MAX ULONG_MAX
# endif
/* 7.18.2.5. Limits of greatest-width integer types */
# ifndef INTMAX_MAX
# undef INTMAX_MIN
# ifdef INT64_MAX
# define INTMAX_MIN INT64_MIN
# define INTMAX_MAX INT64_MAX
# else
# define INTMAX_MIN INT32_MIN
# define INTMAX_MAX INT32_MAX
# endif
# endif
# ifndef UINTMAX_MAX
# ifdef UINT64_MAX
# define UINTMAX_MAX UINT64_MAX
# else
# define UINTMAX_MAX UINT32_MAX
# endif
# endif
/* 7.18.3. Limits of other integer types */
/* ptrdiff_t limits */
# undef PTRDIFF_MIN
# undef PTRDIFF_MAX
# if 0
# ifdef _LP64
# define PTRDIFF_MIN _STDINT_SIGNED_MIN (64, 0l)
# define PTRDIFF_MAX _STDINT_MAX (1, 64, 0l)
# else
# define PTRDIFF_MIN _STDINT_SIGNED_MIN (32, 0)
# define PTRDIFF_MAX _STDINT_MAX (1, 32, 0)
# endif
# else
# define PTRDIFF_MIN \
_STDINT_SIGNED_MIN (64, 0l)
# define PTRDIFF_MAX \
_STDINT_MAX (1, 64, 0l)
# endif
/* sig_atomic_t limits */
# undef SIG_ATOMIC_MIN
# undef SIG_ATOMIC_MAX
# if 1
# define SIG_ATOMIC_MIN \
_STDINT_SIGNED_MIN (32, 0)
# else
# define SIG_ATOMIC_MIN \
_STDINT_UNSIGNED_MIN (32, 0)
# endif
# define SIG_ATOMIC_MAX \
_STDINT_MAX (1, 32, \
0)
/* size_t limit */
# undef SIZE_MAX
# if 0
# ifdef _LP64
# define SIZE_MAX _STDINT_MAX (0, 64, 0ul)
# else
# define SIZE_MAX _STDINT_MAX (0, 32, 0ul)
# endif
# else
# define SIZE_MAX _STDINT_MAX (0, 64, 0ul)
# endif
/* wchar_t limits */
/* Get WCHAR_MIN, WCHAR_MAX.
This include is not on the top, above, because on OSF/1 4.0 we have a
sequence of nested includes
<wchar.h> -> <stdio.h> -> <getopt.h> -> <stdlib.h>, and the latter includes
<stdint.h> and assumes its types are already defined. */
# if 1 && ! (defined WCHAR_MIN && defined WCHAR_MAX)
/* BSD/OS 4.0.1 has a bug: <stddef.h>, <stdio.h> and <time.h> must be
included before <wchar.h>. */
# define _GL_JUST_INCLUDE_SYSTEM_WCHAR_H
# undef _GL_JUST_INCLUDE_SYSTEM_WCHAR_H
# endif
# undef WCHAR_MIN
# undef WCHAR_MAX
# if 1
# define WCHAR_MIN \
_STDINT_SIGNED_MIN (32, 0)
# else
# define WCHAR_MIN \
_STDINT_UNSIGNED_MIN (32, 0)
# endif
# define WCHAR_MAX \
_STDINT_MAX (1, 32, 0)
/* wint_t limits */
/* If gnulib's <wchar.h> or <wctype.h> overrides wint_t, u is not
accurate, therefore use the definitions from above. */
# if !0
# undef WINT_MIN
# undef WINT_MAX
# if 0
# define WINT_MIN \
_STDINT_SIGNED_MIN (32, 0u)
# else
# define WINT_MIN \
_STDINT_UNSIGNED_MIN (32, 0u)
# endif
# define WINT_MAX \
_STDINT_MAX (0, 32, 0u)
# endif
/* 7.18.4. Macros for integer constants */
/* 7.18.4.1. Macros for minimum-width integer constants */
/* According to ISO C 99 Technical Corrigendum 1 */
/* Here we assume a standard architecture where the hardware integer
types have 8, 16, 32, optionally 64 bits, and int is 32 bits. */
# undef INT8_C
# undef UINT8_C
# define INT8_C(x) x
# define UINT8_C(x) x
# undef INT16_C
# undef UINT16_C
# define INT16_C(x) x
# define UINT16_C(x) x
# undef INT32_C
# undef UINT32_C
# define INT32_C(x) x
# define UINT32_C(x) x ## U
# undef INT64_C
# undef UINT64_C
# if LONG_MAX >> 31 >> 31 == 1
# define INT64_C(x) x##L
# elif defined _MSC_VER
# define INT64_C(x) x##i64
# else
# define INT64_C(x) x##LL
# endif
# if ULONG_MAX >> 31 >> 31 >> 1 == 1
# define UINT64_C(x) x##UL
# elif defined _MSC_VER
# define UINT64_C(x) x##ui64
# else
# define UINT64_C(x) x##ULL
# endif
/* 7.18.4.2. Macros for greatest-width integer constants */
# ifndef INTMAX_C
# if LONG_MAX >> 30 == 1
# define INTMAX_C(x) x##LL
# elif defined GL_INT64_T
# define INTMAX_C(x) INT64_C(x)
# else
# define INTMAX_C(x) x##L
# endif
# endif
# ifndef UINTMAX_C
# if ULONG_MAX >> 31 == 1
# define UINTMAX_C(x) x##ULL
# elif defined GL_UINT64_T
# define UINTMAX_C(x) UINT64_C(x)
# else
# define UINTMAX_C(x) x##UL
# endif
# endif
#endif /* !0 */
/* Macros specified by ISO/IEC TS 18661-1:2014. */
#if (!defined UINTMAX_WIDTH \
&& (defined _GNU_SOURCE || defined __STDC_WANT_IEC_60559_BFP_EXT__))
# ifdef INT8_MAX
# define INT8_WIDTH _GL_INTEGER_WIDTH (INT8_MIN, INT8_MAX)
# endif
# ifdef UINT8_MAX
# define UINT8_WIDTH _GL_INTEGER_WIDTH (0, UINT8_MAX)
# endif
# ifdef INT16_MAX
# define INT16_WIDTH _GL_INTEGER_WIDTH (INT16_MIN, INT16_MAX)
# endif
# ifdef UINT16_MAX
# define UINT16_WIDTH _GL_INTEGER_WIDTH (0, UINT16_MAX)
# endif
# ifdef INT32_MAX
# define INT32_WIDTH _GL_INTEGER_WIDTH (INT32_MIN, INT32_MAX)
# endif
# ifdef UINT32_MAX
# define UINT32_WIDTH _GL_INTEGER_WIDTH (0, UINT32_MAX)
# endif
# ifdef INT64_MAX
# define INT64_WIDTH _GL_INTEGER_WIDTH (INT64_MIN, INT64_MAX)
# endif
# ifdef UINT64_MAX
# define UINT64_WIDTH _GL_INTEGER_WIDTH (0, UINT64_MAX)
# endif
# define INT_LEAST8_WIDTH _GL_INTEGER_WIDTH (INT_LEAST8_MIN, INT_LEAST8_MAX)
# define UINT_LEAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST8_MAX)
# define INT_LEAST16_WIDTH _GL_INTEGER_WIDTH (INT_LEAST16_MIN, INT_LEAST16_MAX)
# define UINT_LEAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST16_MAX)
# define INT_LEAST32_WIDTH _GL_INTEGER_WIDTH (INT_LEAST32_MIN, INT_LEAST32_MAX)
# define UINT_LEAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST32_MAX)
# define INT_LEAST64_WIDTH _GL_INTEGER_WIDTH (INT_LEAST64_MIN, INT_LEAST64_MAX)
# define UINT_LEAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_LEAST64_MAX)
# define INT_FAST8_WIDTH _GL_INTEGER_WIDTH (INT_FAST8_MIN, INT_FAST8_MAX)
# define UINT_FAST8_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST8_MAX)
# define INT_FAST16_WIDTH _GL_INTEGER_WIDTH (INT_FAST16_MIN, INT_FAST16_MAX)
# define UINT_FAST16_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST16_MAX)
# define INT_FAST32_WIDTH _GL_INTEGER_WIDTH (INT_FAST32_MIN, INT_FAST32_MAX)
# define UINT_FAST32_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST32_MAX)
# define INT_FAST64_WIDTH _GL_INTEGER_WIDTH (INT_FAST64_MIN, INT_FAST64_MAX)
# define UINT_FAST64_WIDTH _GL_INTEGER_WIDTH (0, UINT_FAST64_MAX)
# define INTPTR_WIDTH _GL_INTEGER_WIDTH (INTPTR_MIN, INTPTR_MAX)
# define UINTPTR_WIDTH _GL_INTEGER_WIDTH (0, UINTPTR_MAX)
# define INTMAX_WIDTH _GL_INTEGER_WIDTH (INTMAX_MIN, INTMAX_MAX)
# define UINTMAX_WIDTH _GL_INTEGER_WIDTH (0, UINTMAX_MAX)
# define PTRDIFF_WIDTH _GL_INTEGER_WIDTH (PTRDIFF_MIN, PTRDIFF_MAX)
# define SIZE_WIDTH _GL_INTEGER_WIDTH (0, SIZE_MAX)
# define WCHAR_WIDTH _GL_INTEGER_WIDTH (WCHAR_MIN, WCHAR_MAX)
# ifdef WINT_MAX
# define WINT_WIDTH _GL_INTEGER_WIDTH (WINT_MIN, WINT_MAX)
# endif
# ifdef SIG_ATOMIC_MAX
# define SIG_ATOMIC_WIDTH _GL_INTEGER_WIDTH (SIG_ATOMIC_MIN, SIG_ATOMIC_MAX)
# endif
#endif /* !WINT_WIDTH && (_GNU_SOURCE || __STDC_WANT_IEC_60559_BFP_EXT__) */
#endif /* _GL_STDINT_H */
#endif /* !(defined __ANDROID__ && ...) */
#endif /* !defined _GL_STDINT_H && !defined _GL_JUST_INCLUDE_SYSTEM_STDINT_H */

1906
third_party/make/stdio.h vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Constant string caching for GNU Make. /* Constant string caching for GNU Make.
Copyright (C) 2006-2020 Free Software Foundation, Inc. Copyright (C) 2006-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,10 +12,14 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/hash.h"
#include <stddef.h>
#include <assert.h>
#include "hash.h"
/* A string cached here will never be freed, so we don't need to worry about /* 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 reference counting. We just store the string, and then remember it in a
@ -49,7 +53,7 @@ static unsigned long total_size = 0;
/* Add a new buffer to the cache. Add it at the front to reduce search time. /* 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 This can also increase the overhead, since it's less likely that older
buffers will be filled in. However, GNU make has so many smaller strings buffers will be filled in. However, GNU Make has so many smaller strings
that this doesn't seem to be much of an issue in practice. that this doesn't seem to be much of an issue in practice.
*/ */
static struct strcache * static struct strcache *
@ -252,8 +256,7 @@ strcache_add_len (const char *str, size_t len)
void void
strcache_init (void) strcache_init (void)
{ {
// [jart] increased from 8000 hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp);
hash_init (&strings, 131072, str_hash_1, str_hash_2, str_hash_cmp);
} }

View file

@ -1,45 +0,0 @@
/* stripslash.c -- remove redundant trailing slashes from a file name
Copyright (C) 1990, 2001, 2003-2006, 2009-2020 Free Software Foundation,
Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/config.h"
#include "third_party/make/dirname.h"
/* Remove trailing slashes from FILE. Return true if a trailing slash
was removed. This is useful when using file name completion from a
shell that adds a "/" after directory names (such as tcsh and
bash), because on symlinks to directories, several system calls
have different semantics according to whether a trailing slash is
present. */
bool
strip_trailing_slashes (char *file)
{
char *base = last_component (file);
char *base_lim;
bool had_slash;
/* last_component returns "" for file system roots, but we need to turn
"///" into "/". */
if (! *base)
base = file;
base_lim = base + base_len (base);
had_slash = (*base_lim != '\0');
*base_lim = '\0';
return had_slash;
}

View file

@ -1,4 +0,0 @@
#include "third_party/make/config.h"
#define _GL_UNISTD_INLINE _GL_EXTERN_INLINE
#include "third_party/make/unistd.h"
typedef int dummy;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* Definitions for using variables in GNU Make. /* Definitions for using variables in GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,9 +12,11 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/hash.h" #include "hash.h"
struct file;
/* Codes in a variable definition saying where the definition came from. /* Codes in a variable definition saying where the definition came from.
Increasing numeric values signify less-overridable definitions. */ Increasing numeric values signify less-overridable definitions. */
@ -35,12 +37,21 @@ enum variable_flavor
f_bogus, /* Bogus (error) */ f_bogus, /* Bogus (error) */
f_simple, /* Simple definition (:= or ::=) */ f_simple, /* Simple definition (:= or ::=) */
f_recursive, /* Recursive definition (=) */ f_recursive, /* Recursive definition (=) */
f_expand, /* POSIX :::= assignment */
f_append, /* Appending definition (+=) */ f_append, /* Appending definition (+=) */
f_conditional, /* Conditional definition (?=) */ f_conditional, /* Conditional definition (?=) */
f_shell, /* Shell assignment (!=) */ f_shell, /* Shell assignment (!=) */
f_append_value /* Append unexpanded value */ f_append_value /* Append unexpanded value */
}; };
enum variable_export
{
v_default = 0, /* Decide in target_environment. */
v_export, /* Export this variable. */
v_noexport, /* Don't export this variable. */
v_ifset /* Export it if it has a non-default value. */
};
/* Structure that represents one variable definition. /* Structure that represents one variable definition.
Each bucket of the hash table is a chain of these, Each bucket of the hash table is a chain of these,
chained through 'next'. */ chained through 'next'. */
@ -73,12 +84,7 @@ struct variable
enum variable_origin enum variable_origin
origin ENUM_BITFIELD (3); /* Variable origin. */ origin ENUM_BITFIELD (3); /* Variable origin. */
enum variable_export enum variable_export
{ export ENUM_BITFIELD (2); /* Export control. */
v_export, /* Export this variable. */
v_noexport, /* Don't export this variable. */
v_ifset, /* Export it if it has a non-default value. */
v_default /* Decide in target_environment. */
} export ENUM_BITFIELD (2);
}; };
/* Structure that represents a variable set. */ /* Structure that represents a variable set. */
@ -108,6 +114,7 @@ struct pattern_var
struct variable variable; struct variable variable;
}; };
extern unsigned long long env_recursion;
extern char *variable_buffer; extern char *variable_buffer;
extern struct variable_set_list *current_variable_set_list; extern struct variable_set_list *current_variable_set_list;
extern struct variable *default_goal_var; extern struct variable *default_goal_var;
@ -126,6 +133,7 @@ char *allocated_variable_expand_for_file (const char *line, struct file *file);
allocated_variable_expand_for_file (line, (struct file *) 0) allocated_variable_expand_for_file (line, (struct file *) 0)
char *expand_argument (const char *str, const char *end); char *expand_argument (const char *str, const char *end);
char *variable_expand_string (char *line, const char *string, size_t length); char *variable_expand_string (char *line, const char *string, size_t length);
char *initialize_variable_output (void);
void install_variable_buffer (char **bufp, size_t *lenp); void install_variable_buffer (char **bufp, size_t *lenp);
void restore_variable_buffer (char *buf, size_t len); void restore_variable_buffer (char *buf, size_t len);
@ -174,6 +182,8 @@ void define_new_function(const floc *flocp, const char *name,
unsigned int min, unsigned int max, unsigned int flags, unsigned int min, unsigned int max, unsigned int flags,
gmk_func_ptr func); gmk_func_ptr func);
struct variable *lookup_variable (const char *name, size_t length); struct variable *lookup_variable (const char *name, size_t length);
struct variable *lookup_variable_for_file (const char *name, size_t length,
struct file *file);
struct variable *lookup_variable_in_set (const char *name, size_t length, struct variable *lookup_variable_in_set (const char *name, size_t length,
const struct variable_set *set); const struct variable_set *set);
@ -183,6 +193,7 @@ struct variable *define_variable_in_set (const char *name, size_t length,
int recursive, int recursive,
struct variable_set *set, struct variable_set *set,
const floc *flocp); const floc *flocp);
void warn_undefined (const char* name, size_t length);
/* Define a variable in the current variable set. */ /* Define a variable in the current variable set. */
@ -221,16 +232,7 @@ void undefine_variable_in_set (const char *name, size_t length,
#define undefine_variable_global(n,l,o) \ #define undefine_variable_global(n,l,o) \
undefine_variable_in_set((n),(l),(o),NULL) undefine_variable_in_set((n),(l),(o),NULL)
/* Warn that NAME is an undefined variable. */ char **target_environment (struct file *file, int recursive);
#define warn_undefined(n,l) do{\
if (warn_undefined_variables_flag) \
error (reading_file, (l), \
_("warning: undefined variable '%.*s'"), \
(int)(l), (n)); \
}while(0)
char **target_environment (struct file *file);
struct pattern_var *create_pattern_var (const char *target, struct pattern_var *create_pattern_var (const char *target,
const char *suffix); const char *suffix);

View file

@ -1,5 +1,5 @@
/* Record version and build host architecture for GNU make. /* Record version and build host architecture for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,18 +12,18 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
/* We use <config.h> instead of "config.h" so that a compilation /* We use <config.h> instead of "config.h" so that a compilation
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
(which it would do because makeint.h was found in $srcdir). */ (which it would do because makeint.h was found in $srcdir). */
#include "third_party/make/config.h" #include "config.h"
#ifndef MAKE_HOST #ifndef MAKE_HOST
# define MAKE_HOST "unknown" # define MAKE_HOST "unknown"
#endif #endif
const char *version_string = VERSION; const char *version_string = PACKAGE_VERSION;
const char *make_host = MAKE_HOST; const char *make_host = MAKE_HOST;
/* /*

View file

@ -1,5 +1,5 @@
/* Implementation of pattern-matching file search paths for GNU Make. /* Implementation of pattern-matching file search paths for GNU Make.
Copyright (C) 1988-2020 Free Software Foundation, Inc. Copyright (C) 1988-2023 Free Software Foundation, Inc.
This file is part of GNU Make. This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,11 +12,11 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */ this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc" #include "makeint.h"
#include "third_party/make/filedef.h" #include "filedef.h"
#include "third_party/make/variable.h" #include "variable.h"
/* Structure used to represent a selective VPATH searchpath. */ /* Structure used to represent a selective VPATH searchpath. */
@ -65,20 +65,11 @@ build_vpath_lists (void)
vpaths = new; vpaths = new;
/* If there is a VPATH variable with a nonnull value, construct the /* If there is a VPATH variable with a nonnull expanded value, construct the
general VPATH list from it. We use variable_expand rather than just general VPATH list from it. */
calling lookup_variable so that it will be recursively expanded. */
{
/* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
p = variable_expand ("$(strip $(VPATH))"); p = variable_expand ("$(strip $(VPATH))");
warn_undefined_variables_flag = save;
}
if (*p != '\0') if (*p != '\0')
{ {
/* Save the list of vpaths. */ /* Save the list of vpaths. */
@ -98,20 +89,11 @@ build_vpath_lists (void)
vpaths = save_vpaths; vpaths = save_vpaths;
} }
/* If there is a GPATH variable with a nonnull value, construct the /* If there is a GPATH variable with a nonnull expanded value, construct the
GPATH list from it. We use variable_expand rather than just GPATH list from it. */
calling lookup_variable so that it will be recursively expanded. */
{
/* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
p = variable_expand ("$(strip $(GPATH))"); p = variable_expand ("$(strip $(GPATH))");
warn_undefined_variables_flag = save;
}
if (*p != '\0') if (*p != '\0')
{ {
/* Save the list of vpaths. */ /* Save the list of vpaths. */
@ -236,8 +218,7 @@ construct_vpath_list (char *pattern, char *dirpath)
also define HAVE_DOS_PATHS would like us to recognize also define HAVE_DOS_PATHS would like us to recognize
colons after the drive letter in the likes of colons after the drive letter in the likes of
"D:/foo/bar:C:/xyzzy". */ "D:/foo/bar:C:/xyzzy". */
&& (*p != PATH_SEPARATOR_CHAR && (*p != PATH_SEPARATOR_CHAR || (p == v + 1 && ISDIRSEP (p[1])))
|| (p == v + 1 && (p[1] == '/' || p[1] == '\\')))
#else #else
&& *p != PATH_SEPARATOR_CHAR && *p != PATH_SEPARATOR_CHAR
#endif #endif
@ -274,7 +255,7 @@ construct_vpath_list (char *pattern, char *dirpath)
entry, to where the nil-pointer terminator goes. entry, to where the nil-pointer terminator goes.
Usually this is maxelem - 1. If not, shrink down. */ Usually this is maxelem - 1. If not, shrink down. */
if (elem < (maxelem - 1)) if (elem < (maxelem - 1))
vpath = xrealloc (vpath, (elem+1) * sizeof (const char *)); vpath = xrealloc ((void *)vpath, (elem+1) * sizeof (const char *));
/* Put the nil-pointer terminator on the end of the VPATH list. */ /* Put the nil-pointer terminator on the end of the VPATH list. */
vpath[elem] = NULL; vpath[elem] = NULL;
@ -376,15 +357,19 @@ selective_vpath_search (struct vpath *path, const char *file,
size_t vlen = strlen (vpath[i]); size_t vlen = strlen (vpath[i]);
/* Put the next VPATH entry into NAME at P and increment P past it. */ /* Put the next VPATH entry into NAME at P and increment P past it. */
memcpy (p, vpath[i], vlen); p = mempcpy (p, vpath[i], vlen);
p += vlen;
/* Add the directory prefix already in *FILE. */ /* Add the directory prefix already in *FILE. */
if (name_dplen > 0) if (name_dplen > 0)
{ {
#ifndef VMS
*p++ = '/'; *p++ = '/';
memcpy (p, file, name_dplen); #else
p += name_dplen; /* VMS: if this is not in VMS format, treat as Unix format */
if ((*p != ':') && (*p != ']') && (*p != '>'))
*p++ = '/';
#endif
p = mempcpy (p, file, name_dplen);
} }
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
@ -393,12 +378,23 @@ selective_vpath_search (struct vpath *path, const char *file,
p[-1] = '/'; p[-1] = '/';
#endif #endif
/* Now add the name-within-directory at the end of NAME. */ /* Now add the name-within-directory at the end of NAME. */
#ifndef VMS
if (p != name && p[-1] != '/') if (p != name && p[-1] != '/')
{ {
*p = '/'; *p = '/';
memcpy (p + 1, filename, flen + 1); memcpy (p + 1, filename, flen + 1);
} }
else else
#else
/* VMS use a slash if no directory terminator present */
if (p != name && p[-1] != '/' && p[-1] != ':' &&
p[-1] != '>' && p[-1] != ']')
{
*p = '/';
memcpy (p + 1, filename, flen + 1);
}
else
#endif
memcpy (p, filename, flen + 1); memcpy (p, filename, flen + 1);
/* Check if the file is mentioned in a makefile. If *FILE is not /* Check if the file is mentioned in a makefile. If *FILE is not
@ -440,6 +436,14 @@ selective_vpath_search (struct vpath *path, const char *file,
{ {
/* That file wasn't mentioned in the makefile. /* That file wasn't mentioned in the makefile.
See if it actually exists. */ See if it actually exists. */
#ifdef VMS
/* For VMS syntax just use the original vpath */
if (*p != '/')
exists_in_cache = exists = dir_file_exists_p (vpath[i], filename);
else
#endif
{
/* Clobber a null into the name at the last slash. /* Clobber a null into the name at the last slash.
Now NAME is the name of the directory to look in. */ Now NAME is the name of the directory to look in. */
*p = '\0'; *p = '\0';
@ -448,6 +452,7 @@ selective_vpath_search (struct vpath *path, const char *file,
Does the file we seek exist in it? */ Does the file we seek exist in it? */
exists_in_cache = exists = dir_file_exists_p (name, filename); exists_in_cache = exists = dir_file_exists_p (name, filename);
} }
}
if (exists) if (exists)
{ {
@ -459,8 +464,14 @@ selective_vpath_search (struct vpath *path, const char *file,
struct stat st; struct stat st;
#ifndef VMS
/* Put the slash back in NAME. */ /* Put the slash back in NAME. */
*p = '/'; *p = '/';
#else
/* If the slash was removed, put it back */
if (*p == 0)
*p = '/';
#endif
if (exists_in_cache) /* Makefile-mentioned file need not exist. */ if (exists_in_cache) /* Makefile-mentioned file need not exist. */
{ {
@ -554,6 +565,8 @@ vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr,
return 0; return 0;
} }
/* Print the data base of VPATH search paths. */ /* Print the data base of VPATH search paths. */

View file

@ -1,41 +0,0 @@
/* Report a memory allocation failure and exit.
Copyright (C) 1997-2000, 2002-2004, 2006, 2009-2020 Free Software
Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/runtime/runtime.h"
#include "third_party/make/config.h"
#include "third_party/make/xalloc.h"
#include "third_party/make/error.h"
#include "third_party/make/exitfail.h"
#include "third_party/make/gettext.h"
#define _(msgid) gettext (msgid)
void
xalloc_die (void)
{
error (exit_failure, 0, "%s", _("memory exhausted"));
/* _Noreturn cannot be given to error, since it may return if
its first argument is 0. To help compilers understand the
xalloc_die does not return, call abort. Also, the abort is a
safety feature if exit_failure is 0 (which shouldn't happen). */
abort ();
}

View file

@ -1,58 +0,0 @@
/* xalloc-oversized.h -- memory allocation size checking
Copyright (C) 1990-2000, 2003-2004, 2006-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef XALLOC_OVERSIZED_H_
#define XALLOC_OVERSIZED_H_
/* True if N * S would overflow in a size_t calculation,
or would generate a value larger than PTRDIFF_MAX.
This expands to a constant expression if N and S are both constants.
By gnulib convention, SIZE_MAX represents overflow in size
calculations, so the conservative size_t-based dividend to use here
is SIZE_MAX - 1. */
#define __xalloc_oversized(n, s) \
((size_t) (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n))
#if PTRDIFF_MAX < SIZE_MAX
typedef ptrdiff_t __xalloc_count_type;
#else
typedef size_t __xalloc_count_type;
#endif
/* Return 1 if an array of N objects, each of size S, cannot exist
reliably due to size or ptrdiff_t arithmetic overflow. S must be
positive and N must be nonnegative. This is a macro, not a
function, so that it works correctly even when SIZE_MAX < N. */
#if 7 <= __GNUC__
# define xalloc_oversized(n, s) \
__builtin_mul_overflow_p (n, s, (__xalloc_count_type) 1)
#elif 5 <= __GNUC__ && !defined __ICC && !__STRICT_ANSI__
# define xalloc_oversized(n, s) \
(__builtin_constant_p (n) && __builtin_constant_p (s) \
? __xalloc_oversized (n, s) \
: ({ __xalloc_count_type __xalloc_count; \
__builtin_mul_overflow (n, s, &__xalloc_count); }))
/* Other compilers use integer division; this may be slower but is
more portable. */
#else
# define xalloc_oversized(n, s) __xalloc_oversized (n, s)
#endif
#endif /* !XALLOC_OVERSIZED_H_ */

View file

@ -1,261 +0,0 @@
/* xalloc.h -- malloc with out-of-memory checking
Copyright (C) 1990-2000, 2003-2004, 2006-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#ifndef XALLOC_H_
#define XALLOC_H_
#include "libc/limits.h"
#include "third_party/make/xalloc-oversized.h"
#ifndef _GL_INLINE_HEADER_BEGIN
#error "Please include config.h first."
#endif
_GL_INLINE_HEADER_BEGIN
#ifndef XALLOC_INLINE
# define XALLOC_INLINE _GL_INLINE
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if ! defined __clang__ && \
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
# define _GL_ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))
#else
# define _GL_ATTRIBUTE_ALLOC_SIZE(args)
#endif
/* This function is always triggered when memory is exhausted.
It must be defined by the application, either explicitly
or by using gnulib's xalloc-die module. This is the
function to call when one wants the program to die because of a
memory allocation failure. */
extern _Noreturn void xalloc_die (void);
void *xmalloc (size_t s)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
void *xzalloc (size_t s)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
void *xcalloc (size_t n, size_t s)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2));
void *xrealloc (void *p, size_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2));
void *x2realloc (void *p, size_t *pn);
void *xmemdup (void const *p, size_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2));
char *xstrdup (char const *str)
_GL_ATTRIBUTE_MALLOC;
/* In the following macros, T must be an elementary or structure/union or
typedef'ed type, or a pointer to such a type. To apply one of the
following macros to a function pointer or array type, you need to typedef
it first and use the typedef name. */
/* Allocate an object of type T dynamically, with error checking. */
/* extern t *XMALLOC (typename t); */
#define XMALLOC(t) ((t *) xmalloc (sizeof (t)))
/* Allocate memory for N elements of type T, with error checking. */
/* extern t *XNMALLOC (size_t n, typename t); */
#define XNMALLOC(n, t) \
((t *) (sizeof (t) == 1 ? xmalloc (n) : xnmalloc (n, sizeof (t))))
/* Allocate an object of type T dynamically, with error checking,
and zero it. */
/* extern t *XZALLOC (typename t); */
#define XZALLOC(t) ((t *) xzalloc (sizeof (t)))
/* Allocate memory for N elements of type T, with error checking,
and zero it. */
/* extern t *XCALLOC (size_t n, typename t); */
#define XCALLOC(n, t) \
((t *) (sizeof (t) == 1 ? xzalloc (n) : xcalloc (n, sizeof (t))))
/* Allocate an array of N objects, each with S bytes of memory,
dynamically, with error checking. S must be nonzero. */
XALLOC_INLINE void *xnmalloc (size_t n, size_t s)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1, 2));
XALLOC_INLINE void *
xnmalloc (size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
return xmalloc (n * s);
}
/* Change the size of an allocated block of memory P to an array of N
objects each of S bytes, with error checking. S must be nonzero. */
XALLOC_INLINE void *xnrealloc (void *p, size_t n, size_t s)
_GL_ATTRIBUTE_ALLOC_SIZE ((2, 3));
XALLOC_INLINE void *
xnrealloc (void *p, size_t n, size_t s)
{
if (xalloc_oversized (n, s))
xalloc_die ();
return xrealloc (p, n * s);
}
/* If P is null, allocate a block of at least *PN such objects;
otherwise, reallocate P so that it contains more than *PN objects
each of S bytes. S must be nonzero. Set *PN to the new number of
objects, and return the pointer to the new block. *PN is never set
to zero, and the returned pointer is never null.
Repeated reallocations are guaranteed to make progress, either by
allocating an initial block with a nonzero size, or by allocating a
larger block.
In the following implementation, nonzero sizes are increased by a
factor of approximately 1.5 so that repeated reallocations have
O(N) overall cost rather than O(N**2) cost, but the
specification for this function does not guarantee that rate.
Here is an example of use:
int *p = NULL;
size_t used = 0;
size_t allocated = 0;
void
append_int (int value)
{
if (used == allocated)
p = x2nrealloc (p, &allocated, sizeof *p);
p[used++] = value;
}
This causes x2nrealloc to allocate a block of some nonzero size the
first time it is called.
To have finer-grained control over the initial size, set *PN to a
nonzero value before calling this function with P == NULL. For
example:
int *p = NULL;
size_t used = 0;
size_t allocated = 0;
size_t allocated1 = 1000;
void
append_int (int value)
{
if (used == allocated)
{
p = x2nrealloc (p, &allocated1, sizeof *p);
allocated = allocated1;
}
p[used++] = value;
}
*/
XALLOC_INLINE void *
x2nrealloc (void *p, size_t *pn, size_t s)
{
size_t n = *pn;
if (! p)
{
if (! n)
{
/* The approximate size to use for initial small allocation
requests, when the invoking code specifies an old size of
zero. This is the largest "small" request for the GNU C
library malloc. */
enum { DEFAULT_MXFAST = 64 * sizeof (size_t) / 4 };
n = DEFAULT_MXFAST / s;
n += !n;
}
if (xalloc_oversized (n, s))
xalloc_die ();
}
else
{
/* Set N = floor (1.5 * N) + 1 so that progress is made even if N == 0.
Check for overflow, so that N * S stays in both ptrdiff_t and
size_t range. The check may be slightly conservative, but an
exact check isn't worth the trouble. */
if ((PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX) / 3 * 2 / s
<= n)
xalloc_die ();
n += n / 2 + 1;
}
*pn = n;
return xrealloc (p, n * s);
}
/* Return a pointer to a new buffer of N bytes. This is like xmalloc,
except it returns char *. */
XALLOC_INLINE char *xcharalloc (size_t n)
_GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1));
XALLOC_INLINE char *
xcharalloc (size_t n)
{
return XNMALLOC (n, char);
}
#ifdef __cplusplus
}
/* C++ does not allow conversions from void * to other pointer types
without a cast. Use templates to work around the problem when
possible. */
template <typename T> inline T *
xrealloc (T *p, size_t s)
{
return (T *) xrealloc ((void *) p, s);
}
template <typename T> inline T *
xnrealloc (T *p, size_t n, size_t s)
{
return (T *) xnrealloc ((void *) p, n, s);
}
template <typename T> inline T *
x2realloc (T *p, size_t *pn)
{
return (T *) x2realloc ((void *) p, pn);
}
template <typename T> inline T *
x2nrealloc (T *p, size_t *pn, size_t s)
{
return (T *) x2nrealloc ((void *) p, pn, s);
}
template <typename T> inline T *
xmemdup (T const *p, size_t s)
{
return (T *) xmemdup ((void const *) p, s);
}
#endif
_GL_INLINE_HEADER_END
#endif /* !XALLOC_H_ */

View file

@ -1,41 +0,0 @@
/* Construct a full filename from a directory and a relative filename.
Copyright (C) 2001-2004, 2006-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Bruno Haible <haible@clisp.cons.org>. */
#include "third_party/make/config.h"
/* Specification. */
#include "third_party/make/concat-filename.h"
#include "third_party/make/xalloc.h"
/* Concatenate a directory filename, a relative filename and an optional
suffix. The directory may end with the directory separator. The second
argument may not start with the directory separator (it is relative).
Return a freshly allocated filename. */
char *
xconcatenated_filename (const char *directory, const char *filename,
const char *suffix)
{
char *result;
result = concatenated_filename (directory, filename, suffix);
if (result == NULL)
xalloc_die ();
return result;
}

View file

@ -1,122 +0,0 @@
/* xmalloc.c -- malloc with out of memory checking
Copyright (C) 1990-2000, 2002-2006, 2008-2020 Free Software Foundation, Inc.
This program 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 Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include "libc/mem/mem.h"
#include "libc/str/str.h"
#include "third_party/make/config.h"
#define XALLOC_INLINE _GL_EXTERN_INLINE
#include "third_party/make/xalloc.h"
/* 1 if calloc is known to be compatible with GNU calloc. This
matters if we are not also using the calloc module, which defines
HAVE_CALLOC_GNU and supports the GNU API even on non-GNU platforms. */
#if defined HAVE_CALLOC_GNU || (defined __GLIBC__ && !defined __UCLIBC__)
enum { HAVE_GNU_CALLOC = 1 };
#else
enum { HAVE_GNU_CALLOC = 0 };
#endif
/* Allocate N bytes of memory dynamically, with error checking. */
void *
xmalloc (size_t n)
{
void *p = malloc (n);
if (!p && n != 0)
xalloc_die ();
return p;
}
/* Change the size of an allocated block of memory P to N bytes,
with error checking. */
void *
xrealloc (void *p, size_t n)
{
if (!n && p)
{
/* The GNU and C99 realloc behaviors disagree here. Act like
GNU, even if the underlying realloc is C99. */
free (p);
return NULL;
}
p = realloc (p, n);
if (!p && n)
xalloc_die ();
return p;
}
/* If P is null, allocate a block of at least *PN bytes; otherwise,
reallocate P so that it contains more than *PN bytes. *PN must be
nonzero unless P is null. Set *PN to the new block's size, and
return the pointer to the new block. *PN is never set to zero, and
the returned pointer is never null. */
void *
x2realloc (void *p, size_t *pn)
{
return x2nrealloc (p, pn, 1);
}
/* Allocate N bytes of zeroed memory dynamically, with error checking.
There's no need for xnzalloc (N, S), since it would be equivalent
to xcalloc (N, S). */
void *
xzalloc (size_t n)
{
return xcalloc (n, 1);
}
/* Allocate zeroed memory for N elements of S bytes, with error
checking. S must be nonzero. */
void *
xcalloc (size_t n, size_t s)
{
void *p;
/* Test for overflow, since objects with size greater than
PTRDIFF_MAX cause pointer subtraction to go awry. Omit size-zero
tests if HAVE_GNU_CALLOC, since GNU calloc never returns NULL if
successful. */
if (xalloc_oversized (n, s)
|| (! (p = calloc (n, s)) && (HAVE_GNU_CALLOC || n != 0)))
xalloc_die ();
return p;
}
/* Clone an object P of size S, with error checking. There's no need
for xnmemdup (P, N, S), since xmemdup (P, N * S) works without any
need for an arithmetic overflow check. */
void *
xmemdup (void const *p, size_t s)
{
return memcpy (xmalloc (s), p, s);
}
/* Clone STRING. */
char *
xstrdup (char const *string)
{
return xmemdup (string, strlen (string) + 1);
}