mirror of
https://github.com/mirror/make.git
synced 2026-08-21 01:13:27 +08:00
Compare commits
241 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
990d6f9b9a | ||
|
|
134480787e | ||
|
|
a9a4919909 | ||
|
|
d12ff78cb2 | ||
|
|
fabb03eac4 | ||
|
|
618c53a225 | ||
|
|
88d126d6c4 | ||
|
|
f6ea899d83 | ||
|
|
ee861a4e9f | ||
|
|
ca4234c4b5 | ||
|
|
257b82ac1f | ||
|
|
aac4004444 | ||
|
|
86fc644dcc | ||
|
|
02b3a6ad46 | ||
|
|
77734be2af | ||
|
|
820210ab85 | ||
|
|
77706874a7 | ||
|
|
a9548aeb8f | ||
|
|
70ba0357a0 | ||
|
|
7d48401707 | ||
|
|
1fc13bf576 | ||
|
|
896908180e | ||
|
|
80e9a422e4 | ||
|
|
15a7e3830f | ||
|
|
26e359c71d | ||
|
|
4da2055a10 | ||
|
|
a2ba5ccbda | ||
|
|
5eff618c8c | ||
|
|
10e130b207 | ||
|
|
62da1c45e5 | ||
|
|
ab31f0b594 | ||
|
|
8f1b6bca46 | ||
|
|
6faa02247e | ||
|
|
c72e1ec446 | ||
|
|
91d87ccf32 | ||
|
|
7ad2593b2d | ||
|
|
09cce75c30 | ||
|
|
07eea3aa49 | ||
|
|
16e14b4114 | ||
|
|
77881d2281 | ||
|
|
2fe96e4a41 | ||
|
|
dd24a4c1cf | ||
|
|
f36c6c7347 | ||
|
|
87d24154af | ||
|
|
614557d04c | ||
|
|
047544785b | ||
|
|
73b08af181 | ||
|
|
5c1d9e54c7 | ||
|
|
2d7b5d6d80 | ||
|
|
5dc7358547 | ||
|
|
e33af0fb4a | ||
|
|
6f7e06ec4e | ||
|
|
3f3eecc115 | ||
|
|
b09e9af0b8 | ||
|
|
9992cb0b83 | ||
|
|
0cbee1b475 | ||
|
|
d63925d863 | ||
|
|
0793658c09 | ||
|
|
98da874c43 | ||
|
|
88d6c22a48 | ||
|
|
c3b39d0654 | ||
|
|
fe55d6e1e3 | ||
|
|
768f287a06 | ||
|
|
8dd302cda6 | ||
|
|
df75efb114 | ||
|
|
3ec497f8f8 | ||
|
|
84ed34ba5a | ||
|
|
08c964b4ac | ||
|
|
97e51c0285 | ||
|
|
59abb46bc9 | ||
|
|
6d6f12b0c3 | ||
|
|
621d3196fa | ||
|
|
e4b7ac21dc | ||
|
|
d444b87173 | ||
|
|
1c179f9636 | ||
|
|
5690084634 | ||
|
|
9fa63eb918 | ||
|
|
668eda0527 | ||
|
|
4e1be4a60c | ||
|
|
5b1e871d2d | ||
|
|
2da3bb46f2 | ||
|
|
b264d3d4f8 | ||
|
|
51c1c07e7a | ||
|
|
700af780af | ||
|
|
f14824878d | ||
|
|
8c2aa889bb | ||
|
|
bb21dd4d2d | ||
|
|
93fd0c0c9a | ||
|
|
cf56036c60 | ||
|
|
88ceff8b2f | ||
|
|
9755d4c09c | ||
|
|
634ef057ad | ||
|
|
949c0464a9 | ||
|
|
416664b1e7 | ||
|
|
667d70eac2 | ||
|
|
b9078e5bd3 | ||
|
|
0de7b74896 | ||
|
|
236589642e | ||
|
|
cb9ac2b0cc | ||
|
|
40a6751abf | ||
|
|
1bc35a7ae7 | ||
|
|
8cdaabbf8e | ||
|
|
2be8661433 | ||
|
|
8b3e678ace | ||
|
|
ec09ec775a | ||
|
|
bdaeca49e9 | ||
|
|
342a9bb54b | ||
|
|
6761122be0 | ||
|
|
1fd0bfaf1e | ||
|
|
8eb171e469 | ||
|
|
7154e316b7 | ||
|
|
f3e345c869 | ||
|
|
d34f46c1f3 | ||
|
|
f0ab709640 | ||
|
|
5f2d114c6d | ||
|
|
cbe0d2e47f | ||
|
|
f485881d4a | ||
|
|
15db387f18 | ||
|
|
aab51f7ef2 | ||
|
|
2b25eac587 | ||
|
|
e72c5e021f | ||
|
|
b6a779d262 | ||
|
|
26f4bb89bd | ||
|
|
320714ae85 | ||
|
|
6682fbc2cb | ||
|
|
f2b130bda8 | ||
|
|
8aba33a8bd | ||
|
|
d365bdfdbc | ||
|
|
f440c3ebe2 | ||
|
|
3efba8a145 | ||
|
|
e7b2f6818c | ||
|
|
c90db9276a | ||
|
|
7192d0ec4a | ||
|
|
9230bfb9ae | ||
|
|
55b993ae09 | ||
|
|
1d20aa7247 | ||
|
|
21f7ac8f47 | ||
|
|
aa376ad638 | ||
|
|
35b51df110 | ||
|
|
e62f4cf9a2 | ||
|
|
116767901f | ||
|
|
71eb0a8038 | ||
|
|
d9291d09b8 | ||
|
|
f3ad572099 | ||
|
|
cefe747e85 | ||
|
|
3ecf97d3af | ||
|
|
21d3865973 | ||
|
|
29d92d4091 | ||
|
|
f8f9d371ff | ||
|
|
f5af979357 | ||
|
|
76cb186732 | ||
|
|
6c06c547dc | ||
|
|
c5d4b7b2f2 | ||
|
|
9e4b3d3f4c | ||
|
|
5a96d5a066 | ||
|
|
4488592dda | ||
|
|
e7eb8b5962 | ||
|
|
0c2fc00544 | ||
|
|
214df0e92a | ||
|
|
b2e898d0bf | ||
|
|
abb1e8d10b | ||
|
|
cc6dc70b16 | ||
|
|
2638552859 | ||
|
|
de48d6a4f7 | ||
|
|
55f06bdc3f | ||
|
|
0d367bbe6e | ||
|
|
f4b8ddf260 | ||
|
|
e13fd5c83d | ||
|
|
7c4e6b0299 | ||
|
|
b9c4fc441b | ||
|
|
65b73ce434 | ||
|
|
2d73c9bf25 | ||
|
|
33468b3f31 | ||
|
|
1cffd0a203 | ||
|
|
b580949ae0 | ||
|
|
f2771aa614 | ||
|
|
5e829188d3 | ||
|
|
297cb5adb7 | ||
|
|
012918bf11 | ||
|
|
1ae90c030d | ||
|
|
0fb6f2d985 | ||
|
|
97a8d9b45a | ||
|
|
c5c02accb7 | ||
|
|
76a099997b | ||
|
|
c5319e75f5 | ||
|
|
510e5ce801 | ||
|
|
144f436c4b | ||
|
|
52056d7b2c | ||
|
|
c66ec5fa20 | ||
|
|
da6fc6aae2 | ||
|
|
d9aff6b817 | ||
|
|
e5f6dc54b9 | ||
|
|
88732a29f2 | ||
|
|
7b0a741857 | ||
|
|
74bd8b3aa5 | ||
|
|
9043b28250 | ||
|
|
fcc11d05a6 | ||
|
|
a8f4669b23 | ||
|
|
bd4829096c | ||
|
|
7044e0c93c | ||
|
|
94d9077691 | ||
|
|
c4cc2e9595 | ||
|
|
5e234e4048 | ||
|
|
950f3d305f | ||
|
|
58a37927e6 | ||
|
|
ec272f3a9c | ||
|
|
ef6aca5a38 | ||
|
|
b262ea5d8f | ||
|
|
cc20f90507 | ||
|
|
9e2fa24649 | ||
|
|
2dc0280d82 | ||
|
|
90959b8b70 | ||
|
|
19ae6fe72a | ||
|
|
0e020bbc24 | ||
|
|
c01222c018 | ||
|
|
957aa450a0 | ||
|
|
e49e11e069 | ||
|
|
f4f353bb54 | ||
|
|
a80b0096f5 | ||
|
|
62e8f029e9 | ||
|
|
db7658e042 | ||
|
|
fa7f95c66c | ||
|
|
df5f30a76a | ||
|
|
1770540217 | ||
|
|
c8a6263eb5 | ||
|
|
a015d1f822 | ||
|
|
c604e53a45 | ||
|
|
d79fe162c0 | ||
|
|
0c326a66c9 | ||
|
|
f79bde1a6d | ||
|
|
289108cc9b | ||
|
|
61c413d5ea | ||
|
|
d3a53d5d16 | ||
|
|
1306023a4f | ||
|
|
80b90b7866 | ||
|
|
8e024a2532 | ||
|
|
660a2eafe5 | ||
|
|
8277806db6 | ||
|
|
6ba5ea022a | ||
|
|
4533348826 | ||
|
|
68fbad6667 |
1
.ccls
1
.ccls
@@ -13,6 +13,7 @@ clang
|
||||
-Wall
|
||||
-Wextra
|
||||
-Werror
|
||||
-Wno-address
|
||||
-Wwrite-strings
|
||||
-Wshadow
|
||||
-Wdeclaration-after-statement
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
(
|
||||
(nil . ((bug-reference-bug-regexp . "\\(\\)\\bSV[- ]\\([0-9]+\\)")
|
||||
(bug-reference-url-format . "https://savannah.gnu.org/bugs/?%s")
|
||||
(ccls-initialization-options . (:index (:threads 6
|
||||
:initialBlacklist ("/make-[0-9]" "tests/work/" "/\\.deps" "/\\..*cache" "/\\.git"))))
|
||||
(lsp-file-watch-ignored . ("/\\.git$"
|
||||
"/\\..*cache$"
|
||||
;; autotools content
|
||||
"/\\.deps$"
|
||||
"/autom4te\\.cache$"
|
||||
"/build-aux$"
|
||||
;; make-specific content
|
||||
"/doc/manual$"
|
||||
"/tests/work$"
|
||||
"/make-[0-9]"))
|
||||
(ccls-initialization-options
|
||||
. (:index (:threads 6
|
||||
:initialBlacklist ["/make-[0-9]" "tests/work/" "/\\.deps"
|
||||
"/\\..*cache" "/\\.git"])))
|
||||
(lsp-file-watch-ignored-directories
|
||||
. ("[/\\\\]\\.git$"
|
||||
"[/\\\\]\\..*cache$"
|
||||
;; autotools content
|
||||
"[/\\\\]\\.deps$"
|
||||
"[/\\\\]autom4te\\.cache$"
|
||||
"[/\\\\]build-aux$"
|
||||
;; make-specific content
|
||||
"[/\\\\]doc[/\\\\]manual$"
|
||||
"[/\\\\]tests[/\\\\]work$"
|
||||
"[/\\\\]make-[0-9]"))
|
||||
))
|
||||
(c-mode . ((c-file-style . "gnu")))
|
||||
)
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -11,8 +11,14 @@ GTAGS
|
||||
*~
|
||||
#*
|
||||
.#*
|
||||
*.diff
|
||||
*.patch
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Configure artifacts
|
||||
/lib/
|
||||
/m4/
|
||||
ABOUT-NLS
|
||||
INSTALL
|
||||
Makefile
|
||||
@@ -31,6 +37,7 @@ configure
|
||||
stamp-h1
|
||||
.dirstamp
|
||||
gnulib
|
||||
convert.sed
|
||||
|
||||
# Build artifacts
|
||||
.deps/
|
||||
|
||||
43
AUTHORS
43
AUTHORS
@@ -10,7 +10,6 @@ Development starting with GNU make 3.76 by:
|
||||
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>
|
||||
@@ -34,6 +33,9 @@ GNU make porting efforts:
|
||||
Port to Amiga by:
|
||||
Aaron Digulla <digulla@fh-konstanz.de>
|
||||
|
||||
Port to MS-Windows (native/MinGW) maintained by:
|
||||
Eli Zaretskii <eliz@gnu.org>
|
||||
|
||||
Port to MS-DOS (DJGPP), OS/2, and MS-Windows (native/MinGW) by:
|
||||
DJ Delorie <dj@delorie.com>
|
||||
Rob Tulloh <rob_tulloh@tivoli.com>
|
||||
@@ -46,35 +48,62 @@ GNU make porting efforts:
|
||||
-----------------------------------
|
||||
Other contributors:
|
||||
|
||||
Luke Allardyce <lukeallardyce@gmail.com>
|
||||
Aron Barath <baratharon@caesar.elte.hu>
|
||||
David Boyce <dsb@boyski.com>
|
||||
Kevin Buettner <kevinb@redhat.com>
|
||||
Janet Carson <janet_carson@tivoli.com>
|
||||
Howard Chu <hyc@highlandsun.com>
|
||||
Ludovic Courtès <ludo@gnu.org>
|
||||
Joe Crayne <oh.hello.joe@gmail.com>
|
||||
Jeremy Devenport <jeremy.devenport@gmail.com>
|
||||
Pete Dietl <petedietl@gmail.com>
|
||||
Martin Dorey <martin.dorey@hds.com>
|
||||
Christian Eggers <ceggers@arri.de>
|
||||
Paul Eggert <eggert@twinsun.com>
|
||||
Mike Frysinger <vapier@gentoo.org>
|
||||
Ramon Garcia Fernandez <ramon.garcia.f@gmail.com>
|
||||
Dmitry Goncharov <dgoncharov@users.sf.net>
|
||||
Mike Haboustak <haboustak@gmail.com>
|
||||
Frank Heckenbach <f.heckenbach@fh-soft.de>
|
||||
Klaus Heinz <kamar@ease.rhein-main.de>
|
||||
Ben Hutchings <ben@decadent.org.uk>
|
||||
Cao jin <caoj.fnst@cn.fujitsu.com>
|
||||
Michael Joosten
|
||||
Christian Jullien <eligis@orange.fr>
|
||||
Jim Kelton <jim_kelton@tivoli.com>
|
||||
Kaz Kylheku <kaz@kylheku.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>
|
||||
Enrique Olaizola <enrique_olaizola16@hotmail.com>
|
||||
Ola Olsson <ola1olsson@gmail.com>
|
||||
Jens Rehsack <sno@netbsd.org>
|
||||
Thomas Riedl <thomas.riedl@siemens.com>
|
||||
Jaak Ristioja <jaak@ristioja.ee>
|
||||
Christoph Schulz <develop@kristov.de>
|
||||
Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
|
||||
spagoveanu <spagoveanu@gmail.com>
|
||||
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>
|
||||
Tobias Stoeckmann <tobias@stoeckmann.org>
|
||||
Sergei Trofimovich <siarheit@google.com>
|
||||
Marc Ullman <marc@mathworks.com>
|
||||
Christof Warlich <cwarlich@gmx.de>
|
||||
Florian Weimer <fweimer@redhat.com>
|
||||
David A. Wheeler <dwheeler@dwheeler.com>
|
||||
Bernhard M. Wiedemann <bwiedemann@suse.de>
|
||||
Ben Wijen <ben@wijen.net>
|
||||
Jouke Witteveen <j.witteveen@gmail.com>
|
||||
|
||||
With suggestions/comments/bug reports from a cast of ... well ...
|
||||
hundreds, anyway :)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1997-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997-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
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# make.exe -f Basic.mk
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
@@ -88,8 +88,9 @@ COMPILE.cmd = $(CC) $(extra_CFLAGS) $(CFLAGS) $(extra_CPPFLAGS) $(CPPFLAGS) $(TA
|
||||
# $(call LINK.cmd,<objectlist>)
|
||||
LINK.cmd = $(LD) $(extra_LDFLAGS) $(LDFLAGS) $(TARGET_ARCH) $1 $(LDLIBS) $(LINK_OUTPUT)
|
||||
|
||||
# $(CHECK.cmd)
|
||||
# $(CHECK.cmd) $(CHECK.args)
|
||||
CHECK.cmd = cd $(SRCDIR)/tests && ./run_make_tests -make $(shell cd $(<D) && pwd)/$(<F)
|
||||
CHECK.args ?=
|
||||
|
||||
# $(call MKDIR.cmd,<dirlist>)
|
||||
MKDIR.cmd = mkdir -p $1
|
||||
@@ -123,7 +124,7 @@ $(OBJDIRS):
|
||||
$(call MKDIR.cmd,$@)
|
||||
|
||||
check:
|
||||
$(CHECK.cmd)
|
||||
$(CHECK.cmd) $(CHECK.args)
|
||||
|
||||
clean:
|
||||
$(CLEANSPACE)
|
||||
|
||||
8
COPYING
8
COPYING
@@ -1,7 +1,7 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
@@ -645,7 +645,7 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
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/>.
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
@@ -664,11 +664,11 @@ 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/>.
|
||||
<https://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>.
|
||||
<https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
|
||||
37
Makefile.am
37
Makefile.am
@@ -1,6 +1,6 @@
|
||||
# This is a -*-Makefile-*-, or close enough
|
||||
#
|
||||
# Copyright (C) 1997-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1997-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
|
||||
@@ -35,8 +35,9 @@ make_SRCS = src/ar.c src/arscan.c src/commands.c src/commands.h \
|
||||
src/hash.c src/hash.h src/implicit.c src/job.c src/job.h \
|
||||
src/load.c src/loadapi.c src/main.c src/makeint.h src/misc.c \
|
||||
src/os.h src/output.c src/output.h src/read.c src/remake.c \
|
||||
src/rule.c src/rule.h src/signame.c src/strcache.c \
|
||||
src/variable.c src/variable.h src/version.c src/vpath.c
|
||||
src/rule.c src/rule.h src/shuffle.h src/shuffle.c \
|
||||
src/signame.c src/strcache.c src/variable.c src/variable.h \
|
||||
src/version.c src/vpath.c
|
||||
|
||||
w32_SRCS = src/w32/pathstuff.c src/w32/w32os.c src/w32/compat/dirent.c \
|
||||
src/w32/compat/posixfcn.c src/w32/include/dirent.h \
|
||||
@@ -59,16 +60,28 @@ loadavg_SRCS = lib/getloadavg.c
|
||||
make_SOURCES = $(make_SRCS)
|
||||
EXTRA_make_SOURCES = $(amiga_SRCS) $(vms_SRCS)
|
||||
|
||||
make_LDADD = $(LIBOBJS) $(GUILE_LIBS) lib/libgnu.a $(GETLOADAVG_LIBS) \
|
||||
if HAVE_GUILE
|
||||
_GUILE_CFLAGS = $(GUILE_CFLAGS)
|
||||
_GUILE_LIBS = $(GUILE_LIBS)
|
||||
else
|
||||
_GUILE_CFLAGS =
|
||||
_GUILE_LIBS =
|
||||
endif
|
||||
|
||||
make_LDADD = $(LIBOBJS) $(_GUILE_LIBS) lib/libgnu.a $(GETLOADAVG_LIBS) \
|
||||
@LIBINTL@
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
AM_CPPFLAGS = -Isrc -I$(top_srcdir)/src -Ilib -I$(top_srcdir)/lib \
|
||||
-DLIBDIR=\"$(libdir)\" -DINCLUDEDIR=\"$(includedir)\" \
|
||||
-DLOCALEDIR=\"$(localedir)\"
|
||||
-DLIBDIR=\"$(libdir)\" -DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
AM_CFLAGS = $(GUILE_CFLAGS)
|
||||
# If prefix is not a standard location, look in prefix as well
|
||||
if !KNOWN_PREFIX
|
||||
AM_CPPFLAGS += -DINCLUDEDIR=\"$(includedir)\"
|
||||
endif
|
||||
|
||||
AM_CFLAGS = $(_GUILE_CFLAGS)
|
||||
|
||||
if WINDOWSENV
|
||||
make_SOURCES += $(w32_SRCS)
|
||||
@@ -98,7 +111,7 @@ test_FILES = tests/run_make_tests tests/run_make_tests.bat \
|
||||
tests/mkshadow tests/thelp.pl tests/guile.supp tests/README
|
||||
# test/scripts are added via dist-hook below.
|
||||
|
||||
EXTRA_DIST = ChangeLog README build.sh build.cfg.in $(man_MANS) \
|
||||
EXTRA_DIST = ChangeLog INSTALL README build.sh build.cfg.in $(man_MANS) \
|
||||
README.customs README.OS2 \
|
||||
README.Amiga SCOPTIONS src/config.ami \
|
||||
README.DOS builddos.bat src/configh.dos \
|
||||
@@ -149,6 +162,8 @@ MAKETESTFLAGS =
|
||||
|
||||
.PHONY: check-regression
|
||||
|
||||
GMK_OUTDIR=..
|
||||
|
||||
check-regression: tests/config-flags.pm
|
||||
@if test -f '$(top_srcdir)/tests/run_make_tests'; then \
|
||||
ulimit -n 128; \
|
||||
@@ -157,12 +172,12 @@ check-regression: tests/config-flags.pm
|
||||
*) test -d tests || mkdir tests; \
|
||||
rm -f srctests; \
|
||||
if ln -s '$(top_srcdir)/tests' srctests; then \
|
||||
for f in run_make_tests run_make_tests.pl test_driver.pl scripts jhelp.pl; do \
|
||||
for f in run_make_tests run_make_tests.pl test_driver.pl scripts thelp.pl; do \
|
||||
rm -f tests/$$f; ln -s ../srctests/$$f tests; \
|
||||
done; fi ;; \
|
||||
esac; \
|
||||
echo "cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir $(abs_top_srcdir) -make ../make$(EXEEXT) $(MAKETESTFLAGS)"; \
|
||||
cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir '$(abs_top_srcdir)' -make '../make$(EXEEXT)' $(MAKETESTFLAGS); \
|
||||
echo "cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir $(abs_top_srcdir) -make $(GMK_OUTDIR)/make$(EXEEXT) $(MAKETESTFLAGS)"; \
|
||||
cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir '$(abs_top_srcdir)' -make '$(GMK_OUTDIR)/make$(EXEEXT)' $(MAKETESTFLAGS); \
|
||||
else \
|
||||
echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \
|
||||
fi; \
|
||||
|
||||
175
NEWS
175
NEWS
@@ -1,6 +1,6 @@
|
||||
GNU make NEWS -*-indented-text-*-
|
||||
History of user-visible changes.
|
||||
19 January 2020
|
||||
20 September 2022
|
||||
|
||||
See the end of this file for copyrights and conditions.
|
||||
|
||||
@@ -8,6 +8,170 @@ All user-visible changes are more fully described in the GNU make manual,
|
||||
which is contained in this distribution as the file doc/make.texi.
|
||||
See the README file and the GNU make manual for instructions for
|
||||
reporting bugs.
|
||||
|
||||
Version 4.3.90 (20 Sep 2022)
|
||||
|
||||
A complete list of bugs fixed in this version is available here:
|
||||
|
||||
https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&set=custom
|
||||
|
||||
* WARNING: Backward-incompatibility!
|
||||
Previously if --no-print-directory was seen anywhere in the environment or
|
||||
command line it would take precedence over any --print-directory. Now, the
|
||||
last setting of directory printing options seen will be used, so a command
|
||||
line such as "--no-print-directory -w" _will_ show directory entry/exits.
|
||||
|
||||
* WARNING: Backward-incompatibility!
|
||||
Previously the order in which makefiles were remade was not explicitly
|
||||
stated, but it was (roughly) the inverse of the order in which they were
|
||||
processed by make. In this release, the order in which makefiles are
|
||||
rebuilt is the same order in which make processed them, and this is defined
|
||||
to be true in the GNU make manual.
|
||||
|
||||
* WARNING: Backward-incompatibility!
|
||||
Previously only simple (one-letter) options were added to the MAKEFLAGS
|
||||
variable that was visible while parsing makefiles. Now, all options are
|
||||
available in MAKEFLAGS. If you want to check MAKEFLAGS for a one-letter
|
||||
option, expanding "$(firstword -$(MAKEFLAGS))" is a reliable way to return
|
||||
the set of one-letter options which can be examined via findstring, etc.
|
||||
|
||||
* WARNING: Backward-incompatibility!
|
||||
Previously makefile variables marked as export were not exported to commands
|
||||
started by the $(shell ...) function. Now, all exported variables are
|
||||
exported to $(shell ...). If this leads to recursion during expansion, then
|
||||
for backward-compatibility the value from the original environment is used.
|
||||
To detect this change search for 'shell-export' in the .FEATURES variable.
|
||||
|
||||
* WARNING: New build requirement
|
||||
GNU make utilizes facilities from GNU Gnulib: Gnulib requires certain C99
|
||||
features in the C compiler and so these features are required by GNU make:
|
||||
https://www.gnu.org/software/gnulib/manual/html_node/C99-features-assumed.html
|
||||
The configure script should verify the compiler has these features.
|
||||
|
||||
* New feature: The .WAIT special target
|
||||
If the .WAIT target appears between two prerequisites of a target, then
|
||||
GNU make will wait for all of the targets to the left of .WAIT in the list
|
||||
to complete before starting any of the targets to the right of .WAIT.
|
||||
This feature is available in some other versions of make, and it will be
|
||||
required by an upcoming version of the POSIX standard for make.
|
||||
Different patches were made by Alexey Neyman <alex.neyman@auriga.ru> (2005)
|
||||
and Steffen Nurpmeso <steffen@sdaoden.eu> (2020) that were useful but the
|
||||
result is a different implementation (closer to Alexey's idea).
|
||||
|
||||
* New feature: .NOTPARALLEL accepts prerequisites
|
||||
If the .NOTPARALLEL special target has prerequisites then all prerequisites
|
||||
of those targets will be run serially (as if .WAIT was specified between
|
||||
each prerequisite).
|
||||
|
||||
* New feature: The .NOTINTERMEDIATE special target
|
||||
.NOTINTERMEDIATE Disables intermediate behavior for specific files, for all
|
||||
files built using a pattern, or for the entire makefile.
|
||||
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
|
||||
|
||||
* New feature: The $(let ...) function
|
||||
This function allows user-defined functions to define a set of local
|
||||
variables: values can be assigned to these variables from within the
|
||||
user-defined function and they will not impact global variable assignments.
|
||||
Implementation provided by Jouke Witteveen <j.witteveen@gmail.com>
|
||||
|
||||
* New feature: The $(intcmp ...) function
|
||||
This function allows conditional evaluation controlled by a numerical
|
||||
comparison.
|
||||
Implementation provided by Jouke Witteveen <j.witteveen@gmail.com>
|
||||
|
||||
* New feature: Improved support for -l / --load-average
|
||||
On systems that provide /proc/loadavg (Linux), GNU make will use it to
|
||||
determine the number of runnable jobs and use this as the current load,
|
||||
avoiding the need for heuristics.
|
||||
Implementation provided by Sven C. Dack <sdack@gmx.com>
|
||||
|
||||
* New feature: The --shuffle command line option
|
||||
This option reorders goals and prerequisites to simulate non-determinism
|
||||
that may be seen using parallel build. Shuffle mode allows a form of "fuzz
|
||||
testing" of parallel builds to verify that all prerequisites are correctly
|
||||
described in the makefile.
|
||||
Implementation provided by Sergei Trofimovich <siarheit@google.com>
|
||||
|
||||
* New feature: The --jobserver-style command line option and named pipes
|
||||
A new jobserver method is used on systems where mkfifo(3) is supported.
|
||||
This solves a number of obscure issues related to using the jobserver
|
||||
and recursive invocations of GNU make. This change means that sub-makes
|
||||
will connect to the jobserver even if they are not marked as recursive.
|
||||
It also means that other tools that want to participate in the jobserver
|
||||
will need to be enhanced as described in the GNU make manual.
|
||||
You can force GNU make to use the simple pipe-based jobserver (perhaps if
|
||||
you are integrating with other tools or older versions of GNU make) by
|
||||
adding the '--jobserver-style=pipe' option to the command line of the
|
||||
top-level invocation of GNU make, or via MAKEFLAGS or GNUMAKEFLAGS.
|
||||
To detect this change search for 'jobserver-fifo' in the .FEATURES variable.
|
||||
|
||||
* New feature: The MAKE_TMPDIR environment variable
|
||||
If you prefer that GNU make place temporary files in a different directory
|
||||
than the standard TMPDIR (or TMP or TEMP on Windows), set the MAKE_TMPDIR
|
||||
environment variable before starting make (this value CANNOT be set inside
|
||||
the makefile, since make needs to find its temporary directory before the
|
||||
makefiles are parsed). This is useful for build systems which reset TMPDIR
|
||||
and clean it out during the build process.
|
||||
|
||||
* Some POSIX systems (*BSD) do not allow locks to be taken on pipes, which
|
||||
caused the output sync feature to not work properly there. Also multiple
|
||||
invocations of make redirecting to the same output file (e.g., /dev/null)
|
||||
would cause hangs. Instead of locking stdout (which does have some useful
|
||||
performance characteristics, but is not portable) create a temporary file
|
||||
and lock that. Windows continues to use a mutex as before.
|
||||
|
||||
* GNU make has sometimes chosen unexpected, and sub-optimal, chains of
|
||||
implicit rules due to the definition of "ought to exist" in the implicit
|
||||
rule search algorithm, which considered any prerequisite mentioned in the
|
||||
makefile as "ought to exist". This algorithm has been modified to prefer
|
||||
prerequisites mentioned explicitly in the target being built and only if
|
||||
that results in no matching rule, will GNU make consider prerequisites
|
||||
mentioned in other targets as "ought to exist".
|
||||
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
|
||||
|
||||
* GNU make was performing secondary expansion of all targets, even targets
|
||||
which didn't need to be considered during the build. In this release
|
||||
only targets which are considered will be secondarily expanded.
|
||||
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
|
||||
|
||||
* If the MAKEFLAGS variable is modified in a makefile, it will be re-parsed
|
||||
immediately rather than after all makefiles have been read. Note that
|
||||
although all options are parsed immediately, some special effects won't
|
||||
appear until after all makefiles are read.
|
||||
|
||||
* The -I option accepts an argument "-" (e.g., "-I-") which means "reset the
|
||||
list of search directories to empty". Among other things this can be used
|
||||
to prevent GNU make from searching in its default list of directories.
|
||||
|
||||
* New debug option "print" will show the recipe to be run, even when silent
|
||||
mode is set, and new debug option "why" will show why a target is rebuilt
|
||||
(which prerequisites caused the target to be considered out of date).
|
||||
Implementation provided by David Boyce <David.S.Boyce@gmail.com>
|
||||
|
||||
* The existing --trace option is made equivalent to --debug=print,why
|
||||
|
||||
* Target-specific variables can now be marked "unexport".
|
||||
|
||||
* Exporting / unexporting target-specific variables is handled correctly, so
|
||||
that the attribute of the most specific variable setting is used.
|
||||
|
||||
* Special targets like .POSIX are detected upon definition, ensuring that any
|
||||
change in behavior takes effect immediately, before the next line is parsed.
|
||||
|
||||
* When the jobserver is enabled and GNU make decides it is invoking a non-make
|
||||
sub-process and closes the jobserver pipes, it will now add a new option to
|
||||
the MAKEFLAGS environment variable that disables the jobserver.
|
||||
This prevents sub-processes that invoke make from accidentally using other
|
||||
open file descriptors as jobserver pipes. For more information see
|
||||
https://savannah.gnu.org/bugs/?57242 and https://savannah.gnu.org/bugs/?62397
|
||||
|
||||
* A long-standing issue with the directory cache has been resolved: changes
|
||||
made as a side-effect of some other target's recipe are now noticed as
|
||||
expected.
|
||||
|
||||
* GNU Make can now be built for MS-Windows using the Tiny C tcc compiler.
|
||||
Port provided by Christian Jullien <eligis@orange.fr>
|
||||
|
||||
|
||||
Version 4.3 (19 Jan 2020)
|
||||
|
||||
@@ -35,6 +199,13 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=108&se
|
||||
already contains some value. Similarly, appending an empty string does not
|
||||
add a trailing space.
|
||||
|
||||
* WARNING: Backward-incompatibility!
|
||||
Previously using the .SILENT pseudo-target in a makefile would force all
|
||||
sub-makes to be invoked with the '-s' option, effectively making all
|
||||
sub-makes silent as well. In this release .SILENT only affects the current
|
||||
invocation of make. A side-effect of this is that .SILENT will no longer
|
||||
enable the --no-print-directory option, which using -s will do.
|
||||
|
||||
* NOTE: Deprecated behavior.
|
||||
Contrary to the documentation, suffix rules with prerequisites are being
|
||||
treated BOTH as simple targets AND as pattern rules. Further, the
|
||||
@@ -1619,7 +1790,7 @@ Version 3.05
|
||||
(Changes from versions 1 through 3.05 were never recorded. Sorry.)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
|
||||
@@ -64,7 +64,7 @@ If you plan to use recursive makes, install make resident:
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
|
||||
@@ -280,7 +280,7 @@ Bug reports:
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-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
|
||||
|
||||
@@ -138,7 +138,7 @@ testsuite itself. -DNO_CMD_DEFAULT causes make to use /bin/sh as default
|
||||
shell in every case. Normally you could simply set MAKESHELL="/bin/sh"
|
||||
to do this but the testsuite ignores the environment. -DNO_CHDIR2 causes
|
||||
make not to use drive letters for directory names (i.e. _chdir2() and
|
||||
_getcwd2() are NOT used). The testsuite interpretes the whole output of
|
||||
_getcwd2() are NOT used). The testsuite interprets the whole output of
|
||||
make, especially statements like make[1]: Entering directory
|
||||
'C:/somewhere/make-3.79.1/tests' where the testsuite does not expect the
|
||||
drive letter. This would be interpreted as an error even if there is
|
||||
@@ -160,7 +160,7 @@ from the make source tree.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2003-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2003-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
|
||||
|
||||
70
README.VMS
70
README.VMS
@@ -11,7 +11,7 @@ Overview: -*-text-mode-*-
|
||||
There is an older implementation of GNU Make that was ported to GNV.
|
||||
Work is now in progress to merge that port to get a single version
|
||||
of GNU Make available. When that merge is done, GNU Make will auto
|
||||
detect that it is running under a Posix shell and then operate as close to
|
||||
detect that it is running under a POSIX shell and then operate as close to
|
||||
GNU Make on Unix as possible.
|
||||
|
||||
The descriptions below are for running GNU make from DCL or equivalent.
|
||||
@@ -62,15 +62,15 @@ Recipe differences:
|
||||
enabled if the GNU Make is set to the older behavior.
|
||||
|
||||
The name GNV$MAKE_SHELL_SIM when enabled will cause GNU Make to try to
|
||||
simulate a Posix shell more closely. The following behaviors occur:
|
||||
simulate a POSIX shell more closely. The following behaviors occur:
|
||||
|
||||
* Single quotes are converted to double quotes and any double
|
||||
quotes inside of them are doubled. No environment variable expansion
|
||||
is simulated.
|
||||
* A exit command status will be converted to a Posix Exit
|
||||
* A exit command status will be converted to a POSIX Exit
|
||||
where 0 is success and non-zero is failure.
|
||||
* The $ character will cause environment variable expansion.
|
||||
* Environent variables can be set on the command line before a command.
|
||||
* Environment variables can be set on the command line before a command.
|
||||
|
||||
VMS generally uses logical name search lists instead of path variables
|
||||
where the resolution is handled by VMS independent of the program. Which
|
||||
@@ -88,7 +88,7 @@ Recipe differences:
|
||||
|
||||
If you are creating a OpenVMS specific makefile from scratch, you should also
|
||||
look at MMK (Madgoat Make) available at https://github.com/endlesssoftware/mmk
|
||||
MMK uses full OpenVMS syntax and a persistent subprocess is used for the
|
||||
MMK uses full OpenVMS syntax and a persistent sub-process is used for the
|
||||
recipe lines, allowing multiple line rules.
|
||||
|
||||
The default makefile search order is "makefile.vms", "gnumakefile",
|
||||
@@ -207,15 +207,15 @@ foo: $(addsuffix .3,$(subs $(comma),$(space),$^)
|
||||
override OpenVMS symbols/logicals.
|
||||
|
||||
OpenVMS logical and symbols names show up as "environment" using the
|
||||
origin function. when the "-e" option is specified, the origion function
|
||||
shows them as "environment override". On Posix the test scripts indicate
|
||||
origin function. when the "-e" option is specified, the origin function
|
||||
shows them as "environment override". On POSIX the test scripts indicate
|
||||
that they should show up just as "environment".
|
||||
|
||||
When GNU make reads in a symbol or logical name into the environment, it
|
||||
converts any dollar signs found to double dollar signs for convenience in
|
||||
using DCL symbols and logical names in recipes. When GNU make exports a
|
||||
DCL symbol for a child process, if the first dollar sign found is followed
|
||||
by second dollar sign, then all double dollar signs will be convirted to
|
||||
by second dollar sign, then all double dollar signs will be converted to
|
||||
single dollar signs.
|
||||
|
||||
The variable $(ARCH) is predefined as IA64, ALPHA or VAX respectively.
|
||||
@@ -233,17 +233,17 @@ endif
|
||||
|
||||
Empty commands are handled correctly and don't end in a new DCL process.
|
||||
|
||||
The exit command needs to have OpenVMS exit codes. To pass a Posix code
|
||||
The exit command needs to have OpenVMS exit codes. To pass a POSIX code
|
||||
back to the make script, you need to encode it by multiplying it by 8
|
||||
and then adding %x1035a002 for a failure code and %x1035a001 for a
|
||||
success. Make will interpret any posix code other than 0 as a failure.
|
||||
TODO: Add an option have simulate Posix exit commands in recipes.
|
||||
success. Make will interpret any POSIX code other than 0 as a failure.
|
||||
TODO: Add an option have simulate POSIX exit commands in recipes.
|
||||
|
||||
Lexical functions can be used in pipes to simulate shell file test rules.
|
||||
|
||||
Example:
|
||||
|
||||
Posix:
|
||||
POSIX:
|
||||
b : c ; [ -f $@ ] || echo >> $@
|
||||
|
||||
OpenVMS:
|
||||
@@ -261,16 +261,16 @@ x = %x1035a00a
|
||||
|
||||
Runtime issues:
|
||||
|
||||
The OpenVMS C Runtime has a convention for encoding a Posix exit status into
|
||||
The OpenVMS C Runtime has a convention for encoding a POSIX exit status into
|
||||
to OpenVMS exit codes. These status codes will have the hex value of
|
||||
0x35a000. OpenVMS exit code may also have a hex value of %x10000000 set on
|
||||
them. This is a flag to tell DCL not to write out the exit code.
|
||||
|
||||
To convert an OpenVMS encoded Posix exit status code to the original code
|
||||
To convert an OpenVMS encoded POSIX exit status code to the original code
|
||||
You subtract %x35a000 and any flags from the OpenVMS code and divide it by 8.
|
||||
|
||||
WARNING: Backward-incompatibility!
|
||||
The make program exit now returns the same encoded Posix exit code as on
|
||||
The make program exit now returns the same encoded POSIX exit code as on
|
||||
Unix. Previous versions returned the OpenVMS exit status code if that is what
|
||||
caused the recipe to fail.
|
||||
TODO: Provide a way for scripts calling make to obtain that OpenVMS status
|
||||
@@ -280,9 +280,9 @@ Runtime issues:
|
||||
will have the error "-E-" severity set on exit.
|
||||
|
||||
MAKE_TROUBLE is returned only if the option "-q" or "--question" is used and
|
||||
has a Posix value of 1 and an OpenVMS status of %x1035a00a.
|
||||
has a POSIX value of 1 and an OpenVMS status of %x1035a00a.
|
||||
|
||||
MAKE_FAILURE has a Posix value of 2 and an OpenVMS status of %x1035a012.
|
||||
MAKE_FAILURE has a POSIX value of 2 and an OpenVMS status of %x1035a012.
|
||||
|
||||
Output from GNU make may have single quotes around some values where on
|
||||
other platforms it does not. Also output that would be in double quotes
|
||||
@@ -294,10 +294,10 @@ Runtime issues:
|
||||
There may be a "Waiting for unfinished jobs..." show up in the output.
|
||||
|
||||
Error messages generated by Make or Unix utilities may slightly vary from
|
||||
Posix platforms. Typically the case may be different.
|
||||
POSIX platforms. Typically the case may be different.
|
||||
|
||||
When make deletes files, on posix platforms it writes out 'rm' and the list
|
||||
of files. On VMS, only the files are writen out, one per line.
|
||||
When make deletes files, on POSIX platforms it writes out 'rm' and the list
|
||||
of files. On VMS, only the files are written out, one per line.
|
||||
TODO: VMS
|
||||
|
||||
There may be extra leading white space or additional or missing whitespace
|
||||
@@ -323,15 +323,15 @@ Runtime issues:
|
||||
to override this in your makefile, or whatever).
|
||||
|
||||
|
||||
Unix compatibilty features:
|
||||
---------------------------
|
||||
Unix compatibility features:
|
||||
----------------------------
|
||||
|
||||
If the command 'echo' is seen, any single quotes on the line will be
|
||||
converted to double quotes.
|
||||
|
||||
The variable $(CD) is implemented as a built in Change Directory
|
||||
command. This invokes the 'builtin_cd' Executing a 'set default'
|
||||
recipe doesn't do the trick, since it only affects the subprocess
|
||||
recipe doesn't do the trick, since it only affects the sub-process
|
||||
spawned for that command.
|
||||
|
||||
The 'builtin_cd' is generally expected to be on its own line.
|
||||
@@ -347,7 +347,7 @@ Unix compatibilty features:
|
||||
Unix shell style I/O redirection is supported. You can now write lines like:
|
||||
"<tab>mcr sys$disk:[]program.exe < input.txt > output.txt &> error.txt"
|
||||
|
||||
Posix shells have ":" as a null command. These are now handled.
|
||||
POSIX shells have ":" as a null command. These are now handled.
|
||||
https://savannah.gnu.org/bugs/index.php?41761
|
||||
|
||||
A note on appending the redirected output. A simple mechanism is
|
||||
@@ -367,10 +367,10 @@ Unix compatibilty features:
|
||||
The older implementation wrote the output to a temporary file in
|
||||
in sys$scratch: and then attempted to append the file to the existing file.
|
||||
The temporary file names looked like "CMDxxxxx.". Any time the created
|
||||
command procedure can not complete, this happens. Pressing Ctrl+Y to
|
||||
command procedure can not complete, this happens. Pressing CTRL+Y to
|
||||
abort make is one case.
|
||||
|
||||
In case of Ctrl+Y the associated command procedure is left in SYS$SCRATCH:.
|
||||
In case of CTRL+Y the associated command procedure is left in SYS$SCRATCH:.
|
||||
The command procedures will be named gnv$make_cmd*.com.
|
||||
|
||||
The CtrlY handler now uses $delprc to delete all children. This way also
|
||||
@@ -378,12 +378,12 @@ Unix compatibilty features:
|
||||
then sends SIGQUIT to itself, which is handled in common code.
|
||||
|
||||
Temporary command files are now deleted in the OpenVMS child termination
|
||||
handler. That deletes them even if a Ctrl+C was pressed.
|
||||
handler. That deletes them even if a CTRL+C was pressed.
|
||||
TODO: Does the previous section about >> leaving files still apply?
|
||||
|
||||
The behavior of pressing Ctrl+C is not changed. It still has only an effect,
|
||||
The behavior of pressing CTRL+C is not changed. It still has only an effect,
|
||||
after the current action is terminated. If that doesn't happen or takes too
|
||||
long, Ctrl+Y should be used instead.
|
||||
long, CTRL+Y should be used instead.
|
||||
|
||||
|
||||
Build Options:
|
||||
@@ -422,7 +422,7 @@ Self test failures and todos:
|
||||
child.
|
||||
|
||||
GNU make was not currently translating the OpenVMS encoded POSIX values
|
||||
returned to it back to the Posix values. I have temporarily modified the
|
||||
returned to it back to the POSIX values. I have temporarily modified the
|
||||
Perl test script to compensate for it. This should be being handled
|
||||
internally to Make.
|
||||
TODO: Verify and update the Perl test script.
|
||||
@@ -435,7 +435,7 @@ Self test failures and todos:
|
||||
Symlink support is not present. Symlinks are supported by OpenVMS 8.3 and
|
||||
later.
|
||||
|
||||
Error messages should be supressed with the "-" at the beginning of a line.
|
||||
Error messages should be suppressed with the "-" at the beginning of a line.
|
||||
On openVMS they were showing up. TODO: Is this still an issue?
|
||||
|
||||
The internal vmsify and unixify OpenVMS to/from UNIX are not handling logical
|
||||
@@ -443,7 +443,7 @@ Self test failures and todos:
|
||||
|
||||
|
||||
Build instructions:
|
||||
------------------
|
||||
-------------------
|
||||
|
||||
Don't use the HP C V7.2-001 compiler, which has an incompatible change
|
||||
how __STDC__ is defined. This results at least in compile time warnings.
|
||||
@@ -478,7 +478,7 @@ Running the tests:
|
||||
https://sourceforge.net/projects/gnv/files/
|
||||
|
||||
As the test scripts need to create some foreign commands that persist
|
||||
after the test is run, it is recommend that either you use a subprocess or
|
||||
after the test is run, it is recommend that either you use a sub-process or
|
||||
a dedicated login to run the tests.
|
||||
|
||||
To get detailed information for running the tests:
|
||||
@@ -499,12 +499,12 @@ Running the tests:
|
||||
$ perl run_make_tests.pl
|
||||
|
||||
|
||||
Acknowlegements:
|
||||
Acknowledgments:
|
||||
----------------
|
||||
|
||||
See NEWS. for details of past changes.
|
||||
|
||||
These are the currently known contributers to this port.
|
||||
These are the currently known contributors to this port.
|
||||
|
||||
Hartmut Becker
|
||||
John Malmberg
|
||||
|
||||
@@ -345,7 +345,7 @@ Bug reports:
|
||||
is described in the GNU make manual and the base README.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-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
|
||||
|
||||
@@ -96,7 +96,7 @@ SunOS 4.1.x:
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1998-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1998-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
|
||||
|
||||
97
README.git
97
README.git
@@ -1,7 +1,7 @@
|
||||
-*-text-*-
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2002-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2002-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
|
||||
@@ -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.
|
||||
|
||||
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/>.
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Obtaining Git Code
|
||||
@@ -23,7 +23,7 @@ Obtaining Git Code
|
||||
This seems redundant, since if you're reading this you most likely have
|
||||
already performed this step; however, for completeness, you can obtain the GNU
|
||||
make source code via Git from the FSF's Savannah project
|
||||
<http://savannah.gnu.org/projects/make/>:
|
||||
<https://savannah.gnu.org/projects/make/>:
|
||||
|
||||
$ git clone git://git.savannah.gnu.org/make.git
|
||||
|
||||
@@ -31,8 +31,11 @@ make source code via Git from the FSF's Savannah project
|
||||
Changes using Git
|
||||
-----------------
|
||||
|
||||
For non-developers, you can continue to provide patches as before, or if you
|
||||
make a public repository I can pull from that if you prefer.
|
||||
If you do not have push privileges to the GNU make Git repository, see the
|
||||
README file section "Submitting Patches" for information.
|
||||
|
||||
If you have push privileges to the GNU make Git repository keep this
|
||||
information in mind:
|
||||
|
||||
Starting with GNU make 4.0 we no longer keep a separate ChangeLog file in
|
||||
source control. We use the Gnulib git-to-changelog conversion script to
|
||||
@@ -43,22 +46,25 @@ added before it so be sure your comment lines are not longer than 72
|
||||
characters; prefer 70 or less. Please use standard ChangeLog formats for
|
||||
your commit messages (sans the leading TAB of course).
|
||||
|
||||
Rule #1: Don't rewrite pushed history (don't use "git push --force").
|
||||
Rule #1: Don't rewrite pushed history on master (no "git push --force").
|
||||
Rule #2: Feel free to rewrite pushed history on personal branches.
|
||||
Rule #3: Prefer to squash-merge or rebase + merge --ff-only, rather than
|
||||
merging from personal branches into master.
|
||||
|
||||
Typical simple workflow might be:
|
||||
|
||||
* Edit files
|
||||
* Edit files / make / make check
|
||||
* Use "git status" and "git diff" to verify your changes
|
||||
* Use "git add" to stage the changes you want to make
|
||||
* Use "git commit" to commit the staged changes to your local repository
|
||||
* Use "git pull" to accept & merge new changes from the Savannah repository
|
||||
* Use "git push" to push your commits back to the Savannah repository
|
||||
* Use "git pull -r" to accept new changes from the upstream repository
|
||||
* Use "git push" to push your commits back to the upstream repository
|
||||
|
||||
For Emacs users, there are many options for Git integration but I strongly
|
||||
recommend the Magit package: http://www.emacswiki.org/emacs/Magit
|
||||
It makes the workflow much clearer, and has advanced features such as
|
||||
constructing multiple commits from various files and even from different
|
||||
diff chunks in the same file. There is a video available which helps a lot.
|
||||
recommend Magit: https://magit.vc/ It makes the workflow much clearer, and
|
||||
has advanced features such as constructing multiple commits from various files
|
||||
and even from different diff chunks in the same file. There is a video
|
||||
available which helps a lot.
|
||||
|
||||
|
||||
Coding Standards
|
||||
@@ -68,9 +74,10 @@ GNU make code adheres to the GNU Coding Standards. Please use only spaces and
|
||||
no TAB characters in source code.
|
||||
|
||||
Additionally, GNU make is a foundational bootstrap package for the GNU
|
||||
project; as such it is very conservative about language features it expects.
|
||||
It should build with any C compiler conforming to the ANSI C89 / ISO C90
|
||||
standard.
|
||||
project; as such it is conservative about language features it expects.
|
||||
However, GNU make does rely on the Gnulib portability library, and Gnulib
|
||||
currently requires a ISO C99 compiler. So features in ISO C99 can be
|
||||
assumed.
|
||||
|
||||
|
||||
Building From Git for POSIX
|
||||
@@ -79,13 +86,13 @@ Building From Git for POSIX
|
||||
To build GNU make from Git on POSIX systems such as GNU/Linux, you will
|
||||
need to install the following extra software:
|
||||
|
||||
* autoconf
|
||||
* autoconf >= 2.69
|
||||
* automake >= 1.16.1
|
||||
* gettext
|
||||
* autopoint
|
||||
* pkg-config
|
||||
* texinfo (for makeinfo)
|
||||
* GCC (Clang's GCC emulation is not sufficient)
|
||||
* GCC
|
||||
* GNU make (POSIX make is not sufficient)
|
||||
|
||||
And any tools that those utilities require (GNU m4, etc.)
|
||||
@@ -94,14 +101,14 @@ To run the tests you must install Perl.
|
||||
|
||||
To build a release you'll need to install lzip.
|
||||
|
||||
GNU make requires gnulib to provide some facilities. If you want to maintain
|
||||
GNU make requires Gnulib to provide some facilities. If you want to maintain
|
||||
a local installation of gnulib you can set GNULIB_SRCDIR to point to it.
|
||||
Otherwise, ./bootstrap will obtain a clone for you.
|
||||
|
||||
Unfortunately due to issues with gnulib's getloadavg, you must have automake
|
||||
1.16.1 or above. This version may not yet be available through GNU/Linux
|
||||
package managers. If you need to install from source be sure to set
|
||||
ACLOCAL_PATH to point to the pkg-config location (e.g., /usr/share/aclocal).
|
||||
Due to issues with gnulib's getloadavg, you must have automake 1.16.1 or
|
||||
above. This version may not yet be available through GNU/Linux package
|
||||
managers. If you need to install from source be sure to set ACLOCAL_PATH to
|
||||
point to the pkg-config location (e.g., /usr/share/aclocal).
|
||||
|
||||
If you want to build from Git with a non-GCC compiler, add "MAKE_CFLAGS=" to
|
||||
your make command line (or at least remove any flags your compiler does not
|
||||
@@ -116,6 +123,16 @@ After checking out the code, you will need to run the bootstrap script:
|
||||
|
||||
$ ./bootstrap
|
||||
|
||||
Alternatively you can just pull content from remote locations with:
|
||||
|
||||
$ ./autopull.sh
|
||||
|
||||
And/or just re-generate auto-generatable files with:
|
||||
|
||||
$ ./autogen.sh
|
||||
|
||||
(Running ./bootstrap does both in one step.)
|
||||
|
||||
At this point you have successfully brought your Git copy of the GNU
|
||||
make source directory up to the point where it can be treated
|
||||
more-or-less like the official package you would get from ftp.gnu.org.
|
||||
@@ -158,6 +175,40 @@ script to prime your Git workspace:
|
||||
Next, rename the file README.W32.template to README.W32 and follow those
|
||||
instructions.
|
||||
|
||||
Note, neither of these methods are tested regularly by the GNU make
|
||||
maintainers. Building for Windows from a distribution tarball IS tested
|
||||
regularly.
|
||||
|
||||
|
||||
Debugging and Testing
|
||||
---------------------
|
||||
|
||||
These instructions have been tested on GNU systems. I have no idea if they
|
||||
work on non-GNU systems (Windows, MacOS, etc.)
|
||||
|
||||
* Alternate Configurations:
|
||||
The maintMakefile has a rule for running configure with various different
|
||||
options, with and without packages. Run:
|
||||
|
||||
make check-alt-config
|
||||
|
||||
* Valgrind:
|
||||
You can run all tests under valgrind by passing the -memcheck option:
|
||||
|
||||
(cd tests && ./run_make_tests -make ../make -memcheck)
|
||||
|
||||
Note, this is slow! Also some tests will fail because of invoking valgrind.
|
||||
|
||||
* ASAN:
|
||||
You can build with ASAN and run tests, like this:
|
||||
|
||||
make clean
|
||||
make -j8 CFLAGS='-ggdb3 -fsanitize=address' LDFLAGS='-ggdb3 -fsanitize=address'
|
||||
(cd tests && ./run_make_tests -make ../make)
|
||||
|
||||
Note that ASAN is reporting many more errors than valgrind. I don't know
|
||||
which one is wrong: I haven't looked at them closely.
|
||||
|
||||
|
||||
Creating a Package
|
||||
------------------
|
||||
|
||||
@@ -34,7 +34,7 @@ Downloading
|
||||
|
||||
GNU Make can be obtained in many different ways. See a description here:
|
||||
|
||||
http://www.gnu.org/software/software.html
|
||||
https://www.gnu.org/software/software.html
|
||||
|
||||
|
||||
Documentation
|
||||
@@ -45,9 +45,9 @@ in this distribution as the file make.texinfo. You can also find
|
||||
on-line and preformatted (PostScript and DVI) versions at the FSF's web
|
||||
site. There is information there about ordering hardcopy documentation.
|
||||
|
||||
http://www.gnu.org/
|
||||
http://www.gnu.org/doc/doc.html
|
||||
http://www.gnu.org/manual/manual.html
|
||||
https://www.gnu.org/
|
||||
https://www.gnu.org/doc/doc.html
|
||||
https://www.gnu.org/manual/manual.html
|
||||
|
||||
|
||||
Development
|
||||
@@ -56,11 +56,11 @@ Development
|
||||
GNU Make development is hosted by Savannah, the FSF's online development
|
||||
management tool. Savannah is here:
|
||||
|
||||
http://savannah.gnu.org
|
||||
https://savannah.gnu.org
|
||||
|
||||
And the GNU Make development page is here:
|
||||
|
||||
http://savannah.gnu.org/projects/make/
|
||||
https://savannah.gnu.org/projects/make/
|
||||
|
||||
You can find most information concerning the development of GNU Make at
|
||||
this site.
|
||||
@@ -76,7 +76,7 @@ information on submitting useful and complete bug reports.
|
||||
You can also use the online bug tracking system in the Savannah GNU Make
|
||||
project to submit new problem reports or search for existing ones:
|
||||
|
||||
http://savannah.gnu.org/bugs/?group=make
|
||||
https://savannah.gnu.org/bugs/?group=make
|
||||
|
||||
If you need help using GNU make, try these forums:
|
||||
|
||||
@@ -86,13 +86,34 @@ If you need help using GNU make, try these forums:
|
||||
news:gnu.utils.bug
|
||||
|
||||
|
||||
Submitting Patches
|
||||
------------------
|
||||
|
||||
If you'd like to propose a change to GNU make, you can provide a patch with
|
||||
your changes. If you are making your changes in a Git workspace you can run
|
||||
"git format-patch" to create a patch file. If not, you can use the diff(1)
|
||||
utility to create a patch file; please use "diff -u".
|
||||
|
||||
Once you have a patch you can submit it in any of these ways:
|
||||
|
||||
* Create a bug on Savannah and add the patch as an attachment:
|
||||
https://savannah.gnu.org/bugs/?group=make&func=additem
|
||||
|
||||
* Send the patch via email to <bug-make@gnu.org>: be sure to add it as an
|
||||
attachment to avoid interference by email processors.
|
||||
|
||||
Be aware that all non-trivial changes proposed for GNU make require FSF
|
||||
copyright paperwork to be completed before they can be accepted. Contact
|
||||
<bug-make@gnu.org> for help.
|
||||
|
||||
|
||||
Git Access
|
||||
----------
|
||||
|
||||
The GNU make source repository is available via Git from the GNU Savannah Git
|
||||
server; look here for details:
|
||||
|
||||
http://savannah.gnu.org/git/?group=make
|
||||
https://savannah.gnu.org/git/?group=make
|
||||
|
||||
Please note: you won't be able to build GNU make from Git without installing
|
||||
appropriate maintainer's tools, such as GNU m4, automake, autoconf, Perl, GNU
|
||||
@@ -115,7 +136,7 @@ The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be
|
||||
used to configure GNU make. Please install a different shell such as
|
||||
bash or pdksh in order to run "configure". See this message for more
|
||||
information:
|
||||
http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html
|
||||
https://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html
|
||||
|
||||
One area that is often a problem in configuration and porting is the code
|
||||
to check the system's current load average. To make it easier to test and
|
||||
@@ -157,7 +178,7 @@ Ports
|
||||
using DJGPP tools.
|
||||
|
||||
A precompiled binary of the MSDOS port of GNU Make is available as part
|
||||
of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more
|
||||
of DJGPP; see the WWW page https://www.delorie.com/djgpp/ for more
|
||||
information.
|
||||
|
||||
The Cygwin project maintains its own port of GNU make. That port may have
|
||||
@@ -172,7 +193,7 @@ at the right README!
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -185,4 +206,4 @@ 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/>.
|
||||
this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
@@ -101,7 +101,7 @@ The Rest of the List
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 1997-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1997-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
|
||||
|
||||
486
autogen.sh
Executable file
486
autogen.sh
Executable file
@@ -0,0 +1,486 @@
|
||||
#!/bin/sh
|
||||
# Convenience script for regenerating all autogeneratable files that are
|
||||
# omitted from the version control repository. In particular, this script
|
||||
# also regenerates all aclocal.m4, config.h.in, Makefile.in, configure files
|
||||
# with new versions of autoconf or automake.
|
||||
|
||||
# Copyright (C) 2003-2022 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/>.
|
||||
|
||||
# Originally written by Paul Eggert. The canonical version of this
|
||||
# script is maintained as top/autogen.sh in gnulib. However, to be
|
||||
# useful to your package, you should place a copy of it under version
|
||||
# control in the top-level directory of your package. The intent is
|
||||
# that all customization can be done with a bootstrap.conf file also
|
||||
# maintained in your version control; gnulib comes with a template
|
||||
# build-aux/bootstrap.conf to get you started.
|
||||
#
|
||||
# Alternatively, you can use an autogen.sh script that is specific
|
||||
# to your package.
|
||||
|
||||
scriptversion=2022-07-24.15; # UTC
|
||||
|
||||
me="$0"
|
||||
medir=`dirname "$me"`
|
||||
|
||||
# Read the function library and the configuration.
|
||||
. "$medir"/bootstrap-funclib.sh
|
||||
|
||||
# Ensure that CDPATH is not set. Otherwise, the output from cd
|
||||
# would cause trouble in at least one use below.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
# Environment variables that may be set by the user.
|
||||
: "${AUTOPOINT=autopoint}"
|
||||
: "${AUTORECONF=autoreconf}"
|
||||
|
||||
if test "$vc_ignore" = auto; then
|
||||
vc_ignore=
|
||||
test -d .git && vc_ignore=.gitignore
|
||||
test -d CVS && vc_ignore="$vc_ignore .cvsignore"
|
||||
fi
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $me [OPTION]...
|
||||
Bootstrap this package from the checked-out sources.
|
||||
|
||||
Optional environment variables:
|
||||
GNULIB_SRCDIR Specifies the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
you want to use these sources.
|
||||
|
||||
Options:
|
||||
--copy copy files instead of creating symbolic links
|
||||
--force attempt to bootstrap even if the sources seem
|
||||
not to have been checked out
|
||||
EOF
|
||||
bootstrap_print_option_usage_hook
|
||||
cat <<EOF
|
||||
If the file bootstrap.conf exists in the same directory as this script, its
|
||||
contents are read as shell variables to configure the bootstrap.
|
||||
|
||||
For build prerequisites, environment variables like \$AUTOCONF and \$AMTAR
|
||||
are honored.
|
||||
|
||||
Gnulib sources are assumed to be present:
|
||||
* in \$GNULIB_SRCDIR, if that environment variable is set,
|
||||
* otherwise, in the 'gnulib' submodule, if such a submodule is configured,
|
||||
* otherwise, in the 'gnulib' subdirectory.
|
||||
|
||||
Running without arguments will suffice in most cases.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse options.
|
||||
|
||||
# Whether to use copies instead of symlinks.
|
||||
copy=false
|
||||
|
||||
for option
|
||||
do
|
||||
case $option in
|
||||
--help)
|
||||
usage
|
||||
exit;;
|
||||
--version)
|
||||
set -e
|
||||
echo "autogen.sh $scriptversion"
|
||||
echo "$copyright"
|
||||
exit 0
|
||||
;;
|
||||
--force)
|
||||
checkout_only_file=;;
|
||||
--copy)
|
||||
copy=true;;
|
||||
*)
|
||||
bootstrap_option_hook $option || die "$option: unknown option";;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$GNULIB_SRCDIR" || test -d "$GNULIB_SRCDIR" \
|
||||
|| die "Error: \$GNULIB_SRCDIR environment variable or --gnulib-srcdir option is specified, but does not denote a directory"
|
||||
|
||||
if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
|
||||
die "Running this script from a non-checked-out distribution is risky."
|
||||
fi
|
||||
|
||||
if $use_gnulib; then
|
||||
if test -z "$GNULIB_SRCDIR"; then
|
||||
gnulib_path=$(test -f .gitmodules && git config --file .gitmodules submodule.gnulib.path)
|
||||
test -z "$gnulib_path" && gnulib_path=gnulib
|
||||
GNULIB_SRCDIR=$gnulib_path
|
||||
fi
|
||||
fi
|
||||
|
||||
version_controlled_file() {
|
||||
parent=$1
|
||||
file=$2
|
||||
if test -d .git; then
|
||||
git rm -n "$file" > /dev/null 2>&1
|
||||
elif test -d .svn; then
|
||||
svn log -r HEAD "$file" > /dev/null 2>&1
|
||||
elif test -d CVS; then
|
||||
grep -F "/${file##*/}/" "$parent/CVS/Entries" 2>/dev/null |
|
||||
grep '^/[^/]*/[0-9]' > /dev/null
|
||||
else
|
||||
warn_ "no version control for $file?"
|
||||
false
|
||||
fi
|
||||
}
|
||||
|
||||
# Strip blank and comment lines to leave significant entries.
|
||||
gitignore_entries() {
|
||||
sed '/^#/d; /^$/d' "$@"
|
||||
}
|
||||
|
||||
# If $STR is not already on a line by itself in $FILE, insert it at the start.
|
||||
# Entries are inserted at the start of the ignore list to ensure existing
|
||||
# entries starting with ! are not overridden. Such entries support
|
||||
# whitelisting exceptions after a more generic blacklist pattern.
|
||||
insert_if_absent() {
|
||||
file=$1
|
||||
str=$2
|
||||
test -f $file || touch $file
|
||||
test -r $file || die "Error: failed to read ignore file: $file"
|
||||
duplicate_entries=$(gitignore_entries $file | sort | uniq -d)
|
||||
if [ "$duplicate_entries" ] ; then
|
||||
die "Error: Duplicate entries in $file: " $duplicate_entries
|
||||
fi
|
||||
linesold=$(gitignore_entries $file | wc -l)
|
||||
linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l)
|
||||
if [ $linesold != $linesnew ] ; then
|
||||
{ echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \
|
||||
|| die "insert_if_absent $file $str: failed"
|
||||
fi
|
||||
}
|
||||
|
||||
# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with
|
||||
# insert_if_absent.
|
||||
insert_vc_ignore() {
|
||||
vc_ignore_file="$1"
|
||||
pattern="$2"
|
||||
case $vc_ignore_file in
|
||||
*.gitignore)
|
||||
# A .gitignore entry that does not start with '/' applies
|
||||
# recursively to subdirectories, so prepend '/' to every
|
||||
# .gitignore entry.
|
||||
pattern=$(echo "$pattern" | sed s,^,/,);;
|
||||
esac
|
||||
insert_if_absent "$vc_ignore_file" "$pattern"
|
||||
}
|
||||
|
||||
symlink_to_dir()
|
||||
{
|
||||
src=$1/$2
|
||||
dst=${3-$2}
|
||||
|
||||
test -f "$src" && {
|
||||
|
||||
# If the destination directory doesn't exist, create it.
|
||||
# This is required at least for "lib/uniwidth/cjk.h".
|
||||
dst_dir=$(dirname "$dst")
|
||||
if ! test -d "$dst_dir"; then
|
||||
mkdir -p "$dst_dir"
|
||||
|
||||
# If we've just created a directory like lib/uniwidth,
|
||||
# tell version control system(s) it's ignorable.
|
||||
# FIXME: for now, this does only one level
|
||||
parent=$(dirname "$dst_dir")
|
||||
for dot_ig in x $vc_ignore; do
|
||||
test $dot_ig = x && continue
|
||||
ig=$parent/$dot_ig
|
||||
insert_vc_ignore $ig "${dst_dir##*/}"
|
||||
done
|
||||
fi
|
||||
|
||||
if $copy; then
|
||||
{
|
||||
test ! -h "$dst" || {
|
||||
echo "$me: rm -f $dst" &&
|
||||
rm -f "$dst"
|
||||
}
|
||||
} &&
|
||||
test -f "$dst" &&
|
||||
cmp -s "$src" "$dst" || {
|
||||
echo "$me: cp -fp $src $dst" &&
|
||||
cp -fp "$src" "$dst"
|
||||
}
|
||||
else
|
||||
# Leave any existing symlink alone, if it already points to the source,
|
||||
# so that broken build tools that care about symlink times
|
||||
# aren't confused into doing unnecessary builds. Conversely, if the
|
||||
# existing symlink's timestamp is older than the source, make it afresh,
|
||||
# so that broken tools aren't confused into skipping needed builds. See
|
||||
# <https://lists.gnu.org/r/bug-gnulib/2011-05/msg00326.html>.
|
||||
test -h "$dst" &&
|
||||
src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 &&
|
||||
dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 &&
|
||||
test "$src_i" = "$dst_i" &&
|
||||
both_ls=$(ls -dt "$src" "$dst") &&
|
||||
test "X$both_ls" = "X$dst$nl$src" || {
|
||||
dot_dots=
|
||||
case $src in
|
||||
/*) ;;
|
||||
*)
|
||||
case /$dst/ in
|
||||
*//* | */../* | */./* | /*/*/*/*/*/)
|
||||
die "invalid symlink calculation: $src -> $dst";;
|
||||
/*/*/*/*/) dot_dots=../../../;;
|
||||
/*/*/*/) dot_dots=../../;;
|
||||
/*/*/) dot_dots=../;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
echo "$me: ln -fs $dot_dots$src $dst" &&
|
||||
ln -fs "$dot_dots$src" "$dst"
|
||||
}
|
||||
fi
|
||||
}
|
||||
}
|
||||
|
||||
# Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac.
|
||||
found_aux_dir=no
|
||||
grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'])' configure.ac \
|
||||
>/dev/null && found_aux_dir=yes
|
||||
grep '^[ ]*AC_CONFIG_AUX_DIR('"$build_aux"')' configure.ac \
|
||||
>/dev/null && found_aux_dir=yes
|
||||
test $found_aux_dir = yes \
|
||||
|| die "configure.ac lacks 'AC_CONFIG_AUX_DIR([$build_aux])'; add it"
|
||||
|
||||
# If $build_aux doesn't exist, create it now, otherwise some bits
|
||||
# below will malfunction. If creating it, also mark it as ignored.
|
||||
if test ! -d $build_aux; then
|
||||
mkdir $build_aux
|
||||
for dot_ig in x $vc_ignore; do
|
||||
test $dot_ig = x && continue
|
||||
insert_vc_ignore $dot_ig $build_aux
|
||||
done
|
||||
fi
|
||||
|
||||
check_build_prerequisites false
|
||||
|
||||
use_libtool=0
|
||||
# We'd like to use grep -E, to see if any of LT_INIT,
|
||||
# AC_PROG_LIBTOOL, AM_PROG_LIBTOOL is used in configure.ac,
|
||||
# but that's not portable enough (e.g., for Solaris).
|
||||
grep '^[ ]*A[CM]_PROG_LIBTOOL' configure.ac >/dev/null \
|
||||
&& use_libtool=1
|
||||
grep '^[ ]*LT_INIT' configure.ac >/dev/null \
|
||||
&& use_libtool=1
|
||||
if test $use_libtool = 1; then
|
||||
find_tool LIBTOOLIZE glibtoolize libtoolize
|
||||
fi
|
||||
|
||||
if $use_gnulib; then
|
||||
gnulib_tool=$GNULIB_SRCDIR/gnulib-tool
|
||||
<$gnulib_tool || exit $?
|
||||
fi
|
||||
|
||||
# NOTE: we have to be careful to run both autopoint and libtoolize
|
||||
# before gnulib-tool, since gnulib-tool is likely to provide newer
|
||||
# versions of files "installed" by these two programs.
|
||||
# Then, *after* gnulib-tool (see below), we have to be careful to
|
||||
# run autoreconf in such a way that it does not run either of these
|
||||
# two just-pre-run programs.
|
||||
|
||||
# Import from gettext.
|
||||
with_gettext=yes
|
||||
grep '^[ ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \
|
||||
with_gettext=no
|
||||
|
||||
if test $with_gettext = yes || test $use_libtool = 1; then
|
||||
|
||||
tempbase=.bootstrap$$
|
||||
trap "rm -f $tempbase.0 $tempbase.1" 1 2 13 15
|
||||
|
||||
> $tempbase.0 > $tempbase.1 &&
|
||||
find . ! -type d -print | sort > $tempbase.0 || exit
|
||||
|
||||
if test $with_gettext = yes; then
|
||||
# Released autopoint has the tendency to install macros that have been
|
||||
# obsoleted in current gnulib, so run this before gnulib-tool.
|
||||
echo "$0: $AUTOPOINT --force"
|
||||
$AUTOPOINT --force || exit
|
||||
fi
|
||||
|
||||
# Autoreconf runs aclocal before libtoolize, which causes spurious
|
||||
# warnings if the initial aclocal is confused by the libtoolized
|
||||
# (or worse out-of-date) macro directory.
|
||||
# libtoolize 1.9b added the --install option; but we support back
|
||||
# to libtoolize 1.5.22, where the install action was default.
|
||||
if test $use_libtool = 1; then
|
||||
install=
|
||||
case $($LIBTOOLIZE --help) in
|
||||
*--install*) install=--install ;;
|
||||
esac
|
||||
echo "running: $LIBTOOLIZE $install --copy"
|
||||
$LIBTOOLIZE $install --copy
|
||||
fi
|
||||
|
||||
find . ! -type d -print | sort >$tempbase.1
|
||||
old_IFS=$IFS
|
||||
IFS=$nl
|
||||
for file in $(comm -13 $tempbase.0 $tempbase.1); do
|
||||
IFS=$old_IFS
|
||||
parent=${file%/*}
|
||||
version_controlled_file "$parent" "$file" || {
|
||||
for dot_ig in x $vc_ignore; do
|
||||
test $dot_ig = x && continue
|
||||
ig=$parent/$dot_ig
|
||||
insert_vc_ignore "$ig" "${file##*/}"
|
||||
done
|
||||
}
|
||||
done
|
||||
IFS=$old_IFS
|
||||
|
||||
rm -f $tempbase.0 $tempbase.1
|
||||
trap - 1 2 13 15
|
||||
fi
|
||||
|
||||
# Import from gnulib.
|
||||
|
||||
if $use_gnulib; then
|
||||
gnulib_tool_options="\
|
||||
--no-changelog\
|
||||
--aux-dir=$build_aux\
|
||||
--doc-base=$doc_base\
|
||||
--lib=$gnulib_name\
|
||||
--m4-base=$m4_base/\
|
||||
--source-base=$source_base/\
|
||||
--tests-base=$tests_base\
|
||||
--local-dir=$local_gl_dir\
|
||||
$gnulib_tool_option_extras\
|
||||
"
|
||||
if test $use_libtool = 1; then
|
||||
case "$gnulib_tool_options " in
|
||||
*' --libtool '*) ;;
|
||||
*) gnulib_tool_options="$gnulib_tool_options --libtool" ;;
|
||||
esac
|
||||
fi
|
||||
echo "$0: $gnulib_tool $gnulib_tool_options --import ..."
|
||||
$gnulib_tool $gnulib_tool_options --import $gnulib_modules \
|
||||
|| die "gnulib-tool failed"
|
||||
|
||||
for file in $gnulib_files; do
|
||||
symlink_to_dir "$GNULIB_SRCDIR" $file \
|
||||
|| die "failed to symlink $file"
|
||||
done
|
||||
fi
|
||||
|
||||
bootstrap_post_import_hook \
|
||||
|| die "bootstrap_post_import_hook failed"
|
||||
|
||||
# Remove any dangling symlink matching "*.m4" or "*.[ch]" in some
|
||||
# gnulib-populated directories. Such .m4 files would cause aclocal to fail.
|
||||
# The following requires GNU find 4.2.3 or newer. Considering the usual
|
||||
# portability constraints of this script, that may seem a very demanding
|
||||
# requirement, but it should be ok. Ignore any failure, which is fine,
|
||||
# since this is only a convenience to help developers avoid the relatively
|
||||
# unusual case in which a symlinked-to .m4 file is git-removed from gnulib
|
||||
# between successive runs of this script.
|
||||
find "$m4_base" "$source_base" \
|
||||
-depth \( -name '*.m4' -o -name '*.[ch]' \) \
|
||||
-type l -xtype l -delete > /dev/null 2>&1
|
||||
|
||||
# Invoke autoreconf with --force --install to ensure upgrades of tools
|
||||
# such as ylwrap.
|
||||
AUTORECONFFLAGS="--verbose --install --force -I $m4_base $ACLOCAL_FLAGS"
|
||||
|
||||
# Some systems (RHEL 5) are using ancient autotools, for which the
|
||||
# --no-recursive option had not been invented. Detect that lack and
|
||||
# omit the option when it's not supported. FIXME in 2017: remove this
|
||||
# hack when RHEL 5 autotools are updated, or when they become irrelevant.
|
||||
case $($AUTORECONF --help) in
|
||||
*--no-recursive*) AUTORECONFFLAGS="$AUTORECONFFLAGS --no-recursive";;
|
||||
esac
|
||||
|
||||
# Tell autoreconf not to invoke autopoint or libtoolize; they were run above.
|
||||
echo "running: AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS"
|
||||
AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS \
|
||||
|| die "autoreconf failed"
|
||||
|
||||
# Get some extra files from gnulib, overriding existing files.
|
||||
for file in $gnulib_extra_files; do
|
||||
case $file in
|
||||
*/INSTALL) dst=INSTALL;;
|
||||
build-aux/*) dst=$build_aux/${file#build-aux/};;
|
||||
*) dst=$file;;
|
||||
esac
|
||||
symlink_to_dir "$GNULIB_SRCDIR" $file $dst \
|
||||
|| die "failed to symlink $file"
|
||||
done
|
||||
|
||||
if test $with_gettext = yes; then
|
||||
# Create gettext configuration.
|
||||
echo "$0: Creating po/Makevars from po/Makevars.template ..."
|
||||
rm -f po/Makevars
|
||||
sed '
|
||||
/^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/
|
||||
/^COPYRIGHT_HOLDER *=/s/=.*/= '"$COPYRIGHT_HOLDER"'/
|
||||
/^MSGID_BUGS_ADDRESS *=/s|=.*|= '"$MSGID_BUGS_ADDRESS"'|
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' po/Makevars.template >po/Makevars \
|
||||
|| die 'cannot generate po/Makevars'
|
||||
|
||||
# If the 'gettext' module is in use, grab the latest Makefile.in.in.
|
||||
# If only the 'gettext-h' module is in use, assume autopoint already
|
||||
# put the correct version of this file into place.
|
||||
case $gnulib_modules in
|
||||
*gettext-h*) ;;
|
||||
*gettext*)
|
||||
cp $GNULIB_SRCDIR/build-aux/po/Makefile.in.in po/Makefile.in.in \
|
||||
|| die "cannot create po/Makefile.in.in"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test -d runtime-po; then
|
||||
# Similarly for runtime-po/Makevars, but not quite the same.
|
||||
rm -f runtime-po/Makevars
|
||||
sed '
|
||||
/^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/
|
||||
/^subdir *=.*/s/=.*/= runtime-po/
|
||||
/^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/
|
||||
/^XGETTEXT_OPTIONS *=/{
|
||||
s/$/ \\/
|
||||
a\
|
||||
'"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+}
|
||||
}
|
||||
' po/Makevars.template >runtime-po/Makevars \
|
||||
|| die 'cannot generate runtime-po/Makevars'
|
||||
|
||||
# Copy identical files from po to runtime-po.
|
||||
(cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po)
|
||||
fi
|
||||
fi
|
||||
|
||||
bootstrap_epilogue
|
||||
|
||||
echo "$0: done. Now you can run './configure'."
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Local Variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
273
autopull.sh
Executable file
273
autopull.sh
Executable file
@@ -0,0 +1,273 @@
|
||||
#!/bin/sh
|
||||
# Convenience script for fetching auxiliary files that are omitted from
|
||||
# the version control repository of this package.
|
||||
|
||||
# Copyright (C) 2003-2022 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/>.
|
||||
|
||||
# Originally written by Paul Eggert. The canonical version of this
|
||||
# script is maintained as top/autopull.sh in gnulib. However, to be
|
||||
# useful to your package, you should place a copy of it under version
|
||||
# control in the top-level directory of your package. The intent is
|
||||
# that all customization can be done with a bootstrap.conf file also
|
||||
# maintained in your version control; gnulib comes with a template
|
||||
# build-aux/bootstrap.conf to get you started.
|
||||
#
|
||||
# Alternatively, you can use an autopull.sh script that is specific
|
||||
# to your package.
|
||||
|
||||
scriptversion=2022-07-24.15; # UTC
|
||||
|
||||
me="$0"
|
||||
medir=`dirname "$me"`
|
||||
|
||||
# Read the function library and the configuration.
|
||||
. "$medir"/bootstrap-funclib.sh
|
||||
|
||||
# Ensure that CDPATH is not set. Otherwise, the output from cd
|
||||
# would cause trouble in at least one use below.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $me [OPTION]...
|
||||
Bootstrap this package from the checked-out sources.
|
||||
|
||||
Optional environment variables:
|
||||
GNULIB_SRCDIR Specifies the local directory where gnulib
|
||||
sources reside. Use this if you already
|
||||
have gnulib sources on your machine, and
|
||||
you want to use these sources.
|
||||
GNULIB_REFDIR Specifies the local directory where a gnulib
|
||||
repository (with a .git subdirectory) resides.
|
||||
Use this if you already have gnulib sources
|
||||
and history on your machine, and do not want
|
||||
to waste your bandwidth downloading them again.
|
||||
GNULIB_URL Cloneable URL of the gnulib repository.
|
||||
|
||||
Options:
|
||||
--bootstrap-sync if this bootstrap script is not identical to
|
||||
the version in the local gnulib sources,
|
||||
update this script, and then restart it with
|
||||
/bin/sh or the shell \$CONFIG_SHELL
|
||||
--no-bootstrap-sync do not check whether bootstrap is out of sync
|
||||
--force attempt to bootstrap even if the sources seem
|
||||
not to have been checked out
|
||||
--no-git do not use git to update gnulib. Requires that
|
||||
\$GNULIB_SRCDIR or the --gnulib-srcdir option
|
||||
points to a gnulib repository with the correct
|
||||
revision
|
||||
--skip-po do not download po files
|
||||
EOF
|
||||
bootstrap_print_option_usage_hook
|
||||
cat <<EOF
|
||||
If the file bootstrap.conf exists in the same directory as this script, its
|
||||
contents are read as shell variables to configure the bootstrap.
|
||||
|
||||
For build prerequisites, environment variables like \$AUTOCONF and \$AMTAR
|
||||
are honored.
|
||||
|
||||
Gnulib sources can be fetched in various ways:
|
||||
|
||||
* If the environment variable GNULIB_SRCDIR is set (either as an
|
||||
environment variable or via the --gnulib-srcdir option), then sources
|
||||
are fetched from that local directory. If it is a git repository and
|
||||
the configuration variable GNULIB_REVISION is set in bootstrap.conf,
|
||||
then that revision is checked out.
|
||||
|
||||
* Otherwise, if this package is in a git repository with a 'gnulib'
|
||||
submodule configured, then that submodule is initialized and updated
|
||||
and sources are fetched from there. If GNULIB_REFDIR is set (either
|
||||
as an environment variable or via the --gnulib-refdir option) and is
|
||||
a git repository, then it is used as a reference.
|
||||
|
||||
* Otherwise, if the 'gnulib' directory does not exist, Gnulib sources
|
||||
are cloned into that directory using git from \$GNULIB_URL, defaulting
|
||||
to $default_gnulib_url.
|
||||
If the configuration variable GNULIB_REVISION is set in bootstrap.conf,
|
||||
then that revision is checked out.
|
||||
|
||||
* Otherwise, the existing Gnulib sources in the 'gnulib' directory are
|
||||
used. If it is a git repository and the configuration variable
|
||||
GNULIB_REVISION is set in bootstrap.conf, then that revision is
|
||||
checked out.
|
||||
|
||||
If you maintain a package and want to pin a particular revision of the
|
||||
Gnulib sources that has been tested with your package, then there are
|
||||
two possible approaches: either configure a 'gnulib' submodule with the
|
||||
appropriate revision, or set GNULIB_REVISION (and if necessary
|
||||
GNULIB_URL) in bootstrap.conf.
|
||||
|
||||
Running without arguments will suffice in most cases.
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse options.
|
||||
|
||||
# Use git to update gnulib sources
|
||||
use_git=true
|
||||
|
||||
for option
|
||||
do
|
||||
case $option in
|
||||
--help)
|
||||
usage
|
||||
exit;;
|
||||
--version)
|
||||
set -e
|
||||
echo "autopull.sh $scriptversion"
|
||||
echo "$copyright"
|
||||
exit 0
|
||||
;;
|
||||
--skip-po)
|
||||
SKIP_PO=t;;
|
||||
--force)
|
||||
checkout_only_file=;;
|
||||
--bootstrap-sync)
|
||||
bootstrap_sync=true;;
|
||||
--no-bootstrap-sync)
|
||||
bootstrap_sync=false;;
|
||||
--no-git)
|
||||
use_git=false;;
|
||||
*)
|
||||
bootstrap_option_hook $option || die "$option: unknown option";;
|
||||
esac
|
||||
done
|
||||
|
||||
$use_git || test -n "$GNULIB_SRCDIR" \
|
||||
|| die "Error: --no-git requires \$GNULIB_SRCDIR environment variable or --gnulib-srcdir option"
|
||||
test -z "$GNULIB_SRCDIR" || test -d "$GNULIB_SRCDIR" \
|
||||
|| die "Error: \$GNULIB_SRCDIR environment variable or --gnulib-srcdir option is specified, but does not denote a directory"
|
||||
|
||||
if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then
|
||||
die "Running this script from a non-checked-out distribution is risky."
|
||||
fi
|
||||
|
||||
check_build_prerequisites $use_git
|
||||
|
||||
if $use_gnulib || $bootstrap_sync; then
|
||||
prepare_GNULIB_SRCDIR
|
||||
if $bootstrap_sync; then
|
||||
upgrade_bootstrap
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find sha1sum, named gsha1sum on MacPorts, shasum on Mac OS X 10.6.
|
||||
# Also find the compatible sha1 utility on the BSDs
|
||||
if test x"$SKIP_PO" = x; then
|
||||
find_tool SHA1SUM sha1sum gsha1sum shasum sha1
|
||||
fi
|
||||
|
||||
# See if we can use gnulib's git-merge-changelog merge driver.
|
||||
if $use_git && test -d .git && check_exists git; then
|
||||
if git config merge.merge-changelog.driver >/dev/null ; then
|
||||
:
|
||||
elif check_exists git-merge-changelog; then
|
||||
echo "$0: initializing git-merge-changelog driver"
|
||||
git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver'
|
||||
git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B'
|
||||
else
|
||||
echo "$0: consider installing git-merge-changelog from gnulib"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ----------------------------- Get translations. -----------------------------
|
||||
|
||||
download_po_files() {
|
||||
subdir=$1
|
||||
domain=$2
|
||||
echo "$me: getting translations into $subdir for $domain..."
|
||||
cmd=$(printf "$po_download_command_format" "$subdir" "$domain")
|
||||
eval "$cmd"
|
||||
}
|
||||
|
||||
# Mirror .po files to $po_dir/.reference and copy only the new
|
||||
# or modified ones into $po_dir. Also update $po_dir/LINGUAS.
|
||||
# Note po files that exist locally only are left in $po_dir but will
|
||||
# not be included in LINGUAS and hence will not be distributed.
|
||||
update_po_files() {
|
||||
# Directory containing primary .po files.
|
||||
# Overwrite them only when we're sure a .po file is new.
|
||||
po_dir=$1
|
||||
domain=$2
|
||||
|
||||
# Mirror *.po files into this dir.
|
||||
# Usually contains *.s1 checksum files.
|
||||
ref_po_dir="$po_dir/.reference"
|
||||
|
||||
test -d $ref_po_dir || mkdir $ref_po_dir || return
|
||||
download_po_files $ref_po_dir $domain \
|
||||
&& ls "$ref_po_dir"/*.po 2>/dev/null |
|
||||
sed 's|.*/||; s|\.po$||' > "$po_dir/LINGUAS" || return
|
||||
|
||||
langs=$(cd $ref_po_dir && echo *.po | sed 's/\.po//g')
|
||||
test "$langs" = '*' && langs=x
|
||||
for po in $langs; do
|
||||
case $po in x) continue;; esac
|
||||
new_po="$ref_po_dir/$po.po"
|
||||
cksum_file="$ref_po_dir/$po.s1"
|
||||
if ! test -f "$cksum_file" ||
|
||||
! test -f "$po_dir/$po.po" ||
|
||||
! $SHA1SUM -c "$cksum_file" < "$new_po" > /dev/null 2>&1; then
|
||||
echo "$me: updated $po_dir/$po.po..."
|
||||
cp "$new_po" "$po_dir/$po.po" \
|
||||
&& $SHA1SUM < "$new_po" > "$cksum_file" || return
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
case $SKIP_PO in
|
||||
'')
|
||||
if test -d po; then
|
||||
update_po_files po $package || exit
|
||||
fi
|
||||
|
||||
if test -d runtime-po; then
|
||||
update_po_files runtime-po $package-runtime || exit
|
||||
fi;;
|
||||
esac
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
bootstrap_post_pull_hook \
|
||||
|| die "bootstrap_post_pull_hook failed"
|
||||
|
||||
# Don't proceed if there are uninitialized submodules. In particular,
|
||||
# autogen.sh will remove dangling links, which might be links into
|
||||
# uninitialized submodules.
|
||||
# But it's OK if the 'gnulib' submodule is uninitialized, as long as
|
||||
# GNULIB_SRCDIR is set.
|
||||
if $use_git; then
|
||||
# Uninitialized submodules are listed with an initial dash.
|
||||
uninitialized=`git submodule | grep '^-' | awk '{ print $2 }'`
|
||||
if test -n "$GNULIB_SRCDIR"; then
|
||||
uninitialized=`echo "$uninitialized" | grep -v '^gnulib$'`
|
||||
fi
|
||||
if test -n "$uninitialized"; then
|
||||
die "Some git submodules are not initialized: "`echo "$uninitialized" | tr '\n' ',' | sed -e 's|,$|.|'`" Either use option '--no-git', or run 'git submodule update --init' and bootstrap again."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$0: done. Now you can run './autogen.sh'."
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Local Variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
594
bootstrap-funclib.sh
Normal file
594
bootstrap-funclib.sh
Normal file
@@ -0,0 +1,594 @@
|
||||
# A library of shell functions for autopull.sh, autogen.sh, and bootstrap.
|
||||
|
||||
# Copyright (C) 2003-2022 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/>.
|
||||
|
||||
# Originally written by Paul Eggert. The canonical version of this
|
||||
# script is maintained as top/bootstrap-funclib.sh in gnulib. However,
|
||||
# to be useful to your package, you should place a copy of it under
|
||||
# version control in the top-level directory of your package. The
|
||||
# intent is that all customization can be done with a bootstrap.conf
|
||||
# file also maintained in your version control; gnulib comes with a
|
||||
# template build-aux/bootstrap.conf to get you started.
|
||||
|
||||
scriptversion=2022-07-24.15; # UTC
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# Ensure file names are sorted consistently across platforms.
|
||||
LC_ALL=C
|
||||
export LC_ALL
|
||||
|
||||
# Honor $PERL, but work even if there is none.
|
||||
PERL="${PERL-perl}"
|
||||
|
||||
default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git
|
||||
|
||||
# Copyright year, for the --version output.
|
||||
copyright_year=`echo "$scriptversion" | sed -e 's/[^0-9].*//'`
|
||||
copyright="Copyright (C) ${copyright_year} Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law."
|
||||
|
||||
# warnf_ FORMAT-STRING ARG1...
|
||||
warnf_ ()
|
||||
{
|
||||
warnf_format_=$1
|
||||
shift
|
||||
nl='
|
||||
'
|
||||
case $* in
|
||||
*$nl*) me_=$(printf "$me"|tr "$nl|" '??')
|
||||
printf "$warnf_format_" "$@" | sed "s|^|$me_: |" ;;
|
||||
*) printf "$me: $warnf_format_" "$@" ;;
|
||||
esac >&2
|
||||
}
|
||||
|
||||
# warn_ WORD1...
|
||||
warn_ ()
|
||||
{
|
||||
# If IFS does not start with ' ', set it and emit the warning in a subshell.
|
||||
case $IFS in
|
||||
' '*) warnf_ '%s\n' "$*";;
|
||||
*) (IFS=' '; warn_ "$@");;
|
||||
esac
|
||||
}
|
||||
|
||||
# die WORD1...
|
||||
die() { warn_ "$@"; exit 1; }
|
||||
|
||||
# ------------------------------ Configuration. ------------------------------
|
||||
|
||||
# Directory that contains package-specific gnulib modules and/or overrides.
|
||||
local_gl_dir=gl
|
||||
|
||||
# Name of the Makefile.am
|
||||
# XXX Not used.
|
||||
gnulib_mk=gnulib.mk
|
||||
|
||||
# List of gnulib modules needed.
|
||||
gnulib_modules=
|
||||
|
||||
# Any gnulib files needed that are not in modules.
|
||||
gnulib_files=
|
||||
|
||||
# A function to be called for each unrecognized option. Returns 0 if
|
||||
# the option in $1 has been processed by the function. Returns 1 if
|
||||
# the option has not been processed by the function. Override it via
|
||||
# your own definition in bootstrap.conf
|
||||
bootstrap_option_hook() { return 1; }
|
||||
|
||||
# A function to be called in order to print the --help information
|
||||
# corresponding to user-defined command-line options.
|
||||
bootstrap_print_option_usage_hook() { :; }
|
||||
|
||||
# A function to be called at the end of autopull.sh.
|
||||
# Override it via your own definition in bootstrap.conf.
|
||||
bootstrap_post_pull_hook() { :; }
|
||||
|
||||
# A function to be called right after gnulib-tool is run.
|
||||
# Override it via your own definition in bootstrap.conf.
|
||||
bootstrap_post_import_hook() { :; }
|
||||
|
||||
# A function to be called after everything else in this script.
|
||||
# Override it via your own definition in bootstrap.conf.
|
||||
bootstrap_epilogue() { :; }
|
||||
|
||||
# The command to download all .po files for a specified domain into a
|
||||
# specified directory. Fill in the first %s with the destination
|
||||
# directory and the second with the domain name.
|
||||
po_download_command_format=\
|
||||
"wget --mirror --level=1 -nd -nv -A.po -P '%s' \
|
||||
https://translationproject.org/latest/%s/"
|
||||
|
||||
# Prefer a non-empty tarname (4th argument of AC_INIT if given), else
|
||||
# fall back to the package name (1st argument with munging).
|
||||
extract_package_name='
|
||||
/^AC_INIT(\[*/{
|
||||
s///
|
||||
/^[^,]*,[^,]*,[^,]*,[ []*\([^][ ,)]\)/{
|
||||
s//\1/
|
||||
s/[],)].*//
|
||||
p
|
||||
q
|
||||
}
|
||||
s/[],)].*//
|
||||
s/^GNU //
|
||||
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
|
||||
s/[^abcdefghijklmnopqrstuvwxyz0123456789_]/-/g
|
||||
p
|
||||
}
|
||||
'
|
||||
package=$(${AUTOCONF:-autoconf} --trace AC_INIT:\$4 configure.ac 2>/dev/null)
|
||||
if test -z "$package"; then
|
||||
package=$(sed -n "$extract_package_name" configure.ac) \
|
||||
|| die 'cannot find package name in configure.ac'
|
||||
fi
|
||||
gnulib_name=lib$package
|
||||
|
||||
build_aux=build-aux
|
||||
source_base=lib
|
||||
m4_base=m4
|
||||
doc_base=doc
|
||||
tests_base=tests
|
||||
gnulib_extra_files="
|
||||
build-aux/install-sh
|
||||
build-aux/mdate-sh
|
||||
build-aux/texinfo.tex
|
||||
build-aux/depcomp
|
||||
build-aux/config.guess
|
||||
build-aux/config.sub
|
||||
doc/INSTALL
|
||||
"
|
||||
|
||||
# Additional gnulib-tool options to use. Use "\newline" to break lines.
|
||||
gnulib_tool_option_extras=
|
||||
|
||||
# Other locale categories that need message catalogs.
|
||||
EXTRA_LOCALE_CATEGORIES=
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
XGETTEXT_OPTIONS='\\\
|
||||
--flag=_:1:pass-c-format\\\
|
||||
--flag=N_:1:pass-c-format\\\
|
||||
--flag=error:3:c-format --flag=error_at_line:5:c-format\\\
|
||||
'
|
||||
|
||||
# Package bug report address and copyright holder for gettext files
|
||||
COPYRIGHT_HOLDER='Free Software Foundation, Inc.'
|
||||
MSGID_BUGS_ADDRESS=bug-$package@gnu.org
|
||||
|
||||
# Files we don't want to import.
|
||||
# XXX Not used.
|
||||
excluded_files=
|
||||
|
||||
# File that should exist in the top directory of a checked out hierarchy,
|
||||
# but not in a distribution tarball.
|
||||
checkout_only_file=README-hacking
|
||||
|
||||
# Set this to '.cvsignore .gitignore' in bootstrap.conf if you want
|
||||
# those files to be generated in directories like lib/, m4/, and po/.
|
||||
# Or set it to 'auto' to make this script select which to use based
|
||||
# on which version control system (if any) is used in the source directory.
|
||||
vc_ignore=auto
|
||||
|
||||
# Set this to true in bootstrap.conf to enable --bootstrap-sync by
|
||||
# default.
|
||||
bootstrap_sync=false
|
||||
|
||||
# Override the default configuration, if necessary.
|
||||
# Make sure that bootstrap.conf is sourced from the current directory
|
||||
# if we were invoked as "sh bootstrap".
|
||||
conffile=`dirname "$me"`/bootstrap.conf
|
||||
test -r "$conffile" && . "$conffile"
|
||||
|
||||
# ------------------------- Build-time prerequisites -------------------------
|
||||
|
||||
check_exists() {
|
||||
if test "$1" = "--verbose"; then
|
||||
($2 --version </dev/null) >/dev/null 2>&1
|
||||
if test $? -ge 126; then
|
||||
# If not found, run with diagnostics as one may be
|
||||
# presented with env variables to set to find the right version
|
||||
($2 --version </dev/null)
|
||||
fi
|
||||
else
|
||||
($1 --version </dev/null) >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
test $? -lt 126
|
||||
}
|
||||
|
||||
# Note this deviates from the version comparison in automake
|
||||
# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
|
||||
# but this should suffice as we won't be specifying old
|
||||
# version formats or redundant trailing .0 in bootstrap.conf.
|
||||
# If we did want full compatibility then we should probably
|
||||
# use m4_version_compare from autoconf.
|
||||
sort_ver() { # sort -V is not generally available
|
||||
ver1="$1"
|
||||
ver2="$2"
|
||||
|
||||
# split on '.' and compare each component
|
||||
i=1
|
||||
while : ; do
|
||||
p1=$(echo "$ver1" | cut -d. -f$i)
|
||||
p2=$(echo "$ver2" | cut -d. -f$i)
|
||||
if [ ! "$p1" ]; then
|
||||
echo "$1 $2"
|
||||
break
|
||||
elif [ ! "$p2" ]; then
|
||||
echo "$2 $1"
|
||||
break
|
||||
elif [ ! "$p1" = "$p2" ]; then
|
||||
if [ "$p1" -gt "$p2" ] 2>/dev/null; then # numeric comparison
|
||||
echo "$2 $1"
|
||||
elif [ "$p2" -gt "$p1" ] 2>/dev/null; then # numeric comparison
|
||||
echo "$1 $2"
|
||||
else # numeric, then lexicographic comparison
|
||||
lp=$(printf "%s\n%s\n" "$p1" "$p2" | LANG=C sort -n | tail -n1)
|
||||
if [ "$lp" = "$p2" ]; then
|
||||
echo "$1 $2"
|
||||
else
|
||||
echo "$2 $1"
|
||||
fi
|
||||
fi
|
||||
break
|
||||
fi
|
||||
i=$(($i+1))
|
||||
done
|
||||
}
|
||||
|
||||
get_version_sed='
|
||||
# Move version to start of line.
|
||||
s/.*[v ]\([0-9]\)/\1/
|
||||
|
||||
# Skip lines that do not start with version.
|
||||
/^[0-9]/!d
|
||||
|
||||
# Remove characters after the version.
|
||||
s/[^.a-z0-9-].*//
|
||||
|
||||
# The first component must be digits only.
|
||||
s/^\([0-9]*\)[a-z-].*/\1/
|
||||
|
||||
#the following essentially does s/5.005/5.5/
|
||||
s/\.0*\([1-9]\)/.\1/g
|
||||
p
|
||||
q'
|
||||
|
||||
get_version() {
|
||||
app=$1
|
||||
|
||||
$app --version >/dev/null 2>&1 || { $app --version; return 1; }
|
||||
|
||||
$app --version 2>&1 | sed -n "$get_version_sed"
|
||||
}
|
||||
|
||||
check_versions() {
|
||||
ret=0
|
||||
|
||||
while read app req_ver; do
|
||||
# We only need libtoolize from the libtool package.
|
||||
if test "$app" = libtool; then
|
||||
app=libtoolize
|
||||
fi
|
||||
# Exempt git if git is not needed.
|
||||
if test "$app" = git; then
|
||||
$check_git || continue
|
||||
fi
|
||||
# Honor $APP variables ($TAR, $AUTOCONF, etc.)
|
||||
appvar=$(echo $app | LC_ALL=C tr '[a-z]-' '[A-Z]_')
|
||||
test "$appvar" = TAR && appvar=AMTAR
|
||||
case $appvar in
|
||||
GZIP) ;; # Do not use $GZIP: it contains gzip options.
|
||||
PERL::*) ;; # Keep perl modules as-is
|
||||
*) eval "app=\${$appvar-$app}" ;;
|
||||
esac
|
||||
|
||||
# Handle the still-experimental Automake-NG programs specially.
|
||||
# They remain named as the mainstream Automake programs ("automake",
|
||||
# and "aclocal") to avoid gratuitous incompatibilities with
|
||||
# pre-existing usages (by, say, autoreconf, or custom autogen.sh
|
||||
# scripts), but correctly identify themselves (as being part of
|
||||
# "GNU automake-ng") when asked their version.
|
||||
case $app in
|
||||
automake-ng|aclocal-ng)
|
||||
app=${app%-ng}
|
||||
($app --version | grep '(GNU automake-ng)') >/dev/null 2>&1 || {
|
||||
warn_ "Error: '$app' not found or not from Automake-NG"
|
||||
ret=1
|
||||
continue
|
||||
} ;;
|
||||
# Another check is for perl modules. These can be written as
|
||||
# e.g. perl::XML::XPath in case of XML::XPath module, etc.
|
||||
perl::*)
|
||||
# Extract module name
|
||||
app="${app#perl::}"
|
||||
if ! $PERL -m"$app" -e 'exit 0' >/dev/null 2>&1; then
|
||||
warn_ "Error: perl module '$app' not found"
|
||||
ret=1
|
||||
fi
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
if [ "$req_ver" = "-" ]; then
|
||||
# Merely require app to exist; not all prereq apps are well-behaved
|
||||
# so we have to rely on $? rather than get_version.
|
||||
if ! check_exists --verbose $app; then
|
||||
warn_ "Error: '$app' not found"
|
||||
ret=1
|
||||
fi
|
||||
else
|
||||
# Require app to produce a new enough version string.
|
||||
inst_ver=$(get_version $app)
|
||||
if [ ! "$inst_ver" ]; then
|
||||
warn_ "Error: '$app' not found"
|
||||
ret=1
|
||||
else
|
||||
latest_ver=$(sort_ver $req_ver $inst_ver | cut -d' ' -f2)
|
||||
if [ ! "$latest_ver" = "$inst_ver" ]; then
|
||||
warnf_ '%s\n' \
|
||||
"Error: '$app' version == $inst_ver is too old" \
|
||||
" '$app' version >= $req_ver is required"
|
||||
ret=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return $ret
|
||||
}
|
||||
|
||||
print_versions() {
|
||||
echo "Program Min_version"
|
||||
echo "----------------------"
|
||||
printf %s "$buildreq"
|
||||
echo "----------------------"
|
||||
# can't depend on column -t
|
||||
}
|
||||
|
||||
# check_build_prerequisites check_git
|
||||
check_build_prerequisites()
|
||||
{
|
||||
check_git="$1"
|
||||
|
||||
# gnulib-tool requires at least automake and autoconf.
|
||||
# If either is not listed, add it (with minimum version) as a prerequisite.
|
||||
case $buildreq in
|
||||
*automake*) ;;
|
||||
*) buildreq="automake 1.9
|
||||
$buildreq" ;;
|
||||
esac
|
||||
case $buildreq in
|
||||
*autoconf*) ;;
|
||||
*) buildreq="autoconf 2.59
|
||||
$buildreq" ;;
|
||||
esac
|
||||
|
||||
# When we can deduce that gnulib-tool will require patch,
|
||||
# and when patch is not already listed as a prerequisite, add it, too.
|
||||
if test -d "$local_gl_dir" \
|
||||
&& ! find "$local_gl_dir" -name '*.diff' -exec false {} +; then
|
||||
case $buildreq in
|
||||
*patch*) ;;
|
||||
*) buildreq="patch -
|
||||
$buildreq" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if ! printf '%s' "$buildreq" | check_versions; then
|
||||
echo >&2
|
||||
if test -f README-prereq; then
|
||||
die "See README-prereq for how to get the prerequisite programs"
|
||||
else
|
||||
die "Please install the prerequisite programs"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Warn the user if autom4te appears to be broken; this causes known
|
||||
# issues with at least gettext 0.18.3.
|
||||
probe=$(echo 'm4_quote([hi])' | autom4te -l M4sugar -t 'm4_quote:$%' -)
|
||||
if test "x$probe" != xhi; then
|
||||
warn_ "WARNING: your autom4te wrapper eats stdin;"
|
||||
warn_ "if bootstrap fails, consider upgrading your autotools"
|
||||
fi
|
||||
}
|
||||
|
||||
# find_tool ENVVAR NAMES...
|
||||
# -------------------------
|
||||
# Search for a required program. Use the value of ENVVAR, if set,
|
||||
# otherwise find the first of the NAMES that can be run.
|
||||
# If found, set ENVVAR to the program name, die otherwise.
|
||||
#
|
||||
# FIXME: code duplication, see also gnu-web-doc-update.
|
||||
find_tool ()
|
||||
{
|
||||
find_tool_envvar=$1
|
||||
shift
|
||||
find_tool_names=$@
|
||||
eval "find_tool_res=\$$find_tool_envvar"
|
||||
if test x"$find_tool_res" = x; then
|
||||
for i; do
|
||||
if check_exists $i; then
|
||||
find_tool_res=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test x"$find_tool_res" = x; then
|
||||
warn_ "one of these is required: $find_tool_names;"
|
||||
die "alternatively set $find_tool_envvar to a compatible tool"
|
||||
fi
|
||||
eval "$find_tool_envvar=\$find_tool_res"
|
||||
eval "export $find_tool_envvar"
|
||||
}
|
||||
|
||||
# --------------------- Preparing GNULIB_SRCDIR for use. ---------------------
|
||||
# This is part of autopull.sh, but bootstrap needs it too, for self-upgrading.
|
||||
|
||||
cleanup_gnulib() {
|
||||
status=$?
|
||||
# XXX It's a bad idea to erase the submodule directory if it contains local
|
||||
# modifications.
|
||||
rm -fr "$gnulib_path"
|
||||
exit $status
|
||||
}
|
||||
|
||||
git_modules_config () {
|
||||
test -f .gitmodules && git config --file .gitmodules "$@"
|
||||
}
|
||||
|
||||
prepare_GNULIB_SRCDIR ()
|
||||
{
|
||||
if test -n "$GNULIB_SRCDIR"; then
|
||||
# Use GNULIB_SRCDIR directly.
|
||||
# We already checked that $GNULIB_SRCDIR references a directory.
|
||||
# Verify that it contains a gnulib checkout.
|
||||
test -f "$GNULIB_SRCDIR/gnulib-tool" \
|
||||
|| die "Error: --gnulib-srcdir or \$GNULIB_SRCDIR is specified, but does not contain gnulib-tool"
|
||||
elif $use_git; then
|
||||
gnulib_path=$(git_modules_config submodule.gnulib.path)
|
||||
test -z "$gnulib_path" && gnulib_path=gnulib
|
||||
|
||||
# Get gnulib files. Populate $gnulib_path, possibly updating a
|
||||
# submodule, for use in the rest of the script.
|
||||
|
||||
if test -n "$GNULIB_REFDIR" && test -d "$GNULIB_REFDIR"/.git \
|
||||
&& git_modules_config submodule.gnulib.url >/dev/null; then
|
||||
# Use GNULIB_REFDIR as a reference.
|
||||
echo "$0: getting gnulib files..."
|
||||
if git submodule -h|grep -- --reference > /dev/null; then
|
||||
# Prefer the one-liner available in git 1.6.4 or newer.
|
||||
git submodule update --init --reference "$GNULIB_REFDIR" \
|
||||
"$gnulib_path" || exit $?
|
||||
else
|
||||
# This fallback allows at least git 1.5.5.
|
||||
if test -f "$gnulib_path"/gnulib-tool; then
|
||||
# Since file already exists, assume submodule init already complete.
|
||||
git submodule update -- "$gnulib_path" || exit $?
|
||||
else
|
||||
# Older git can't clone into an empty directory.
|
||||
rmdir "$gnulib_path" 2>/dev/null
|
||||
git clone --reference "$GNULIB_REFDIR" \
|
||||
"$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \
|
||||
&& git submodule init -- "$gnulib_path" \
|
||||
&& git submodule update -- "$gnulib_path" \
|
||||
|| exit $?
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# GNULIB_REFDIR is not set or not usable. Ignore it.
|
||||
if git_modules_config submodule.gnulib.url >/dev/null; then
|
||||
echo "$0: getting gnulib files..."
|
||||
git submodule init -- "$gnulib_path" || exit $?
|
||||
git submodule update -- "$gnulib_path" || exit $?
|
||||
|
||||
elif [ ! -d "$gnulib_path" ]; then
|
||||
echo "$0: getting gnulib files..."
|
||||
|
||||
trap cleanup_gnulib 1 2 13 15
|
||||
|
||||
shallow=
|
||||
if test -z "$GNULIB_REVISION"; then
|
||||
if git clone -h 2>&1 | grep -- --depth > /dev/null; then
|
||||
shallow='--depth 2'
|
||||
fi
|
||||
git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \
|
||||
|| cleanup_gnulib
|
||||
else
|
||||
if git fetch -h 2>&1 | grep -- --depth > /dev/null; then
|
||||
shallow='--depth 2'
|
||||
fi
|
||||
mkdir -p "$gnulib_path"
|
||||
# Only want a shallow checkout of $GNULIB_REVISION, but git does not
|
||||
# support cloning by commit hash. So attempt a shallow fetch by commit
|
||||
# hash to minimize the amount of data downloaded and changes needed to
|
||||
# be processed, which can drastically reduce download and processing
|
||||
# time for checkout. If the fetch by commit fails, a shallow fetch can
|
||||
# not be performed because we do not know what the depth of the commit
|
||||
# is without fetching all commits. So fallback to fetching all commits.
|
||||
git -C "$gnulib_path" init
|
||||
git -C "$gnulib_path" remote add origin \
|
||||
${GNULIB_URL:-$default_gnulib_url}
|
||||
git -C "$gnulib_path" fetch $shallow origin "$GNULIB_REVISION" \
|
||||
|| git -C "$gnulib_path" fetch origin \
|
||||
|| cleanup_gnulib
|
||||
git -C "$gnulib_path" reset --hard FETCH_HEAD
|
||||
fi
|
||||
|
||||
trap - 1 2 13 15
|
||||
fi
|
||||
fi
|
||||
GNULIB_SRCDIR=$gnulib_path
|
||||
# Verify that the submodule contains a gnulib checkout.
|
||||
test -f "$gnulib_path/gnulib-tool" \
|
||||
|| die "Error: $gnulib_path is supposed to contain a gnulib checkout, but does not contain gnulib-tool"
|
||||
fi
|
||||
|
||||
# XXX Should this be done if $use_git is false?
|
||||
if test -d "$GNULIB_SRCDIR"/.git && test -n "$GNULIB_REVISION" \
|
||||
&& ! git_modules_config submodule.gnulib.url >/dev/null; then
|
||||
(cd "$GNULIB_SRCDIR" && git checkout "$GNULIB_REVISION") || cleanup_gnulib
|
||||
fi
|
||||
|
||||
# $GNULIB_SRCDIR now points to the version of gnulib to use, and
|
||||
# we no longer need to use git or $gnulib_path below here.
|
||||
}
|
||||
|
||||
# -------- Upgrading bootstrap to the version found in GNULIB_SRCDIR. --------
|
||||
|
||||
upgrade_bootstrap ()
|
||||
{
|
||||
{ cmp -s "$medir"/bootstrap "$GNULIB_SRCDIR/top/bootstrap" \
|
||||
&& cmp -s "$medir"/bootstrap-funclib.sh "$GNULIB_SRCDIR/top/bootstrap-funclib.sh" \
|
||||
&& cmp -s "$medir"/autopull.sh "$GNULIB_SRCDIR/top/autopull.sh" \
|
||||
&& cmp -s "$medir"/autogen.sh "$GNULIB_SRCDIR/top/autogen.sh"; \
|
||||
} || {
|
||||
echo "$0: updating bootstrap & companions and restarting..."
|
||||
case $(sh -c 'echo "$1"' -- a) in
|
||||
a) ignored=--;;
|
||||
*) ignored=ignored;;
|
||||
esac
|
||||
exec sh -c \
|
||||
'{ if test -f "$1"; then cp "$1" "$3"; else cp "$2" "$3"; fi; } && { if test -f "$4"; then cp "$4" "$5"; else rm -f "$5"; fi; } && { if test -f "$6"; then cp "$6" "$7"; else rm -f "$7"; fi; } && { if test -f "$8"; then cp "$8" "$9"; else rm -f "$9"; fi; } && shift && shift && shift && shift && shift && shift && shift && shift && shift && exec "${CONFIG_SHELL-/bin/sh}" "$@"' \
|
||||
$ignored \
|
||||
"$GNULIB_SRCDIR/top/bootstrap" "$GNULIB_SRCDIR/build-aux/bootstrap" "$medir/bootstrap" \
|
||||
"$GNULIB_SRCDIR/top/bootstrap-funclib.sh" "$medir/bootstrap-funclib.sh" \
|
||||
"$GNULIB_SRCDIR/top/autopull.sh" "$medir/autopull.sh" \
|
||||
"$GNULIB_SRCDIR/top/autogen.sh" "$medir/autogen.sh" \
|
||||
"$0" "$@" --no-bootstrap-sync
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
if test x"$gnulib_modules$gnulib_files$gnulib_extra_files" = x; then
|
||||
use_gnulib=false
|
||||
else
|
||||
use_gnulib=true
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# Local Variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
:: Copyright (C) 2018-2020 Free Software Foundation, Inc.
|
||||
:: Copyright (C) 2018-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
|
||||
@@ -19,16 +19,66 @@ setlocal
|
||||
set "svurl=https://git.savannah.gnu.org/cgit"
|
||||
set "gnuliburl=%svurl%/gnulib.git/plain"
|
||||
|
||||
where curl >nul 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo Cannot find curl: it must be installed for bootstrap
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
where sed >nul 2>&1
|
||||
if ERRORLEVEL 1 (
|
||||
echo Cannot find sed: it must be installed for bootstrap
|
||||
echo Hint: you can use the sed provided in the Git for Windows install
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if exist lib goto Downloads
|
||||
mkdir lib
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
|
||||
:Downloads
|
||||
echo -- Downloading Gnulib modules
|
||||
call :Download lib getloadavg.c
|
||||
call :Download lib intprops.h
|
||||
goto :Done
|
||||
call :Download lib intprops-internal.h
|
||||
|
||||
echo -- Configuring the workspace
|
||||
copy /Y gl\lib\*.* lib > nul
|
||||
|
||||
:: Create a sed script to convert templates
|
||||
if exist convert.sed del /Q convert.sed
|
||||
echo s,%%PACKAGE%%,make,g > convert.sed
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
sed -n "s/^AC_INIT(\[GNU.make\],\[\([0-9.]*\)\].*/s,%%VERSION%%,\1,g/p" configure.ac >> convert.sed
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
sed -z -e s/\\\n//g -e "s/[ \t][ \t]*/ /g" -e "s, [^ ]*\.h,,g" -e "s,src/,$(src),g" -e "s,lib/,$(lib),g" Makefile.am | sed -n "s/^\([A-Za-z0-9]*\)_SRCS *= *\(.*\)/s,%%\1_SOURCES%%,\2,/p" >> convert.sed
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
|
||||
echo - Creating Basic.mk
|
||||
call sed -f convert.sed Basic.mk.template > Basic.mk
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
echo - Creating src\config.h.W32
|
||||
call sed -f convert.sed src\config.h.W32.template > src\config.h.W32
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
|
||||
echo - Creating src\gmk-default.h
|
||||
echo static const char *const GUILE_module_defn = ^" \ > src\gmk-default.h
|
||||
call sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" src\gmk-default.scm >> src\gmk-default.h
|
||||
if ERRORLEVEL 1 goto Failed
|
||||
echo ^";>> src\gmk-default.h
|
||||
|
||||
echo.
|
||||
echo Done. Run build_w32.bat to build GNU make.
|
||||
goto :EOF
|
||||
|
||||
:Download
|
||||
echo Downloading %1\%2
|
||||
curl -sS -o %1\%2 "%gnuliburl%/%1/%2"
|
||||
if exist "%1\%2" goto :EOF
|
||||
echo - Downloading %1\%2
|
||||
curl -sS -o "%1\%2" "%gnuliburl%/%1/%2"
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
goto :EOF
|
||||
|
||||
:Done
|
||||
echo Done. Run build_w32.bat to build GNU make.
|
||||
goto :EOF
|
||||
:Failed
|
||||
echo *** Bootstrap failed.
|
||||
echo Resolve the issue, or use the configured source in the release tarball
|
||||
exit /b 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Bootstrap configuration. -*-shell-script-*-
|
||||
|
||||
# Copyright (C) 2018-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2018-2022 Free Software Foundation, Inc.
|
||||
|
||||
# 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
|
||||
@@ -18,6 +18,12 @@
|
||||
# Allow bootstrap to know that this is not a package
|
||||
checkout_only_file=README.git
|
||||
|
||||
# Choose a specific version of gnulib, when checking out
|
||||
GNULIB_REVISION=stable-202207
|
||||
|
||||
# Always copy files rather than symlink
|
||||
copy=true
|
||||
|
||||
# Additional xgettext options to use. Use "\\\newline" to break lines.
|
||||
# Ensure that all our magical output macros are correctly marked as
|
||||
# C (printf) format strings.
|
||||
@@ -43,11 +49,16 @@ automake 1.16.1
|
||||
gnulib_name=libgnu
|
||||
gnulib_files=doc/make-stds.texi
|
||||
|
||||
# Using the full strtoll module pulls in a lot of stuff. But, it's pretty
|
||||
# simple to use just the base source file, so pull that. We'll use it in
|
||||
# src/misc.c if strtoll() is not found.
|
||||
gnulib_files="$gnulib_files lib/strtol.c"
|
||||
|
||||
gnulib_modules="\
|
||||
alloca
|
||||
fdl
|
||||
findprog-in
|
||||
getloadavg
|
||||
host-cpu-c-abi
|
||||
strerror
|
||||
make-glob"
|
||||
make-glob
|
||||
make-macros"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Configuration for building GNU Make in the absence of any 'make' program.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1993-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
|
||||
|
||||
16
build.sh
16
build.sh
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
# Shell script to build GNU Make in the absence of any 'make' program.
|
||||
|
||||
# Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1993-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
|
||||
@@ -57,7 +57,12 @@ compile ()
|
||||
{
|
||||
objs=
|
||||
for ofile in "$@"; do
|
||||
# We should try to use a Makefile variable like libgnu_a_SOURCES or
|
||||
# something but just hardcode it.
|
||||
file="${ofile%.$OBJEXT}.c"
|
||||
case $file in
|
||||
(lib/libgnu_a-*.c) file="lib/${file#lib/libgnu_a-}" ;;
|
||||
esac
|
||||
echo "compiling $file..."
|
||||
of="$OUTDIR/$ofile"
|
||||
mkdir -p "${of%/*}"
|
||||
@@ -75,10 +80,13 @@ convert ()
|
||||
var="GENERATE_$(echo $base | tr 'a-z./+' A-Z__X)"
|
||||
|
||||
# Is this file disabled?
|
||||
grep "${var}_FALSE\"]=\"\"" config.status >/dev/null && return
|
||||
grep "${var}_FALSE\"]=\"\"" config.status >/dev/null && return 0
|
||||
|
||||
# If there's no .in file then no conversion needed
|
||||
in="$top_srcdir/lib/$(echo ${base%.*}.in.${base##*.} | tr / _)"
|
||||
test -f "$in" || return 0
|
||||
|
||||
# Not disabled, so create it
|
||||
in="$top_srcdir/lib/$(echo ${base%.*}.in.${base##*.} | tr / _)"
|
||||
out="$OUTLIB/$base"
|
||||
mkdir -p "${out%/*}"
|
||||
|
||||
@@ -103,7 +111,7 @@ convert ()
|
||||
esac
|
||||
|
||||
fn="$top_srcdir/lib/${fn##*/}"
|
||||
[ -f "$fn" ] || { echo "Missing file: $fn"; exit 1; }
|
||||
test -f "$fn" || { echo "Missing file: $fn"; exit 1; }
|
||||
|
||||
sed "/definitions* of $inc/r $fn" "$int" > "${int}_"
|
||||
int=${int}_
|
||||
|
||||
132
build_w32.bat
Executable file → Normal file
132
build_w32.bat
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
:: Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
:: Copyright (C) 1996-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
|
||||
@@ -37,6 +37,8 @@ set COMPILER=cl.exe
|
||||
set O=obj
|
||||
set ARCH=x64
|
||||
set DEBUG=N
|
||||
set DIRENT=Y
|
||||
set VERBOSE=N
|
||||
|
||||
if exist maintMakefile (
|
||||
set MAINT=Y
|
||||
@@ -45,13 +47,20 @@ if exist maintMakefile (
|
||||
)
|
||||
|
||||
:ParseSW
|
||||
if "%1" == "--verbose" goto SetVerbose
|
||||
if "%1" == "--debug" goto SetDebug
|
||||
if "%1" == "--without-guile" goto NoGuile
|
||||
if "%1" == "--x86" goto Set32Bit
|
||||
if "%1" == "gcc" goto SetCC
|
||||
if "%1" == "tcc" goto SetTCC
|
||||
if "%1" == "" goto DoneSW
|
||||
goto Usage
|
||||
|
||||
:SetVerbose
|
||||
set VERBOSE=Y
|
||||
shift
|
||||
goto ParseSW
|
||||
|
||||
:SetDebug
|
||||
set DEBUG=Y
|
||||
echo - Building without compiler optimizations
|
||||
@@ -77,20 +86,28 @@ echo - Building with GCC
|
||||
shift
|
||||
goto ParseSW
|
||||
|
||||
:SetTCC
|
||||
set COMPILER=tcc
|
||||
set O=o
|
||||
echo - Building with TinyC
|
||||
shift
|
||||
goto ParseSW
|
||||
|
||||
:DoneSW
|
||||
if "%MAINT%" == "Y" echo - Enabling maintainer mode
|
||||
|
||||
if "%COMPILER%" == "gcc" goto FindGcc
|
||||
if "%COMPILER%" == "tcc" goto FindTcc
|
||||
|
||||
:: Find a compiler. Visual Studio requires a lot of effort to locate :-/.
|
||||
%COMPILER% >nul 2>&1
|
||||
call %COMPILER% >nul 2>&1
|
||||
if not ERRORLEVEL 1 goto FoundMSVC
|
||||
|
||||
:: Visual Studio 17 and above provides the "vswhere" tool
|
||||
call :FindVswhere
|
||||
if ERRORLEVEL 1 goto LegacyVS
|
||||
|
||||
for /f "tokens=* usebackq" %%i in (`%VSWHERE% -latest -property installationPath`) do (
|
||||
for /f "tokens=* usebackq" %%i in (`"%VSWHERE%" -latest -property installationPath`) do (
|
||||
set InstallPath=%%i
|
||||
)
|
||||
set "VSVARS=%InstallPath%\VC\Auxiliary\Build\vcvarsall.bat"
|
||||
@@ -165,20 +182,36 @@ if "%MAINT%" == "Y" set "OPTS=%OPTS% /D MAKE_MAINTAINER_MODE"
|
||||
:: Show the compiler version that we found
|
||||
:: Unfortunately this also shows a "usage" note; I can't find anything better.
|
||||
echo.
|
||||
%COMPILER%
|
||||
call %COMPILER%
|
||||
goto Build
|
||||
|
||||
:FindGcc
|
||||
set OUTDIR=.\GccRel
|
||||
set LNKOUT=./GccRel
|
||||
set OPTS=-O2
|
||||
set DIRENT=N
|
||||
if "%DEBUG%" == "Y" set OPTS=-O0
|
||||
if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug
|
||||
if "%DEBUG%" == "Y" set LNKOUT=./GccDebug
|
||||
if "%MAINT%" == "Y" set "OPTS=%OPTS% -DMAKE_MAINTAINER_MODE"
|
||||
:: Show the compiler version that we found
|
||||
echo.
|
||||
%COMPILER% --version
|
||||
call %COMPILER% --version
|
||||
if not ERRORLEVEL 1 goto Build
|
||||
echo No %COMPILER% found.
|
||||
exit 1
|
||||
|
||||
:FindTcc
|
||||
set OUTDIR=.\TccRel
|
||||
set LNKOUT=./TccRel
|
||||
set OPTS=-O2
|
||||
if "%DEBUG%" == "Y" set OPTS=-O0
|
||||
if "%DEBUG%" == "Y" set OUTDIR=.\TccDebug
|
||||
if "%DEBUG%" == "Y" set LNKOUT=./TccDebug
|
||||
if "%MAINT%" == "Y" set "OPTS=%OPTS% -DMAKE_MAINTAINER_MODE"
|
||||
:: Show the compiler version that we found
|
||||
echo.
|
||||
call %COMPILER% -v
|
||||
if not ERRORLEVEL 1 goto Build
|
||||
echo No %COMPILER% found.
|
||||
exit 1
|
||||
@@ -197,10 +230,11 @@ mkdir %OUTDIR%\lib
|
||||
|
||||
if "%GUILE%" == "Y" call :ChkGuile
|
||||
|
||||
if not exist src\config.h.W32 goto NotConfig
|
||||
|
||||
echo.
|
||||
echo Compiling %OUTDIR% version
|
||||
|
||||
if exist src\config.h.W32.template call :ConfigSCM
|
||||
copy src\config.h.W32 %OUTDIR%\src\config.h
|
||||
|
||||
copy lib\glob.in.h %OUTDIR%\lib\glob.h
|
||||
@@ -231,6 +265,7 @@ call :Compile src/read
|
||||
call :Compile src/remake
|
||||
call :Compile src/remote-stub
|
||||
call :Compile src/rule
|
||||
call :Compile src/shuffle
|
||||
call :Compile src/signame
|
||||
call :Compile src/strcache
|
||||
call :Compile src/variable
|
||||
@@ -246,7 +281,8 @@ call :Compile lib/fnmatch
|
||||
call :Compile lib/glob
|
||||
call :Compile lib/getloadavg
|
||||
|
||||
if not "%COMPILER%" == "gcc" call :Compile src\w32\compat\dirent
|
||||
:: Compile dirent unless it is supported by compiler library (like with gcc).
|
||||
if "%DIRENT%" == "Y" call :Compile src\w32\compat\dirent
|
||||
|
||||
call :Link
|
||||
|
||||
@@ -267,23 +303,33 @@ goto :EOF
|
||||
::
|
||||
|
||||
:Compile
|
||||
if "%VERBOSE%" == "N" echo - Compiling %1.c
|
||||
echo %LNKOUT%/%1.%O% >>%OUTDIR%\link.sc
|
||||
set EXTRAS=
|
||||
if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%"
|
||||
if exist "%OUTDIR%\%1.%O%" del "%OUTDIR%\%1.%O%"
|
||||
if "%COMPILER%" == "gcc" goto GccCompile
|
||||
if "%COMPILER%" == "tcc" goto TccCompile
|
||||
|
||||
:: MSVC Compile
|
||||
echo on
|
||||
%COMPILER% /nologo /MT /W4 /EHsc %OPTS% /I %OUTDIR%/src /I src /I %OUTDIR%/lib /I lib /I src/w32/include /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR%OUTDIR% /Fp%OUTDIR%\%MAKE%.pch /Fo%OUTDIR%\%1.%O% /Fd%OUTDIR%\%MAKE%.pdb %EXTRAS% /c %1.c
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
call %COMPILER% /nologo /MT /W4 /EHsc %OPTS% /I %OUTDIR%/src /I src /I %OUTDIR%/lib /I lib /I src/w32/include /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR%OUTDIR% /Fp%OUTDIR%\%MAKE%.pch /Fo%OUTDIR%\%1.%O% /Fd%OUTDIR%\%MAKE%.pdb %EXTRAS% /c %1.c
|
||||
@echo off
|
||||
goto CompileDone
|
||||
|
||||
:GccCompile
|
||||
:: GCC Compile
|
||||
echo on
|
||||
%COMPILER% -mthreads -Wall -std=gnu99 -gdwarf-2 -g3 %OPTS% -I%OUTDIR%/src -I./src -I%OUTDIR%/lib -I./lib -I./src/w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%/%1.%O% -c %1.c
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
call %COMPILER% -mthreads -Wall -std=gnu99 -gdwarf-2 -g3 %OPTS% -I%OUTDIR%/src -I./src -I%OUTDIR%/lib -I./lib -I./src/w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%/%1.%O% -c %1.c
|
||||
@echo off
|
||||
goto CompileDone
|
||||
|
||||
:TccCompile
|
||||
:: TCC Compile
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
call %COMPILER% -mthreads -Wall -std=c11 %OPTS% -I%OUTDIR%/src -I./src -I%OUTDIR%/lib -I./lib -I./src/w32/include -D_cdecl= -D_MSC_VER -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%/%1.%O% -c %1.c
|
||||
@echo off
|
||||
goto CompileDone
|
||||
|
||||
:CompileDone
|
||||
if not exist "%OUTDIR%\%1.%O%" exit 1
|
||||
@@ -291,56 +337,57 @@ goto :EOF
|
||||
|
||||
:Link
|
||||
echo.
|
||||
echo Linking %LNKOUT%/%MAKE%.exe
|
||||
echo - Linking %LNKOUT%/%MAKE%.exe
|
||||
if "%COMPILER%" == "gcc" goto GccLink
|
||||
if "%COMPILER%" == "tcc" goto TccLink
|
||||
|
||||
:: MSVC Link
|
||||
echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib >>%OUTDIR%\link.sc
|
||||
echo on
|
||||
link.exe /NOLOGO /SUBSYSTEM:console /PDB:%LNKOUT%\%MAKE%.pdb %LINKOPTS% /OUT:%LNKOUT%\%MAKE%.exe @%LNKOUT%\link.sc
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
call link.exe /NOLOGO /SUBSYSTEM:console /PDB:%LNKOUT%\%MAKE%.pdb %LINKOPTS% /OUT:%LNKOUT%\%MAKE%.exe @%LNKOUT%\link.sc
|
||||
@echo off
|
||||
goto :EOF
|
||||
|
||||
:GccLink
|
||||
:: GCC Link
|
||||
echo on
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
echo %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 >>%OUTDIR%\link.sc
|
||||
%COMPILER% -mthreads -gdwarf-2 -g3 %OPTS% -o %LNKOUT%/%MAKE%.exe @%LNKOUT%/link.sc -Wl,--out-implib=%LNKOUT%/libgnumake-1.dll.a
|
||||
call %COMPILER% -mthreads -gdwarf-2 -g3 %OPTS% -o %LNKOUT%/%MAKE%.exe @%LNKOUT%/link.sc -Wl,--out-implib=%LNKOUT%/libgnumake-1.dll.a
|
||||
@echo off
|
||||
goto :EOF
|
||||
|
||||
:ConfigSCM
|
||||
echo Generating config from SCM templates
|
||||
sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\src\config.h.W32.sed
|
||||
echo s,%%PACKAGE%%,make,g >> %OUTDIR%\src\config.h.W32.sed
|
||||
sed -f %OUTDIR%\src\config.h.W32.sed src\config.h.W32.template > src\config.h.W32
|
||||
echo static const char *const GUILE_module_defn = ^" \ > src\gmk-default.h
|
||||
sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" src\gmk-default.scm >> src\gmk-default.h
|
||||
echo ^";>> src\gmk-default.h
|
||||
:TccLink
|
||||
:: TCC Link
|
||||
if "%VERBOSE%" == "Y" echo on
|
||||
echo %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lodbc32 -lodbccp32 >>%OUTDIR%\link.sc
|
||||
call %COMPILER% -mthreads %OPTS% -o %LNKOUT%/%MAKE%.exe @%LNKOUT%/link.sc
|
||||
@echo off
|
||||
goto :EOF
|
||||
|
||||
:ChkGuile
|
||||
:: Build with Guile is supported only on NT and later versions
|
||||
if not "%OS%" == "Windows_NT" goto NoGuile
|
||||
pkg-config --help > %OUTDIR%\guile.tmp 2> NUL
|
||||
call pkg-config --help > %OUTDIR%\guile.tmp 2> NUL
|
||||
if ERRORLEVEL 1 goto NoPkgCfg
|
||||
|
||||
echo Checking for Guile 2.0
|
||||
set PKGMSC=
|
||||
if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax
|
||||
pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp
|
||||
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
|
||||
|
||||
pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp
|
||||
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
|
||||
echo Checking for Guile 2.0
|
||||
call pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\gl-c2.tmp 2> NUL
|
||||
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\gl-c2.tmp
|
||||
|
||||
call pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\gl-l2.tmp 2> NUL
|
||||
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\gl-l2.tmp
|
||||
|
||||
if not "%GUILECFLAGS%" == "" goto GuileDone
|
||||
|
||||
echo Checking for Guile 1.8
|
||||
pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp
|
||||
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
|
||||
call pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\gl-c18.tmp 2> NUL
|
||||
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\gl-c18.tmp
|
||||
|
||||
pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp
|
||||
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
|
||||
call pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\gl-l18.tmp 2> NUL
|
||||
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\gl-l18.tmp
|
||||
|
||||
if not "%GUILECFLAGS%" == "" goto GuileDone
|
||||
|
||||
@@ -359,10 +406,10 @@ goto :EOF
|
||||
|
||||
:FindVswhere
|
||||
set VSWHERE=vswhere
|
||||
%VSWHERE% -help >nul 2>&1
|
||||
call "%VSWHERE%" -help >nul 2>&1
|
||||
if not ERRORLEVEL 1 exit /b 0
|
||||
set "VSWHERE=C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere"
|
||||
%VSWHERE% -help >nul 2>&1
|
||||
call "%VSWHERE%" -help >nul 2>&1
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
goto :EOF
|
||||
|
||||
@@ -370,17 +417,26 @@ goto :EOF
|
||||
if not exist "%VSVARS%" exit /b 1
|
||||
call "%VSVARS%" %ARCH%
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
%COMPILER% >nul 2>&1
|
||||
call %COMPILER% >nul 2>&1
|
||||
if ERRORLEVEL 1 exit /b 1
|
||||
goto :EOF
|
||||
|
||||
:NotConfig
|
||||
echo.
|
||||
echo *** This workspace is not configured.
|
||||
echo Either retrieve the configured source in the release tarball
|
||||
echo or, if building from Git, run the .\bootstrap.bat script first.
|
||||
exit /b 1
|
||||
|
||||
:Usage
|
||||
echo Usage: %0 [options] [gcc]
|
||||
echo Usage: %0 [options] [gcc] OR [tcc]
|
||||
echo Options:
|
||||
echo. --without-guile Do not compile Guile support even if found
|
||||
echo. --debug Make a Debug build--default is Release
|
||||
echo. --x86 Make a 32bit binary--default is 64bit
|
||||
echo. --help Display these instructions and exit
|
||||
echo.
|
||||
echo. "gcc" means compile with GCC, "tcc" means compile with Tiny C's TCC
|
||||
goto :EOF
|
||||
|
||||
:Reset
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
@echo off
|
||||
rem Copyright (C) 1998-2020 Free Software Foundation, Inc.
|
||||
rem Copyright (C) 1998-2022 Free Software Foundation, Inc.
|
||||
rem This file is part of GNU Make.
|
||||
rem
|
||||
rem GNU Make is free software; you can redistribute it and/or modify it under
|
||||
@@ -68,12 +68,13 @@ gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/s
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/remote-stub.c -o remote-stub.o
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/getopt.c -o getopt.o
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/getopt1.c -o getopt1.o
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/src/shuffle.c -o shuffle.o
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/lib/glob.c -o lib/glob.o
|
||||
gcc -c -I./src -I%XSRC%/src -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/lib/fnmatch.c -o lib/fnmatch.o
|
||||
@echo off
|
||||
echo commands.o > respf.$$$
|
||||
for %%f in (job output dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$
|
||||
for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$
|
||||
for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1 shuffle) do echo %%f.o >> respf.$$$
|
||||
for %%f in (lib\glob lib\fnmatch) do echo %%f.o >> respf.$$$
|
||||
rem gcc -c -I./src -I%XSRC% -I./lib -I%XSRC%/lib -DHAVE_CONFIG_H -O2 -g %XSRC%/guile.c -o guile.o
|
||||
rem echo guile.o >> respf.$$$
|
||||
|
||||
52
configure.ac
52
configure.ac
@@ -1,6 +1,6 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
#
|
||||
# Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1993-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
|
||||
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU make],[4.3],[bug-make@gnu.org])
|
||||
AC_INIT([GNU make],[4.3.90],[bug-make@gnu.org])
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
@@ -51,9 +51,6 @@ AC_CHECK_PROG([PERL], [perl], [perl], [perl])
|
||||
|
||||
# Specialized system macros
|
||||
AC_CANONICAL_HOST
|
||||
AC_AIX
|
||||
AC_ISC_POSIX
|
||||
AC_MINIX
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
# Enable gettext, in "external" mode.
|
||||
@@ -66,20 +63,18 @@ AM_GNU_GETTEXT([external])
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# Checks for libraries.
|
||||
AC_SEARCH_LIBS([strerror],[cposix])
|
||||
AC_SEARCH_LIBS([getpwnam], [sun])
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STAT
|
||||
AC_HEADER_TIME
|
||||
|
||||
AC_CHECK_HEADERS([stdlib.h locale.h unistd.h limits.h fcntl.h string.h \
|
||||
memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h \
|
||||
memory.h sys/param.h sys/resource.h sys/timeb.h sys/time.h \
|
||||
sys/select.h sys/file.h spawn.h])
|
||||
|
||||
AM_PROG_CC_C_O
|
||||
AC_C_CONST
|
||||
AC_TYPE_SIGNAL
|
||||
AC_TYPE_UID_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_OFF_T
|
||||
@@ -115,9 +110,6 @@ AS_IF([test "$make_cv_file_timestamp_hi_res" = yes],
|
||||
])
|
||||
])
|
||||
|
||||
# Check for DOS-style pathnames.
|
||||
pds_AC_DOS_PATHS
|
||||
|
||||
# See if we have a standard version of gettimeofday(). Since actual
|
||||
# implementations can differ, just make sure we have the most common
|
||||
# one.
|
||||
@@ -138,10 +130,10 @@ AS_IF([test "$ac_cv_func_gettimeofday" = yes],
|
||||
[Define to 1 if you have a standard gettimeofday function])
|
||||
])
|
||||
|
||||
AC_CHECK_FUNCS([strdup strndup memrchr umask mkstemp mktemp fdopen \
|
||||
dup dup2 getcwd realpath sigsetmask sigaction \
|
||||
AC_CHECK_FUNCS([strtoll strdup strndup stpcpy memrchr mempcpy umask mkstemp \
|
||||
mktemp fdopen dup dup2 getcwd realpath sigsetmask sigaction \
|
||||
getgroups seteuid setegid setlinebuf setreuid setregid \
|
||||
getrlimit setrlimit setvbuf pipe strsignal \
|
||||
mkfifo getrlimit setrlimit setvbuf pipe strerror strsignal \
|
||||
lstat readlink atexit isatty ttyname pselect posix_spawn \
|
||||
posix_spawnattr_setsigmask])
|
||||
|
||||
@@ -153,8 +145,6 @@ AC_CHECK_DECLS([bsd_signal], [], [], [[#define _GNU_SOURCE 1
|
||||
|
||||
AC_FUNC_FORK
|
||||
|
||||
AC_FUNC_SETVBUF_REVERSED
|
||||
|
||||
# Rumor has it that strcasecmp lives in -lresolv on some odd systems.
|
||||
# It doesn't hurt much to use our own if we can't find it so I don't
|
||||
# make the effort here.
|
||||
@@ -251,8 +241,7 @@ AS_IF([test "$PATH_SEPARATOR" = ';'],
|
||||
AC_SUBST([REMOTE]) REMOTE=stub
|
||||
use_customs=false
|
||||
AC_ARG_WITH([customs],
|
||||
[AC_HELP_STRING([--with-customs=DIR],
|
||||
[enable remote jobs via Customs--see README.customs])],
|
||||
[AS_HELP_STRING([--with-customs=DIR],[enable remote jobs via Customs--see README.customs])],
|
||||
[ AS_CASE([$withval], [n|no], [:],
|
||||
[make_cppflags="$CPPFLAGS"
|
||||
AS_CASE([$withval],
|
||||
@@ -275,14 +264,12 @@ AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true])
|
||||
# See if the user asked to handle case insensitive file systems.
|
||||
AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names])
|
||||
AC_ARG_ENABLE([case-insensitive-file-system],
|
||||
AC_HELP_STRING([--enable-case-insensitive-file-system],
|
||||
[assume file systems are case insensitive]),
|
||||
AS_HELP_STRING([--enable-case-insensitive-file-system],[assume file systems are case insensitive]),
|
||||
[AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])])
|
||||
|
||||
# See if we can handle the job server feature, and if the user wants it.
|
||||
AC_ARG_ENABLE([job-server],
|
||||
AC_HELP_STRING([--disable-job-server],
|
||||
[disallow recursive make communication during -jN]),
|
||||
AS_HELP_STRING([--disable-job-server],[disallow recursive make communication during -jN]),
|
||||
[make_cv_job_server="$enableval" user_job_server="$enableval"],
|
||||
[make_cv_job_server="yes"])
|
||||
|
||||
@@ -320,8 +307,7 @@ AC_CHECK_DECLS([dlopen, dlsym, dlerror], [], [],
|
||||
[[#include <dlfcn.h>]])
|
||||
|
||||
AC_ARG_ENABLE([load],
|
||||
AC_HELP_STRING([--disable-load],
|
||||
[disable support for the 'load' operation]),
|
||||
AS_HELP_STRING([--disable-load],[disable support for the 'load' operation]),
|
||||
[make_cv_load="$enableval" user_load="$enableval"],
|
||||
[make_cv_load="yes"])
|
||||
|
||||
@@ -371,8 +357,7 @@ AS_IF([test "$ac_cv_func_lstat" = yes && test "$ac_cv_func_readlink" = yes],
|
||||
# Use posix_spawn if we have support and the user didn't disable it
|
||||
|
||||
AC_ARG_ENABLE([posix-spawn],
|
||||
AC_HELP_STRING([--disable-posix-spawn],
|
||||
[disable support for posix_spawn()]),
|
||||
AS_HELP_STRING([--disable-posix-spawn],[disable support for posix_spawn()]),
|
||||
[make_cv_posix_spawn="$enableval" user_posix_spawn="$enableval"],
|
||||
[make_cv_posix_spawn="yes"])
|
||||
|
||||
@@ -452,6 +437,9 @@ AS_CASE([$host],
|
||||
AC_DEFINE_UNQUOTED([PATH_SEPARATOR_CHAR],['$PATH_SEPARATOR'],
|
||||
[Define to the character that separates directories in PATH.])
|
||||
|
||||
AC_DEFINE_UNQUOTED([HAVE_DECL_GETLOADAVG],[$HAVE_DECL_GETLOADAVG],
|
||||
[Define to 1 if you have the declaration of 'getloadavg'.])
|
||||
|
||||
# Include the Maintainer's Makefile section, if it's here.
|
||||
|
||||
MAINT_MAKEFILE=/dev/null
|
||||
@@ -520,12 +508,20 @@ AS_IF([test "x$make_cv_posix_spawn" = xno && test "x$user_posix_spawn" = xyes],
|
||||
echo
|
||||
])
|
||||
|
||||
# autoconf initializes $prefix to NONE.
|
||||
AM_CONDITIONAL([KNOWN_PREFIX],
|
||||
[test "x$prefix" = xNONE -o "x$prefix" = x/usr/local \
|
||||
-o "x$prefix" = x/usr/gnu -o "x$prefix" = x/usr])
|
||||
|
||||
# Specify what files are to be created.
|
||||
AC_CONFIG_FILES([Makefile build.cfg lib/Makefile po/Makefile.in doc/Makefile \
|
||||
tests/config-flags.pm])
|
||||
# We don't need this: the standard automake output suffices for POSIX systems.
|
||||
#mk/Posix.mk
|
||||
|
||||
# Put build.sh in the build directory so it's easy to find
|
||||
AC_CONFIG_LINKS([build.sh:build.sh])
|
||||
|
||||
# OK, do it!
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*-Makefile-*-, or close enough
|
||||
# Copyright (C) 2000-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2000-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
|
||||
|
||||
77
doc/make.1
77
doc/make.1
@@ -1,4 +1,4 @@
|
||||
.TH MAKE 1 "28 February 2016" "GNU" "User Commands"
|
||||
.TH MAKE 1 "31 May 2022" "GNU" "User Commands"
|
||||
.SH NAME
|
||||
make \- GNU make utility to maintain groups of programs
|
||||
.SH SYNOPSIS
|
||||
@@ -26,9 +26,9 @@ To prepare to use
|
||||
.BR make ,
|
||||
you must write a file called the
|
||||
.I makefile
|
||||
that describes the relationships among files in your program, and the states
|
||||
the commands for updating each file. In a program, typically the executable
|
||||
file is updated from object files, which are in turn made by compiling source
|
||||
that describes the relationships among files in your program, and provides
|
||||
commands for updating each file. In a program, typically the executable file
|
||||
is updated from object files, which are in turn made by compiling source
|
||||
files.
|
||||
.LP
|
||||
Once a suitable makefile exists, each time you change some source files,
|
||||
@@ -48,10 +48,10 @@ files, it issues the commands recorded in the makefile.
|
||||
.B make
|
||||
executes commands in the
|
||||
.I makefile
|
||||
to update one or more target
|
||||
.IR names ,
|
||||
to update one or more
|
||||
.IR targets ,
|
||||
where
|
||||
.I name
|
||||
.I target
|
||||
is typically a program.
|
||||
If no
|
||||
.B \-f
|
||||
@@ -130,21 +130,28 @@ are omitted, then the behavior is the same as if
|
||||
.B \-d
|
||||
was specified.
|
||||
.I FLAGS
|
||||
may be
|
||||
.I a
|
||||
may be any or all of the following names, comma- or space-separated. Only the
|
||||
first character is significant: the rest may be omitted:
|
||||
.I all
|
||||
for all debugging output (same as using
|
||||
.BR \-d ),
|
||||
.I b
|
||||
.I basic
|
||||
for basic debugging,
|
||||
.I v
|
||||
.I verbose
|
||||
for more verbose basic debugging,
|
||||
.I i
|
||||
for showing implicit rules,
|
||||
.I j
|
||||
for details on invocation of commands, and
|
||||
.I m
|
||||
for debugging while remaking makefiles. Use
|
||||
.I n
|
||||
.I implicit
|
||||
for showing implicit rule search operations,
|
||||
.I jobs
|
||||
for details on invocation of commands,
|
||||
.I makefile
|
||||
for debugging while remaking makefiles,
|
||||
.I print
|
||||
shows all recipes that are run even if they are silent, and
|
||||
.I why
|
||||
shows the reason
|
||||
.BR make
|
||||
decided to rebuild each target. Use
|
||||
.I none
|
||||
to disable all previous debugging flags.
|
||||
.TP 0.5i
|
||||
\fB\-e\fR, \fB\-\-environment\-overrides\fR
|
||||
@@ -198,6 +205,16 @@ option is given without an argument,
|
||||
.BR make
|
||||
will not limit the number of jobs that can run simultaneously.
|
||||
.TP 0.5i
|
||||
\fB\--jobserver-style=\fR\fIstyle\fR
|
||||
The style of jobserver to use. The
|
||||
.I style
|
||||
may be one of
|
||||
.BR fifo ,
|
||||
.BR pipe ,
|
||||
or
|
||||
.B sem
|
||||
(Windows only).
|
||||
.TP 0.5i
|
||||
\fB\-k\fR, \fB\-\-keep\-going\fR
|
||||
Continue as much as possible after an error.
|
||||
While the target that failed, and those that depend on it, cannot
|
||||
@@ -312,6 +329,26 @@ Turn off
|
||||
.BR \-w ,
|
||||
even if it was turned on implicitly.
|
||||
.TP 0.5i
|
||||
.BI \-\-shuffle "[=MODE]"
|
||||
Enable shuffling of goal and prerequisite ordering.
|
||||
.I MODE
|
||||
is one of
|
||||
.I none
|
||||
to disable shuffle mode,
|
||||
.I random
|
||||
to shuffle prerequisites in random order,
|
||||
.I reverse
|
||||
to consider prerequisites in reverse order, or an integer
|
||||
.I <seed>
|
||||
which enables
|
||||
.I random
|
||||
mode with a specific
|
||||
.I seed
|
||||
value. If
|
||||
.I MODE
|
||||
is omitted the default is
|
||||
.IR random .
|
||||
.TP 0.5i
|
||||
\fB\-W\fR \fIfile\fR, \fB\-\-what\-if\fR=\fIfile\fR, \fB\-\-new\-file\fR=\fIfile\fR, \fB\-\-assume\-new\fR=\fIfile\fR
|
||||
Pretend that the target
|
||||
.I file
|
||||
@@ -361,7 +398,7 @@ This manual page contributed by Dennis Morse of Stanford University.
|
||||
Further updates contributed by Mike Frysinger. It has been reworked by Roland
|
||||
McGrath. Maintained by Paul Smith.
|
||||
.SH "COPYRIGHT"
|
||||
Copyright \(co 1992-1993, 1996-2020 Free Software Foundation, Inc.
|
||||
Copyright \(co 1992-1993, 1996-2022 Free Software Foundation, Inc.
|
||||
This file is part of
|
||||
.IR "GNU make" .
|
||||
.LP
|
||||
@@ -376,4 +413,4 @@ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
.LP
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see
|
||||
.IR http://www.gnu.org/licenses/ .
|
||||
.IR https://www.gnu.org/licenses/ .
|
||||
|
||||
1693
doc/make.texi
1693
doc/make.texi
File diff suppressed because it is too large
Load Diff
10
gl/.gitignore
vendored
Normal file
10
gl/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
*~
|
||||
#*
|
||||
.#*
|
||||
.*cache
|
||||
*.diff
|
||||
*.patch
|
||||
*.orig
|
||||
*.rej
|
||||
*.out
|
||||
*.log
|
||||
65
gl/README
Normal file
65
gl/README
Normal file
@@ -0,0 +1,65 @@
|
||||
04 July 2022 -*-text-*-
|
||||
|
||||
The gnulib project provides a fantastic array of modules that can support both
|
||||
POSIX and also extended features for GNU software.
|
||||
|
||||
Unfortunately using it in GNU make is problematic: GNU make is a foundational
|
||||
utility (if you don't have a "make" program you pretty much can't build any
|
||||
software), one of our goals in GNU make is to provide scripts (e.g.,
|
||||
"build.sh") that will build GNU make without needing an instance of make.
|
||||
|
||||
Instead of running "./configure && make", you should be able to run
|
||||
"./configure && ./build.sh" and get a build of GNU make as a result.
|
||||
|
||||
However, more and more gnulib modules are relying not on M4 macros and
|
||||
the configure script to manage their configuration, but in addition special
|
||||
makefile recipes that perform various post-configure operations. Since we
|
||||
don't have an instance of "make", we cannot use these modules as-is.
|
||||
|
||||
There are various options we could choose for solving this:
|
||||
|
||||
- Avoid gnulib modules and write our own portability interfaces.
|
||||
I really am not too excited about this.
|
||||
|
||||
- Give up on "build.sh" and require users to already have "make".
|
||||
The argument here is that you must already have a compiler, and it couldn't
|
||||
have been built without "make", and/or if you build it with a cross-compiler
|
||||
then you should be able to use that cross-development environment to build
|
||||
GNU make as well.
|
||||
|
||||
- Provide a "mini-make" with just enough functionality to support the gnulib
|
||||
makefiles but no extra features, that didn't need any complex gnulib
|
||||
modules. As with the first option, I'm not too excited about this.
|
||||
|
||||
Although arguably the second option is the sane one, I'm not really excited
|
||||
about any of them for the time being. So I elected to try something between
|
||||
the first and second options:
|
||||
|
||||
The gnulib-port Git branch will contain unmodified copies of gnulib modules
|
||||
that we want to use with GNU make. From there, we merge them into the main
|
||||
Git branch then modify / simplify them to avoid unnecessary extra modules and
|
||||
allow "build.sh" to be used.
|
||||
|
||||
By keeping the unmodified versions on the gnulib-port branch, we enable Git
|
||||
merge facilities to merge in new versions as follows:
|
||||
|
||||
* Check out the gnulib-port branch
|
||||
|
||||
* Update its content with any updates to gnulib modules. Something like:
|
||||
(
|
||||
cd gl \
|
||||
&& find */. -type f \
|
||||
| while read fn; do
|
||||
test -f "$GNULIB_SRCDIR/$fn" && cp "$GNULIB_SRCDIR/$fn" "$fn"
|
||||
done
|
||||
)
|
||||
|
||||
* Commit the changes _without modification_
|
||||
|
||||
* Check out the main branch
|
||||
|
||||
* Run "git merge --no-ff gnulib-port" to merge in the changes
|
||||
|
||||
* Resolve any conflicts and commit the merge.
|
||||
|
||||
-- pds
|
||||
@@ -1,7 +1,7 @@
|
||||
dnl acinclude.m4 -- Extra macros needed for GNU make.
|
||||
dnl
|
||||
dnl Automake will incorporate this into its generated aclocal.m4.
|
||||
dnl Copyright (C) 1998-2020 Free Software Foundation, Inc.
|
||||
dnl Copyright (C) 1998-2022 Free Software Foundation, Inc.
|
||||
dnl This file is part of GNU Make.
|
||||
dnl
|
||||
dnl GNU Make is free software; you can redistribute it and/or modify it under
|
||||
@@ -1,7 +1,7 @@
|
||||
# Test if the system uses DOS-style pathnames (drive specs and backslashes)
|
||||
# By Paul Smith <psmith@gnu.org>. Based on dos.m4 by Jim Meyering.
|
||||
#
|
||||
# Copyright (C) 1993-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1993-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
|
||||
216
gl/m4/getloadavg.m4
Normal file
216
gl/m4/getloadavg.m4
Normal file
@@ -0,0 +1,216 @@
|
||||
# Check for getloadavg.
|
||||
|
||||
# Copyright (C) 1992-1996, 1999-2000, 2002-2003, 2006, 2008-2022 Free Software
|
||||
# Foundation, Inc.
|
||||
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
#serial 10
|
||||
|
||||
# Autoconf defines AC_FUNC_GETLOADAVG, but that is obsolescent.
|
||||
# New applications should use gl_GETLOADAVG instead.
|
||||
|
||||
# gl_GETLOADAVG
|
||||
# -------------
|
||||
AC_DEFUN([gl_GETLOADAVG],
|
||||
[AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
|
||||
|
||||
# Persuade glibc <stdlib.h> to declare getloadavg().
|
||||
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
gl_save_LIBS=$LIBS
|
||||
|
||||
# getloadavg is present in libc on glibc >= 2.2, Mac OS X, FreeBSD >= 2.0,
|
||||
# NetBSD >= 0.9, OpenBSD >= 2.0, Solaris >= 7.
|
||||
HAVE_GETLOADAVG=1
|
||||
AC_CHECK_FUNC([getloadavg], [],
|
||||
[gl_func_getloadavg_done=no
|
||||
|
||||
# Some systems with -lutil have (and need) -lkvm as well, some do not.
|
||||
# On Solaris, -lkvm requires nlist from -lelf, so check that first
|
||||
# to get the right answer into the cache.
|
||||
# For kstat on solaris, we need to test for libelf and libkvm to force the
|
||||
# definition of SVR4 below.
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_LIB([elf], [elf_begin], [LIBS="-lelf $LIBS"])
|
||||
AC_CHECK_LIB([kvm], [kvm_open], [LIBS="-lkvm $LIBS"])
|
||||
# Check for the 4.4BSD definition of getloadavg.
|
||||
AC_CHECK_LIB([util], [getloadavg],
|
||||
[LIBS="-lutil $LIBS" gl_func_getloadavg_done=yes])
|
||||
fi
|
||||
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
# There is a commonly available library for RS/6000 AIX.
|
||||
# Since it is not a standard part of AIX, it might be installed locally.
|
||||
gl_getloadavg_LIBS=$LIBS
|
||||
if test $cross_compiling != yes; then
|
||||
LIBS="-L/usr/local/lib $LIBS"
|
||||
fi
|
||||
AC_CHECK_LIB([getloadavg], [getloadavg],
|
||||
[LIBS="-lgetloadavg $LIBS" gl_func_getloadavg_done=yes],
|
||||
[LIBS=$gl_getloadavg_LIBS])
|
||||
fi
|
||||
|
||||
# Set up the replacement function if necessary.
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
HAVE_GETLOADAVG=0
|
||||
|
||||
# Solaris has libkstat which does not require root.
|
||||
AC_CHECK_LIB([kstat], [kstat_open])
|
||||
test $ac_cv_lib_kstat_kstat_open = yes && gl_func_getloadavg_done=yes
|
||||
|
||||
# AIX has libperfstat which does not require root
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_LIB([perfstat], [perfstat_cpu_total])
|
||||
test $ac_cv_lib_perfstat_perfstat_cpu_total = yes && gl_func_getloadavg_done=yes
|
||||
fi
|
||||
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_HEADER([sys/dg_sys_info.h],
|
||||
[gl_func_getloadavg_done=yes
|
||||
AC_DEFINE([DGUX], [1], [Define to 1 for DGUX with <sys/dg_sys_info.h>.])
|
||||
AC_CHECK_LIB([dgc], [dg_sys_info])])
|
||||
fi
|
||||
fi])
|
||||
|
||||
if test "x$gl_save_LIBS" = x; then
|
||||
GETLOADAVG_LIBS=$LIBS
|
||||
else
|
||||
GETLOADAVG_LIBS=`echo "$LIBS" | sed "s!$gl_save_LIBS!!"`
|
||||
fi
|
||||
LIBS=$gl_save_LIBS
|
||||
|
||||
AC_SUBST([GETLOADAVG_LIBS])dnl
|
||||
|
||||
# Test whether the system declares getloadavg. Solaris has the function
|
||||
# but declares it in <sys/loadavg.h>, not <stdlib.h>.
|
||||
AC_CHECK_HEADERS([sys/loadavg.h])
|
||||
if test $ac_cv_header_sys_loadavg_h = yes; then
|
||||
HAVE_SYS_LOADAVG_H=1
|
||||
else
|
||||
HAVE_SYS_LOADAVG_H=0
|
||||
fi
|
||||
AC_CHECK_DECL([getloadavg], [], [HAVE_DECL_GETLOADAVG=0],
|
||||
[[#if HAVE_SYS_LOADAVG_H
|
||||
/* OpenIndiana has a bug: <sys/time.h> must be included before
|
||||
<sys/loadavg.h>. */
|
||||
# include <sys/time.h>
|
||||
# include <sys/loadavg.h>
|
||||
#endif
|
||||
#include <stdlib.h>]])
|
||||
])# gl_GETLOADAVG
|
||||
|
||||
|
||||
# gl_PREREQ_GETLOADAVG
|
||||
# --------------------
|
||||
# Set up the AC_LIBOBJ replacement of 'getloadavg'.
|
||||
AC_DEFUN([gl_PREREQ_GETLOADAVG],
|
||||
[
|
||||
# Figure out what our getloadavg.c needs.
|
||||
|
||||
AC_CHECK_HEADERS_ONCE([sys/param.h unistd.h])
|
||||
|
||||
# On HPUX9, an unprivileged user can get load averages this way.
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_FUNCS([pstat_getdynamic], [gl_func_getloadavg_done=yes])
|
||||
fi
|
||||
|
||||
# We cannot check for <dwarf.h>, because Solaris 2 does not use dwarf (it
|
||||
# uses stabs), but it is still SVR4. We cannot check for <elf.h> because
|
||||
# Irix 4.0.5F has the header but not the library.
|
||||
if test $gl_func_getloadavg_done = no && test "$ac_cv_lib_elf_elf_begin" = yes \
|
||||
&& test "$ac_cv_lib_kvm_kvm_open" = yes; then
|
||||
gl_func_getloadavg_done=yes
|
||||
AC_DEFINE([SVR4], [1], [Define to 1 on System V Release 4.])
|
||||
fi
|
||||
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_HEADER([inq_stats/cpustats.h],
|
||||
[gl_func_getloadavg_done=yes
|
||||
AC_DEFINE([UMAX], [1], [Define to 1 for Encore UMAX.])
|
||||
AC_DEFINE([UMAX4_3], [1],
|
||||
[Define to 1 for Encore UMAX 4.3 that has <inq_status/cpustats.h>
|
||||
instead of <sys/cpustats.h>.])])
|
||||
fi
|
||||
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_HEADER([sys/cpustats.h],
|
||||
[gl_func_getloadavg_done=yes; AC_DEFINE([UMAX])])
|
||||
fi
|
||||
|
||||
if test $gl_func_getloadavg_done = no; then
|
||||
AC_CHECK_HEADERS([mach/mach.h])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS([nlist.h],
|
||||
[AC_CHECK_MEMBERS([struct nlist.n_un.n_name],
|
||||
[], [],
|
||||
[#include <nlist.h>])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <nlist.h>]],
|
||||
[[struct nlist x;
|
||||
#ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
|
||||
x.n_un.n_name = "";
|
||||
#else
|
||||
x.n_name = "";
|
||||
#endif]])],
|
||||
[AC_DEFINE([N_NAME_POINTER], [1],
|
||||
[Define to 1 if the nlist n_name member is a pointer])])
|
||||
])dnl
|
||||
])# gl_PREREQ_GETLOADAVG
|
||||
|
||||
# ---- GNU make
|
||||
# These macros are imported from stdlib which we don't want to include
|
||||
# Only the getloadavg content is imported.
|
||||
|
||||
AC_DEFUN_ONCE([gl_STDLIB_H],
|
||||
[
|
||||
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
|
||||
|
||||
dnl Check for declarations of anything we want to poison if the
|
||||
dnl corresponding gnulib module is not in use, and which is not
|
||||
dnl guaranteed by C89.
|
||||
gl_WARN_ON_USE_PREPARE([[#include <stdlib.h>
|
||||
#if HAVE_SYS_LOADAVG_H
|
||||
/* OpenIndiana has a bug: <sys/time.h> must be included before
|
||||
<sys/loadavg.h>. */
|
||||
# include <sys/time.h>
|
||||
# include <sys/loadavg.h>
|
||||
#endif
|
||||
#if HAVE_RANDOM_H
|
||||
# include <random.h>
|
||||
#endif
|
||||
]], [getloadavg])
|
||||
])
|
||||
|
||||
# gl_STDLIB_MODULE_INDICATOR([modulename])
|
||||
# sets the shell variable that indicates the presence of the given module
|
||||
# to a C preprocessor expression that will evaluate to 1.
|
||||
# This macro invocation must not occur in macros that are AC_REQUIREd.
|
||||
AC_DEFUN([gl_STDLIB_MODULE_INDICATOR],
|
||||
[
|
||||
dnl Ensure to expand the default settings once only.
|
||||
gl_STDLIB_H_REQUIRE_DEFAULTS
|
||||
gl_MODULE_INDICATOR_SET_VARIABLE([$1])
|
||||
dnl Define it also as a C macro, for the benefit of the unit tests.
|
||||
gl_MODULE_INDICATOR_FOR_TESTS([$1])
|
||||
])
|
||||
|
||||
# Initializes the default values for AC_SUBSTed shell variables.
|
||||
# This macro must not be AC_REQUIREd. It must only be invoked, and only
|
||||
# outside of macros or in macros that are not AC_REQUIREd.
|
||||
AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS],
|
||||
[
|
||||
m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETLOADAVG])
|
||||
])
|
||||
m4_require(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS])
|
||||
AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_STDLIB_H_DEFAULTS],
|
||||
[
|
||||
dnl Assume proper GNU behavior unless another module says otherwise.
|
||||
HAVE_DECL_GETLOADAVG=1; AC_SUBST([HAVE_DECL_GETLOADAVG])
|
||||
])
|
||||
24
gl/modules/concat-filename
Normal file
24
gl/modules/concat-filename
Normal file
@@ -0,0 +1,24 @@
|
||||
Description:
|
||||
Construct a full filename by concatenating a directory name, a relative
|
||||
filename, and a suffix.
|
||||
|
||||
Files:
|
||||
lib/concat-filename.h
|
||||
lib/concat-filename.c
|
||||
|
||||
Depends-on:
|
||||
filename
|
||||
|
||||
configure.ac:
|
||||
|
||||
Makefile.am:
|
||||
lib_SOURCES += concat-filename.c
|
||||
|
||||
Include:
|
||||
"concat-filename.h"
|
||||
|
||||
License:
|
||||
LGPLv2+
|
||||
|
||||
Maintainer:
|
||||
all
|
||||
28
gl/modules/findprog-in
Normal file
28
gl/modules/findprog-in
Normal file
@@ -0,0 +1,28 @@
|
||||
Description:
|
||||
Locating a program in a given path.
|
||||
|
||||
Files:
|
||||
lib/findprog.h
|
||||
lib/findprog-in.c
|
||||
m4/findprog-in.m4
|
||||
m4/eaccess.m4
|
||||
|
||||
Depends-on:
|
||||
stdbool
|
||||
filename
|
||||
concat-filename
|
||||
|
||||
configure.ac:
|
||||
gl_FINDPROG_IN
|
||||
|
||||
Makefile.am:
|
||||
lib_SOURCES += findprog.h findprog-in.c
|
||||
|
||||
Include:
|
||||
"findprog.h"
|
||||
|
||||
License:
|
||||
LGPLv2+
|
||||
|
||||
Maintainer:
|
||||
all
|
||||
40
gl/modules/getloadavg
Normal file
40
gl/modules/getloadavg
Normal file
@@ -0,0 +1,40 @@
|
||||
Description:
|
||||
Return the current system load averages.
|
||||
|
||||
Files:
|
||||
lib/getloadavg.c
|
||||
m4/getloadavg.m4
|
||||
|
||||
Depends-on:
|
||||
snippet/warn-on-use
|
||||
extensions
|
||||
intprops [test $HAVE_GETLOADAVG = 0]
|
||||
stdbool [test $HAVE_GETLOADAVG = 0]
|
||||
|
||||
configure.ac:
|
||||
gl_STDLIB_H
|
||||
gl_STDLIB_H_REQUIRE_DEFAULTS
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
gl_GETLOADAVG
|
||||
gl_CONDITIONAL([GL_COND_OBJ_GETLOADAVG], [test $HAVE_GETLOADAVG = 0])
|
||||
AM_COND_IF([GL_COND_OBJ_GETLOADAVG], [
|
||||
gl_PREREQ_GETLOADAVG
|
||||
])
|
||||
gl_STDLIB_MODULE_INDICATOR([getloadavg])
|
||||
|
||||
Makefile.am:
|
||||
if GL_COND_OBJ_GETLOADAVG
|
||||
lib_SOURCES += getloadavg.c
|
||||
endif
|
||||
|
||||
Include:
|
||||
<stdlib.h>
|
||||
|
||||
Link:
|
||||
$(GETLOADAVG_LIBS)
|
||||
|
||||
License:
|
||||
GPL
|
||||
|
||||
Maintainer:
|
||||
Jim Meyering
|
||||
@@ -2,6 +2,11 @@ Description:
|
||||
GNU make version of fnmatch()/glob() functions. This is a holdover from
|
||||
a very old version of the globbing library.
|
||||
|
||||
Files:
|
||||
lib/fnmatch.c
|
||||
lib/fnmatch.in.h
|
||||
lib/glob.c
|
||||
lib/glob.in.h
|
||||
|
||||
configure.ac:
|
||||
# Check the system to see if it provides GNU glob. If not, use our
|
||||
@@ -28,7 +33,6 @@ AM_CONDITIONAL([USE_SYSTEM_GLOB], [test "$make_cv_sys_gnu_glob" = yes])
|
||||
USE_SYSTEM_GLOB="$make_cv_sys_gnu_glob"
|
||||
AC_SUBST([USE_SYSTEM_GLOB])
|
||||
|
||||
|
||||
Makefile.am:
|
||||
if !USE_SYSTEM_GLOB
|
||||
libgnu_a_SOURCES += fnmatch.c
|
||||
@@ -60,7 +64,6 @@ endif
|
||||
|
||||
EXTRA_DIST += fnmatch.in.h glob.in.h
|
||||
|
||||
|
||||
Include:
|
||||
<glob.h>
|
||||
|
||||
|
||||
16
gl/modules/make-macros
Normal file
16
gl/modules/make-macros
Normal file
@@ -0,0 +1,16 @@
|
||||
Description:
|
||||
Install m4 macros for GNU make.
|
||||
|
||||
Files:
|
||||
m4/acinclude.m4
|
||||
m4/dospaths.m4
|
||||
|
||||
configure.ac:
|
||||
# Check for DOS-style pathnames.
|
||||
pds_AC_DOS_PATHS
|
||||
|
||||
License:
|
||||
GPLv3+
|
||||
|
||||
Maintainer:
|
||||
gnumake
|
||||
11
lib/.gitignore
vendored
11
lib/.gitignore
vendored
@@ -1,11 +0,0 @@
|
||||
*
|
||||
!/.gitignore
|
||||
|
||||
!/fnmatch.c
|
||||
!/fnmatch.in.h
|
||||
/fnmatch.h
|
||||
|
||||
!/glob.c
|
||||
!/glob.in.h
|
||||
/glob.h
|
||||
|
||||
5
m4/.gitignore
vendored
5
m4/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
*
|
||||
!/.gitignore
|
||||
!/aclocal.m4
|
||||
!/dospaths.m4
|
||||
|
||||
126
maintMakefile
126
maintMakefile
@@ -17,9 +17,6 @@ GPG_KEYID := 80CB727A20C79BB2
|
||||
# SRCROOTDIR is just a handy location to keep source files in
|
||||
SRCROOTDIR ?= $(HOME)/src
|
||||
|
||||
# Where the gnulib project has been locally cloned
|
||||
GNULIBDIR ?= $(SRCROOTDIR)/gnulib
|
||||
|
||||
# Where to put the CVS checkout of the GNU web repository
|
||||
GNUWEBDIR ?= $(SRCROOTDIR)/gnu-www
|
||||
|
||||
@@ -82,9 +79,8 @@ Basic.mk: Basic.mk.template .dep_segment Makefile
|
||||
sed -e 's@^\([^ ]*\)\.o:@$$(OUTDIR)\1.$$(OBJEXT):@' \
|
||||
-e 's@\([^ ]*\.[ch]\)@$$(SRCDIR)/\1@g' \
|
||||
-e 's@$$(SRCDIR)/src/config.h@$$(OUTDIR)src/config.h@g' \
|
||||
-e 's@$$(SRCDIR)/lib/stdlib.h@@g' \
|
||||
-e 's@$$(SRCDIR)/lib/sys/types.h@@g' \
|
||||
-e 's@$$(SRCDIR)/lib/unistd.h@@g' \
|
||||
-e 's@$$(SRCDIR)/lib/alloca.h@@g' \
|
||||
-e 's@$$(SRCDIR)/lib/stdbool.h@@g' \
|
||||
$(word 2,$^) >>$@
|
||||
chmod a-w $@
|
||||
|
||||
@@ -119,13 +115,16 @@ GIT := git
|
||||
git-clean:
|
||||
-$(GIT) clean -fdX
|
||||
git-very-clean: git-clean
|
||||
-$(GIT) clean -fd
|
||||
-$(GIT) clean -fdx
|
||||
|
||||
|
||||
## ---------------------- ##
|
||||
## Generating ChangeLog. ##
|
||||
## ---------------------- ##
|
||||
|
||||
# Where the gnulib project has been locally cloned
|
||||
GNULIBDIR ?= $(or $(wildcard $(GNULIB_SRCDIR)),./gnulib)
|
||||
|
||||
gl2cl-date := 2013-10-10
|
||||
gl2cl := $(GNULIBDIR)/build-aux/gitlog-to-changelog
|
||||
|
||||
@@ -137,12 +136,13 @@ ChangeLog: .check-git-HEAD
|
||||
echo "WARNING: $(gl2cl) is not available. No $@ generated."; \
|
||||
fi
|
||||
|
||||
.PHONY: .check-git-HEAD
|
||||
.check-git-HEAD:
|
||||
.check-git-HEAD: FORCE
|
||||
sha="`git rev-parse HEAD`"; \
|
||||
[ -f '$@' ] && [ "`cat '$@' 2>/dev/null`" = "$$sha" ] \
|
||||
test -f '$@' && [ "`cat '$@' 2>/dev/null`" = "$$sha" ] \
|
||||
|| echo "$$sha" > '$@'
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:;@:
|
||||
|
||||
## ---------------- ##
|
||||
## Updating files. ##
|
||||
@@ -168,10 +168,9 @@ update: po-check
|
||||
|
||||
# PO archive mirrors --- Be careful; some might not be fully populated!
|
||||
# ftp://ftp.unex.es/pub/gnu-i18n/po/maint/
|
||||
# http://translation.sf.net/maint/
|
||||
# ftp://tiger.informatik.hu-berlin.de/pub/po/maint/
|
||||
|
||||
po_wget_flags = --recursive --level=1 --no-directories --no-check-certificate
|
||||
po_wget_flags = --recursive --level=1 --no-directories --no-check-certificate
|
||||
po_repo = https://translationproject.org/latest/$(PACKAGE)
|
||||
po_sync = translationproject.org::tp/latest/$(PACKAGE)/
|
||||
|
||||
@@ -187,7 +186,7 @@ do-po-update:
|
||||
$(MAKE) po-check
|
||||
|
||||
po-update:
|
||||
[ -d "po" ] && $(MAKE) do-po-update
|
||||
test -d "po" && $(MAKE) do-po-update
|
||||
|
||||
# -------------------------- #
|
||||
# Updating GNU build files. #
|
||||
@@ -210,31 +209,59 @@ target = $(patsubst get-%,%,$@)
|
||||
|
||||
config-url = $(git-url)/config.git/plain/$(patsubst get-build-aux/%,%,$@)
|
||||
get-build-aux/config.guess get-build-aux/config.sub:
|
||||
@echo $(WGET) $(config-url) -O $(target) \
|
||||
&& $(WGET) $(config-url) -O $(target).t \
|
||||
@echo Retrieving $(target) from $(config-url)
|
||||
$(WGET) $(config-url) -O $(target).t \
|
||||
&& $(move_if_change)
|
||||
|
||||
gnulib-url = $(git-url)/gnulib.git/plain/build-aux/$(patsubst get-build-aux/%,%,$@)
|
||||
get-build-aux/texinfo.tex:
|
||||
@echo $(WGET) $(gnulib-url) -O $(target) \
|
||||
&& $(WGET) $(gnulib-url) -O $(target).t \
|
||||
@echo Retrieving $(target) from $(gnulib-url)
|
||||
$(WGET) $(gnulib-url) -O $(target).t \
|
||||
&& $(move_if_change)
|
||||
|
||||
gnustandards-url = $(cvs-url)/gnustandards/gnustandards/$(patsubst get-doc/%,%,$@)
|
||||
get-doc/make-stds.texi get-doc/fdl.texi:
|
||||
@echo $(WGET) $(gnustandards-url) -O $(target) \
|
||||
&& $(WGET) $(gnustandards-url) -O $(target).t \
|
||||
@echo Retrieving $(target) from $(gnustandards-url)
|
||||
$(WGET) $(gnustandards-url) -O $(target).t \
|
||||
&& $(move_if_change)
|
||||
|
||||
|
||||
# ---------------------------- #
|
||||
# Extra configuration checks. #
|
||||
# ---------------------------- #
|
||||
|
||||
# Make the dist file contents more regular, if we're using GNU tar.
|
||||
# Suggested by Tzvetelin Katchov <katchov@gnu.org>
|
||||
|
||||
export TAR_OPTIONS := --mode=u+w,go-w --owner=0 --group=0 --numeric-owner --sort=name
|
||||
|
||||
# When I released 4.3 somehow the INSTALL file was missing.
|
||||
# When I tried to build it again, it was there. I have no idea what happened
|
||||
# but add a new check to be sure it doesn't happen again.
|
||||
mk_dist_files = AUTHORS ChangeLog COPYING INSTALL README
|
||||
|
||||
dist: mk-distcheck
|
||||
|
||||
.PHONY: mk-distcheck
|
||||
mk-distcheck: distdir
|
||||
@echo "Checking for extra installed files..."
|
||||
for fn in $(mk_dist_files); do \
|
||||
test -f '$(distdir)'/"$$fn" \
|
||||
|| { echo "Missing dist file: $$fn"; exit 1; }; \
|
||||
done; true
|
||||
|
||||
|
||||
# ---------------------------------- #
|
||||
# Alternative configuration checks. #
|
||||
# ---------------------------------- #
|
||||
|
||||
CFGCHECK_CONFIGFLAGS =
|
||||
CFGCHECK_BUILDFLAGS =
|
||||
CFGCHECK_MAKEFLAGS = CFLAGS='$(AM_CFLAGS)'
|
||||
# We can't use our mondo warnings as these are used to compile gnulib modules
|
||||
# as well, and that will fail.
|
||||
CFGCHECK_MAKEFLAGS = # CFLAGS='$(AM_CFLAGS)'
|
||||
|
||||
# This test can no longer be run: now that we rely on gnulib we must use C99+
|
||||
checkcfg.strict-c90: CFGCHECK_CONFIGFLAGS = CFLAGS='-std=c90 -pedantic'
|
||||
checkcfg.strict-c90: CFGCHECK_MAKEFLAGS =
|
||||
|
||||
@@ -244,15 +271,14 @@ checkcfg.no-guile: CFGCHECK_CONFIGFLAGS = --without-guile
|
||||
checkcfg.no-spawn: CFGCHECK_CONFIGFLAGS = --disable-posix-spawn
|
||||
checkcfg.no-sysglob: CFGCHECK_CONFIGFLAGS = make_cv_sys_gnu_glob=no
|
||||
checkcfg.no-loadavg: CFGCHECK_CONFIGFLAGS = ac_cv_func_getloadavg=no \
|
||||
ac_cv_have_decl_getloadavg=no \
|
||||
gl_cv_have_raw_decl_getloadavg=no \
|
||||
ac_cv_lib_util_getloadavg=no \
|
||||
ac_cv_lib_getloadavg_getloadavg=no
|
||||
ac_cv_have_decl_getloadavg=no \
|
||||
gl_cv_have_raw_decl_getloadavg=no \
|
||||
ac_cv_lib_util_getloadavg=no \
|
||||
ac_cv_lib_getloadavg_getloadavg=no
|
||||
checkcfg.no-sync: CFGCHECK_CONFIGFLAGS = CPPFLAGS=-DNO_OUTPUT_SYNC
|
||||
checkcfg.no-archives: CFGCHECK_CONFIGFLAGS = CPPFLAGS=-DNO_ARCHIVES
|
||||
|
||||
CONFIG_CHECKS := \
|
||||
checkcfg.strict-c90 \
|
||||
checkcfg.no-jobserver \
|
||||
checkcfg.no-load \
|
||||
checkcfg.no-guile \
|
||||
@@ -269,6 +295,18 @@ check-alt-config: $(CONFIG_CHECKS)
|
||||
NR_MAKE = $(MAKE)
|
||||
|
||||
# Check builds both with build.sh and with make
|
||||
build.sh_SCRIPT = exec >>'checkcfg.$*.log' 2>&1; set -x; \
|
||||
cd $(distdir)/_build \
|
||||
&& OUTDIR=_bld ../build.sh $(CFGCHECK_BUILD_FLAGS) \
|
||||
&& _bld/make GMK_OUTDIR=../_bld $(AM_MAKEFLAGS) check-local \
|
||||
&& _bld/make GMK_OUTDIR=../_bld $(AM_MAKEFLAGS) clean
|
||||
|
||||
nrmake_SCRIPT = exec >>'checkcfg.$*.log' 2>&1; set -x; \
|
||||
cd $(distdir)/_build \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) $(CFGCHECK_MAKEFLAGS) \
|
||||
&& ./make $(AM_MAKEFLAGS) check \
|
||||
&& ./make $(AM_MAKEFLAGS) clean
|
||||
|
||||
$(CONFIG_CHECKS): checkcfg.%: distdir
|
||||
@echo "Building $@ (output in checkcfg.$*.log)"
|
||||
exec >'checkcfg.$*.log' 2>&1; \
|
||||
@@ -277,17 +315,9 @@ $(CONFIG_CHECKS): checkcfg.%: distdir
|
||||
&& mkdir $(distdir)/_build \
|
||||
&& cd $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. $(CFGCHECK_CONFIGFLAGS) \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS)
|
||||
exec >>'checkcfg.$*.log' 2>&1; set -x; \
|
||||
cd $(distdir)/_build \
|
||||
&& OUTDIR=_bld ../build.sh $(CFGCHECK_BUILD_FLAGS) \
|
||||
&& _bld/make $(AM_MAKEFLAGS) check-local \
|
||||
&& _bld/make $(AM_MAKEFLAGS) clean
|
||||
exec >>'checkcfg.$*.log' 2>&1; set -x; \
|
||||
cd $(distdir)/_build \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) $(CFGCHECK_MAKEFLAGS) \
|
||||
&& ./make $(AM_MAKEFLAGS) check \
|
||||
&& ./make $(AM_MAKEFLAGS) clean
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS)
|
||||
$(build.sh_SCRIPT)
|
||||
$(nrmake_SCRIPT)
|
||||
|
||||
# Try using Basic.mk. I can't test this on POSIX systems because it is only
|
||||
# used for non-POSIX systems; POSIX systems can just use normal
|
||||
@@ -300,10 +330,10 @@ checkcfg.basicmk: checkcfg.% : distdir
|
||||
&& mkdir $(distdir)/_build \
|
||||
&& cd $(distdir)/_build \
|
||||
&& ../configure --srcdir=.. \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS)
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS)
|
||||
exec >>'checkcfg.$*.log' 2>&1; set -x; \
|
||||
cd $(distdir)/_build \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) -f ../Basic.mk SRCDIR=.. CFLAGS='$(AM_CFLAGS)' \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) -f ../Basic.mk SRCDIR=.. $(CFGCHECK_MAKEFLAGS)
|
||||
&& ./make $(AM_MAKEFLAGS) -f ../Basic.mk SRCDIR=.. check \
|
||||
&& ./make $(AM_MAKEFLAGS) -f ../Basic.mk SRCDIR=.. clean
|
||||
exec >>'checkcfg.$*.log' 2>&1; \
|
||||
@@ -311,8 +341,8 @@ checkcfg.basicmk: checkcfg.% : distdir
|
||||
&& rm -rf $(distdir)/_build \
|
||||
&& cd $(distdir) \
|
||||
&& ./configure \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) -f Basic.mk CFLAGS='$(AM_CFLAGS)' \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
&& $(NR_MAKE) $(AM_MAKEFLAGS) -f Basic.mk $(CFGCHECK_MAKEFLAGS)' \
|
||||
&& ./make $(AM_MAKEFLAGS) -f Basic.mk check \
|
||||
&& ./make $(AM_MAKEFLAGS) -f Basic.mk clean
|
||||
|
||||
@@ -365,16 +395,16 @@ gnuweb-dir = www/server/standards
|
||||
|
||||
# Get the GNU make web page boilerplate etc.
|
||||
update-makeweb:
|
||||
[ -d '$(MAKEWEBDIR)' ] || mkdir -p '$(MAKEWEBDIR)'
|
||||
[ -d '$(MAKEWEBDIR)'/CVS ] \
|
||||
test -d '$(MAKEWEBDIR)' || mkdir -p '$(MAKEWEBDIR)'
|
||||
test -d '$(MAKEWEBDIR)'/CVS \
|
||||
&& { cd '$(MAKEWEBDIR)' && $(CVS) update; } \
|
||||
|| { mkdir -p '$(dir $(MAKEWEBDIR))' && cd '$(dir $(MAKEWEBDIR))' \
|
||||
&& $(CVS) -d $(makeweb-repo) co -d '$(notdir $(MAKEWEBDIR))' make; }
|
||||
|
||||
# Get the GNU web page boilerplate etc.
|
||||
update-gnuweb:
|
||||
[ -d '$(GNUWEBDIR)' ] || mkdir -p '$(GNUWEBDIR)'
|
||||
[ -d '$(GNUWEBDIR)/$(gnuweb-dir)'/CVS ] \
|
||||
test -d '$(GNUWEBDIR)' || mkdir -p '$(GNUWEBDIR)'
|
||||
test -d '$(GNUWEBDIR)/$(gnuweb-dir)'/CVS \
|
||||
&& { cd '$(GNUWEBDIR)/$(gnuweb-dir)' && $(CVS) update; } \
|
||||
|| { cd '$(GNUWEBDIR)' && $(CVS) -d $(gnuweb-repo) co '$(gnuweb-dir)'; }
|
||||
|
||||
@@ -416,7 +446,7 @@ $(COV_BUILD_FILE): $(filter %.c %.h,$(DISTFILES))
|
||||
cd '$(distdir)'/_build \
|
||||
&& ../configure --srcdir=.. \
|
||||
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS) \
|
||||
CFLAGS='$(AM_CFLAGS)'
|
||||
$(CFGCHECK_MAKEFLAGS)
|
||||
PATH="$${COVERITY_PATH:+$$COVERITY_PATH/bin:}$$PATH"; \
|
||||
cd '$(distdir)'/_build \
|
||||
&& cov-build --dir cov-int ../build.sh
|
||||
@@ -426,8 +456,8 @@ $(COV_BUILD_FILE): $(filter %.c %.h,$(DISTFILES))
|
||||
cov-submit: $(COV_BUILD_FILE)-submitted
|
||||
|
||||
$(COV_BUILD_FILE)-submitted: $(COV_BUILD_FILE)
|
||||
@[ -n "$(COVERITY_TOKEN)" ] || { echo 'COVERITY_TOKEN not set'; exit 1; }
|
||||
@[ -n "$(COVERITY_EMAIL)" ] || { echo 'COVERITY_EMAIL not set'; exit 1; }
|
||||
@test -n "$(COVERITY_TOKEN)" || { echo 'COVERITY_TOKEN not set'; exit 1; }
|
||||
@test -n "$(COVERITY_EMAIL)" || { echo 'COVERITY_EMAIL not set'; exit 1; }
|
||||
rm -f '$@'
|
||||
case '$(VERSION)' in \
|
||||
(*.*.9*) type="daily build"; ext=".$$(date +%Y%m%d)" ;; \
|
||||
@@ -504,7 +534,7 @@ $(UPLOADS): $(DIST_ARCHIVES) $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE)
|
||||
# Rebuild Makefile.in if this file is modifed.
|
||||
Makefile.in: maintMakefile
|
||||
|
||||
# Copyright (C) 1997-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1997-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
|
||||
|
||||
162
make-gdb.py
162
make-gdb.py
@@ -1,11 +1,15 @@
|
||||
import re
|
||||
"""GDB pretty-printer macros for GNU make."""
|
||||
|
||||
import gdb # pylint: disable=import-error
|
||||
import gdb.printing # pylint: disable=import-error
|
||||
|
||||
import gdb #pylint: disable=import-error
|
||||
import gdb.printing #pylint: disable=import-error
|
||||
|
||||
# Memoize types we commonly use
|
||||
_TYPES = {}
|
||||
|
||||
|
||||
def getType(tname):
|
||||
"""Given a type name return a GDB type."""
|
||||
global _TYPES
|
||||
if tname not in _TYPES:
|
||||
tn = tname.rstrip('*')
|
||||
@@ -18,48 +22,129 @@ def getType(tname):
|
||||
_TYPES[tn] = _TYPES[t].pointer()
|
||||
return _TYPES[tname]
|
||||
|
||||
class ShowArgv(gdb.Function):
|
||||
"""Return the pretty-print of a null-terminated array of strings
|
||||
|
||||
def isNullptr(val):
|
||||
"""Return True if the value is a null pointer."""
|
||||
return int(val.cast(getType('unsigned long long'))) == 0
|
||||
|
||||
|
||||
class ShowArgv(gdb.Command):
|
||||
"""Print a null-terminated array of strings.
|
||||
|
||||
Argument:
|
||||
A char** where the last one is NULL (e.g., argv)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
gdb.Function.__init__(self, "showargv")
|
||||
"""Create the showargv function."""
|
||||
gdb.Command.__init__(self, "showargv", gdb.COMMAND_USER)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""Show the argv."""
|
||||
args = gdb.string_to_argv(arg)
|
||||
if len(args) != 1:
|
||||
raise gdb.GdbError(self._usage)
|
||||
|
||||
val = gdb.parse_and_eval(args[0])
|
||||
if val is None:
|
||||
raise gdb.GdbError('%s is not a valid expression' % (args[0]))
|
||||
|
||||
strs = []
|
||||
while not isNullptr(val.dereference()):
|
||||
strs.append('"'+val.dereference().string()+'"')
|
||||
val += 1
|
||||
|
||||
gdb.write("[%d] = [%s]\n" % (len(strs), ', '.join(strs)))
|
||||
gdb.flush()
|
||||
|
||||
def invoke(self, argv):
|
||||
str = '['
|
||||
i = 0
|
||||
while argv[i] != 0:
|
||||
if i > 0:
|
||||
str += ', '
|
||||
str += argv[i].string()
|
||||
i += 1
|
||||
str += ']'
|
||||
return str
|
||||
|
||||
ShowArgv()
|
||||
|
||||
|
||||
class ShowNextList(gdb.Command):
|
||||
"""Print a structure that has a "next" pointer.
|
||||
|
||||
Argument:
|
||||
A pointer to a struct which contains a "next" member.
|
||||
"""
|
||||
|
||||
_usage = 'usage: showlist <listptr>'
|
||||
|
||||
def __init__(self):
|
||||
"""Create a "showlist" function."""
|
||||
gdb.Command.__init__(self, "showlist", gdb.COMMAND_USER)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
"""Show the elements in the provided list."""
|
||||
args = gdb.string_to_argv(arg)
|
||||
if len(args) != 1:
|
||||
raise gdb.GdbError(self._usage)
|
||||
|
||||
val = gdb.parse_and_eval(args[0])
|
||||
if val is None:
|
||||
raise gdb.GdbError('%s is not a valid expression' % (args[0]))
|
||||
i = 0
|
||||
while not isNullptr(val):
|
||||
gdb.write("%s : %s\n" % (val, val.dereference()))
|
||||
gdb.flush()
|
||||
i += 1
|
||||
val = val['next']
|
||||
gdb.write("%s contains %d elements\n" % (args[0], i))
|
||||
gdb.flush()
|
||||
|
||||
|
||||
ShowNextList()
|
||||
|
||||
|
||||
class FileLocation(object):
|
||||
"""Print a file location"""
|
||||
"""Print a file location."""
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a FileLocation object."""
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
if long(self.val['filenm']):
|
||||
"""Convert a FileLocation to a string."""
|
||||
if int(self.val['filenm']):
|
||||
return "%s:%d" % (str(self.val['filenm']), self.val['lineno'])
|
||||
return ''
|
||||
return 'NILF'
|
||||
|
||||
|
||||
class StringListPrinter(object):
|
||||
"""Print a stringlist."""
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a StringListPrinter object."""
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
"""Convert a HashTable into a string."""
|
||||
return "size=%d, capacity=%d" % (self.val['idx'], self.val['max'])
|
||||
|
||||
def children(self):
|
||||
"""Yield each string in the list."""
|
||||
i = 0
|
||||
elts = self.val['list']
|
||||
while i < self.val['idx']:
|
||||
nm = '[%d] ' % i
|
||||
yield (nm, elts.dereference())
|
||||
i += 1
|
||||
elts += 1
|
||||
|
||||
def display_hint(self):
|
||||
"""Show the display hint for the pretty-printer."""
|
||||
return 'array'
|
||||
|
||||
|
||||
class VariablePrinter(object):
|
||||
"""Print a struct variable"""
|
||||
"""Print a struct variable."""
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a VariablePrinter object."""
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
"""Convert a VariablePrinter object into a string."""
|
||||
if self.val['append']:
|
||||
a = '+='
|
||||
elif self.val['conditional']:
|
||||
@@ -80,48 +165,58 @@ class VariablePrinter(object):
|
||||
self.val['fileinfo'], ','.join(flags),
|
||||
self.val['name'].string(), a, self.val['value'].string())
|
||||
|
||||
|
||||
class HashTablePrinter(object):
|
||||
"""Manage a hash table."""
|
||||
"""Pretty-print a hash table."""
|
||||
|
||||
DELITEM = None
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a HashTablePrinter object."""
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
"""Convert a HashTable into a string."""
|
||||
return "size=%d, capacity=%d, empty=%d, collisions=%d, rehashes=%d" % (
|
||||
self.val['ht_size'], self.val['ht_capacity'],
|
||||
self.val['ht_empty_slots'], self.val['ht_collisions'],
|
||||
self.val['ht_rehashes'])
|
||||
|
||||
def children(self):
|
||||
"""Yield each ID and value."""
|
||||
for (i, v) in self.iterator():
|
||||
nm = '[%d] ' % i
|
||||
yield (nm, i)
|
||||
yield (nm, v)
|
||||
|
||||
def iterator(self):
|
||||
"""Provide an iterator for HashTable."""
|
||||
if HashTablePrinter.DELITEM is None:
|
||||
HashTablePrinter.DELITEM = gdb.lookup_global_symbol('hash_deleted_item').value()
|
||||
lst = self.val['ht_vec']
|
||||
for i in xrange(0, self.val['ht_size']):
|
||||
for i in range(0, self.val['ht_size']):
|
||||
v = lst[i]
|
||||
if long(v) != 0 and v != HashTablePrinter.DELITEM:
|
||||
if int(v) != 0 and v != HashTablePrinter.DELITEM:
|
||||
yield (i, v)
|
||||
|
||||
def display_hint(self):
|
||||
"""Show the display hint for the pretty-printer."""
|
||||
return 'map'
|
||||
|
||||
|
||||
class VariableSetPrinter(object):
|
||||
"""Print a variable_set"""
|
||||
"""Print a variable_set."""
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a variable_set pretty-printer."""
|
||||
self.tbl = HashTablePrinter(val['table'])
|
||||
|
||||
def to_string(self):
|
||||
"""Convert a variable_set to string."""
|
||||
return self.tbl.to_string()
|
||||
|
||||
def children(self):
|
||||
"""Iterate through variables and values."""
|
||||
for (i, v) in self.tbl.iterator():
|
||||
ptr = v.cast(getType('struct variable*'))
|
||||
nm = '[%d] ' % (i)
|
||||
@@ -129,29 +224,35 @@ class VariableSetPrinter(object):
|
||||
yield (nm, str(ptr.dereference()))
|
||||
|
||||
def display_hint(self):
|
||||
"""Show the display hint for the pretty-printer."""
|
||||
return 'map'
|
||||
|
||||
|
||||
class VariableSetListPrinter(object):
|
||||
"""Print a variable_set_list"""
|
||||
"""Print a variable_set_list."""
|
||||
|
||||
GLOBALSET = None
|
||||
|
||||
def __init__(self, val):
|
||||
"""Create a variable_set_list pretty-printer."""
|
||||
self.val = val
|
||||
|
||||
def to_string(self):
|
||||
"""Convert a variable_set_list to string."""
|
||||
return str(self.val.address)
|
||||
|
||||
def children(self):
|
||||
"""Iterate through variables and values."""
|
||||
if VariableSetListPrinter.GLOBALSET is None:
|
||||
block = gdb.lookup_global_symbol('init_hash_global_variable_set').symtab.static_block()
|
||||
VariableSetListPrinter.GLOBALSET = gdb.lookup_symbol('global_variable_set', block)[0].value().address
|
||||
VariableSetListPrinter.GLOBALSET = gdb.lookup_symbol(
|
||||
'global_variable_set', block)[0].value().address
|
||||
ptr = self.val.address
|
||||
i = 0
|
||||
while long(ptr) != 0:
|
||||
while not isNullptr(ptr):
|
||||
nm = '[%d] ' % (i)
|
||||
yield (nm, ptr['set'])
|
||||
if long(ptr['set']) == long(VariableSetListPrinter.GLOBALSET):
|
||||
if int(ptr['set']) == int(VariableSetListPrinter.GLOBALSET):
|
||||
yield (nm, "global_variable_set")
|
||||
else:
|
||||
yield (nm, str(ptr['set'].dereference()))
|
||||
@@ -159,17 +260,22 @@ class VariableSetListPrinter(object):
|
||||
ptr = ptr['next']
|
||||
|
||||
def display_hint(self):
|
||||
"""Show the display hint for the pretty-printer."""
|
||||
return 'map'
|
||||
|
||||
|
||||
def build_pretty_printer():
|
||||
"""Install all the pretty-printers."""
|
||||
pp = gdb.printing.RegexpCollectionPrettyPrinter("gnumake")
|
||||
pp.add_printer('floc', r'^floc$', FileLocation)
|
||||
pp.add_printer('stringlist', r'^stringlist$', StringListPrinter)
|
||||
pp.add_printer('variable', r'^variable$', VariablePrinter)
|
||||
pp.add_printer('hashtable', r'^hash_table$', HashTablePrinter)
|
||||
pp.add_printer('variableset', r'^variable_set$', VariableSetPrinter)
|
||||
pp.add_printer('variablesetlist', r'^variable_set_list$', VariableSetListPrinter)
|
||||
return pp
|
||||
|
||||
|
||||
# Use replace=True so we can re-source this file
|
||||
gdb.printing.register_pretty_printer(gdb.current_objfile(),
|
||||
build_pretty_printer(), replace=True)
|
||||
|
||||
@@ -76,7 +76,7 @@ $ filelist = "[.src]ar [.src]arscan [.src]commands [.src]default [.src]dir " + -
|
||||
"[.src]hash [.src]implicit [.src]job [.src]load [.src]main " + -
|
||||
"[.src]misc [.src]read [.src]remake [.src]remote-stub " + -
|
||||
"[.src]rule [.src]output [.src]signame [.src]variable " + -
|
||||
"[.src]version [.src]strcache [.src]vpath " + -
|
||||
"[.src]version [.src]shuffle [.src]strcache [.src]vpath " + -
|
||||
"[.src]vmsfunctions [.src]vmsify [.src]vms_progname " + -
|
||||
"[.src]vms_exit [.src]vms_export_symbol " + -
|
||||
"[.lib]alloca [.lib]fnmatch [.lib]glob [.src]getopt1 [.src]getopt"
|
||||
@@ -154,7 +154,7 @@ $ exit
|
||||
$ endsubroutine : compileit
|
||||
$!
|
||||
$!-----------------------------------------------------------------------------
|
||||
$!Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
$!Copyright (C) 1996-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Amiga overrides for use with Basic.mk.
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# POSIX overrides for use with Basic.mk.
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# VMS overrides for use with Basic.mk.
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Windows overrides for use with Basic.mk.
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# MS-DOS overrides for use with Basic.mk.
|
||||
#
|
||||
# Copyright (C) 2017-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2017-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
|
||||
|
||||
@@ -19,6 +19,7 @@ nl
|
||||
pl
|
||||
pt
|
||||
pt_BR
|
||||
ro
|
||||
ru
|
||||
sr
|
||||
sv
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# List of source files containing translatable strings.
|
||||
# Copyright (C) 2000-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2000-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
|
||||
@@ -37,6 +37,7 @@ src/read.c
|
||||
src/remake.c
|
||||
src/remote-cstms.c
|
||||
src/rule.c
|
||||
src/shuffle.c
|
||||
src/signame.c
|
||||
src/strcache.c
|
||||
src/variable.c
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||
# Copyright (C) 2014-2022 Free Software Foundation, Inc.
|
||||
# This file is part of GNU Make.
|
||||
#
|
||||
# Update GNU make copyrights using gnulib update-copyright
|
||||
@@ -17,7 +17,7 @@ getfiles () {
|
||||
|
||||
run () {
|
||||
cmd=$(command -v "$update") || die "Cannot locate update-copyright ($update)"
|
||||
[ -x "$cmd" ] || die "Cannot locate update-copyright ($update)"
|
||||
test -x "$cmd" || die "Cannot locate update-copyright ($update)"
|
||||
|
||||
force=false
|
||||
|
||||
@@ -30,9 +30,9 @@ run () {
|
||||
|
||||
if $force; then
|
||||
: just do it
|
||||
elif [ ! -f src/makeint.h ]; then
|
||||
elif test ! -f src/makeint.h; then
|
||||
die "Run in the root of the GNU make workspace"
|
||||
elif [ -f configure ]; then
|
||||
elif test -f configure; then
|
||||
die "Run in a clean workspace (git clean -fdX)"
|
||||
fi
|
||||
|
||||
|
||||
14
src/amiga.c
14
src/amiga.c
@@ -1,5 +1,5 @@
|
||||
/* Running commands on Amiga
|
||||
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
@@ -42,7 +42,7 @@ MyExecute (char **argv)
|
||||
buffer = AllocMem (len, MEMF_ANY);
|
||||
|
||||
if (!buffer)
|
||||
O (fatal, NILF, "MyExecute: Cannot allocate space for calling a command\n");
|
||||
O (fatal, NILF, "MyExecute: Cannot allocate space for calling a command");
|
||||
|
||||
ptr = buffer;
|
||||
|
||||
@@ -51,9 +51,8 @@ MyExecute (char **argv)
|
||||
if (((*aptr)[0] == ';' && !(*aptr)[1]))
|
||||
{
|
||||
*ptr ++ = '"';
|
||||
strcpy (ptr, *aptr);
|
||||
ptr += strlen (ptr);
|
||||
*ptr ++ = '"';
|
||||
ptr = stpcpy (ptr, *aptr);
|
||||
*(ptr++) = '"';
|
||||
}
|
||||
else if ((*aptr)[0] == '@' && (*aptr)[1] == '@' && !(*aptr)[2])
|
||||
{
|
||||
@@ -61,10 +60,7 @@ MyExecute (char **argv)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (ptr, *aptr);
|
||||
ptr += strlen (ptr);
|
||||
}
|
||||
ptr = stpcpy (ptr, *aptr);
|
||||
*ptr ++ = ' ';
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Definitions for amiga specific things
|
||||
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
|
||||
2
src/ar.c
2
src/ar.c
@@ -1,5 +1,5 @@
|
||||
/* Interface to 'ar' archives for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Make.
|
||||
|
||||
|
||||
55
src/arscan.c
55
src/arscan.c
@@ -1,5 +1,5 @@
|
||||
/* Library function for scanning an archive file.
|
||||
Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1987-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
|
||||
@@ -378,6 +378,31 @@ struct ar_hdr
|
||||
|
||||
#include "output.h"
|
||||
|
||||
|
||||
static unsigned long int
|
||||
parse_int (const char *ptr, const size_t len, const int base,
|
||||
const char *type, const char *archive, const char *name)
|
||||
{
|
||||
const char *const ep = ptr + len;
|
||||
const char max = '0' + base - 1;
|
||||
long int 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 != ' ')
|
||||
{
|
||||
if (*ptr < '0' || *ptr > max)
|
||||
OSSS (fatal, NILF, _("Invalid %s for archive %s member %s"),
|
||||
type, archive, name);
|
||||
val = (val * base) + (*ptr - '0');
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Takes three arguments ARCHIVE, FUNCTION and ARG.
|
||||
|
||||
Open the archive named ARCHIVE, find its members one by one,
|
||||
@@ -416,7 +441,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
# endif
|
||||
#endif
|
||||
char *namemap = 0;
|
||||
int namemap_size = 0;
|
||||
unsigned int namemap_size = 0;
|
||||
int desc = open (archive, O_RDONLY, 0);
|
||||
if (desc < 0)
|
||||
return -1;
|
||||
@@ -516,7 +541,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
|
||||
while (1)
|
||||
{
|
||||
int nread;
|
||||
ssize_t nread;
|
||||
struct ar_hdr member_header;
|
||||
#ifdef AIAMAGBIG
|
||||
struct ar_hdr_big member_header_big;
|
||||
@@ -540,6 +565,8 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
long int fnval;
|
||||
off_t o;
|
||||
|
||||
memset(&member_header, '\0', sizeof (member_header));
|
||||
|
||||
EINTRLOOP (o, lseek (desc, member_offset, 0));
|
||||
if (o < 0)
|
||||
goto invalid;
|
||||
@@ -669,10 +696,11 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
&& (name[0] == ' ' || name[0] == '/')
|
||||
&& namemap != 0)
|
||||
{
|
||||
int name_off = atoi (name + 1);
|
||||
int name_len;
|
||||
const char* err;
|
||||
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;
|
||||
|
||||
name = namemap + name_off;
|
||||
@@ -685,9 +713,10 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
&& name[1] == '1'
|
||||
&& 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 > PATH_MAX)
|
||||
goto invalid;
|
||||
|
||||
name = alloca (name_len + 1);
|
||||
@@ -703,8 +732,8 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
}
|
||||
|
||||
#ifndef M_XENIX
|
||||
sscanf (TOCHAR (member_header.ar_mode), "%8o", &eltmode);
|
||||
eltsize = atol (TOCHAR (member_header.ar_size));
|
||||
eltmode = parse_int (TOCHAR (member_header.ar_mode), sizeof (member_header.ar_mode), 8, "mode", archive, name);
|
||||
eltsize = parse_int (TOCHAR (member_header.ar_size), sizeof (member_header.ar_size), 10, "size", archive, name);
|
||||
#else /* Xenix. */
|
||||
eltmode = (unsigned short int) member_header.ar_mode;
|
||||
eltsize = member_header.ar_size;
|
||||
@@ -714,9 +743,9 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
|
||||
(*function) (desc, name, ! long_name, member_offset,
|
||||
member_offset + AR_HDR_SIZE, eltsize,
|
||||
#ifndef M_XENIX
|
||||
atol (TOCHAR (member_header.ar_date)),
|
||||
atoi (TOCHAR (member_header.ar_uid)),
|
||||
atoi (TOCHAR (member_header.ar_gid)),
|
||||
parse_int (TOCHAR (member_header.ar_date), sizeof (member_header.ar_date), 10, "date", archive, name),
|
||||
parse_int (TOCHAR (member_header.ar_uid), sizeof (member_header.ar_uid), 10, "uid", archive, name),
|
||||
parse_int (TOCHAR (member_header.ar_gid), sizeof (member_header.ar_gid), 10, "gid", archive, name),
|
||||
#else /* Xenix. */
|
||||
member_header.ar_date,
|
||||
member_header.ar_uid,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Command processing for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -30,10 +30,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#else
|
||||
# define FILE_LIST_SEPARATOR ' '
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_UNISTD_H
|
||||
pid_t getpid ();
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned long
|
||||
@@ -58,10 +54,13 @@ dep_hash_cmp (const void *x, const void *y)
|
||||
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
|
||||
set_file_variables (struct file *file)
|
||||
set_file_variables (struct file *file, const char *stem)
|
||||
{
|
||||
struct dep *d;
|
||||
const char *at, *percent, *star, *less;
|
||||
@@ -95,7 +94,7 @@ set_file_variables (struct file *file)
|
||||
}
|
||||
|
||||
/* $* 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
|
||||
any suffix in the .SUFFIXES list stripped off for
|
||||
@@ -118,25 +117,25 @@ set_file_variables (struct file *file)
|
||||
|
||||
for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
|
||||
{
|
||||
size_t slen = strlen (dep_name (d));
|
||||
if (len > slen && strneq (dep_name (d), name + (len - slen), slen))
|
||||
const char *dn = dep_name (d);
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (d == 0)
|
||||
file->stem = "";
|
||||
file->stem = stem = "";
|
||||
}
|
||||
star = file->stem;
|
||||
star = stem;
|
||||
|
||||
/* $< is the first not order-only dependency. */
|
||||
less = "";
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -214,8 +213,7 @@ set_file_variables (struct file *file)
|
||||
#endif
|
||||
len = strlen (c);
|
||||
|
||||
memcpy (cp, c, len);
|
||||
cp += len;
|
||||
cp = mempcpy (cp, c, len);
|
||||
*cp++ = FILE_LIST_SEPARATOR;
|
||||
if (! (d->changed || always_make_flag))
|
||||
qmark_len -= len + 1; /* Don't space in $? for this one. */
|
||||
@@ -285,19 +283,16 @@ set_file_variables (struct file *file)
|
||||
|
||||
if (d->ignore_mtime)
|
||||
{
|
||||
memcpy (bp, c, len);
|
||||
bp += len;
|
||||
bp = mempcpy (bp, c, len);
|
||||
*bp++ = FILE_LIST_SEPARATOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (cp, c, len);
|
||||
cp += len;
|
||||
cp = mempcpy (cp, c, len);
|
||||
*cp++ = FILE_LIST_SEPARATOR;
|
||||
if (d->changed || always_make_flag)
|
||||
{
|
||||
memcpy (qp, c, len);
|
||||
qp += len;
|
||||
qp = mempcpy (qp, c, len);
|
||||
*qp++ = FILE_LIST_SEPARATOR;
|
||||
}
|
||||
}
|
||||
@@ -465,12 +460,17 @@ execute_file_commands (struct file *file)
|
||||
|
||||
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. */
|
||||
if (file->loaded)
|
||||
unload_file (file->name);
|
||||
/* Some systems don't support overwriting a loaded object so if this one
|
||||
unload it before remaking. Keep its name in .LOADED: it will be rebuilt
|
||||
and loaded again. If rebuilding or loading again fail, then we'll exit
|
||||
anyway and it won't matter. */
|
||||
if (file->loaded && unload_file (file->name) == 0)
|
||||
{
|
||||
file->loaded = 0;
|
||||
file->unloaded = 1;
|
||||
}
|
||||
|
||||
/* Start the commands running. */
|
||||
new_job (file);
|
||||
@@ -483,7 +483,7 @@ int handling_fatal_signal = 0;
|
||||
|
||||
/* Handle fatal signals. */
|
||||
|
||||
RETSIGTYPE
|
||||
void
|
||||
fatal_error_signal (int sig)
|
||||
{
|
||||
#ifdef __MSDOS__
|
||||
@@ -508,7 +508,7 @@ fatal_error_signal (int sig)
|
||||
#ifdef WINDOWS32
|
||||
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
|
||||
when both threads call reap_children. */
|
||||
if (main_thread)
|
||||
@@ -516,12 +516,12 @@ fatal_error_signal (int sig)
|
||||
DWORD susp_count = SuspendThread (main_thread);
|
||||
|
||||
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)
|
||||
{
|
||||
DWORD ierr = GetLastError ();
|
||||
|
||||
fprintf (stderr, "SuspendThread: error %ld: %s\n",
|
||||
fprintf (stderr, "SuspendThread: error %lu: %s\n",
|
||||
ierr, map_windows32_error_to_string (ierr));
|
||||
}
|
||||
}
|
||||
@@ -596,7 +596,7 @@ fatal_error_signal (int sig)
|
||||
#else
|
||||
/* 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. */
|
||||
if (kill (getpid (), sig) < 0)
|
||||
if (kill (make_pid (), sig) < 0)
|
||||
pfatal_with_name ("kill");
|
||||
#endif /* not WINDOWS32 */
|
||||
#endif /* not Amiga */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Definition of data structures describing shell commands for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -34,9 +34,12 @@ struct commands
|
||||
#define COMMANDS_SILENT 2 /* Silent: @. */
|
||||
#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 print_commands (const struct commands *cmds);
|
||||
void delete_child_targets (struct child *child);
|
||||
void chop_commands (struct commands *cmds);
|
||||
void set_file_variables (struct file *file);
|
||||
void set_file_variables (struct file *file, const char *stem);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* config.h -- hand-massaged for Amiga -*-C-*-
|
||||
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
@@ -37,9 +37,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define for DGUX with <sys/dg_sys_info.h>. */
|
||||
/* #undef DGUX */
|
||||
|
||||
/* Define if the 'getloadavg' function needs to be run setuid or setgid. */
|
||||
/* #undef GETLOADAVG_PRIVILEGED */
|
||||
|
||||
/* Define to 'unsigned long' or 'unsigned long long'
|
||||
if <inttypes.h> doesn't define. */
|
||||
#define uintmax_t unsigned long
|
||||
@@ -53,12 +50,12 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* Define to 1 if you have the declaration of 'getloadavg'. */
|
||||
/* #undef HAVE_DECL_GETLOADAVG */
|
||||
|
||||
/* Define if your system has a working fnmatch function. */
|
||||
/* #undef HAVE_FNMATCH */
|
||||
|
||||
/* Define if your system has its own 'getloadavg' function. */
|
||||
/* #undef HAVE_GETLOADAVG */
|
||||
|
||||
/* Define if you have the getmntent function. */
|
||||
/* #undef HAVE_GETMNTENT */
|
||||
|
||||
@@ -134,14 +131,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define if you need to in order for stat and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Define as the return type of signal handlers (int or void). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Define if the setvbuf function takes the buffering type as its second
|
||||
argument and the buffer pointer as the third, as on System V
|
||||
before release 3. */
|
||||
/* #undef SETVBUF_REVERSED */
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at run-time.
|
||||
@@ -261,6 +250,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define if you have the strsignal function. */
|
||||
/* #undef HAVE_STRSIGNAL */
|
||||
|
||||
/* Define if you have the strtoll function. */
|
||||
/* #undef HAVE_STRTOLL */
|
||||
|
||||
/* Define if you have the wait3 function. */
|
||||
/* #undef HAVE_WAIT3 */
|
||||
|
||||
@@ -324,10 +316,10 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define if you have the sun library (-lsun). */
|
||||
/* #undef HAVE_LIBSUN */
|
||||
|
||||
/* Output sync sypport */
|
||||
/* Output sync support */
|
||||
#define NO_OUTPUT_SYNC
|
||||
|
||||
/* Define for Case Insensitve behavior */
|
||||
/* Define for Case Insensitive behavior */
|
||||
#define HAVE_CASE_INSENSITIVE_FS
|
||||
|
||||
/* Build host information. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* config.h-vms. Generated by hand by Klaus Kämpf <kkaempf@rmi.de> -*-C-*-
|
||||
|
||||
Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-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
|
||||
@@ -65,9 +65,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define for DGUX with <sys/dg_sys_info.h>. */
|
||||
/* #undef DGUX */
|
||||
|
||||
/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid. */
|
||||
/* #undef GETLOADAVG_PRIVILEGED */
|
||||
|
||||
/* Define to 'unsigned long' or 'unsigned long long'
|
||||
if <inttypes.h> doesn't define. */
|
||||
#define uintmax_t unsigned long
|
||||
@@ -81,15 +78,15 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* Define to 1 if you have the declaration of 'getloadavg'. */
|
||||
/* #undef HAVE_DECL_GETLOADAVG */
|
||||
|
||||
/* Define to 1 if you have the fdopen function. */
|
||||
#define HAVE_FDOPEN 1
|
||||
|
||||
/* Define to 1 if your system has a working fnmatch function. */
|
||||
/* #undef HAVE_FNMATCH */
|
||||
|
||||
/* Define to 1 if your system has its own 'getloadavg' function. */
|
||||
/* #undef HAVE_GETLOADAVG */
|
||||
|
||||
/* Define to 1 if you have the getmntent function. */
|
||||
/* #undef HAVE_GETMNTENT */
|
||||
|
||||
@@ -172,14 +169,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you need to in order for stat and other things to work. */
|
||||
/* #undef _POSIX_SOURCE */
|
||||
|
||||
/* Define as the return type of signal handlers (int or void). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Define to 1 if the setvbuf function takes the buffering type as its second
|
||||
argument and the buffer pointer as the third, as on System V
|
||||
before release 3. */
|
||||
/* #undef SETVBUF_REVERSED */
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at run-time.
|
||||
@@ -216,6 +205,18 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Name of this package (needed by automake) */
|
||||
#define PACKAGE "%PACKAGE%"
|
||||
|
||||
/* 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 home page for this package. */
|
||||
#define PACKAGE_URL "https://www.gnu.org/software/make/"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "%VERSION%"
|
||||
|
||||
/* Version of this package (needed by automake) */
|
||||
#define VERSION "%VERSION%"
|
||||
|
||||
@@ -259,6 +260,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the memmove function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the 'mkfifo' function. */
|
||||
/* #undef HAVE_MKFIFO */
|
||||
|
||||
/* Define to 1 if you have the mktemp function. */
|
||||
#define HAVE_MKTEMP 1
|
||||
|
||||
@@ -301,6 +305,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the strsignal function. */
|
||||
/* #undef HAVE_STRSIGNAL */
|
||||
|
||||
/* Define to 1 if you have the `strtoll' function. */
|
||||
#define HAVE_STRTOLL 1
|
||||
|
||||
/* Define to 1 if you have the wait3 function. */
|
||||
/* #undef HAVE_WAIT3 */
|
||||
|
||||
@@ -324,6 +331,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
/* #undef HAVE_MEMORY_H */
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
/* #undef HAVE_MEMPCPY */
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file. */
|
||||
/* #undef HAVE_NDIR_H */
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* config.h.W32 -- hand-massaged config.h file for Windows builds -*-C-*-
|
||||
|
||||
Copyright (C) 1996-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996-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
|
||||
@@ -19,28 +19,19 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
Maybe after the code cleanup for ISO C we can remove some/all of these. */
|
||||
#if _MSC_VER > 1000
|
||||
# pragma warning(disable:4100) /* unreferenced formal parameter */
|
||||
# pragma warning(disable:4102) /* unreferenced label */
|
||||
# pragma warning(disable:4127) /* conditional expression is constant */
|
||||
# pragma warning(disable:4130) /* logical operation on address of string constant */
|
||||
# pragma warning(disable:4131) /* uses old-style declarator */
|
||||
# pragma warning(disable:4702) /* unreachable code */
|
||||
# define _CRT_SECURE_NO_WARNINGS /* function or variable may be unsafe */
|
||||
# define _CRT_NONSTDC_NO_WARNINGS /* functions w/o a leading underscore */
|
||||
# define _CRT_SECURE_NO_WARNINGS 1 /* function or variable may be unsafe */
|
||||
# define _CRT_NONSTDC_NO_WARNINGS 1 /* functions w/o a leading underscore */
|
||||
#endif
|
||||
|
||||
/* Define to 1 if the 'closedir' function returns void instead of 'int'. */
|
||||
/* #undef CLOSEDIR_VOID */
|
||||
|
||||
/* Define to one of '_getb67', 'GETB67', 'getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for 'alloca.c' support on those systems.
|
||||
*/
|
||||
/* #undef CRAY_STACKSEG_END */
|
||||
|
||||
/* Define to 1 if using 'alloca.c'. */
|
||||
/* #undef C_ALLOCA */
|
||||
|
||||
/* Define to 1 if using 'getloadavg.c'. */
|
||||
#define C_GETLOADAVG 1
|
||||
|
||||
/* Define to 1 for DGUX with <sys/dg_sys_info.h>. */
|
||||
/* #undef DGUX */
|
||||
|
||||
@@ -51,15 +42,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Use high resolution file timestamps if nonzero. */
|
||||
#define FILE_TIMESTAMP_HI_RES 0
|
||||
|
||||
/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid.
|
||||
*/
|
||||
/* #undef GETLOADAVG_PRIVILEGED */
|
||||
|
||||
/* Define to 1 if you have 'alloca', as a function or macro. */
|
||||
/* Define to 1 if you have 'alloca' after including <alloca.h>, a header that
|
||||
may be supplied by this distribution. */
|
||||
#define HAVE_ALLOCA 1
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
/* Define to 1 if <alloca.h> works. */
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* Define to 1 if you have the 'atexit' function. */
|
||||
@@ -71,10 +58,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the clock_gettime function. */
|
||||
/* #undef HAVE_CLOCK_GETTIME */
|
||||
|
||||
/* Embed GNU Guile support. Windows build sets this on the
|
||||
compilation command line. */
|
||||
/* #undef HAVE_GUILE */
|
||||
|
||||
/* Define if the GNU dcgettext() function is already present or preinstalled.
|
||||
*/
|
||||
/* #undef HAVE_DCGETTEXT */
|
||||
@@ -83,6 +66,21 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
don't. */
|
||||
#define HAVE_DECL_BSD_SIGNAL 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `dlerror', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_DLERROR 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `dlopen', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_DLOPEN 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `dlsym', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_DLSYM 0
|
||||
|
||||
/* Define to 1 if you have the declaration of 'getloadavg'. */
|
||||
/* #undef HAVE_DECL_GETLOADAVG */
|
||||
|
||||
/* Define to 1 if you have the declaration of 'sys_siglist', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_SYS_SIGLIST 0
|
||||
@@ -102,13 +100,16 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the <direct.h> header file, and it defines getcwd()
|
||||
and chdir().
|
||||
*/
|
||||
#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__INTERIX)
|
||||
#if (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TINYC__)) && !defined(__INTERIX)
|
||||
# define HAVE_DIRECT_H 1
|
||||
#endif
|
||||
|
||||
/* Use platform specific coding */
|
||||
#define HAVE_DOS_PATHS 1
|
||||
|
||||
/* Define to 1 if you have the 'dup' function. */
|
||||
#define HAVE_DUP 1
|
||||
|
||||
/* Define to 1 if you have the 'dup2' function. */
|
||||
#define HAVE_DUP2 1
|
||||
|
||||
@@ -120,8 +121,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define HAVE_FDOPEN 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the 'fileno' function. */
|
||||
#define HAVE_FILENO 1
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
/* #undef HAVE_FORK */
|
||||
|
||||
/* Define to 1 if you have the 'getcwd' function. */
|
||||
#define HAVE_GETCWD 1
|
||||
@@ -135,9 +136,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'gethostname' function. */
|
||||
/* #undef HAVE_GETHOSTNAME */
|
||||
|
||||
/* Define to 1 if you have the 'getloadavg' function. */
|
||||
/* #undef HAVE_GETLOADAVG */
|
||||
|
||||
/* Define to 1 if you have the 'getrlimit' function. */
|
||||
/* #undef HAVE_GETRLIMIT */
|
||||
|
||||
@@ -149,6 +147,10 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
#endif
|
||||
|
||||
/* Embed GNU Guile support. Windows build sets this on the
|
||||
compilation command line. */
|
||||
/* #undef HAVE_GUILE */
|
||||
|
||||
/* Define if you have the iconv() function. */
|
||||
/* #undef HAVE_ICONV */
|
||||
|
||||
@@ -157,17 +159,23 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `isatty' function. */
|
||||
#define HAVE_ISATTY 1
|
||||
|
||||
/* Define to 1 if you have the 'dgc' library (-ldgc). */
|
||||
/* #undef HAVE_LIBDGC */
|
||||
|
||||
/* Define to 1 if you have the 'kstat' library (-lkstat). */
|
||||
/* #undef HAVE_LIBKSTAT */
|
||||
|
||||
/* Define to 1 if you have the `perfstat' library (-lperfstat). */
|
||||
/* #undef HAVE_LIBPERFSTAT */
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
/*#define HAVE_LOCALE_H 1*/
|
||||
/* #undef HAVE_LOCALE_H */
|
||||
|
||||
/* Define to 1 if you have the 'lstat' function. */
|
||||
/* #undef HAVE_LSTAT */
|
||||
@@ -178,9 +186,24 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
/* #undef HAVE_MEMPCPY */
|
||||
|
||||
/* Define to 1 if you have the `memrchr' function. */
|
||||
/* #undef HAVE_MEMRCHR */
|
||||
|
||||
/* Define to 1 if you have the <minix/config.h> header file. */
|
||||
/* #undef HAVE_MINIX_CONFIG_H */
|
||||
|
||||
/* Define to 1 if you have the 'mkfifo' function. */
|
||||
/* #undef HAVE_MKFIFO */
|
||||
|
||||
/* Define to 1 if you have the 'mkstemp' function. */
|
||||
/* #undef HAVE_MKSTEMP */
|
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */
|
||||
/* #undef HAVE_MKSTEMP */
|
||||
|
||||
/* Define to 1 if you have the 'mktemp' function. */
|
||||
#define HAVE_MKTEMP 1
|
||||
|
||||
@@ -193,6 +216,15 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'pipe' function. */
|
||||
/* #undef HAVE_PIPE */
|
||||
|
||||
/* Define to 1 if you have the `posix_spawn' function. */
|
||||
/* #undef HAVE_POSIX_SPAWN */
|
||||
|
||||
/* Define to 1 if you have the `posix_spawnattr_setsigmask' function. */
|
||||
/* #undef HAVE_POSIX_SPAWNATTR_SETSIGMASK */
|
||||
|
||||
/* Define to 1 if you have the `pselect' function. */
|
||||
/* #undef HAVE_PSELECT */
|
||||
|
||||
/* Define to 1 if you have the 'pstat_getdynamic' function. */
|
||||
/* #undef HAVE_PSTAT_GETDYNAMIC */
|
||||
|
||||
@@ -214,9 +246,6 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'setlinebuf' function. */
|
||||
/* #undef HAVE_SETLINEBUF */
|
||||
|
||||
/* Define to 1 if you have the 'setlocale' function. */
|
||||
/*#define HAVE_SETLOCALE 1*/
|
||||
|
||||
/* Define to 1 if you have the 'setregid' function. */
|
||||
/* #undef HAVE_SETREGID */
|
||||
|
||||
@@ -238,16 +267,25 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'socket' function. */
|
||||
/* #undef HAVE_SOCKET */
|
||||
|
||||
/* Define to 1 if you have the <spawn.h> header file. */
|
||||
/* #undef HAVE_SPAWN_H */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#ifdef __MINGW32__
|
||||
#define HAVE_STDINT_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <stdio.h> header file. */
|
||||
#define HAVE_STDIO_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `stpcpy' function. */
|
||||
/* #undef HAVE_STPCPY */
|
||||
|
||||
/* Define to 1 if you have the 'strcasecmp' function. */
|
||||
#ifdef __MINGW32__
|
||||
#if defined(__MINGW32__) || defined(__TINYC__)
|
||||
#define HAVE_STRCASECMP 1
|
||||
#endif
|
||||
|
||||
@@ -261,6 +299,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the 'stricmp' function. */
|
||||
#define HAVE_STRICMP 1
|
||||
|
||||
@@ -273,7 +314,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the 'strncasecmp' function. */
|
||||
#ifdef __MINGW32__
|
||||
#if defined(__MINGW32__) || defined(__TINYC__)
|
||||
#define HAVE_STRNCASECMP 1
|
||||
#endif
|
||||
|
||||
@@ -291,24 +332,15 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the 'strsignal' function. */
|
||||
/* #undef HAVE_STRSIGNAL */
|
||||
|
||||
/* Define to 1 if you have the `strtoll' function. */
|
||||
#define HAVE_STRTOLL 1
|
||||
|
||||
/* Define to 1 if `d_type' is a member of `struct dirent'. */
|
||||
/* SV 57152: MinGW64 version of dirent doesn't support d_type. */
|
||||
#ifndef __MINGW64__
|
||||
# define HAVE_STRUCT_DIRENT_D_TYPE 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the `isatty' function. */
|
||||
#define HAVE_ISATTY 1
|
||||
|
||||
/* Define to 1 if you have the `ttyname' function. */
|
||||
#define HAVE_TTYNAME 1
|
||||
char *ttyname (int);
|
||||
|
||||
/* Define to 1 if you have the `umask' function. */
|
||||
#ifdef __MINGW32__
|
||||
# define HAVE_UMASK 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if 'n_un.n_name' is a member of 'struct nlist'. */
|
||||
/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */
|
||||
|
||||
@@ -316,6 +348,12 @@ char *ttyname (int);
|
||||
*/
|
||||
/* #undef HAVE_SYS_DIR_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/file.h> header file. */
|
||||
/* #undef HAVE_SYS_FILE_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/loadavg.h> header file. */
|
||||
/* #undef HAVE_SYS_LOADAVG_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines 'DIR'.
|
||||
*/
|
||||
/* #undef HAVE_SYS_NDIR_H */
|
||||
@@ -328,6 +366,9 @@ char *ttyname (int);
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
/* #undef HAVE_SYS_RESOURCE_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
/* #undef HAVE_SYS_SELECT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
@@ -345,6 +386,18 @@ char *ttyname (int);
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
/* #undef HAVE_SYS_WAIT_H */
|
||||
|
||||
/* Define to 1 if you have the `ttyname' function. */
|
||||
#define HAVE_TTYNAME 1
|
||||
char *ttyname (int);
|
||||
|
||||
/* Define to 1 if the system has the type `uintmax_t'. */
|
||||
#define HAVE_UINTMAX_T 1
|
||||
|
||||
/* Define to 1 if you have the `umask' function. */
|
||||
#if defined(__MINGW32__) || defined(__TINYC__)
|
||||
# define HAVE_UMASK 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the \'union wait' type in <sys/wait.h>. */
|
||||
/* #undef HAVE_UNION_WAIT */
|
||||
|
||||
@@ -353,12 +406,33 @@ char *ttyname (int);
|
||||
#define HAVE_UNISTD_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if the system has the type 'unsigned long long int'. */
|
||||
#define HAVE_UNSIGNED_LONG_LONG_INT 1
|
||||
|
||||
/* Define to 1 if you have the `vfork' function. */
|
||||
/* #undef HAVE_VFORK */
|
||||
|
||||
/* Define to 1 if you have the <vfork.h> header file. */
|
||||
/* #undef HAVE_VFORK_H */
|
||||
|
||||
/* Define to 1 if you have the 'wait3' function. */
|
||||
/* #undef HAVE_WAIT3 */
|
||||
|
||||
/* Define to 1 if you have the 'waitpid' function. */
|
||||
/* #undef HAVE_WAITPID */
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
/* #undef HAVE_WCHAR_H */
|
||||
|
||||
/* Define to 1 if `fork' works. */
|
||||
/* #undef HAVE_WORKING_FORK */
|
||||
|
||||
/* Define to 1 if `vfork' works. */
|
||||
/* #undef HAVE_WORKING_VFORK */
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
/* #undef HAVE__BOOL */
|
||||
|
||||
/* Build host information. */
|
||||
#define MAKE_HOST "Windows32"
|
||||
|
||||
@@ -391,7 +465,7 @@ char *ttyname (int);
|
||||
#define PACKAGE_NAME "GNU make"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL "http://www.gnu.org/software/make/"
|
||||
#define PACKAGE_URL "https://www.gnu.org/software/make/"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "%VERSION%"
|
||||
@@ -399,20 +473,12 @@ char *ttyname (int);
|
||||
/* Define to the character that separates directories in PATH. */
|
||||
#define PATH_SEPARATOR_CHAR ';'
|
||||
|
||||
/* Define as the return type of signal handlers ('int' or 'void'). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Define to the name of the SCCS 'get' command. */
|
||||
#define SCCS_GET "echo no sccs get"
|
||||
|
||||
/* Define this if the SCCS 'get' command understands the '-G<file>' option. */
|
||||
/* #undef SCCS_GET_MINUS_G */
|
||||
|
||||
/* Define to 1 if the 'setvbuf' function takes the buffering type as its
|
||||
second argument and the buffer pointer as the third, as on System V before
|
||||
release 3. */
|
||||
/* #undef SETVBUF_REVERSED */
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at run time.
|
||||
@@ -433,11 +499,6 @@ char *ttyname (int);
|
||||
/* Define to 1 on System V Release 4. */
|
||||
/* #undef SVR4 */
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#ifdef __MINGW32__
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 for Encore UMAX. */
|
||||
/* #undef UMAX */
|
||||
|
||||
@@ -525,10 +586,14 @@ char *ttyname (int);
|
||||
|
||||
/*
|
||||
* If you have a shell that does not grok 'sh -c quoted-command-line'
|
||||
* correctly, you need this setting. Please see below for specific
|
||||
* shell support.
|
||||
* correctly, you need this setting; it is the default for tcc.
|
||||
* Please see below for specific shell support.
|
||||
*/
|
||||
#if defined(__TINYC__)
|
||||
#define BATCH_MODE_ONLY_SHELL 1
|
||||
#else
|
||||
/*#define BATCH_MODE_ONLY_SHELL 1 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define if you have the Cygnus "Cygwin" GNU Windows32 tool set.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* configh.dos -- hand-massaged config.h file for MS-DOS builds -*-C-*-
|
||||
|
||||
Copyright (C) 1994-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1994-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
|
||||
@@ -100,7 +100,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "%VERSION%"
|
||||
|
||||
/* Output sync sypport */
|
||||
/* Output sync support */
|
||||
#define NO_OUTPUT_SYNC
|
||||
|
||||
/* Version number of package */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Debugging macros and interface.
|
||||
Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1999-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
|
||||
@@ -19,6 +19,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#define DB_VERBOSE (0x002)
|
||||
#define DB_JOBS (0x004)
|
||||
#define DB_IMPLICIT (0x008)
|
||||
#define DB_PRINT (0x010)
|
||||
#define DB_WHY (0x020)
|
||||
#define DB_MAKEFILES (0x100)
|
||||
|
||||
#define DB_ALL (0xfff)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Data base of default implicit rules for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -506,7 +506,7 @@ static const char *default_variables[] =
|
||||
"COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
|
||||
"LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)",
|
||||
"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.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
|
||||
"LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
|
||||
@@ -518,7 +518,12 @@ static const char *default_variables[] =
|
||||
#else /* !VMS */
|
||||
|
||||
"AR", "ar",
|
||||
"ARFLAGS", "rv",
|
||||
#ifdef _AIX
|
||||
/* AIX requires object file format specification: choose -Xany. */
|
||||
"ARFLAGS", "-Xany -rv",
|
||||
#else
|
||||
"ARFLAGS", "-rv",
|
||||
#endif
|
||||
"AS", "as",
|
||||
#ifdef GCC_IS_NATIVE
|
||||
"CC", "gcc",
|
||||
@@ -636,7 +641,7 @@ static const char *default_variables[] =
|
||||
"COMPILE.s", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
|
||||
"LINK.S", "$(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)",
|
||||
"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.r", "$(FC) $(FFLAGS) $(RFLAGS) $(TARGET_ARCH) -F",
|
||||
"LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
|
||||
@@ -663,7 +668,7 @@ static const char *default_variables[] =
|
||||
|
||||
#endif /* !VMS */
|
||||
/* Make this assignment to avoid undefined variable warnings. */
|
||||
"GNUMAKEFLAGS", "",
|
||||
GNUMAKEFLAGS_NAME, "",
|
||||
0, 0
|
||||
};
|
||||
|
||||
|
||||
15
src/dep.h
15
src/dep.h
@@ -1,5 +1,5 @@
|
||||
/* Definitions of dependency data structures for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -30,26 +30,32 @@ struct nameseq
|
||||
These flags are saved in the 'flags' field of each
|
||||
'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_INCLUDED (1 << 1) /* Search makefile search path. */
|
||||
#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_NOFLAG 0
|
||||
|
||||
/* Structure representing one dependency of a file.
|
||||
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) \
|
||||
NAMESEQ (_t); \
|
||||
struct file *file; \
|
||||
_t *shuf; \
|
||||
const char *stem; \
|
||||
unsigned int flags : 8; \
|
||||
unsigned int changed : 1; \
|
||||
unsigned int ignore_mtime : 1; \
|
||||
unsigned int staticpattern : 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
|
||||
{
|
||||
@@ -76,6 +82,7 @@ struct goaldep
|
||||
#define PARSEFS_EXISTS 0x0008
|
||||
#define PARSEFS_NOCACHE 0x0010
|
||||
#define PARSEFS_ONEWORD 0x0020
|
||||
#define PARSEFS_WAIT 0x0040
|
||||
|
||||
#define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \
|
||||
(_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f))
|
||||
|
||||
293
src/dir.c
293
src/dir.c
@@ -1,5 +1,5 @@
|
||||
/* Directory hashing for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -18,6 +18,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "hash.h"
|
||||
#include "filedef.h"
|
||||
#include "dep.h"
|
||||
#include "debug.h"
|
||||
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
@@ -175,7 +176,7 @@ vms_hash (const char *name)
|
||||
|
||||
while (*name)
|
||||
{
|
||||
unsigned char uc = *name;
|
||||
unsigned char uc = (unsigned char) *name;
|
||||
int g;
|
||||
#ifdef HAVE_CASE_INSENSITIVE_FS
|
||||
h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
|
||||
@@ -232,6 +233,12 @@ vmsstat_dir (const char *name, struct stat *st)
|
||||
#endif /* _USE_STD_STAT */
|
||||
#endif /* VMS */
|
||||
|
||||
/* Never have more than this many directories open at once. */
|
||||
|
||||
#define MAX_OPEN_DIRECTORIES 10
|
||||
|
||||
static unsigned int open_directories = 0;
|
||||
|
||||
/* Hash table of directories. */
|
||||
|
||||
#ifndef DIRECTORY_BUCKETS
|
||||
@@ -262,9 +269,25 @@ struct directory_contents
|
||||
# endif
|
||||
#endif /* WINDOWS32 */
|
||||
struct hash_table dirfiles; /* Files in this directory. */
|
||||
unsigned long counter; /* command_count value when last read. */
|
||||
DIR *dirstream; /* Stream reading this directory. */
|
||||
};
|
||||
|
||||
static struct directory_contents *
|
||||
clear_directory_contents (struct directory_contents *dc)
|
||||
{
|
||||
dc->counter = 0;
|
||||
if (dc->dirstream)
|
||||
{
|
||||
--open_directories;
|
||||
closedir (dc->dirstream);
|
||||
dc->dirstream = 0;
|
||||
}
|
||||
hash_free (&dc->dirfiles, 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
directory_contents_hash_1 (const void *key_0)
|
||||
{
|
||||
@@ -363,7 +386,9 @@ static struct hash_table directory_contents;
|
||||
|
||||
struct directory
|
||||
{
|
||||
const char *name; /* Name of the directory. */
|
||||
const char *name; /* Name of the directory. */
|
||||
unsigned long counter; /* command_count value when last read.
|
||||
Used for non-existent directories. */
|
||||
|
||||
/* The directory's contents. This data may be shared by several
|
||||
entries in the hash table, which refer to the same directory
|
||||
@@ -393,12 +418,6 @@ directory_hash_cmp (const void *x, const void *y)
|
||||
/* Table of directories hashed by name. */
|
||||
static struct hash_table directories;
|
||||
|
||||
/* Never have more than this many directories open at once. */
|
||||
|
||||
#define MAX_OPEN_DIRECTORIES 10
|
||||
|
||||
static unsigned int open_directories = 0;
|
||||
|
||||
|
||||
/* Hash table of files in each directory. */
|
||||
|
||||
@@ -449,150 +468,164 @@ find_directory (const char *name)
|
||||
struct directory *dir;
|
||||
struct directory **dir_slot;
|
||||
struct directory dir_key;
|
||||
struct directory_contents *dc;
|
||||
struct directory_contents **dc_slot;
|
||||
struct directory_contents dc_key;
|
||||
|
||||
struct stat st;
|
||||
int r;
|
||||
#ifdef WINDOWS32
|
||||
char *w32_path;
|
||||
#endif
|
||||
|
||||
dir_key.name = name;
|
||||
dir_slot = (struct directory **) hash_find_slot (&directories, &dir_key);
|
||||
dir = *dir_slot;
|
||||
|
||||
if (HASH_VACANT (dir))
|
||||
if (!HASH_VACANT (dir))
|
||||
{
|
||||
unsigned long ctr = dir->contents ? dir->contents->counter : dir->counter;
|
||||
|
||||
/* No commands have run since we parsed this directory so it's good. */
|
||||
if (ctr == command_count)
|
||||
return dir;
|
||||
|
||||
DB (DB_VERBOSE, ("Directory %s cache invalidated (count %lu != command %lu)\n",
|
||||
name, ctr, command_count));
|
||||
|
||||
if (dir->contents)
|
||||
clear_directory_contents (dir->contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The directory was not found. Create a new entry for it. */
|
||||
const char *p = name + strlen (name);
|
||||
struct stat st;
|
||||
int r;
|
||||
size_t len = strlen (name);
|
||||
|
||||
dir = xmalloc (sizeof (struct directory));
|
||||
#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
|
||||
/* Todo: Why is this only needed on VMS? */
|
||||
{
|
||||
char *lname = downcase_inplace (xstrdup (name));
|
||||
dir->name = strcache_add_len (lname, p - name);
|
||||
dir->name = strcache_add_len (lname, len);
|
||||
free (lname);
|
||||
}
|
||||
#else
|
||||
dir->name = strcache_add_len (name, p - name);
|
||||
dir->name = strcache_add_len (name, len);
|
||||
#endif
|
||||
hash_insert_at (&directories, dir, dir_slot);
|
||||
/* The directory is not in the name hash table.
|
||||
Find its device and inode numbers, and look it up by them. */
|
||||
}
|
||||
|
||||
dir->contents = NULL;
|
||||
dir->counter = command_count;
|
||||
|
||||
/* See if the directory exists. */
|
||||
#if defined(WINDOWS32)
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
size_t len = strlen (name);
|
||||
|
||||
/* Remove any trailing slashes. Windows32 stat fails even on
|
||||
valid directories if they end in a slash. */
|
||||
memcpy (tem, name, p - name + 1);
|
||||
tstart = tem;
|
||||
if (tstart[1] == ':')
|
||||
tstart += 2;
|
||||
for (tend = tem + (p - name - 1);
|
||||
tend > tstart && (*tend == '/' || *tend == '\\');
|
||||
tend--)
|
||||
*tend = '\0';
|
||||
/* Remove any trailing slashes. Windows32 stat fails even on
|
||||
valid directories if they end in a slash. */
|
||||
memcpy (tem, name, len + 1);
|
||||
tstart = tem;
|
||||
if (tstart[1] == ':')
|
||||
tstart += 2;
|
||||
for (tend = tem + (len - 1);
|
||||
tend > tstart && (*tend == '/' || *tend == '\\');
|
||||
tend--)
|
||||
*tend = '\0';
|
||||
|
||||
r = stat (tem, &st);
|
||||
}
|
||||
r = stat (tem, &st);
|
||||
}
|
||||
#else
|
||||
EINTRLOOP (r, stat (name, &st));
|
||||
EINTRLOOP (r, stat (name, &st));
|
||||
#endif
|
||||
|
||||
if (r < 0)
|
||||
{
|
||||
/* Couldn't stat the directory. Mark this by
|
||||
setting the 'contents' member to a nil pointer. */
|
||||
dir->contents = 0;
|
||||
}
|
||||
if (r < 0)
|
||||
/* Couldn't stat the directory; nothing else to do. */
|
||||
return dir;
|
||||
|
||||
/* Search the contents hash table; device and inode are the key. */
|
||||
|
||||
memset (&dc_key, '\0', sizeof (dc_key));
|
||||
dc_key.dev = st.st_dev;
|
||||
#ifdef WINDOWS32
|
||||
dc_key.path_key = w32_path = w32ify (name, 1);
|
||||
dc_key.ctime = st.st_ctime;
|
||||
#else
|
||||
# ifdef VMS_INO_T
|
||||
dc_key.ino[0] = st.st_ino[0];
|
||||
dc_key.ino[1] = st.st_ino[1];
|
||||
dc_key.ino[2] = st.st_ino[2];
|
||||
# else
|
||||
dc_key.ino = st.st_ino;
|
||||
# endif
|
||||
#endif
|
||||
dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
|
||||
dc = *dc_slot;
|
||||
|
||||
if (HASH_VACANT (dc))
|
||||
{
|
||||
/* Nope; this really is a directory we haven't seen before. */
|
||||
#ifdef WINDOWS32
|
||||
char fs_label[BUFSIZ];
|
||||
char fs_type[BUFSIZ];
|
||||
unsigned long fs_serno;
|
||||
unsigned long fs_flags;
|
||||
unsigned long fs_len;
|
||||
#endif
|
||||
/* Enter it in the contents hash table. */
|
||||
dc = xcalloc (sizeof (struct directory_contents));
|
||||
*dc = dc_key;
|
||||
|
||||
#ifdef WINDOWS32
|
||||
dc->path_key = xstrdup (w32_path);
|
||||
dc->mtime = st.st_mtime;
|
||||
|
||||
/* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
|
||||
directory when files are added/deleted from a directory. */
|
||||
w32_path[3] = '\0';
|
||||
if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
|
||||
&fs_serno, &fs_len, &fs_flags, fs_type,
|
||||
sizeof (fs_type)) == FALSE)
|
||||
dc->fs_flags = FS_UNKNOWN;
|
||||
else if (!strcmp (fs_type, "FAT"))
|
||||
dc->fs_flags = FS_FAT;
|
||||
else if (!strcmp (fs_type, "NTFS"))
|
||||
dc->fs_flags = FS_NTFS;
|
||||
else
|
||||
dc->fs_flags = FS_UNKNOWN;
|
||||
#endif /* WINDOWS32 */
|
||||
|
||||
hash_insert_at (&directory_contents, dc, dc_slot);
|
||||
}
|
||||
|
||||
/* Point the name-hashed entry for DIR at its contents data. */
|
||||
dir->contents = dc;
|
||||
|
||||
/* If the contents have changed, we need to reseet. */
|
||||
if (dc->counter != command_count)
|
||||
{
|
||||
if (dc->counter)
|
||||
clear_directory_contents (dc);
|
||||
|
||||
dc->counter = command_count;
|
||||
|
||||
ENULLLOOP (dc->dirstream, opendir (name));
|
||||
if (dc->dirstream == 0)
|
||||
/* Couldn't open the directory. Mark this by setting the
|
||||
'files' member to a nil pointer. */
|
||||
dc->dirfiles.ht_vec = 0;
|
||||
else
|
||||
{
|
||||
/* Search the contents hash table; device and inode are the key. */
|
||||
|
||||
#ifdef WINDOWS32
|
||||
char *w32_path;
|
||||
#endif
|
||||
struct directory_contents *dc;
|
||||
struct directory_contents **dc_slot;
|
||||
struct directory_contents dc_key;
|
||||
|
||||
dc_key.dev = st.st_dev;
|
||||
#ifdef WINDOWS32
|
||||
dc_key.path_key = w32_path = w32ify (name, 1);
|
||||
dc_key.ctime = st.st_ctime;
|
||||
#else
|
||||
# ifdef VMS_INO_T
|
||||
dc_key.ino[0] = st.st_ino[0];
|
||||
dc_key.ino[1] = st.st_ino[1];
|
||||
dc_key.ino[2] = st.st_ino[2];
|
||||
# else
|
||||
dc_key.ino = st.st_ino;
|
||||
# endif
|
||||
#endif
|
||||
dc_slot = (struct directory_contents **) hash_find_slot (&directory_contents, &dc_key);
|
||||
dc = *dc_slot;
|
||||
|
||||
if (HASH_VACANT (dc))
|
||||
{
|
||||
/* Nope; this really is a directory we haven't seen before. */
|
||||
#ifdef WINDOWS32
|
||||
char fs_label[BUFSIZ];
|
||||
char fs_type[BUFSIZ];
|
||||
unsigned long fs_serno;
|
||||
unsigned long fs_flags;
|
||||
unsigned long fs_len;
|
||||
#endif
|
||||
dc = (struct directory_contents *)
|
||||
xmalloc (sizeof (struct directory_contents));
|
||||
|
||||
/* Enter it in the contents hash table. */
|
||||
dc->dev = st.st_dev;
|
||||
#ifdef WINDOWS32
|
||||
dc->path_key = xstrdup (w32_path);
|
||||
dc->ctime = st.st_ctime;
|
||||
dc->mtime = st.st_mtime;
|
||||
|
||||
/* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
|
||||
directory when files are added/deleted from a directory. */
|
||||
w32_path[3] = '\0';
|
||||
if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
|
||||
&fs_serno, &fs_len, &fs_flags, fs_type,
|
||||
sizeof (fs_type)) == FALSE)
|
||||
dc->fs_flags = FS_UNKNOWN;
|
||||
else if (!strcmp (fs_type, "FAT"))
|
||||
dc->fs_flags = FS_FAT;
|
||||
else if (!strcmp (fs_type, "NTFS"))
|
||||
dc->fs_flags = FS_NTFS;
|
||||
else
|
||||
dc->fs_flags = FS_UNKNOWN;
|
||||
#else
|
||||
# ifdef VMS_INO_T
|
||||
dc->ino[0] = st.st_ino[0];
|
||||
dc->ino[1] = st.st_ino[1];
|
||||
dc->ino[2] = st.st_ino[2];
|
||||
# else
|
||||
dc->ino = st.st_ino;
|
||||
# endif
|
||||
#endif /* WINDOWS32 */
|
||||
hash_insert_at (&directory_contents, dc, dc_slot);
|
||||
ENULLLOOP (dc->dirstream, opendir (name));
|
||||
if (dc->dirstream == 0)
|
||||
/* Couldn't open the directory. Mark this by setting the
|
||||
'files' member to a nil pointer. */
|
||||
dc->dirfiles.ht_vec = 0;
|
||||
else
|
||||
{
|
||||
hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
|
||||
dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
|
||||
/* Keep track of how many directories are open. */
|
||||
++open_directories;
|
||||
if (open_directories == MAX_OPEN_DIRECTORIES)
|
||||
/* We have too many directories open already.
|
||||
Read the entire directory and then close it. */
|
||||
dir_contents_file_exists_p (dc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Point the name-hashed entry for DIR at its contents data. */
|
||||
dir->contents = dc;
|
||||
hash_init (&dc->dirfiles, DIRFILE_BUCKETS,
|
||||
dirfile_hash_1, dirfile_hash_2, dirfile_hash_cmp);
|
||||
/* Keep track of how many directories are open. */
|
||||
++open_directories;
|
||||
if (open_directories == MAX_OPEN_DIRECTORIES)
|
||||
/* We have too many directories open already.
|
||||
Read the entire directory and then close it. */
|
||||
dir_contents_file_exists_p (dc, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1286,13 +1319,13 @@ local_stat (const char *path, struct stat *buf)
|
||||
/* Make sure the parent of "." exists and is a directory, not a
|
||||
file. This is because 'stat' on Windows normalizes the argument
|
||||
foo/. => foo without checking first that foo is a directory. */
|
||||
if (plen > 1 && path[plen - 1] == '.'
|
||||
if (plen > 2 && path[plen - 1] == '.'
|
||||
&& (path[plen - 2] == '/' || path[plen - 2] == '\\'))
|
||||
{
|
||||
char parent[MAXPATHLEN];
|
||||
char parent[MAXPATHLEN+1];
|
||||
|
||||
strncpy (parent, path, plen - 2);
|
||||
parent[plen - 2] = '\0';
|
||||
strncpy (parent, path, MAXPATHLEN);
|
||||
parent[MIN(plen - 2, MAXPATHLEN)] = '\0';
|
||||
if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
|
||||
return -1;
|
||||
}
|
||||
|
||||
40
src/expand.c
40
src/expand.c
@@ -1,5 +1,5 @@
|
||||
/* Variable expansion functions for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -18,9 +18,10 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "commands.h"
|
||||
#include "debug.h"
|
||||
#include "filedef.h"
|
||||
#include "job.h"
|
||||
#include "commands.h"
|
||||
#include "variable.h"
|
||||
#include "rule.h"
|
||||
|
||||
@@ -67,14 +68,14 @@ variable_buffer_output (char *ptr, const char *string, size_t length)
|
||||
ptr = variable_buffer + offset;
|
||||
}
|
||||
|
||||
memcpy (ptr, string, length);
|
||||
return ptr + length;
|
||||
return mempcpy (ptr, string, 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 *
|
||||
initialize_variable_output (void)
|
||||
char *
|
||||
initialize_variable_output ()
|
||||
{
|
||||
/* If we don't have a variable output buffer yet, get one. */
|
||||
|
||||
@@ -101,6 +102,29 @@ recursively_expand_for_file (struct variable *v, struct file *file)
|
||||
struct variable_set_list *save = 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.
|
||||
This can happen for command-line variables, builtin variables, etc. */
|
||||
saved_varp = expanding_var;
|
||||
@@ -207,7 +231,7 @@ variable_expand_string (char *line, const char *string, size_t length)
|
||||
if (length == 0)
|
||||
{
|
||||
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
|
||||
|
||||
253
src/file.c
253
src/file.c
@@ -1,5 +1,5 @@
|
||||
/* Target file management for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -25,6 +25,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "variable.h"
|
||||
#include "debug.h"
|
||||
#include "hash.h"
|
||||
#include "shuffle.h"
|
||||
|
||||
|
||||
/* Remember whether snap_deps has been invoked: we need this to be sure we
|
||||
@@ -62,6 +63,9 @@ static struct hash_table files;
|
||||
/* Whether or not .SECONDARY with no prerequisites was given. */
|
||||
static int all_secondary = 0;
|
||||
|
||||
/* Whether or not .NOTINTERMEDIATE with no prerequisites was given. */
|
||||
static int no_intermediates = 0;
|
||||
|
||||
/* Access the hash table of all file records.
|
||||
lookup_file given a name, return the struct file * for that name,
|
||||
or nil if there is none.
|
||||
@@ -270,14 +274,14 @@ rehash_file (struct file *from_file, const char *to_hname)
|
||||
{
|
||||
size_t l = strlen (from_file->name);
|
||||
/* 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. */
|
||||
if (to_file->cmds->fileinfo.filenm != 0)
|
||||
error (&from_file->cmds->fileinfo,
|
||||
l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH,
|
||||
_("Recipe was specified for file '%s' at %s:%lu,"),
|
||||
from_file->name, to_file->cmds->fileinfo.filenm,
|
||||
to_file->cmds->fileinfo.lineno);
|
||||
from_file->name, from_file->cmds->fileinfo.filenm,
|
||||
from_file->cmds->fileinfo.lineno);
|
||||
else
|
||||
error (&from_file->cmds->fileinfo, l,
|
||||
_("Recipe for file '%s' was found by implicit rule search,"),
|
||||
@@ -288,7 +292,7 @@ rehash_file (struct file *from_file, const char *to_hname)
|
||||
from_file->name, to_hname);
|
||||
error (&from_file->cmds->fileinfo, l,
|
||||
_("Recipe for '%s' will be ignored in favor of the one for '%s'."),
|
||||
to_hname, from_file->name);
|
||||
from_file->name, to_hname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,14 +331,19 @@ rehash_file (struct file *from_file, const char *to_hname)
|
||||
|
||||
#define MERGE(field) to_file->field |= from_file->field
|
||||
MERGE (precious);
|
||||
MERGE (loaded);
|
||||
MERGE (tried_implicit);
|
||||
MERGE (updating);
|
||||
MERGE (updated);
|
||||
MERGE (is_target);
|
||||
MERGE (cmd_target);
|
||||
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 (snapped);
|
||||
#undef MERGE
|
||||
|
||||
to_file->builtin = 0;
|
||||
@@ -386,7 +395,7 @@ remove_intermediates (int sig)
|
||||
given on the command line, and it's either a -include makefile or
|
||||
it's not precious. */
|
||||
if (f->intermediate && (f->dontcare || !f->precious)
|
||||
&& !f->secondary && !f->cmd_target)
|
||||
&& !f->secondary && !f->notintermediate && !f->cmd_target)
|
||||
{
|
||||
int status;
|
||||
if (f->update_status == us_none)
|
||||
@@ -424,7 +433,11 @@ remove_intermediates (int sig)
|
||||
}
|
||||
}
|
||||
if (status < 0)
|
||||
perror_with_name ("unlink: ", f->name);
|
||||
{
|
||||
perror_with_name ("\nunlink: ", f->name);
|
||||
/* Start printing over. */
|
||||
doneany = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,8 +455,7 @@ remove_intermediates (int sig)
|
||||
struct dep *
|
||||
split_prereqs (char *p)
|
||||
{
|
||||
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL,
|
||||
PARSEFS_NONE);
|
||||
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_WAIT);
|
||||
|
||||
if (*p)
|
||||
{
|
||||
@@ -452,7 +464,7 @@ split_prereqs (char *p)
|
||||
struct dep *ood;
|
||||
|
||||
++p;
|
||||
ood = PARSE_SIMPLE_SEQ (&p, struct dep);
|
||||
ood = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_WAIT);
|
||||
|
||||
if (! new)
|
||||
new = ood;
|
||||
@@ -486,7 +498,6 @@ enter_prereqs (struct dep *deps, const char *stem)
|
||||
if (stem)
|
||||
{
|
||||
const char *pattern = "%";
|
||||
char *buffer = variable_expand ("");
|
||||
struct dep *dp = deps, *dl = 0;
|
||||
|
||||
while (dp != 0)
|
||||
@@ -506,14 +517,15 @@ enter_prereqs (struct dep *deps, const char *stem)
|
||||
if (stem[0] == '\0')
|
||||
{
|
||||
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
|
||||
o = patsubst_expand_pat (buffer, stem, pattern, nm,
|
||||
o = patsubst_expand_pat (variable_buffer, stem, pattern, nm,
|
||||
pattern+1, percent+1);
|
||||
|
||||
/* If the name expanded to the empty string, ignore it. */
|
||||
if (buffer[0] == '\0')
|
||||
if (variable_buffer[0] == '\0')
|
||||
{
|
||||
struct dep *df = dp;
|
||||
if (dp == deps)
|
||||
@@ -525,7 +537,8 @@ enter_prereqs (struct dep *deps, const char *stem)
|
||||
}
|
||||
|
||||
/* 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->staticpattern = 1;
|
||||
@@ -545,21 +558,29 @@ enter_prereqs (struct dep *deps, const char *stem)
|
||||
d1->file = enter_file (d1->name);
|
||||
d1->staticpattern = 0;
|
||||
d1->name = 0;
|
||||
if (!stem)
|
||||
/* This file is explicitly mentioned as a prereq. */
|
||||
d1->file->is_explicit = 1;
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
/* Expand and parse each dependency line. */
|
||||
static void
|
||||
/* Expand and parse each dependency line.
|
||||
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)
|
||||
{
|
||||
struct dep *d;
|
||||
struct dep **dp;
|
||||
const char *file_stem = f->stem;
|
||||
const char *fstem;
|
||||
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
|
||||
expansion, expand it then insert the result into the list. */
|
||||
@@ -569,7 +590,6 @@ expand_deps (struct file *f)
|
||||
{
|
||||
char *p;
|
||||
struct dep *new, *next;
|
||||
char *name = (char *)d->name;
|
||||
|
||||
if (! d->name || ! d->need_2nd_expansion)
|
||||
{
|
||||
@@ -579,16 +599,46 @@ expand_deps (struct file *f)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If it's from a static pattern rule, convert the patterns into
|
||||
"$*" so they'll expand properly. */
|
||||
/* If it's from a static pattern rule, convert the initial pattern in
|
||||
each word to "$*" so they'll expand properly. */
|
||||
if (d->staticpattern)
|
||||
{
|
||||
char *o = variable_expand ("");
|
||||
o = subst_expand (o, name, "%", "$*", 1, 2, 0);
|
||||
*o = '\0';
|
||||
free (name);
|
||||
d->name = name = xstrdup (variable_buffer);
|
||||
d->staticpattern = 0;
|
||||
const char *cs = d->name;
|
||||
size_t nperc = 0;
|
||||
|
||||
/* Count the number of % in the string. */
|
||||
while ((cs = strchr (cs, '%')) != NULL)
|
||||
{
|
||||
++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
|
||||
@@ -600,39 +650,53 @@ expand_deps (struct file *f)
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
if (d->stem != 0)
|
||||
f->stem = d->stem;
|
||||
|
||||
set_file_variables (f);
|
||||
set_file_variables (f, d->stem ? d->stem : f->stem);
|
||||
|
||||
/* Perform second expansion. */
|
||||
p = variable_expand_for_file (d->name, f);
|
||||
|
||||
if (d->stem != 0)
|
||||
f->stem = file_stem;
|
||||
|
||||
/* At this point we don't need the name anymore: free it. */
|
||||
free (name);
|
||||
/* Free the un-expanded name. */
|
||||
free ((char*)d->name);
|
||||
|
||||
/* 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 (new == 0)
|
||||
{
|
||||
*dp = d->next;
|
||||
changed_dep = 1;
|
||||
free_dep (d);
|
||||
d = *dp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add newly parsed prerequisites. */
|
||||
fstem = d->stem;
|
||||
next = d->next;
|
||||
changed_dep = 1;
|
||||
free_dep (d);
|
||||
*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;
|
||||
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. */
|
||||
@@ -667,10 +731,18 @@ snap_file (const void *item, void *arg)
|
||||
if (!second_expansion)
|
||||
f->updating = 0;
|
||||
|
||||
/* If .SECONDARY is set with no deps, mark all targets as intermediate. */
|
||||
if (all_secondary)
|
||||
/* More specific setting has priority. */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 (f->variables)
|
||||
prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set));
|
||||
@@ -701,10 +773,7 @@ snap_file (const void *item, void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* For each dependency of each file, make the 'struct dep' point
|
||||
at the appropriate 'struct file' (which may have to be created).
|
||||
|
||||
Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
|
||||
/* Mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
|
||||
and various other special targets. */
|
||||
|
||||
void
|
||||
@@ -718,37 +787,6 @@ snap_deps (void)
|
||||
longer define new targets. */
|
||||
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. */
|
||||
|
||||
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
|
||||
@@ -772,11 +810,32 @@ snap_deps (void)
|
||||
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 connot 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)
|
||||
/* Mark .INTERMEDIATE deps as intermediate files. */
|
||||
for (d = f->deps; d != 0; d = d->next)
|
||||
for (f2 = d->file; f2 != 0; f2 = f2->prev)
|
||||
f2->intermediate = 1;
|
||||
if (f2->notintermediate)
|
||||
OS (fatal, NILF,
|
||||
_("%s cannot be both .NOTINTERMEDIATE and .INTERMEDIATE"),
|
||||
f2->name);
|
||||
else
|
||||
f2->intermediate = 1;
|
||||
/* .INTERMEDIATE with no deps does nothing.
|
||||
Marking all files as intermediates is useless since the goal targets
|
||||
would be deleted after they are built. */
|
||||
@@ -786,11 +845,20 @@ snap_deps (void)
|
||||
if (f->deps)
|
||||
for (d = f->deps; d != 0; d = d->next)
|
||||
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;
|
||||
/* .SECONDARY with no deps listed marks *all* files that way. */
|
||||
else
|
||||
all_secondary = 1;
|
||||
|
||||
if (no_intermediates && all_secondary)
|
||||
O (fatal, NILF,
|
||||
_(".NOTINTERMEDIATE and .SECONDARY are mutually exclusive"));
|
||||
|
||||
f = lookup_file (".EXPORT_ALL_VARIABLES");
|
||||
if (f != 0 && f->is_target)
|
||||
export_all_variables = 1;
|
||||
@@ -819,7 +887,19 @@ snap_deps (void)
|
||||
|
||||
f = lookup_file (".NOTPARALLEL");
|
||||
if (f != 0 && f->is_target)
|
||||
not_parallel = 1;
|
||||
{
|
||||
struct dep *d2;
|
||||
|
||||
if (!f->deps)
|
||||
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")));
|
||||
@@ -970,17 +1050,17 @@ print_prereqs (const struct dep *deps)
|
||||
/* Print all normal dependencies; note any order-only deps. */
|
||||
for (; deps != 0; deps = deps->next)
|
||||
if (! deps->ignore_mtime)
|
||||
printf (" %s", dep_name (deps));
|
||||
printf (" %s%s", deps->wait_here ? ".WAIT " : "", dep_name (deps));
|
||||
else if (! ood)
|
||||
ood = deps;
|
||||
|
||||
/* Print order-only deps, if we have any. */
|
||||
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)
|
||||
if (ood->ignore_mtime)
|
||||
printf (" %s", dep_name (ood));
|
||||
printf (" %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood));
|
||||
}
|
||||
|
||||
putchar ('\n');
|
||||
@@ -1034,6 +1114,10 @@ print_file (const void *item)
|
||||
printf (_("# Implicit/static pattern stem: '%s'\n"), f->stem);
|
||||
if (f->intermediate)
|
||||
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)
|
||||
{
|
||||
const struct dep *d;
|
||||
@@ -1181,8 +1265,7 @@ build_target_list (char *value)
|
||||
p = &value[off];
|
||||
}
|
||||
|
||||
memcpy (p, f->name, l);
|
||||
p += l;
|
||||
p = mempcpy (p, f->name, l);
|
||||
*(p++) = ' ';
|
||||
}
|
||||
*(p-1) = '\0';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Definition of target file data structures for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -84,6 +84,7 @@ struct file
|
||||
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 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
|
||||
has only one-second resolution. */
|
||||
unsigned int tried_implicit:1; /* Nonzero if have searched
|
||||
@@ -96,8 +97,11 @@ struct file
|
||||
unsigned int phony:1; /* Nonzero if this is a phony file
|
||||
i.e., a prerequisite of .PHONY. */
|
||||
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
|
||||
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
|
||||
this target cannot be remade. */
|
||||
unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */
|
||||
@@ -105,6 +109,10 @@ struct file
|
||||
pattern-specific variables. */
|
||||
unsigned int no_diag:1; /* True if the file failed to update and no
|
||||
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. */
|
||||
};
|
||||
|
||||
|
||||
@@ -115,6 +123,7 @@ struct file *lookup_file (const char *name);
|
||||
struct file *enter_file (const char *name);
|
||||
struct dep *split_prereqs (char *prereqstr);
|
||||
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);
|
||||
void remove_intermediates (int sig);
|
||||
void snap_deps (void);
|
||||
|
||||
553
src/function.c
553
src/function.c
@@ -1,5 +1,5 @@
|
||||
/* Builtin function expansion for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -40,6 +40,7 @@ struct function_table_entry
|
||||
unsigned char maximum_args;
|
||||
unsigned int expand_args:1;
|
||||
unsigned int alloc_fn:1;
|
||||
unsigned int adds_command:1;
|
||||
};
|
||||
|
||||
static unsigned long
|
||||
@@ -465,7 +466,6 @@ func_origin (char *o, char **argv, const char *funcname UNUSED)
|
||||
else
|
||||
switch (v->origin)
|
||||
{
|
||||
default:
|
||||
case o_invalid:
|
||||
abort ();
|
||||
break;
|
||||
@@ -738,14 +738,14 @@ func_lastword (char *o, char **argv, const char *funcname UNUSED)
|
||||
static char *
|
||||
func_words (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int i = 0;
|
||||
const char *word_iterator = argv[0];
|
||||
char buf[20];
|
||||
char buf[INTSTR_LENGTH];
|
||||
|
||||
while (find_next_token (&word_iterator, NULL) != 0)
|
||||
++i;
|
||||
|
||||
sprintf (buf, "%d", i);
|
||||
sprintf (buf, "%u", i);
|
||||
o = variable_buffer_output (o, buf, strlen (buf));
|
||||
|
||||
return o;
|
||||
@@ -766,35 +766,39 @@ strip_whitespace (const char **begpp, const char **endpp)
|
||||
return (char *)*begpp;
|
||||
}
|
||||
|
||||
static void
|
||||
check_numeric (const char *s, const char *msg)
|
||||
static long long
|
||||
parse_numeric (const char *s, const char *msg)
|
||||
{
|
||||
const char *end = s + strlen (s) - 1;
|
||||
const char *beg = s;
|
||||
strip_whitespace (&s, &end);
|
||||
const char *end = s + strlen (s) - 1;
|
||||
char *endp;
|
||||
long long num;
|
||||
strip_whitespace (&beg, &end);
|
||||
|
||||
for (; s <= end; ++s)
|
||||
if (!ISDIGIT (*s)) /* ISDIGIT only evals its arg once: see makeint.h. */
|
||||
break;
|
||||
if (beg > end)
|
||||
OS (fatal, *expanding_var, _("%s: empty value"), msg);
|
||||
|
||||
if (s <= end || end - beg < 0)
|
||||
OSS (fatal, *expanding_var, "%s: '%s'", msg, beg);
|
||||
errno = 0;
|
||||
num = strtoll (beg, &endp, 10);
|
||||
if (errno == ERANGE)
|
||||
OSS (fatal, *expanding_var, _("%s: '%s' out of range"), msg, s);
|
||||
else if (endp == beg || endp <= end)
|
||||
/* Empty or non-numeric input */
|
||||
OSS (fatal, *expanding_var, "%s: '%s'", msg, s);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *
|
||||
func_word (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
const char *end_p;
|
||||
const char *p;
|
||||
int i;
|
||||
long long i;
|
||||
|
||||
/* Check the first argument. */
|
||||
check_numeric (argv[0], _("non-numeric first argument to 'word' function"));
|
||||
i = atoi (argv[0]);
|
||||
|
||||
if (i == 0)
|
||||
i = parse_numeric (argv[0],
|
||||
_("invalid first argument to 'word' function"));
|
||||
if (i < 1)
|
||||
O (fatal, *expanding_var,
|
||||
_("first argument to 'word' function must be greater than 0"));
|
||||
|
||||
@@ -812,20 +816,22 @@ func_word (char *o, char **argv, const char *funcname UNUSED)
|
||||
static char *
|
||||
func_wordlist (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
int start, count;
|
||||
long long start, stop, count;
|
||||
|
||||
/* Check the arguments. */
|
||||
check_numeric (argv[0],
|
||||
_("non-numeric first argument to 'wordlist' function"));
|
||||
check_numeric (argv[1],
|
||||
_("non-numeric second argument to 'wordlist' function"));
|
||||
start = parse_numeric (argv[0],
|
||||
_("invalid first argument to 'wordlist' function"));
|
||||
stop = parse_numeric (argv[1],
|
||||
_("invalid second argument to 'wordlist' function"));
|
||||
|
||||
start = atoi (argv[0]);
|
||||
if (start < 1)
|
||||
ON (fatal, *expanding_var,
|
||||
"invalid first argument to 'wordlist' function: '%d'", start);
|
||||
"invalid first argument to 'wordlist' function: '%lld'", start);
|
||||
|
||||
count = atoi (argv[1]) - start + 1;
|
||||
if (stop < 0)
|
||||
ON (fatal, *expanding_var,
|
||||
"invalid second argument to 'wordlist' function: '%lld'", stop);
|
||||
|
||||
count = stop - start + 1;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
@@ -908,9 +914,58 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED)
|
||||
return o;
|
||||
}
|
||||
|
||||
static char *
|
||||
func_let (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
/* expand only the first two. */
|
||||
char *varnames = expand_argument (argv[0], NULL);
|
||||
char *list = expand_argument (argv[1], NULL);
|
||||
const char *body = argv[2];
|
||||
|
||||
const char *vp;
|
||||
const char *vp_next = varnames;
|
||||
const char *list_iterator = list;
|
||||
char *p;
|
||||
size_t len;
|
||||
size_t vlen;
|
||||
|
||||
push_new_variable_scope ();
|
||||
|
||||
/* loop through LIST for all but the last VARNAME */
|
||||
vp = find_next_token (&vp_next, &vlen);
|
||||
NEXT_TOKEN (vp_next);
|
||||
while (*vp_next != '\0')
|
||||
{
|
||||
p = find_next_token (&list_iterator, &len);
|
||||
if (*list_iterator != '\0')
|
||||
{
|
||||
++list_iterator;
|
||||
p[len] = '\0';
|
||||
}
|
||||
define_variable (vp, vlen, p ? p : "", o_automatic, 0);
|
||||
|
||||
vp = find_next_token (&vp_next, &vlen);
|
||||
NEXT_TOKEN (vp_next);
|
||||
}
|
||||
|
||||
/* set the last VARNAME to the remainder of LIST */
|
||||
if (vp)
|
||||
define_variable (vp, vlen, next_token (list_iterator), o_automatic, 0);
|
||||
|
||||
/* Expand the body in the context of the arguments, adding the result to
|
||||
the variable buffer. */
|
||||
|
||||
o = variable_expand_string (o, body, SIZE_MAX);
|
||||
|
||||
pop_variable_scope ();
|
||||
free (varnames);
|
||||
free (list);
|
||||
|
||||
return o + strlen (o);
|
||||
}
|
||||
|
||||
struct a_word
|
||||
{
|
||||
struct a_word *next;
|
||||
struct a_word *chain;
|
||||
char *str;
|
||||
size_t length;
|
||||
@@ -935,13 +990,13 @@ a_word_hash_cmp (const void *x, const void *y)
|
||||
int result = (int) ((struct a_word const *) x)->length - ((struct a_word const *) y)->length;
|
||||
if (result)
|
||||
return result;
|
||||
return_STRING_COMPARE (((struct a_word const *) x)->str,
|
||||
((struct a_word const *) y)->str);
|
||||
return_STRING_N_COMPARE (((struct a_word const *) x)->str,
|
||||
((struct a_word const *) y)->str,
|
||||
((struct a_word const *) y)->length);
|
||||
}
|
||||
|
||||
struct a_pattern
|
||||
{
|
||||
struct a_pattern *next;
|
||||
char *str;
|
||||
char *percent;
|
||||
size_t length;
|
||||
@@ -950,78 +1005,84 @@ struct a_pattern
|
||||
static char *
|
||||
func_filter_filterout (char *o, char **argv, const char *funcname)
|
||||
{
|
||||
struct a_word *wordhead;
|
||||
struct a_word **wordtail;
|
||||
struct a_word *words;
|
||||
struct a_word *word_end;
|
||||
struct a_word *wp;
|
||||
struct a_pattern *pathead;
|
||||
struct a_pattern **pattail;
|
||||
struct a_pattern *patterns;
|
||||
struct a_pattern *pat_end;
|
||||
struct a_pattern *pp;
|
||||
size_t pat_count = 0, word_count = 0;
|
||||
|
||||
struct hash_table a_word_table;
|
||||
int is_filter = funcname[CSTRLEN ("filter")] == '\0';
|
||||
const char *pat_iterator = argv[0];
|
||||
const char *word_iterator = argv[1];
|
||||
const char *cp;
|
||||
int literals = 0;
|
||||
int words = 0;
|
||||
int hashing = 0;
|
||||
char *p;
|
||||
size_t len;
|
||||
int doneany = 0;
|
||||
|
||||
/* Chop ARGV[0] up into patterns to match against the words.
|
||||
We don't need to preserve it because our caller frees all the
|
||||
argument memory anyway. */
|
||||
/* Find the number of words and get memory for them. */
|
||||
cp = argv[1];
|
||||
while ((p = find_next_token (&cp, NULL)) != 0)
|
||||
++word_count;
|
||||
|
||||
pattail = &pathead;
|
||||
while ((p = find_next_token (&pat_iterator, &len)) != 0)
|
||||
if (!word_count)
|
||||
return o;
|
||||
|
||||
words = xcalloc (word_count * sizeof (struct a_word));
|
||||
word_end = words + word_count;
|
||||
|
||||
/* Find the number of patterns and get memory for them. */
|
||||
cp = argv[0];
|
||||
while ((p = find_next_token (&cp, NULL)) != 0)
|
||||
++pat_count;
|
||||
|
||||
patterns = xcalloc (pat_count * sizeof (struct a_pattern));
|
||||
pat_end = patterns + pat_count;
|
||||
|
||||
/* Chop argv[0] up into patterns to match against the words. */
|
||||
|
||||
cp = argv[0];
|
||||
pp = patterns;
|
||||
while ((p = find_next_token (&cp, &len)) != 0)
|
||||
{
|
||||
struct a_pattern *pat = alloca (sizeof (struct a_pattern));
|
||||
if (*cp != '\0')
|
||||
++cp;
|
||||
|
||||
*pattail = pat;
|
||||
pattail = &pat->next;
|
||||
|
||||
if (*pat_iterator != '\0')
|
||||
++pat_iterator;
|
||||
|
||||
pat->str = p;
|
||||
p[len] = '\0';
|
||||
pat->percent = find_percent (p);
|
||||
if (pat->percent == 0)
|
||||
pp->str = p;
|
||||
pp->percent = find_percent (p);
|
||||
if (pp->percent == 0)
|
||||
literals++;
|
||||
|
||||
/* find_percent() might shorten the string so LEN is wrong. */
|
||||
pat->length = strlen (pat->str);
|
||||
pp->length = strlen (pp->str);
|
||||
|
||||
++pp;
|
||||
}
|
||||
*pattail = 0;
|
||||
|
||||
/* Chop ARGV[1] up into words to match against the patterns. */
|
||||
|
||||
wordtail = &wordhead;
|
||||
while ((p = find_next_token (&word_iterator, &len)) != 0)
|
||||
cp = argv[1];
|
||||
wp = words;
|
||||
while ((p = find_next_token (&cp, &len)) != 0)
|
||||
{
|
||||
struct a_word *word = alloca (sizeof (struct a_word));
|
||||
|
||||
*wordtail = word;
|
||||
wordtail = &word->next;
|
||||
|
||||
if (*word_iterator != '\0')
|
||||
++word_iterator;
|
||||
if (*cp != '\0')
|
||||
++cp;
|
||||
|
||||
p[len] = '\0';
|
||||
word->str = p;
|
||||
word->length = len;
|
||||
word->matched = 0;
|
||||
word->chain = 0;
|
||||
words++;
|
||||
wp->str = p;
|
||||
wp->length = len;
|
||||
++wp;
|
||||
}
|
||||
*wordtail = 0;
|
||||
|
||||
/* Only use a hash table if arg list lengths justifies the cost. */
|
||||
hashing = (literals >= 2 && (literals * words) >= 10);
|
||||
hashing = (literals > 1 && (literals * word_count) >= 10);
|
||||
if (hashing)
|
||||
{
|
||||
hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2,
|
||||
hash_init (&a_word_table, word_count, a_word_hash_1, a_word_hash_2,
|
||||
a_word_hash_cmp);
|
||||
for (wp = wordhead; wp != 0; wp = wp->next)
|
||||
for (wp = words; wp < word_end; ++wp)
|
||||
{
|
||||
struct a_word *owp = hash_insert (&a_word_table, wp);
|
||||
if (owp)
|
||||
@@ -1029,51 +1090,49 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
|
||||
}
|
||||
}
|
||||
|
||||
if (words)
|
||||
/* Run each pattern through the words, killing words. */
|
||||
for (pp = patterns; pp < pat_end; ++pp)
|
||||
{
|
||||
int doneany = 0;
|
||||
|
||||
/* Run each pattern through the words, killing words. */
|
||||
for (pp = pathead; pp != 0; pp = pp->next)
|
||||
if (pp->percent)
|
||||
for (wp = words; wp < word_end; ++wp)
|
||||
wp->matched |= pattern_matches (pp->str, pp->percent, wp->str);
|
||||
else if (hashing)
|
||||
{
|
||||
if (pp->percent)
|
||||
for (wp = wordhead; wp != 0; wp = wp->next)
|
||||
wp->matched |= pattern_matches (pp->str, pp->percent, wp->str);
|
||||
else if (hashing)
|
||||
struct a_word a_word_key;
|
||||
a_word_key.str = pp->str;
|
||||
a_word_key.length = pp->length;
|
||||
wp = hash_find_item (&a_word_table, &a_word_key);
|
||||
while (wp)
|
||||
{
|
||||
struct a_word a_word_key;
|
||||
a_word_key.str = pp->str;
|
||||
a_word_key.length = pp->length;
|
||||
wp = hash_find_item (&a_word_table, &a_word_key);
|
||||
while (wp)
|
||||
{
|
||||
wp->matched |= 1;
|
||||
wp = wp->chain;
|
||||
}
|
||||
wp->matched |= 1;
|
||||
wp = wp->chain;
|
||||
}
|
||||
else
|
||||
for (wp = wordhead; wp != 0; wp = wp->next)
|
||||
wp->matched |= (wp->length == pp->length
|
||||
&& strneq (pp->str, wp->str, wp->length));
|
||||
}
|
||||
|
||||
/* Output the words that matched (or didn't, for filter-out). */
|
||||
for (wp = wordhead; wp != 0; wp = wp->next)
|
||||
if (is_filter ? wp->matched : !wp->matched)
|
||||
{
|
||||
o = variable_buffer_output (o, wp->str, strlen (wp->str));
|
||||
o = variable_buffer_output (o, " ", 1);
|
||||
doneany = 1;
|
||||
}
|
||||
|
||||
if (doneany)
|
||||
/* Kill the last space. */
|
||||
--o;
|
||||
else
|
||||
for (wp = words; wp < word_end; ++wp)
|
||||
wp->matched |= (wp->length == pp->length
|
||||
&& memcmp (pp->str, wp->str, wp->length) == 0);
|
||||
}
|
||||
|
||||
/* Output the words that matched (or didn't, for filter-out). */
|
||||
for (wp = words; wp < word_end; ++wp)
|
||||
if (is_filter ? wp->matched : !wp->matched)
|
||||
{
|
||||
o = variable_buffer_output (o, wp->str, strlen (wp->str));
|
||||
o = variable_buffer_output (o, " ", 1);
|
||||
doneany = 1;
|
||||
}
|
||||
|
||||
if (doneany)
|
||||
/* Kill the last space. */
|
||||
--o;
|
||||
|
||||
if (hashing)
|
||||
hash_free (&a_word_table, 0);
|
||||
|
||||
free (patterns);
|
||||
free (words);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -1113,41 +1172,25 @@ func_strip (char *o, char **argv, const char *funcname UNUSED)
|
||||
static char *
|
||||
func_error (char *o, char **argv, const char *funcname)
|
||||
{
|
||||
char **argvp;
|
||||
char *msg, *p;
|
||||
size_t len;
|
||||
|
||||
/* The arguments will be broken on commas. Rather than create yet
|
||||
another special case where function arguments aren't broken up,
|
||||
just create a format string that puts them back together. */
|
||||
for (len=0, argvp=argv; *argvp != 0; ++argvp)
|
||||
len += strlen (*argvp) + 2;
|
||||
|
||||
p = msg = alloca (len + 1);
|
||||
msg[0] = '\0';
|
||||
|
||||
for (argvp=argv; argvp[1] != 0; ++argvp)
|
||||
{
|
||||
strcpy (p, *argvp);
|
||||
p += strlen (*argvp);
|
||||
*(p++) = ',';
|
||||
*(p++) = ' ';
|
||||
}
|
||||
strcpy (p, *argvp);
|
||||
|
||||
switch (*funcname)
|
||||
{
|
||||
case 'e':
|
||||
OS (fatal, reading_file, "%s", msg);
|
||||
OS (fatal, reading_file, "%s", argv[0]);
|
||||
|
||||
case 'w':
|
||||
OS (error, reading_file, "%s", msg);
|
||||
OS (error, reading_file, "%s", argv[0]);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
outputs (0, msg);
|
||||
outputs (0, "\n");
|
||||
break;
|
||||
{
|
||||
size_t len = strlen (argv[0]);
|
||||
char *msg = alloca (len + 2);
|
||||
memcpy (msg, argv[0], len);
|
||||
msg[len] = '\n';
|
||||
msg[len + 1] = '\0';
|
||||
outputs (0, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
OS (fatal, *expanding_var, "Internal error: func_error: '%s'", funcname);
|
||||
@@ -1203,7 +1246,7 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
len = strlen (words[i]);
|
||||
if (i == wordi - 1 || strlen (words[i + 1]) != len
|
||||
|| strcmp (words[i], words[i + 1]))
|
||||
|| memcmp (words[i], words[i + 1], len))
|
||||
{
|
||||
o = variable_buffer_output (o, words[i], len);
|
||||
o = variable_buffer_output (o, " ", 1);
|
||||
@@ -1219,6 +1262,115 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
Traverse NUMBER consisting of optional leading white space, optional
|
||||
sign, digits, and optional trailing white space.
|
||||
If number is not of the proper form, diagnose with MSG. Otherwise,
|
||||
return the address of of the first character after NUMBER, store
|
||||
into *SIGN an integer consistent with the number's sign (-1, 0, or 1)
|
||||
and store into *NUMSTART the address of NUMBER's first nonzero digit
|
||||
(if NUMBER contains only zero digits, store the address of the first
|
||||
character after NUMBER).
|
||||
*/
|
||||
static const char *
|
||||
parse_textint (const char *number, const char *msg,
|
||||
int *sign, const char **numstart)
|
||||
{
|
||||
const char *after_sign, *after_number;
|
||||
const char *p = next_token (number);
|
||||
int negative = *p == '-';
|
||||
int nonzero;
|
||||
|
||||
if (*p == '\0')
|
||||
OS (fatal, *expanding_var, _("%s: empty value"), msg);
|
||||
|
||||
p += negative || *p == '+';
|
||||
after_sign = p;
|
||||
|
||||
while (*p == '0')
|
||||
p++;
|
||||
*numstart = p;
|
||||
|
||||
while (ISDIGIT (*p))
|
||||
++p;
|
||||
after_number = p;
|
||||
nonzero = *numstart != after_number;
|
||||
*sign = negative ? -nonzero : nonzero;
|
||||
|
||||
/* Check for extra non-whitespace stuff after the value. */
|
||||
if (after_number == after_sign || *next_token (p) != '\0')
|
||||
OSS (fatal, *expanding_var, "%s: '%s'", msg, number);
|
||||
|
||||
return after_number;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
$(intcmp lhs,rhs[,lt-part[,eq-part[,gt-part]]])
|
||||
|
||||
LHS and RHS must be integer values (leading/trailing whitespace is ignored).
|
||||
If none of LT-PART, EQ-PART, or GT-PART are given then the function expands
|
||||
to empty if LHS and RHS are not equal, or the numeric value if they are equal.
|
||||
LT-PART is evaluated when LHS is strictly less than RHS, EQ-PART is evaluated
|
||||
when LHS is equal to RHS, and GT-part is evaluated when LHS is strictly
|
||||
greater than RHS.
|
||||
If GT-PART is not provided, it defaults to EQ-PART. When neither EQ-PART
|
||||
nor GT-PART are provided, the function expands to empty if LHS is not
|
||||
strictly less than RHS.
|
||||
*/
|
||||
|
||||
static char *
|
||||
func_intcmp (char *o, char **argv, const char *funcname UNUSED)
|
||||
{
|
||||
int lsign, rsign;
|
||||
const char *lnum, *rnum;
|
||||
char *lhs_str = expand_argument (argv[0], NULL);
|
||||
char *rhs_str = expand_argument (argv[1], NULL);
|
||||
const char *llim = parse_textint (lhs_str, _("non-numeric first argument to 'intcmp' function"), &lsign, &lnum);
|
||||
const char *rlim = parse_textint (rhs_str, _("non-numeric second argument to 'intcmp' function"), &rsign, &rnum);
|
||||
ptrdiff_t llen = llim - lnum;
|
||||
ptrdiff_t rlen = rlim - rnum;
|
||||
int cmp = lsign - rsign;
|
||||
|
||||
if (cmp == 0)
|
||||
{
|
||||
cmp = (llen > rlen) - (llen < rlen);
|
||||
if (cmp == 0)
|
||||
cmp = memcmp (lnum, rnum, llen);
|
||||
}
|
||||
|
||||
argv += 2;
|
||||
|
||||
/* Handle the special case where there are only two arguments. */
|
||||
if (!*argv && cmp == 0)
|
||||
{
|
||||
if (lsign < 0)
|
||||
o = variable_buffer_output (o, "-", 1);
|
||||
o = variable_buffer_output(o, lnum - !lsign, llen + !lsign);
|
||||
}
|
||||
|
||||
free (lhs_str);
|
||||
free (rhs_str);
|
||||
|
||||
if (*argv && cmp >= 0)
|
||||
{
|
||||
++argv;
|
||||
if (cmp > 0 && *argv && *(argv + 1))
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (*argv)
|
||||
{
|
||||
char *expansion = expand_argument (*argv, NULL);
|
||||
|
||||
o = variable_buffer_output (o, expansion, strlen (expansion));
|
||||
|
||||
free (expansion);
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
$(if condition,true-part[,false-part])
|
||||
|
||||
@@ -1464,7 +1616,7 @@ static int shell_function_completed;
|
||||
void
|
||||
shell_completed (int exit_code, int exit_sig)
|
||||
{
|
||||
char buf[256];
|
||||
char buf[INTSTR_LENGTH];
|
||||
|
||||
shell_function_pid = 0;
|
||||
if (exit_sig == 0 && exit_code == 127)
|
||||
@@ -1530,7 +1682,7 @@ windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv,
|
||||
if (hIn == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ON (error, NILF,
|
||||
_("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e);
|
||||
_("windows32_openpipe: DuplicateHandle(In) failed (e=%lu)\n"), e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -1554,14 +1706,14 @@ windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv,
|
||||
if (hErr == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ON (error, NILF,
|
||||
_("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e);
|
||||
_("windows32_openpipe: DuplicateHandle(Err) failed (e=%lu)\n"), e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (! CreatePipe (&hChildOutRd, &hChildOutWr, &saAttr, 0))
|
||||
{
|
||||
ON (error, NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError());
|
||||
ON (error, NILF, _("CreatePipe() failed (e=%lu)\n"), GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1573,12 +1725,6 @@ windows32_openpipe (int *pipedes, int errfd, pid_t *pid_p, char **command_argv,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure that CreateProcess() has Path it needs */
|
||||
sync_Path_environment ();
|
||||
/* 'sync_Path_environment' may realloc 'environ', so take note of
|
||||
the new value. */
|
||||
envp = environ;
|
||||
|
||||
if (! process_begin (hProcess, command_argv, envp, command_argv[0], NULL))
|
||||
{
|
||||
/* register process for wait */
|
||||
@@ -1693,13 +1839,13 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
char *
|
||||
func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
{
|
||||
struct childbase child = {0};
|
||||
char *batch_filename = NULL;
|
||||
int errfd;
|
||||
#ifdef __MSDOS__
|
||||
FILE *fpipe;
|
||||
#endif
|
||||
char **command_argv = NULL;
|
||||
char **envp;
|
||||
int pipedes[2];
|
||||
pid_t pid;
|
||||
|
||||
@@ -1724,26 +1870,14 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
}
|
||||
#endif /* !__MSDOS__ */
|
||||
|
||||
/* Using a target environment for 'shell' loses in cases like:
|
||||
export var = $(shell echo foobie)
|
||||
bad := $(var)
|
||||
because target_environment hits a loop trying to expand $(var) to put it
|
||||
in the environment. This is even more confusing when 'var' was not
|
||||
explicitly exported, but just appeared in the calling environment.
|
||||
|
||||
See Savannah bug #10593.
|
||||
|
||||
envp = target_environment (NULL);
|
||||
*/
|
||||
|
||||
envp = environ;
|
||||
|
||||
/* Set up the output in case the shell writes something. */
|
||||
output_start ();
|
||||
|
||||
errfd = (output_context && output_context->err >= 0
|
||||
? output_context->err : FD_STDERR);
|
||||
|
||||
child.environment = target_environment (NULL, 0);
|
||||
|
||||
#if defined(__MSDOS__)
|
||||
fpipe = msdos_openpipe (pipedes, &pid, argv[0]);
|
||||
if (pipedes[0] < 0)
|
||||
@@ -1754,7 +1888,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
}
|
||||
|
||||
#elif defined(WINDOWS32)
|
||||
windows32_openpipe (pipedes, errfd, &pid, command_argv, envp);
|
||||
windows32_openpipe (pipedes, errfd, &pid, command_argv, child.environment);
|
||||
/* Restore the value of just_print_flag. */
|
||||
just_print_flag = j_p_f;
|
||||
|
||||
@@ -1779,18 +1913,11 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
fd_noinherit (pipedes[1]);
|
||||
fd_noinherit (pipedes[0]);
|
||||
|
||||
{
|
||||
struct childbase child;
|
||||
child.cmd_name = NULL;
|
||||
child.output.syncout = 1;
|
||||
child.output.out = pipedes[1];
|
||||
child.output.err = errfd;
|
||||
child.environment = envp;
|
||||
child.output.syncout = 1;
|
||||
child.output.out = pipedes[1];
|
||||
child.output.err = errfd;
|
||||
|
||||
pid = child_execute_job (&child, 1, command_argv);
|
||||
|
||||
free (child.cmd_name);
|
||||
}
|
||||
pid = child_execute_job (&child, 1, command_argv);
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
@@ -1861,24 +1988,10 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
}
|
||||
shell_function_pid = 0;
|
||||
|
||||
/* shell_completed() will set shell_function_completed to 1 when the
|
||||
child dies normally, or to -1 if it dies with status 127, which is
|
||||
most likely an exec fail. */
|
||||
|
||||
if (shell_function_completed == -1)
|
||||
{
|
||||
/* This likely means that the execvp failed, so we should just
|
||||
write the error message in the pipe from the child. */
|
||||
fputs (buffer, stderr);
|
||||
fflush (stderr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The child finished normally. Replace all newlines in its output
|
||||
with spaces, and put that in the variable output buffer. */
|
||||
fold_newlines (buffer, &i, trim_newlines);
|
||||
o = variable_buffer_output (o, buffer, i);
|
||||
}
|
||||
/* Replace all newlines in the command's output with spaces, and put that
|
||||
in the variable output buffer. */
|
||||
fold_newlines (buffer, &i, trim_newlines);
|
||||
o = variable_buffer_output (o, buffer, i);
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
@@ -1891,6 +2004,8 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
free (command_argv);
|
||||
}
|
||||
|
||||
free_childbase (&child);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
@@ -1945,8 +2060,8 @@ func_shell_base (char *o, char **argv, int trim_newlines)
|
||||
{
|
||||
strcpy (ptr, *aptr);
|
||||
ptr += strlen (ptr) + 1;
|
||||
*ptr ++ = ' ';
|
||||
*ptr = 0;
|
||||
*(ptr++) = ' ';
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
ptr[-1] = '\n';
|
||||
@@ -2134,8 +2249,7 @@ abspath (const char *name, char *apath)
|
||||
if (dest + len >= apath_limit)
|
||||
return NULL;
|
||||
|
||||
dest = memcpy (dest, start, len);
|
||||
dest += len;
|
||||
dest = mempcpy (dest, start, len);
|
||||
*dest = '\0';
|
||||
}
|
||||
}
|
||||
@@ -2233,6 +2347,11 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
|
||||
if (fp == NULL)
|
||||
OSS (fatal, reading_file, _("open: %s: %s"), fn, strerror (errno));
|
||||
|
||||
/* We've changed the contents of a directory, possibly.
|
||||
Another option would be to look up the directory we changed and reset
|
||||
its counter to 0. */
|
||||
++command_count;
|
||||
|
||||
if (argv[1])
|
||||
{
|
||||
size_t l = strlen (argv[1]);
|
||||
@@ -2246,7 +2365,7 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
|
||||
}
|
||||
else if (fn[0] == '<')
|
||||
{
|
||||
char *preo = o;
|
||||
size_t n = 0;
|
||||
FILE *fp;
|
||||
|
||||
++fn;
|
||||
@@ -2270,8 +2389,10 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
|
||||
char buf[1024];
|
||||
size_t l = fread (buf, 1, sizeof (buf), fp);
|
||||
if (l > 0)
|
||||
o = variable_buffer_output (o, buf, l);
|
||||
|
||||
{
|
||||
o = variable_buffer_output (o, buf, l);
|
||||
n += l;
|
||||
}
|
||||
if (ferror (fp))
|
||||
if (errno != EINTR)
|
||||
OSS (fatal, reading_file, _("read: %s: %s"), fn, strerror (errno));
|
||||
@@ -2282,9 +2403,8 @@ func_file (char *o, char **argv, const char *funcname UNUSED)
|
||||
OSS (fatal, reading_file, _("close: %s: %s"), fn, strerror (errno));
|
||||
|
||||
/* Remove trailing newline. */
|
||||
if (o > preo && o[-1] == '\n')
|
||||
if (--o > preo && o[-1] == '\r')
|
||||
--o;
|
||||
if (n && o[-1] == '\n')
|
||||
o -= 1 + (n > 1 && o[-2] == '\r');
|
||||
}
|
||||
else
|
||||
OS (fatal, *expanding_var, _("file: invalid file operation: %s"), fn);
|
||||
@@ -2337,12 +2457,13 @@ func_abspath (char *o, char **argv, const char *funcname UNUSED)
|
||||
comma-separated values are treated as arguments.
|
||||
|
||||
EXPAND_ARGS means that all arguments should be expanded before invocation.
|
||||
Functions that do namespace tricks (foreach) don't automatically expand. */
|
||||
Functions that do namespace tricks (foreach, let) don't automatically
|
||||
expand. */
|
||||
|
||||
static char *func_call (char *o, char **argv, const char *funcname);
|
||||
|
||||
#define FT_ENTRY(_name, _min, _max, _exp, _func) \
|
||||
{ { (_func) }, STRING_SIZE_TUPLE(_name), (_min), (_max), (_exp), 0 }
|
||||
{ { (_func) }, STRING_SIZE_TUPLE(_name), (_min), (_max), (_exp), 0, 0 }
|
||||
|
||||
static struct function_table_entry function_table_init[] =
|
||||
{
|
||||
@@ -2373,10 +2494,12 @@ static struct function_table_entry function_table_init[] =
|
||||
FT_ENTRY ("words", 0, 1, 1, func_words),
|
||||
FT_ENTRY ("origin", 0, 1, 1, func_origin),
|
||||
FT_ENTRY ("foreach", 3, 3, 0, func_foreach),
|
||||
FT_ENTRY ("let", 3, 3, 0, func_let),
|
||||
FT_ENTRY ("call", 1, 0, 1, func_call),
|
||||
FT_ENTRY ("info", 0, 1, 1, func_error),
|
||||
FT_ENTRY ("error", 0, 1, 1, func_error),
|
||||
FT_ENTRY ("warning", 0, 1, 1, func_error),
|
||||
FT_ENTRY ("intcmp", 2, 5, 0, func_intcmp),
|
||||
FT_ENTRY ("if", 2, 3, 0, func_if),
|
||||
FT_ENTRY ("or", 1, 0, 0, func_or),
|
||||
FT_ENTRY ("and", 1, 0, 0, func_and),
|
||||
@@ -2416,6 +2539,9 @@ expand_builtin_function (char *o, int argc, char **argv,
|
||||
OS (fatal, *expanding_var,
|
||||
_("unimplemented on this platform: function '%s'"), entry_p->name);
|
||||
|
||||
if (entry_p->adds_command)
|
||||
++command_count;
|
||||
|
||||
if (!entry_p->alloc_fn)
|
||||
return entry_p->fptr.func_ptr (o, argv, entry_p->name);
|
||||
|
||||
@@ -2519,9 +2645,8 @@ handle_function (char **op, const char **stringp)
|
||||
char *p, *aend;
|
||||
|
||||
abeg = xmalloc (len+1);
|
||||
memcpy (abeg, beg, len);
|
||||
abeg[len] = '\0';
|
||||
aend = abeg + len;
|
||||
aend = mempcpy (abeg, beg, len);
|
||||
*aend = '\0';
|
||||
|
||||
for (p=abeg, nargs=0; p <= aend; ++argvp)
|
||||
{
|
||||
@@ -2614,7 +2739,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
|
||||
|
||||
for (i=0; *argv; ++i, ++argv)
|
||||
{
|
||||
char num[11];
|
||||
char num[INTSTR_LENGTH];
|
||||
|
||||
sprintf (num, "%d", i);
|
||||
define_variable (num, strlen (num), *argv, o_automatic, 0);
|
||||
@@ -2627,7 +2752,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
|
||||
|
||||
for (; i < max_args; ++i)
|
||||
{
|
||||
char num[11];
|
||||
char num[INTSTR_LENGTH];
|
||||
|
||||
sprintf (num, "%d", i);
|
||||
define_variable (num, strlen (num), "", o_automatic, 0);
|
||||
@@ -2683,6 +2808,8 @@ define_new_function (const floc *flocp, const char *name,
|
||||
ent->maximum_args = (unsigned char) max;
|
||||
ent->expand_args = ANY_SET(flags, GMK_FUNC_NOEXPAND) ? 0 : 1;
|
||||
ent->alloc_fn = 1;
|
||||
/* We don't know what this function will do. */
|
||||
ent->adds_command = 1;
|
||||
ent->fptr.alloc_func_ptr = func;
|
||||
|
||||
hash_insert (&function_table, ent);
|
||||
|
||||
@@ -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
|
||||
before changing it!
|
||||
|
||||
Copyright (C) 1987-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1987-2022 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@gnu.org.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Declarations for getopt.
|
||||
Copyright (C) 1989-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1989-2022 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@gnu.org.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* 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-2022 Free Software Foundation, Inc.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C Library.
|
||||
Bugs can be reported to bug-glibc@gnu.org.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Convenience header for conditional use of GNU <libintl.h>.
|
||||
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995-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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
;; Contents of the (gnu make) Guile module
|
||||
;; Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
;; Copyright (C) 2011-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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* External interfaces usable by dynamic objects loaded into GNU Make.
|
||||
--THIS API IS A "TECHNOLOGY PREVIEW" ONLY. IT IS NOT A STABLE INTERFACE--
|
||||
|
||||
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2013-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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* GNU Guile interface for GNU Make.
|
||||
Copyright (C) 2011-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2011-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
|
||||
|
||||
@@ -44,11 +44,11 @@ hash_init (struct hash_table *ht, unsigned long size,
|
||||
{
|
||||
ht->ht_size = round_up_2 (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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ hash_rehash (struct hash_table *ht)
|
||||
ht->ht_capacity = ht->ht_size - (ht->ht_size >> 4);
|
||||
}
|
||||
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++)
|
||||
{
|
||||
|
||||
@@ -56,9 +56,9 @@ struct hash_table
|
||||
typedef int (*qsort_cmp_t) __P((void const *, void const *));
|
||||
|
||||
void hash_init __P((struct hash_table *ht, unsigned long size,
|
||||
hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp));
|
||||
hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp));
|
||||
void hash_load __P((struct hash_table *ht, void *item_table,
|
||||
unsigned long cardinality, unsigned long size));
|
||||
unsigned long cardinality, unsigned long size));
|
||||
void **hash_find_slot __P((struct hash_table *ht, void const *key));
|
||||
void *hash_find_item __P((struct hash_table *ht, void const *key));
|
||||
void *hash_insert __P((struct hash_table *ht, const void *item));
|
||||
@@ -154,7 +154,7 @@ extern void *hash_deleted_item;
|
||||
#define ISTRING_HASH_1(KEY, RESULT) do { \
|
||||
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
|
||||
while (*++_key_) \
|
||||
(RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0xf)); \
|
||||
(RESULT) += (tolower (*_key_) << (_key_[1] & 0xf)); \
|
||||
} while (0)
|
||||
#define return_ISTRING_HASH_1(KEY) do { \
|
||||
unsigned long _result_ = 0; \
|
||||
@@ -165,7 +165,7 @@ extern void *hash_deleted_item;
|
||||
#define ISTRING_HASH_2(KEY, RESULT) do { \
|
||||
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
|
||||
while (*++_key_) \
|
||||
(RESULT) += ((isupper (*_key_) ? tolower (*_key_) : *_key_) << (_key_[1] & 0x7)); \
|
||||
(RESULT) += (tolower (*_key_) << (_key_[1] & 0x7)); \
|
||||
} while (0)
|
||||
#define return_ISTRING_HASH_2(KEY) do { \
|
||||
unsigned long _result_ = 0; \
|
||||
|
||||
340
src/implicit.c
340
src/implicit.c
@@ -1,5 +1,5 @@
|
||||
/* Implicit rule searching for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -22,9 +22,12 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "variable.h"
|
||||
#include "job.h" /* struct child, used inside commands.h */
|
||||
#include "commands.h" /* set_file_variables */
|
||||
#include "shuffle.h"
|
||||
#include <assert.h>
|
||||
|
||||
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
|
||||
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
|
||||
should come first. */
|
||||
|
||||
if (pattern_search (file, 0, depth, 0))
|
||||
if (pattern_search (file, 0, depth, 0, 0))
|
||||
return 1;
|
||||
|
||||
#ifndef NO_ARCHIVES
|
||||
@@ -52,8 +55,11 @@ try_implicit_rule (struct file *file, unsigned int depth)
|
||||
{
|
||||
DBF (DB_IMPLICIT,
|
||||
_("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;
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("No archive-member implicit rule found for '%s'.\n"),
|
||||
file->name));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -153,6 +159,8 @@ struct patdeps
|
||||
struct file *file;
|
||||
unsigned int ignore_mtime : 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
|
||||
@@ -200,7 +208,8 @@ stemlen_compare (const void *v1, const void *v2)
|
||||
|
||||
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)
|
||||
{
|
||||
/* Filename we are searching for a rule for. */
|
||||
const char *filename = archive ? strchr (file->name, '(') : file->name;
|
||||
@@ -223,7 +232,9 @@ pattern_search (struct file *file, int archive,
|
||||
|
||||
/* Names of possible dependencies are constructed in this buffer.
|
||||
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);
|
||||
char *dend = depname + deplen;
|
||||
|
||||
/* The start and length of the stem of FILENAME for the current rule. */
|
||||
const char *stem = 0;
|
||||
@@ -251,6 +262,7 @@ pattern_search (struct file *file, int archive,
|
||||
int specific_rule_matched = 0;
|
||||
|
||||
unsigned int ri; /* uninit checks OK */
|
||||
int found_compat_rule = 0;
|
||||
struct rule *rule;
|
||||
|
||||
char *pathdir = NULL;
|
||||
@@ -308,7 +320,9 @@ pattern_search (struct file *file, int archive,
|
||||
don't use it here. */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -431,6 +445,8 @@ pattern_search (struct file *file, int archive,
|
||||
for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok)
|
||||
{
|
||||
pat = deplist;
|
||||
if (intermed_ok)
|
||||
DBS (DB_IMPLICIT, (_("Trying harder.\n")));
|
||||
|
||||
/* Try each pattern rule till we find one that applies. If it does,
|
||||
expand its dependencies (as substituted) and chain them in DEPS. */
|
||||
@@ -479,6 +495,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)
|
||||
{
|
||||
DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"),
|
||||
@@ -487,9 +507,6 @@ pattern_search (struct file *file, int archive,
|
||||
continue;
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"),
|
||||
(int) stemlen, stem));
|
||||
|
||||
if (!check_lastslash)
|
||||
{
|
||||
memcpy (stem_str, stem, stemlen);
|
||||
@@ -508,10 +525,6 @@ pattern_search (struct file *file, int archive,
|
||||
if (rule->deps == 0)
|
||||
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
|
||||
to use it. */
|
||||
rule->in_use = 1;
|
||||
@@ -526,7 +539,6 @@ pattern_search (struct file *file, int archive,
|
||||
while (1)
|
||||
{
|
||||
struct dep *dl, *d;
|
||||
char *p;
|
||||
|
||||
/* If we're out of name to parse, start the next prereq. */
|
||||
if (! nptr)
|
||||
@@ -540,32 +552,33 @@ pattern_search (struct file *file, int archive,
|
||||
/* If we don't need a second expansion, just replace the %. */
|
||||
if (! dep->need_2nd_expansion)
|
||||
{
|
||||
p = strchr (nptr, '%');
|
||||
if (p == 0)
|
||||
char *p;
|
||||
int is_explicit = 1;
|
||||
const char *cp = strchr (nptr, '%');
|
||||
if (cp == 0)
|
||||
strcpy (depname, nptr);
|
||||
else
|
||||
{
|
||||
char *o = depname;
|
||||
if (check_lastslash)
|
||||
{
|
||||
memcpy (o, filename, pathlen);
|
||||
o += pathlen;
|
||||
}
|
||||
memcpy (o, nptr, p - nptr);
|
||||
o += p - nptr;
|
||||
memcpy (o, stem, stemlen);
|
||||
o += stemlen;
|
||||
strcpy (o, p + 1);
|
||||
o = mempcpy (o, filename, pathlen);
|
||||
o = mempcpy (o, nptr, cp - nptr);
|
||||
o = mempcpy (o, stem, stemlen);
|
||||
strcpy (o, cp + 1);
|
||||
is_explicit = 0;
|
||||
}
|
||||
|
||||
/* Parse the expanded string. It might have wildcards. */
|
||||
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)
|
||||
{
|
||||
++deps_found;
|
||||
d->ignore_mtime = dep->ignore_mtime;
|
||||
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. */
|
||||
@@ -585,17 +598,22 @@ pattern_search (struct file *file, int archive,
|
||||
{
|
||||
int add_dir = 0;
|
||||
size_t len;
|
||||
const char *end;
|
||||
struct dep **dptr;
|
||||
int is_explicit;
|
||||
const char *cp;
|
||||
char *p;
|
||||
|
||||
nptr = get_next_word (nptr, &len);
|
||||
if (nptr == 0)
|
||||
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] == '|')
|
||||
{
|
||||
order_only = 1;
|
||||
nptr += len;
|
||||
nptr = end;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -610,49 +628,76 @@ pattern_search (struct file *file, int archive,
|
||||
(since $* and $(*F) are simple variables) there won't be
|
||||
additional re-expansion of the stem. */
|
||||
|
||||
p = lindex (nptr, nptr + len, '%');
|
||||
if (p == 0)
|
||||
cp = lindex (nptr, end, '%');
|
||||
if (cp == 0)
|
||||
{
|
||||
memcpy (depname, nptr, len);
|
||||
depname[len] = '\0';
|
||||
is_explicit = 1;
|
||||
}
|
||||
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;
|
||||
memcpy (o, nptr, i);
|
||||
o += i;
|
||||
if (check_lastslash)
|
||||
|
||||
is_explicit = 0;
|
||||
for (;;)
|
||||
{
|
||||
add_dir = 1;
|
||||
memcpy (o, "$(*F)", 5);
|
||||
o += 5;
|
||||
size_t i = cp - nptr;
|
||||
assert (o + i < dend);
|
||||
o = mempcpy (o, nptr, i);
|
||||
if (check_lastslash)
|
||||
{
|
||||
add_dir = 1;
|
||||
assert (o + 5 < dend);
|
||||
o = mempcpy (o, "$(*F)", 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (o + 2 < dend);
|
||||
o = mempcpy (o, "$*", 2);
|
||||
}
|
||||
assert (o < dend);
|
||||
++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;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (o, "$*", 2);
|
||||
o += 2;
|
||||
}
|
||||
memcpy (o, p + 1, len - i - 1);
|
||||
o[len - i - 1] = '\0';
|
||||
len = end - nptr;
|
||||
memcpy (o, nptr, len);
|
||||
o[len] = '\0';
|
||||
}
|
||||
|
||||
/* Set up for the next word. */
|
||||
nptr += len;
|
||||
nptr = end;
|
||||
|
||||
/* Initialize and set file variables if we haven't already
|
||||
done so. */
|
||||
if (!file_vars_initialized)
|
||||
{
|
||||
initialize_file_variables (file, 0);
|
||||
set_file_variables (file);
|
||||
set_file_variables (file, stem_str);
|
||||
file_vars_initialized = 1;
|
||||
}
|
||||
/* Update the stem value in $* for this rule. */
|
||||
else if (!file_variables_set)
|
||||
{
|
||||
define_variable_for_file (
|
||||
"*", 1, file->stem, o_automatic, 0, file);
|
||||
"*", 1, stem_str, o_automatic, 0, file);
|
||||
file_variables_set = 1;
|
||||
}
|
||||
|
||||
@@ -666,7 +711,8 @@ pattern_search (struct file *file, int archive,
|
||||
/* Parse the expanded string. */
|
||||
struct dep *dp = PARSE_FILE_SEQ (&p, struct dep,
|
||||
order_only ? MAP_NUL : MAP_PIPE,
|
||||
add_dir ? pathdir : NULL, PARSEFS_NONE);
|
||||
add_dir ? pathdir : NULL,
|
||||
PARSEFS_WAIT);
|
||||
*dptr = dp;
|
||||
|
||||
for (d = dp; d != NULL; d = d->next)
|
||||
@@ -674,6 +720,7 @@ pattern_search (struct file *file, int archive,
|
||||
++deps_found;
|
||||
if (order_only)
|
||||
d->ignore_mtime = 1;
|
||||
d->is_explicit = is_explicit;
|
||||
dptr = &d->next;
|
||||
}
|
||||
|
||||
@@ -704,8 +751,10 @@ pattern_search (struct file *file, int archive,
|
||||
/* Go through the nameseq and handle each as a prereq name. */
|
||||
for (d = dl; d != 0; d = d->next)
|
||||
{
|
||||
struct dep *expl_d;
|
||||
struct file *df;
|
||||
int is_rule = d->name == dep_name (dep);
|
||||
int explicit = 0;
|
||||
struct dep *dp = 0;
|
||||
|
||||
if (file_impossible_p (d->name))
|
||||
{
|
||||
@@ -714,9 +763,11 @@ pattern_search (struct file *file, int archive,
|
||||
second pass either since we know that will fail. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(is_rule
|
||||
? _("Rejecting impossible rule prerequisite '%s'.\n")
|
||||
: _("Rejecting impossible implicit prerequisite '%s'.\n"),
|
||||
d->name));
|
||||
? _("Rejecting rule '%s' due to impossible rule"
|
||||
" prerequisite '%s'.\n")
|
||||
: _("Rejecting rule '%s' due to impossible implicit"
|
||||
" prerequisite '%s'.\n"),
|
||||
get_rule_defn (rule), d->name));
|
||||
tryrules[ri].rule = 0;
|
||||
|
||||
failed = 1;
|
||||
@@ -726,41 +777,86 @@ pattern_search (struct file *file, int archive,
|
||||
memset (pat, '\0', sizeof (struct patdeps));
|
||||
pat->ignore_mtime = d->ignore_mtime;
|
||||
pat->ignore_automatic_vars = d->ignore_automatic_vars;
|
||||
pat->wait_here = d->wait_here;
|
||||
pat->is_explicit = d->is_explicit;
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(is_rule
|
||||
? _("Trying rule prerequisite '%s'.\n")
|
||||
: _("Trying implicit prerequisite '%s'.\n"), d->name));
|
||||
|
||||
/* If this prereq is also explicitly mentioned for FILE,
|
||||
skip all tests below since it must be built no matter
|
||||
which implicit rule we choose. */
|
||||
df = lookup_file (d->name);
|
||||
|
||||
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next)
|
||||
if (streq (dep_name (expl_d), d->name))
|
||||
break;
|
||||
if (expl_d != 0)
|
||||
if (df && df->is_explicit)
|
||||
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;
|
||||
|
||||
/* If dp is set, this prerequisite is mentioned explicitly as
|
||||
a prerequisite of the current target. */
|
||||
|
||||
if (explicit || dp)
|
||||
{
|
||||
(pat++)->name = d->name;
|
||||
DBS (DB_IMPLICIT, (_("'%s' ought to exist.\n"), d->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The DEP->changed flag says that this dependency resides
|
||||
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))
|
||||
if (file_exists_p (d->name))
|
||||
{
|
||||
(pat++)->name = d->name;
|
||||
DBS (DB_IMPLICIT, (_("Found '%s'.\n"), d->name));
|
||||
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
|
||||
"lib/foo.c", and VPATH=src, searches for
|
||||
"src/lib/foo.c". */
|
||||
@@ -769,7 +865,7 @@ pattern_search (struct file *file, int archive,
|
||||
if (vname)
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite '%s' as VPATH '%s'\n"),
|
||||
(_("Found prerequisite '%s' as VPATH '%s'.\n"),
|
||||
d->name, vname));
|
||||
(pat++)->name = d->name;
|
||||
continue;
|
||||
@@ -777,13 +873,15 @@ pattern_search (struct file *file, int archive,
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (intermed_ok)
|
||||
{
|
||||
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));
|
||||
|
||||
if (int_file == 0)
|
||||
@@ -794,7 +892,8 @@ pattern_search (struct file *file, int archive,
|
||||
if (pattern_search (int_file,
|
||||
0,
|
||||
depth + 1,
|
||||
recursions + 1))
|
||||
recursions + 1,
|
||||
allow_compat_rules))
|
||||
{
|
||||
pat->pattern = int_file->name;
|
||||
int_file->name = d->name;
|
||||
@@ -811,11 +910,24 @@ pattern_search (struct file *file, int archive,
|
||||
free_variable_set (int_file->variables);
|
||||
if (int_file->pat_variables)
|
||||
free_variable_set (int_file->pat_variables);
|
||||
file_impossible (d->name);
|
||||
|
||||
/* Keep prerequisites explicitly mentioned on unrelated
|
||||
rules as "possible" to let compatibility search find
|
||||
such prerequisites. */
|
||||
if (df == 0)
|
||||
file_impossible (d->name);
|
||||
}
|
||||
|
||||
/* A dependency of this rule does not exist. Therefore, this
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@@ -827,10 +939,6 @@ pattern_search (struct file *file, int archive,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset the stem in FILE. */
|
||||
|
||||
file->stem = 0;
|
||||
|
||||
/* This rule is no longer 'in use' for recursive searches. */
|
||||
rule->in_use = 0;
|
||||
|
||||
@@ -882,24 +990,24 @@ pattern_search (struct file *file, int archive,
|
||||
struct file *imf = pat->file;
|
||||
struct file *f = lookup_file (imf->name);
|
||||
|
||||
/* We don't want to delete an intermediate file that happened
|
||||
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
|
||||
if (!f)
|
||||
f = enter_file (imf->name);
|
||||
|
||||
f->deps = imf->deps;
|
||||
f->cmds = imf->cmds;
|
||||
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_searched = imf->pat_searched;
|
||||
f->also_make = imf->also_make;
|
||||
f->is_target = 1;
|
||||
f->intermediate = 1;
|
||||
f->is_explicit |= imf->is_explicit || pat->is_explicit;
|
||||
f->notintermediate |= imf->notintermediate;
|
||||
f->intermediate |= !f->is_explicit && !f->notintermediate;
|
||||
f->tried_implicit = 1;
|
||||
|
||||
imf = lookup_file (pat->pattern);
|
||||
@@ -916,7 +1024,9 @@ pattern_search (struct file *file, int archive,
|
||||
|
||||
dep = alloc_dep ();
|
||||
dep->ignore_mtime = pat->ignore_mtime;
|
||||
dep->is_explicit = pat->is_explicit;
|
||||
dep->ignore_automatic_vars = pat->ignore_automatic_vars;
|
||||
dep->wait_here = pat->wait_here;
|
||||
s = strcache_add (pat->name);
|
||||
if (recursions)
|
||||
dep->name = s;
|
||||
@@ -942,8 +1052,14 @@ pattern_search (struct file *file, int archive,
|
||||
|
||||
dep->next = file->deps;
|
||||
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)
|
||||
{
|
||||
/* Always allocate new storage, since STEM might be on the stack for an
|
||||
@@ -965,11 +1081,16 @@ pattern_search (struct file *file, int archive,
|
||||
file->cmds = rule->cmds;
|
||||
file->is_target = 1;
|
||||
|
||||
/* Set precious flag. */
|
||||
/* Set precious and notintermediate flags. */
|
||||
{
|
||||
struct file *f = lookup_file (rule->targets[tryrules[foundrule].matches]);
|
||||
if (f && f->precious)
|
||||
file->precious = 1;
|
||||
if (f)
|
||||
{
|
||||
if (f->precious)
|
||||
file->precious = 1;
|
||||
if (f->notintermediate)
|
||||
file->notintermediate = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this rule builds other targets, too, put the others into FILE's
|
||||
@@ -985,11 +1106,9 @@ pattern_search (struct file *file, int archive,
|
||||
struct dep *new = alloc_dep ();
|
||||
|
||||
/* GKM FIMXE: handle '|' here too */
|
||||
memcpy (p, rule->targets[ri],
|
||||
rule->suffixes[ri] - rule->targets[ri] - 1);
|
||||
p += rule->suffixes[ri] - rule->targets[ri] - 1;
|
||||
memcpy (p, file->stem, fullstemlen);
|
||||
p += fullstemlen;
|
||||
p = mempcpy (p, rule->targets[ri],
|
||||
rule->suffixes[ri] - rule->targets[ri] - 1);
|
||||
p = mempcpy (p, file->stem, fullstemlen);
|
||||
memcpy (p, rule->suffixes[ri],
|
||||
rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1);
|
||||
new->name = strcache_add (nm);
|
||||
@@ -998,8 +1117,13 @@ pattern_search (struct file *file, int archive,
|
||||
|
||||
/* Set precious flag. */
|
||||
f = lookup_file (rule->targets[ri]);
|
||||
if (f && f->precious)
|
||||
new->file->precious = 1;
|
||||
if (f)
|
||||
{
|
||||
if (f->precious)
|
||||
new->file->precious = 1;
|
||||
if (f->notintermediate)
|
||||
new->file->notintermediate = 1;
|
||||
}
|
||||
|
||||
/* Set the is_target flag so that this file is not treated as
|
||||
intermediate by the pattern rule search algorithm and
|
||||
@@ -1013,5 +1137,21 @@ pattern_search (struct file *file, int archive,
|
||||
free (tryrules);
|
||||
free (deplist);
|
||||
|
||||
return rule != 0;
|
||||
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;
|
||||
}
|
||||
|
||||
229
src/job.c
229
src/job.c
@@ -1,5 +1,5 @@
|
||||
/* Job execution and handling for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -25,11 +25,13 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "commands.h"
|
||||
#include "variable.h"
|
||||
#include "os.h"
|
||||
#include "dep.h"
|
||||
#include "shuffle.h"
|
||||
|
||||
/* Default shell to use. */
|
||||
#ifdef WINDOWS32
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h> /* for strcasecmp, strncasecmp */
|
||||
# include <strings.h> /* for strcasecmp, strncasecmp */
|
||||
# endif
|
||||
# include <windows.h>
|
||||
|
||||
@@ -121,6 +123,10 @@ static void vmsWaitForChildren (int *);
|
||||
# include <process.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_FCNTL_H)
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT)
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
@@ -214,7 +220,7 @@ pid2str (pid_t pid)
|
||||
return pidstring;
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETLOADAVG
|
||||
#ifndef HAVE_DECL_GETLOADAVG
|
||||
int getloadavg (double loadavg[], int nelem);
|
||||
#endif
|
||||
|
||||
@@ -367,7 +373,7 @@ create_batch_file (char const *base, int unixy, int *fd)
|
||||
|
||||
*fd = -1;
|
||||
if (error_string == NULL)
|
||||
error_string = _("Cannot create a temporary file\n");
|
||||
error_string = _("Cannot create a temporary file");
|
||||
O (fatal, NILF, error_string);
|
||||
|
||||
/* not reached */
|
||||
@@ -504,7 +510,7 @@ block_sigs ()
|
||||
static void
|
||||
unblock_sigs ()
|
||||
{
|
||||
sigsetmask (siggetmask (0) & ~fatal_signal_mask)
|
||||
sigsetmask (siggetmask () & ~fatal_signal_mask);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -539,6 +545,7 @@ child_error (struct child *child,
|
||||
const struct file *f = child->file;
|
||||
const floc *flocp = &f->cmds->fileinfo;
|
||||
const char *nm;
|
||||
const char *smode;
|
||||
size_t l;
|
||||
|
||||
if (ignored && run_silent)
|
||||
@@ -564,18 +571,29 @@ child_error (struct child *child,
|
||||
|
||||
l = strlen (pre) + strlen (nm) + strlen (f->name) + strlen (post);
|
||||
|
||||
smode = shuffle_get_mode ();
|
||||
if (smode)
|
||||
{
|
||||
#define SHUFFLE_PREFIX " shuffle="
|
||||
char *a = alloca (CSTRLEN(SHUFFLE_PREFIX) + strlen (smode) + 1);
|
||||
sprintf (a, SHUFFLE_PREFIX "%s", smode);
|
||||
smode = a;
|
||||
l += strlen (smode);
|
||||
#undef SHUFFLE_PREFIX
|
||||
}
|
||||
|
||||
OUTPUT_SET (&child->output);
|
||||
|
||||
show_goal_error ();
|
||||
|
||||
if (exit_sig == 0)
|
||||
error (NILF, l + INTSTR_LENGTH,
|
||||
_("%s[%s: %s] Error %d%s"), pre, nm, f->name, exit_code, post);
|
||||
error (NILF, l + INTSTR_LENGTH, _("%s[%s: %s] Error %d%s%s"),
|
||||
pre, nm, f->name, exit_code, post, smode ? smode : "");
|
||||
else
|
||||
{
|
||||
const char *s = strsignal (exit_sig);
|
||||
error (NILF, l + strlen (s) + strlen (dump),
|
||||
"%s[%s: %s] %s%s%s", pre, nm, f->name, s, dump, post);
|
||||
error (NILF, l + strlen (s) + strlen (dump), "%s[%s: %s] %s%s%s%s",
|
||||
pre, nm, f->name, s, dump, post, smode ? smode : "");
|
||||
}
|
||||
|
||||
OUTPUT_UNSET ();
|
||||
@@ -595,7 +613,7 @@ child_error (struct child *child,
|
||||
|
||||
static unsigned int dead_children = 0;
|
||||
|
||||
RETSIGTYPE
|
||||
void
|
||||
child_handler (int sig UNUSED)
|
||||
{
|
||||
++dead_children;
|
||||
@@ -721,9 +739,6 @@ reap_children (int block, int err)
|
||||
else if (pid < 0)
|
||||
{
|
||||
/* A remote status command failed miserably. Punt. */
|
||||
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
|
||||
remote_status_lose:
|
||||
#endif
|
||||
pfatal_with_name ("remote_status");
|
||||
}
|
||||
else
|
||||
@@ -779,8 +794,9 @@ reap_children (int block, int err)
|
||||
/* Now try a blocking wait for a remote child. */
|
||||
pid = remote_status (&exit_code, &exit_sig, &coredump, 1);
|
||||
if (pid < 0)
|
||||
goto remote_status_lose;
|
||||
else if (pid == 0)
|
||||
pfatal_with_name ("remote_status");
|
||||
|
||||
if (pid == 0)
|
||||
/* No remote children either. Finally give up. */
|
||||
break;
|
||||
|
||||
@@ -876,6 +892,9 @@ reap_children (int block, int err)
|
||||
#endif /* WINDOWS32 */
|
||||
}
|
||||
|
||||
/* Some child finished: increment the command count. */
|
||||
++command_count;
|
||||
|
||||
/* Check if this is the child of the 'shell' function. */
|
||||
if (!remote && pid == shell_function_pid)
|
||||
{
|
||||
@@ -921,7 +940,7 @@ reap_children (int block, int err)
|
||||
to fork/exec but I don't want to bother with that. Just do the
|
||||
best we can. */
|
||||
|
||||
EINTRLOOP(r, stat(c->cmd_name, &st));
|
||||
EINTRLOOP(r, stat (c->cmd_name, &st));
|
||||
if (r < 0)
|
||||
e = strerror (errno);
|
||||
else if (S_ISDIR(st.st_mode) || !(st.st_mode & S_IXUSR))
|
||||
@@ -1007,12 +1026,10 @@ reap_children (int block, int err)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
/* If we're sync'ing per line, write the previous line's
|
||||
output before starting the next one. */
|
||||
if (output_sync == OUTPUT_SYNC_LINE)
|
||||
output_dump (&c->output);
|
||||
#endif
|
||||
/* Check again whether to start remotely.
|
||||
Whether or not we want to changes over time.
|
||||
Also, start_remote_job may need state set up
|
||||
@@ -1043,10 +1060,8 @@ reap_children (int block, int err)
|
||||
|
||||
/* When we get here, all the commands for c->file are finished. */
|
||||
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
/* Synchronize any remaining parallel output. */
|
||||
output_dump (&c->output);
|
||||
#endif
|
||||
|
||||
/* At this point c->file->update_status is success or failed. But
|
||||
c->file->command_state is still cs_running if all the commands
|
||||
@@ -1102,13 +1117,27 @@ reap_children (int block, int err)
|
||||
|
||||
/* Free the storage allocated for CHILD. */
|
||||
|
||||
void
|
||||
free_childbase (struct childbase *child)
|
||||
{
|
||||
if (child->environment != 0)
|
||||
{
|
||||
char **ep = child->environment;
|
||||
while (*ep != 0)
|
||||
free (*ep++);
|
||||
free (child->environment);
|
||||
}
|
||||
|
||||
free (child->cmd_name);
|
||||
}
|
||||
|
||||
static void
|
||||
free_child (struct child *child)
|
||||
{
|
||||
output_close (&child->output);
|
||||
|
||||
if (!jobserver_tokens)
|
||||
ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n",
|
||||
ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left",
|
||||
child, child->file->name);
|
||||
|
||||
/* If we're using the jobserver and this child is not the only outstanding
|
||||
@@ -1134,15 +1163,8 @@ free_child (struct child *child)
|
||||
free (child->command_lines);
|
||||
}
|
||||
|
||||
if (child->environment != 0)
|
||||
{
|
||||
char **ep = child->environment;
|
||||
while (*ep != 0)
|
||||
free (*ep++);
|
||||
free (child->environment);
|
||||
}
|
||||
free_childbase ((struct childbase*)child);
|
||||
|
||||
free (child->cmd_name);
|
||||
free (child);
|
||||
}
|
||||
|
||||
@@ -1332,15 +1354,13 @@ start_job_command (struct child *child)
|
||||
|
||||
OUTPUT_SET (&child->output);
|
||||
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
if (! child->output.syncout)
|
||||
/* We don't want to sync this command: to avoid misordered
|
||||
output ensure any already-synced content is written. */
|
||||
output_dump (&child->output);
|
||||
#endif
|
||||
|
||||
/* Print the command if appropriate. */
|
||||
if (just_print_flag || trace_flag
|
||||
if (just_print_flag || ISDB (DB_PRINT)
|
||||
|| (!(flags & COMMANDS_SILENT) && !run_silent))
|
||||
OS (message, 0, "%s", p);
|
||||
|
||||
@@ -1408,7 +1428,7 @@ start_job_command (struct child *child)
|
||||
#ifndef _AMIGA
|
||||
/* Set up the environment for the child. */
|
||||
if (child->environment == 0)
|
||||
child->environment = target_environment (child->file);
|
||||
child->environment = target_environment (child->file, child->recursive);
|
||||
#endif
|
||||
|
||||
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
|
||||
@@ -1538,8 +1558,8 @@ start_job_command (struct child *child)
|
||||
{
|
||||
HANDLE hPID;
|
||||
char* arg0;
|
||||
int outfd = FD_STDOUT;
|
||||
int errfd = FD_STDERR;
|
||||
int outfd = -1;
|
||||
int errfd = -1;
|
||||
|
||||
/* make UNC paths safe for CreateProcess -- backslash format */
|
||||
arg0 = argv[0];
|
||||
@@ -1551,7 +1571,6 @@ start_job_command (struct child *child)
|
||||
/* make sure CreateProcess() has Path it needs */
|
||||
sync_Path_environment ();
|
||||
|
||||
#ifndef NO_OUTPUT_SYNC
|
||||
/* Divert child output if output_sync in use. */
|
||||
if (child->output.syncout)
|
||||
{
|
||||
@@ -1560,9 +1579,7 @@ start_job_command (struct child *child)
|
||||
if (child->output.err >= 0)
|
||||
errfd = child->output.err;
|
||||
}
|
||||
#else
|
||||
outfd = errfd = -1;
|
||||
#endif
|
||||
|
||||
hPID = process_easy (argv, child->environment, outfd, errfd);
|
||||
|
||||
if (hPID != INVALID_HANDLE_VALUE)
|
||||
@@ -1864,7 +1881,7 @@ new_job (struct file *file)
|
||||
/* There must be at least one child already, or we have no business
|
||||
waiting for a token. */
|
||||
if (!children)
|
||||
O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n");
|
||||
O (fatal, NILF, "INTERNAL: no children as we go to sleep on read");
|
||||
|
||||
/* Get a token. */
|
||||
got_token = jobserver_acquire (waiting_jobs != NULL);
|
||||
@@ -1883,7 +1900,7 @@ new_job (struct file *file)
|
||||
|
||||
/* Trace the build.
|
||||
Use message here so that changes to working directories are logged. */
|
||||
if (trace_flag)
|
||||
if (ISDB (DB_WHY))
|
||||
{
|
||||
char *newer = allocated_variable_expand_for_file ("$?", c->file);
|
||||
const char *nm;
|
||||
@@ -1897,12 +1914,9 @@ new_job (struct file *file)
|
||||
nm = n;
|
||||
}
|
||||
|
||||
if (newer[0] == '\0')
|
||||
OSS (message, 0,
|
||||
_("%s: target '%s' does not exist"), nm, c->file->name);
|
||||
else
|
||||
OSSS (message, 0,
|
||||
_("%s: update target '%s' due to: %s"), nm, c->file->name, newer);
|
||||
OSSS (message, 0,
|
||||
_("%s: update target '%s' due to: %s"), nm, c->file->name,
|
||||
newer[0] == '\0' ? _("target does not exist") : newer);
|
||||
|
||||
free (newer);
|
||||
}
|
||||
@@ -1950,12 +1964,13 @@ job_next_command (struct child *child)
|
||||
|
||||
On systems which provide /proc/loadavg (e.g., Linux), we use an idea
|
||||
provided by Sven C. Dack <sven.c.dack@sky.com>: retrieve the current number
|
||||
of processes the kernel is running and, if it's greater than the requested
|
||||
load we don't allow another job to start. We allow a job to start with
|
||||
equal processes since one of those will be for make itself, which will then
|
||||
pause waiting for jobs to clear.
|
||||
of runnable processes, if it's greater than the requested load we don't
|
||||
allow another job to start. We allow a job to start with equal processes
|
||||
since one of those will be for make itself, which will then pause waiting
|
||||
for jobs to clear.
|
||||
|
||||
Otherwise, we obtain the system load average and compare that.
|
||||
If /proc/loadavg is not available for some reason, we obtain the system
|
||||
load average and compare that.
|
||||
|
||||
The system load average is only recomputed once every N (N>=1) seconds.
|
||||
However, a very parallel make can easily start tens or even hundreds of
|
||||
@@ -2008,17 +2023,7 @@ load_too_high (void)
|
||||
#else
|
||||
static double last_sec;
|
||||
static time_t last_now;
|
||||
|
||||
/* This is disabled by default for now, because it will behave badly if the
|
||||
user gives a value > the number of cores; in that situation the load will
|
||||
never be exceeded, this function always returns false, and we'll start
|
||||
all the jobs. Also, it's not quite right to limit jobs to the number of
|
||||
cores not busy since a job takes some time to start etc. Maybe that's
|
||||
OK, I'm not sure exactly how to handle that, but for sure we need to
|
||||
clamp this value at the number of cores before this can be enabled.
|
||||
*/
|
||||
#define PROC_FD_INIT -1
|
||||
static int proc_fd = PROC_FD_INIT;
|
||||
static int proc_fd = -2;
|
||||
|
||||
double load, guess;
|
||||
time_t now;
|
||||
@@ -2076,8 +2081,8 @@ load_too_high (void)
|
||||
|
||||
if (p && ISDIGIT(p[1]))
|
||||
{
|
||||
int cnt = atoi (p+1);
|
||||
DB (DB_JOBS, ("Running: system = %d / make = %u (max requested = %f)\n",
|
||||
unsigned int cnt = make_toui (p+1, NULL);
|
||||
DB (DB_JOBS, ("Running: system = %u / make = %u (max requested = %f)\n",
|
||||
cnt, job_slots_used, max_load_average));
|
||||
return (double)cnt > max_load_average;
|
||||
}
|
||||
@@ -2095,7 +2100,6 @@ load_too_high (void)
|
||||
}
|
||||
|
||||
/* Find the real system load average. */
|
||||
make_access ();
|
||||
if (getloadavg (&load, 1) != 1)
|
||||
{
|
||||
static int lossage = -1;
|
||||
@@ -2112,7 +2116,6 @@ load_too_high (void)
|
||||
lossage = errno;
|
||||
load = 0;
|
||||
}
|
||||
user_access ();
|
||||
|
||||
/* If we're in a new second zero the counter and correct the backlog
|
||||
value. Only keep the backlog for one extra second; after that it's 0. */
|
||||
@@ -2197,7 +2200,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
{
|
||||
save_fdin = dup (FD_STDIN);
|
||||
if (save_fdin < 0)
|
||||
O (fatal, NILF, _("no more file handles: could not duplicate stdin\n"));
|
||||
O (fatal, NILF, _("no more file handles: could not duplicate stdin"));
|
||||
fd_noinherit (save_fdin);
|
||||
|
||||
dup2 (fdin, FD_STDIN);
|
||||
@@ -2209,7 +2212,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
save_fdout = dup (FD_STDOUT);
|
||||
if (save_fdout < 0)
|
||||
O (fatal, NILF,
|
||||
_("no more file handles: could not duplicate stdout\n"));
|
||||
_("no more file handles: could not duplicate stdout"));
|
||||
fd_noinherit (save_fdout);
|
||||
|
||||
dup2 (fdout, FD_STDOUT);
|
||||
@@ -2223,7 +2226,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
save_fderr = dup (FD_STDERR);
|
||||
if (save_fderr < 0)
|
||||
O (fatal, NILF,
|
||||
_("no more file handles: could not duplicate stderr\n"));
|
||||
_("no more file handles: could not duplicate stderr"));
|
||||
fd_noinherit (save_fderr);
|
||||
}
|
||||
|
||||
@@ -2238,7 +2241,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
if (save_fdin >= 0)
|
||||
{
|
||||
if (dup2 (save_fdin, FD_STDIN) != FD_STDIN)
|
||||
O (fatal, NILF, _("Could not restore stdin\n"));
|
||||
O (fatal, NILF, _("Could not restore stdin"));
|
||||
else
|
||||
close (save_fdin);
|
||||
}
|
||||
@@ -2246,7 +2249,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
if (save_fdout >= 0)
|
||||
{
|
||||
if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT)
|
||||
O (fatal, NILF, _("Could not restore stdout\n"));
|
||||
O (fatal, NILF, _("Could not restore stdout"));
|
||||
else
|
||||
close (save_fdout);
|
||||
}
|
||||
@@ -2254,7 +2257,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
if (save_fderr >= 0)
|
||||
{
|
||||
if (dup2 (save_fderr, FD_STDERR) != FD_STDERR)
|
||||
O (fatal, NILF, _("Could not restore stderr\n"));
|
||||
O (fatal, NILF, _("Could not restore stderr"));
|
||||
else
|
||||
close (save_fderr);
|
||||
}
|
||||
@@ -2320,6 +2323,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
|
||||
/* Run the command. */
|
||||
exec_command (argv, child->environment);
|
||||
_exit (127);
|
||||
|
||||
#else /* USE_POSIX_SPAWN */
|
||||
|
||||
@@ -2361,8 +2365,8 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
if ((r = posix_spawn_file_actions_adddup2 (&fa, fderr, FD_STDERR)) != 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Be the user, permanently. */
|
||||
flags |= POSIX_SPAWN_RESETIDS;
|
||||
/* We can't use the POSIX_SPAWN_RESETIDS flag: when make is invoked under
|
||||
restrictive environments like unshare it will fail with EINVAL. */
|
||||
|
||||
/* Apply the spawn flags. */
|
||||
if ((r = posix_spawnattr_setflags (&attr, flags)) != 0)
|
||||
@@ -2381,7 +2385,19 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
cmd = (char *)find_in_given_path (argv[0], p, 0);
|
||||
/* execvp() will use a default PATH if none is set; emulate that. */
|
||||
if (p == NULL)
|
||||
{
|
||||
size_t l = confstr (_CS_PATH, NULL, 0);
|
||||
if (l)
|
||||
{
|
||||
char *dp = alloca (l);
|
||||
confstr (_CS_PATH, dp, l);
|
||||
p = dp;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = (char *)find_in_given_path (argv[0], p, NULL, 0);
|
||||
}
|
||||
|
||||
if (!cmd)
|
||||
@@ -2451,12 +2467,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
/* Replace the current process with one running the command in ARGV,
|
||||
with environment ENVP. This function does not return. */
|
||||
|
||||
/* EMX: This function returns the pid of the child process. */
|
||||
# ifdef __EMX__
|
||||
pid_t
|
||||
# else
|
||||
void
|
||||
# endif
|
||||
exec_command (char **argv, char **envp)
|
||||
{
|
||||
#ifdef VMS
|
||||
@@ -2523,17 +2534,12 @@ exec_command (char **argv, char **envp)
|
||||
}
|
||||
}
|
||||
|
||||
/* return child's exit code as our exit code */
|
||||
/* Use the child's exit code as our exit code */
|
||||
exit (exit_code);
|
||||
|
||||
#else /* !WINDOWS32 */
|
||||
|
||||
# ifdef __EMX__
|
||||
pid_t pid;
|
||||
# endif
|
||||
|
||||
/* Be the user, permanently. */
|
||||
child_access ();
|
||||
pid_t pid = -1;
|
||||
|
||||
# ifdef __EMX__
|
||||
/* Run the program. */
|
||||
@@ -2629,11 +2635,7 @@ exec_command (char **argv, char **envp)
|
||||
break;
|
||||
}
|
||||
|
||||
# ifdef __EMX__
|
||||
return pid;
|
||||
# else
|
||||
_exit (127);
|
||||
# endif
|
||||
#endif /* !WINDOWS32 */
|
||||
#endif /* !VMS */
|
||||
}
|
||||
@@ -2656,8 +2658,8 @@ void clean_tmp (void)
|
||||
avoid using a shell. This routine handles only ' quoting, and " quoting
|
||||
when no backslash, $ or ' characters are seen in the quotes. Starting
|
||||
quotes may be escaped with a backslash. If any of the characters in
|
||||
sh_chars is seen, or any of the builtin commands listed in sh_cmds
|
||||
is the first word of a line, the shell is used.
|
||||
sh_chars is seen, or any of the builtin commands listed in sh_cmds is the
|
||||
first word of a line, the shell is used.
|
||||
|
||||
If RESTP is not NULL, *RESTP is set to point to the first newline in LINE.
|
||||
If *RESTP is NULL, newlines will be ignored.
|
||||
@@ -2665,10 +2667,14 @@ void clean_tmp (void)
|
||||
SHELL is the shell to use, or nil to use the default shell.
|
||||
IFS is the value of $IFS, or nil (meaning the default).
|
||||
|
||||
FLAGS is the value of lines_flags for this command line. It is
|
||||
used in the WINDOWS32 port to check whether + or $(MAKE) were found
|
||||
in this command line, in which case the effect of just_print_flag
|
||||
is overridden. */
|
||||
FLAGS is the value of lines_flags for this command line. It is used in the
|
||||
WINDOWS32 port to check whether + or $(MAKE) were found in this command
|
||||
line, in which case the effect of just_print_flag is overridden.
|
||||
|
||||
The returned value is either NULL if the line was empty, or else a pointer
|
||||
to an array of strings. The fist pointer points to the memory used by all
|
||||
the strings, so to free you free the 0'th element then the returned pointer
|
||||
(see the FREE_ARGV macro). */
|
||||
|
||||
static char **
|
||||
construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
@@ -2754,7 +2760,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
/* We used to have a double quote (") in sh_chars_dos[] below, but
|
||||
that caused any command line with quoted file names be run
|
||||
through a temporary batch file, which introduces command-line
|
||||
limit of 4K charcaters imposed by cmd.exe. Since CreateProcess
|
||||
limit of 4K characters imposed by cmd.exe. Since CreateProcess
|
||||
can handle quoted file names just fine, removing the quote lifts
|
||||
the limit from a very frequent use case, because using quoted
|
||||
file names is commonplace on MS-Windows. */
|
||||
@@ -3368,11 +3374,16 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
new_argv[n++] = xstrdup ("");
|
||||
else
|
||||
{
|
||||
const char *s = shellflags;
|
||||
char *t;
|
||||
size_t len;
|
||||
while ((t = find_next_token (&s, &len)) != 0)
|
||||
new_argv[n++] = xstrndup (t, len);
|
||||
/* Parse shellflags using construct_command_argv_internal to
|
||||
handle quotes. */
|
||||
char **argv;
|
||||
char *f;
|
||||
f = alloca (sflags_len + 1); // +1 for null terminator.
|
||||
memcpy (f, shellflags, sflags_len + 1);
|
||||
argv = construct_command_argv_internal (f, 0, 0, 0, 0, flags, 0);
|
||||
for (char **a = argv; a && *a; ++a)
|
||||
new_argv[n++] = *a;
|
||||
free (argv);
|
||||
}
|
||||
|
||||
/* Set the command to invoke. */
|
||||
@@ -3397,9 +3408,10 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
}
|
||||
*(ap++) = ' ';
|
||||
if (shellflags)
|
||||
memcpy (ap, shellflags, sflags_len);
|
||||
ap += sflags_len;
|
||||
*(ap++) = ' ';
|
||||
{
|
||||
ap = mempcpy (ap, shellflags, sflags_len);
|
||||
*(ap++) = ' ';
|
||||
}
|
||||
#ifdef WINDOWS32
|
||||
command_ptr = ap;
|
||||
#endif
|
||||
@@ -3444,8 +3456,7 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
else if (unixy_shell && strneq (p, "...", 3))
|
||||
{
|
||||
/* The case of '...' wildcard again. */
|
||||
strcpy (ap, "\\.\\.\\");
|
||||
ap += 5;
|
||||
ap = stpcpy (ap, "\\.\\.\\");
|
||||
p += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
11
src/job.h
11
src/job.h
@@ -1,5 +1,5 @@
|
||||
/* Definitions for managing subprocesses in GNU Make.
|
||||
Copyright (C) 1992-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1992-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
|
||||
@@ -29,7 +29,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#endif
|
||||
|
||||
#define CHILDBASE \
|
||||
char *cmd_name; /* Alloced copy of command run. */ \
|
||||
char *cmd_name; /* Allocated copy of command run. */ \
|
||||
char **environment; /* Environment for commands. */ \
|
||||
VMSCHILD \
|
||||
struct output output /* Output for this child. */
|
||||
@@ -68,11 +68,12 @@ struct child
|
||||
extern struct child *children;
|
||||
|
||||
/* 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);
|
||||
void new_job (struct file *file);
|
||||
void reap_children (int block, int err);
|
||||
void start_waiting_jobs (void);
|
||||
void free_childbase (struct childbase* child);
|
||||
|
||||
char **construct_command_argv (char *line, char **restp, struct file *file,
|
||||
int cmd_flags, char** batch_file);
|
||||
@@ -81,10 +82,8 @@ pid_t child_execute_job (struct childbase *child, int good_stdin, char **argv);
|
||||
|
||||
#ifdef _AMIGA
|
||||
void exec_command (char **argv) NORETURN;
|
||||
#elif defined(__EMX__)
|
||||
int exec_command (char **argv, char **envp);
|
||||
#else
|
||||
void exec_command (char **argv, char **envp) NORETURN;
|
||||
pid_t exec_command (char **argv, char **envp);
|
||||
#endif
|
||||
|
||||
void unblock_all_sigs (void);
|
||||
|
||||
89
src/load.c
89
src/load.c
@@ -1,5 +1,5 @@
|
||||
/* Loading dynamic objects for GNU Make.
|
||||
Copyright (C) 2012-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2012-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
|
||||
@@ -84,12 +84,14 @@ load_object (const floc *flocp, int noerror, const char *ldname,
|
||||
{
|
||||
const char *err = dlerror ();
|
||||
if (noerror)
|
||||
DB (DB_BASIC, ("%s", err));
|
||||
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)
|
||||
@@ -119,19 +121,19 @@ load_object (const floc *flocp, int noerror, const char *ldname,
|
||||
}
|
||||
|
||||
int
|
||||
load_file (const floc *flocp, const char **ldname, int noerror)
|
||||
load_file (const floc *flocp, struct file *file, int noerror)
|
||||
{
|
||||
size_t nmlen = strlen (*ldname);
|
||||
const char *ldname = file->name;
|
||||
size_t nmlen = strlen (ldname);
|
||||
char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1);
|
||||
char *symname = NULL;
|
||||
char *loaded;
|
||||
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, '(');
|
||||
fp = strchr (ldname, '(');
|
||||
if (fp)
|
||||
{
|
||||
const char *ep;
|
||||
@@ -142,16 +144,16 @@ load_file (const floc *flocp, const char **ldname, int noerror)
|
||||
ep = strchr (fp+1, ')');
|
||||
if (ep && ep[1] == '\0')
|
||||
{
|
||||
size_t l = fp - *ldname;;
|
||||
size_t l = fp - ldname;
|
||||
|
||||
++fp;
|
||||
if (fp == ep)
|
||||
OS (fatal, flocp, _("Empty symbol name for load: %s"), *ldname);
|
||||
OS (fatal, flocp, _("Empty symbol name for load: %s"), ldname);
|
||||
|
||||
/* Make a copy of the ldname part. */
|
||||
memcpy (new, *ldname, l);
|
||||
memcpy (new, ldname, l);
|
||||
new[l] = '\0';
|
||||
*ldname = new;
|
||||
ldname = new;
|
||||
nmlen = l;
|
||||
|
||||
/* Make a copy of the symbol name part. */
|
||||
@@ -161,22 +163,22 @@ load_file (const floc *flocp, const char **ldname, int noerror)
|
||||
}
|
||||
}
|
||||
|
||||
/* Add this name to the string cache so it can be reused later. */
|
||||
*ldname = strcache_add (*ldname);
|
||||
/* Make sure this name is in the string cache. */
|
||||
ldname = file->name = strcache_add (ldname);
|
||||
|
||||
/* If this object has been loaded, we're done. */
|
||||
loaded = allocated_variable_expand ("$(.LOADED)");
|
||||
fp = strstr (loaded, *ldname);
|
||||
r = fp && (fp==loaded || fp[-1]==' ') && (fp[nmlen]=='\0' || fp[nmlen]==' ');
|
||||
if (r)
|
||||
goto exit;
|
||||
/* 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, '/');
|
||||
fp = strrchr (ldname, '/');
|
||||
#ifdef HAVE_DOS_PATHS
|
||||
if (fp)
|
||||
{
|
||||
@@ -186,82 +188,75 @@ load_file (const floc *flocp, const char **ldname, int noerror)
|
||||
fp = fp2;
|
||||
}
|
||||
else
|
||||
fp = strrchr (*ldname, '\\');
|
||||
fp = strrchr (ldname, '\\');
|
||||
/* The (improbable) case of d:foo. */
|
||||
if (fp && *fp && fp[1] == ':')
|
||||
fp++;
|
||||
#endif
|
||||
if (!fp)
|
||||
fp = *ldname;
|
||||
fp = ldname;
|
||||
else
|
||||
++fp;
|
||||
while (isalnum (*fp) || *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));
|
||||
DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, ldname));
|
||||
|
||||
/* Load it! */
|
||||
symp = load_object (flocp, noerror, *ldname, symname);
|
||||
symp = load_object (flocp, noerror, ldname, symname);
|
||||
if (! symp)
|
||||
return 0;
|
||||
|
||||
/* Invoke the symbol. */
|
||||
r = (*symp) (flocp);
|
||||
|
||||
/* If it succeeded, add the load file to the loaded variable. */
|
||||
if (r > 0)
|
||||
{
|
||||
size_t loadlen = strlen (loaded);
|
||||
char *newval = alloca (loadlen + strlen (*ldname) + 2);
|
||||
/* Don't add a space if it's empty. */
|
||||
if (loadlen)
|
||||
{
|
||||
memcpy (newval, loaded, loadlen);
|
||||
newval[loadlen++] = ' ';
|
||||
}
|
||||
strcpy (&newval[loadlen], *ldname);
|
||||
do_variable_definition (flocp, ".LOADED", newval, o_default, f_simple, 0);
|
||||
}
|
||||
/* 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);
|
||||
|
||||
exit:
|
||||
free (loaded);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
if (dlclose (d->dlp))
|
||||
DB (DB_VERBOSE, (_("Unloading shared object %s\n"), name));
|
||||
rc = dlclose (d->dlp);
|
||||
if (rc)
|
||||
perror_with_name ("dlclose: ", d->name);
|
||||
d->dlp = NULL;
|
||||
else
|
||||
d->dlp = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
load_file (const floc *flocp, const char **ldname UNUSED, int noerror)
|
||||
load_file (const floc *flocp, struct file *file UNUSED, int noerror)
|
||||
{
|
||||
if (! noerror)
|
||||
O (fatal, flocp,
|
||||
_("The 'load' operation is not supported on this platform."));
|
||||
_("The 'load' operation is not supported on this platform"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
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 */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* API for GNU Make dynamic objects.
|
||||
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2013-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
|
||||
|
||||
1354
src/main.c
1354
src/main.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/* Miscellaneous global declarations and portability cruft for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -41,6 +41,21 @@ char *alloca ();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Some versions of GCC (e.g., 10.x) set the warn_unused_result attribute on
|
||||
__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 */
|
||||
|
||||
#if defined (__has_builtin)
|
||||
# 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.
|
||||
Some asserts are compute-intensive. */
|
||||
#ifndef MAKE_MAINTAINER_MODE
|
||||
@@ -79,16 +94,10 @@ char *alloca ();
|
||||
unless <sys/timeb.h> has been included first. */
|
||||
# include <sys/timeb.h>
|
||||
#endif
|
||||
#if TIME_WITH_SYS_TIME
|
||||
#if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
@@ -115,7 +124,7 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
/* Some systems define _POSIX_VERSION but are not really POSIX.1. */
|
||||
#if (defined (butterfly) || defined (__arm) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386)))
|
||||
#if (defined (butterfly) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386)))
|
||||
# undef POSIX
|
||||
#endif
|
||||
|
||||
@@ -123,10 +132,6 @@ extern int errno;
|
||||
# define POSIX 1
|
||||
#endif
|
||||
|
||||
#ifndef RETSIGTYPE
|
||||
# define RETSIGTYPE void
|
||||
#endif
|
||||
|
||||
#ifndef sigmask
|
||||
# define sigmask(sig) (1 << ((sig) - 1))
|
||||
#endif
|
||||
@@ -388,11 +393,13 @@ extern int unixy_shell;
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
#endif /* WINDOWS32 */
|
||||
|
||||
/* ALL_SET() evaluates the second argument twice. */
|
||||
#define ANY_SET(_v,_m) (((_v)&(_m)) != 0)
|
||||
#define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m)))
|
||||
#define ALL_SET(_v,_m) (((_v)&(_m)) == (_m))
|
||||
|
||||
#define MAP_NUL 0x0001
|
||||
#define MAP_BLANK 0x0002
|
||||
#define MAP_BLANK 0x0002 /* space, TAB */
|
||||
#define MAP_NEWLINE 0x0004
|
||||
#define MAP_COMMENT 0x0008
|
||||
#define MAP_SEMI 0x0010
|
||||
@@ -446,10 +453,14 @@ extern int unixy_shell;
|
||||
|
||||
#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)
|
||||
/* True if C is whitespace including newlines. */
|
||||
#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 END_OF_TOKEN(s) while (! STOP_SET (*(s), MAP_SPACE|MAP_NUL)) ++(s)
|
||||
|
||||
/* 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)
|
||||
@@ -464,11 +475,15 @@ extern struct rlimit stack_limit;
|
||||
|
||||
#define NILF ((floc *)0)
|
||||
|
||||
/* Number of characters in a string constant. Does NOT include the \0 byte. */
|
||||
#define CSTRLEN(_s) (sizeof (_s)-1)
|
||||
#define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s)
|
||||
|
||||
/* The number of bytes needed to represent the largest integer as a string. */
|
||||
#define INTSTR_LENGTH CSTRLEN ("18446744073709551616")
|
||||
/* The number of bytes needed to represent the largest signed and unsigned
|
||||
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"
|
||||
#ifdef HAVE_TTYNAME
|
||||
@@ -479,6 +494,8 @@ extern struct rlimit stack_limit;
|
||||
|
||||
|
||||
|
||||
struct file;
|
||||
|
||||
/* Specify the location of elements read from makefiles. */
|
||||
typedef struct
|
||||
{
|
||||
@@ -512,10 +529,13 @@ void out_of_memory () NORETURN;
|
||||
#define ONS(_t,_a,_f,_n,_s) _t((_a), INTSTR_LENGTH + strlen (_s), \
|
||||
(_f), (_n), (_s))
|
||||
|
||||
void decode_env_switches (const char*, size_t line);
|
||||
void die (int) NORETURN;
|
||||
void pfatal_with_name (const char *) NORETURN;
|
||||
void perror_with_name (const char *, const char *);
|
||||
#define xstrlen(_s) ((_s)==NULL ? 0 : strlen (_s))
|
||||
unsigned int make_toui (const char*, const char**);
|
||||
pid_t make_pid ();
|
||||
void *xmalloc (size_t);
|
||||
void *xcalloc (size_t);
|
||||
void *xrealloc (void *, size_t);
|
||||
@@ -530,7 +550,9 @@ int alpha_compare (const void *, const void *);
|
||||
void print_spaces (unsigned int);
|
||||
char *find_percent (char *);
|
||||
const char *find_percent_cached (const char **);
|
||||
FILE *get_tmpfile (char **, const char *);
|
||||
char *get_tmppath ();
|
||||
int get_tmpfd (char **);
|
||||
FILE *get_tmpfile (char **);
|
||||
ssize_t writebuf (int, const void *, size_t);
|
||||
ssize_t readbuf (int, void *, size_t);
|
||||
|
||||
@@ -580,10 +602,6 @@ int gpath_search (const char *file, size_t len);
|
||||
|
||||
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);
|
||||
|
||||
void show_goal_error (void);
|
||||
@@ -600,8 +618,8 @@ int guile_gmake_setup (const floc *flocp);
|
||||
|
||||
/* Loadable object support. Sets to the strcached name of the loaded file. */
|
||||
typedef int (*load_func_t)(const floc *flocp);
|
||||
int load_file (const floc *flocp, const char **filename, int noerror);
|
||||
void unload_file (const char *name);
|
||||
int load_file (const floc *flocp, struct file *file, int noerror);
|
||||
int unload_file (const char *name);
|
||||
|
||||
/* Maintainer mode support */
|
||||
#ifdef MAKE_MAINTAINER_MODE
|
||||
@@ -616,7 +634,6 @@ void spin (const char* suffix);
|
||||
|
||||
#if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION) && !defined(WINDOWS32)
|
||||
|
||||
long int atol ();
|
||||
# ifndef VMS
|
||||
long int lseek ();
|
||||
# endif
|
||||
@@ -654,6 +671,16 @@ int strncasecmp (const char *s1, const char *s2, int n);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_MEMPCPY
|
||||
/* Create our own, in misc.c */
|
||||
void *mempcpy (void *dest, const void *src, size_t n);
|
||||
#endif
|
||||
|
||||
#if !HAVE_STPCPY
|
||||
/* Create our own, in misc.c */
|
||||
char *stpcpy (char *dest, const char *src);
|
||||
#endif
|
||||
|
||||
#define OUTPUT_SYNC_NONE 0
|
||||
#define OUTPUT_SYNC_LINE 1
|
||||
#define OUTPUT_SYNC_TARGET 2
|
||||
@@ -670,21 +697,28 @@ extern unsigned short stopchar_map[];
|
||||
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 env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
|
||||
extern int print_version_flag, print_directory_flag, check_symlink_flag;
|
||||
extern int warn_undefined_variables_flag, trace_flag, posix_pedantic;
|
||||
extern int print_version_flag, print_directory, check_symlink_flag;
|
||||
extern int warn_undefined_variables_flag, posix_pedantic;
|
||||
extern int not_parallel, second_expansion, clock_skew_detected;
|
||||
extern int rebuilding_makefiles, one_shell, output_sync, verify_flag;
|
||||
extern unsigned long command_count;
|
||||
|
||||
extern const char *default_shell;
|
||||
|
||||
/* can we run commands via 'sh -c xxx' or must we use batch files? */
|
||||
extern int batch_mode_shell;
|
||||
|
||||
#define GNUMAKEFLAGS_NAME "GNUMAKEFLAGS"
|
||||
#define MAKEFLAGS_NAME "MAKEFLAGS"
|
||||
|
||||
/* Resetting the command script introduction prefix character. */
|
||||
#define RECIPEPREFIX_NAME ".RECIPEPREFIX"
|
||||
#define RECIPEPREFIX_DEFAULT '\t'
|
||||
#define RECIPEPREFIX_NAME ".RECIPEPREFIX"
|
||||
#define RECIPEPREFIX_DEFAULT '\t'
|
||||
extern char cmd_prefix;
|
||||
|
||||
#define JOBSERVER_AUTH_OPT "jobserver-auth"
|
||||
|
||||
extern char *jobserver_auth;
|
||||
extern unsigned int job_slots;
|
||||
extern double max_load_average;
|
||||
|
||||
|
||||
612
src/misc.c
612
src/misc.c
@@ -1,5 +1,5 @@
|
||||
/* Miscellaneous generic support functions for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -17,6 +17,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "makeint.h"
|
||||
#include "filedef.h"
|
||||
#include "dep.h"
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* GNU make no longer supports pre-ANSI89 environments. */
|
||||
@@ -34,6 +35,25 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
# 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;
|
||||
}
|
||||
|
||||
/* Compare strings *S1 and *S2.
|
||||
Return negative if the first is less, positive if it is greater,
|
||||
zero if they are equal. */
|
||||
@@ -173,6 +193,16 @@ concat (unsigned int num, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#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. */
|
||||
|
||||
@@ -308,7 +338,8 @@ lindex (const char *s, const char *limit, int c)
|
||||
char *
|
||||
end_of_token (const char *s)
|
||||
{
|
||||
END_OF_TOKEN (s);
|
||||
while (! END_OF_TOKEN (*s))
|
||||
++s;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
@@ -475,54 +506,155 @@ umask (mode_t mask)
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE *
|
||||
get_tmpfile (char **name, const char *template)
|
||||
{
|
||||
FILE *file;
|
||||
#ifdef HAVE_FDOPEN
|
||||
int fd;
|
||||
#define MAKE_TMPDIR "MAKE_TMPDIR"
|
||||
#ifdef VMS
|
||||
# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
|
||||
# define DEFAULT_TMPDIR "/sys$scratch/"
|
||||
#else
|
||||
# define DEFAULT_TMPFILE "GmXXXXXX"
|
||||
# ifdef P_tmpdir
|
||||
# define DEFAULT_TMPDIR P_tmpdir
|
||||
# else
|
||||
# define DEFAULT_TMPDIR "/tmp"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static const char *
|
||||
get_tmpdir ()
|
||||
{
|
||||
static const char *tmpdir = NULL;
|
||||
|
||||
if (!tmpdir)
|
||||
{
|
||||
if (((tmpdir = getenv (MAKE_TMPDIR)) == NULL || *tmpdir == '\0')
|
||||
#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
|
||||
&& ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0')
|
||||
&& ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0')
|
||||
#endif
|
||||
&& ((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
|
||||
tmpdir = DEFAULT_TMPDIR;
|
||||
}
|
||||
|
||||
return tmpdir;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_tmptemplate ()
|
||||
{
|
||||
const char *tmpdir = get_tmpdir ();
|
||||
char *template;
|
||||
size_t len;
|
||||
|
||||
len = strlen (tmpdir);
|
||||
template = xmalloc (len + CSTRLEN (DEFAULT_TMPFILE) + 2);
|
||||
strcpy (template, tmpdir);
|
||||
|
||||
#ifdef HAVE_DOS_PATHS
|
||||
if (template[len - 1] != '/' && template[len - 1] != '\\')
|
||||
strcat (template, "/");
|
||||
#else
|
||||
# ifndef VMS
|
||||
if (template[len - 1] != '/')
|
||||
strcat (template, "/");
|
||||
# endif /* !VMS */
|
||||
#endif /* !HAVE_DOS_PATHS */
|
||||
|
||||
strcat (template, DEFAULT_TMPFILE);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
char *
|
||||
get_tmppath ()
|
||||
{
|
||||
char *path;
|
||||
|
||||
#ifdef HAVE_MKTEMP
|
||||
path = get_tmptemplate();
|
||||
if (*mktemp (path) == '\0')
|
||||
pfatal_with_name ("mktemp");
|
||||
#else
|
||||
path = xmalloc (L_tmpnam + 1);
|
||||
if (tmpnam (path) == NULL)
|
||||
pfatal_with_name ("tmpnam");
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
int
|
||||
get_tmpfd (char **name)
|
||||
{
|
||||
int fd = -1;
|
||||
char *tmpnm;
|
||||
mode_t mask;
|
||||
|
||||
/* If there's an os-specific way to get an anoymous temp file use it. */
|
||||
if (!name)
|
||||
{
|
||||
fd = os_anontmp ();
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Preserve the current umask, and set a restrictive one for temp files. */
|
||||
mode_t mask = umask (0077);
|
||||
mask = umask (0077);
|
||||
|
||||
#if defined(HAVE_MKSTEMP) || defined(HAVE_MKTEMP)
|
||||
# define TEMPLATE_LEN strlen (template)
|
||||
#else
|
||||
# define TEMPLATE_LEN L_tmpnam
|
||||
#endif
|
||||
*name = xmalloc (TEMPLATE_LEN + 1);
|
||||
strcpy (*name, template);
|
||||
#if defined(HAVE_MKSTEMP)
|
||||
tmpnm = get_tmptemplate ();
|
||||
|
||||
#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN)
|
||||
/* It's safest to use mkstemp(), if we can. */
|
||||
EINTRLOOP (fd, mkstemp (*name));
|
||||
if (fd == -1)
|
||||
file = NULL;
|
||||
else
|
||||
file = fdopen (fd, "w");
|
||||
EINTRLOOP (fd, mkstemp (tmpnm));
|
||||
#else
|
||||
# ifdef HAVE_MKTEMP
|
||||
(void) mktemp (*name);
|
||||
# else
|
||||
(void) tmpnam (*name);
|
||||
# endif
|
||||
tmpnm = get_tmppath ();
|
||||
|
||||
# ifdef HAVE_FDOPEN
|
||||
/* Can't use mkstemp(), but guard against a race condition. */
|
||||
EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
file = fdopen (fd, "w");
|
||||
# else
|
||||
/* Not secure, but what can we do? */
|
||||
file = fopen (*name, "w");
|
||||
# endif
|
||||
/* Can't use mkstemp(), but try to guard against a race condition. */
|
||||
EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600));
|
||||
#endif
|
||||
|
||||
umask (mask);
|
||||
|
||||
if (name)
|
||||
*name = tmpnm;
|
||||
else
|
||||
{
|
||||
unlink (tmpnm);
|
||||
free (tmpnm);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
FILE *
|
||||
get_tmpfile (char **name)
|
||||
{
|
||||
#if defined(HAVE_FDOPEN)
|
||||
int fd = get_tmpfd (name);
|
||||
|
||||
return fd < 0 ? NULL : fdopen (fd, "w");
|
||||
#else
|
||||
/* Preserve the current umask, and set a restrictive one for temp files. */
|
||||
mode_t mask = umask (0077);
|
||||
|
||||
char *tmpnm = get_tmppath ();
|
||||
|
||||
/* Not secure, but...? If name is NULL we could use tmpfile()... */
|
||||
FILE *file = fopen (tmpnm, "w");
|
||||
|
||||
umask (mask);
|
||||
|
||||
if (name)
|
||||
*name = tmpnm;
|
||||
else
|
||||
{
|
||||
unlink (tmpnm);
|
||||
free (tmpnm);
|
||||
}
|
||||
|
||||
return file;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -535,8 +667,8 @@ strcasecmp (const char *s1, const char *s2)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int c1 = (int) *(s1++);
|
||||
int c2 = (int) *(s2++);
|
||||
int c1 = (unsigned char) *(s1++);
|
||||
int c2 = (unsigned char) *(s2++);
|
||||
|
||||
if (isalpha (c1))
|
||||
c1 = tolower (c1);
|
||||
@@ -560,8 +692,8 @@ strncasecmp (const char *s1, const char *s2, int n)
|
||||
{
|
||||
while (n-- > 0)
|
||||
{
|
||||
int c1 = (int) *(s1++);
|
||||
int c2 = (int) *(s2++);
|
||||
int c1 = (unsigned char) *(s1++);
|
||||
int c2 = (unsigned char) *(s2++);
|
||||
|
||||
if (isalpha (c1))
|
||||
c1 = tolower (c1);
|
||||
@@ -578,254 +710,6 @@ strncasecmp (const char *s1, const char *s2, int n)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GETLOADAVG_PRIVILEGED
|
||||
|
||||
#ifdef POSIX
|
||||
|
||||
/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
|
||||
functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
|
||||
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. */
|
||||
|
||||
#ifndef HAVE_UNISTD_H
|
||||
extern int getuid (), getgid (), geteuid (), getegid ();
|
||||
extern int setuid (), setgid ();
|
||||
#ifdef HAVE_SETEUID
|
||||
extern int seteuid ();
|
||||
#else
|
||||
#ifdef HAVE_SETREUID
|
||||
extern int setreuid ();
|
||||
#endif /* Have setreuid. */
|
||||
#endif /* Have seteuid. */
|
||||
#ifdef HAVE_SETEGID
|
||||
extern int setegid ();
|
||||
#else
|
||||
#ifdef HAVE_SETREGID
|
||||
extern int setregid ();
|
||||
#endif /* Have setregid. */
|
||||
#endif /* Have setegid. */
|
||||
#endif /* No <unistd.h>. */
|
||||
|
||||
/* 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))
|
||||
return;
|
||||
|
||||
/* All the other debugging messages go to stdout,
|
||||
but we write this one to stderr because it might be
|
||||
run in a child fork whose stdout is piped. */
|
||||
|
||||
fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
|
||||
flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
|
||||
(unsigned long) getegid (), (unsigned long) getgid ());
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_access (void)
|
||||
{
|
||||
#ifndef VMS
|
||||
user_uid = getuid ();
|
||||
user_gid = getgid ();
|
||||
|
||||
make_uid = geteuid ();
|
||||
make_gid = getegid ();
|
||||
|
||||
/* Do these ever fail? */
|
||||
if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
|
||||
pfatal_with_name ("get{e}[gu]id");
|
||||
|
||||
log_access (_("Initialized access"));
|
||||
|
||||
current_access = make;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* GETLOADAVG_PRIVILEGED */
|
||||
|
||||
/* Give the process appropriate permissions for access to
|
||||
user data (i.e., to stat files, or to spawn a child process). */
|
||||
void
|
||||
user_access (void)
|
||||
{
|
||||
#ifdef GETLOADAVG_PRIVILEGED
|
||||
|
||||
if (!access_inited)
|
||||
init_access ();
|
||||
|
||||
if (current_access == user)
|
||||
return;
|
||||
|
||||
/* We are in "make access" mode. This means that the effective user and
|
||||
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
|
||||
|
||||
current_access = user;
|
||||
|
||||
log_access (_("User access"));
|
||||
|
||||
#endif /* GETLOADAVG_PRIVILEGED */
|
||||
}
|
||||
|
||||
/* Give the process appropriate permissions for access to
|
||||
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
|
||||
|
||||
#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
|
||||
unsigned int
|
||||
@@ -845,3 +729,153 @@ get_path_max (void)
|
||||
return value;
|
||||
}
|
||||
#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
|
||||
|
||||
132
src/os.h
132
src/os.h
@@ -1,5 +1,5 @@
|
||||
/* Declarations for operating system interfaces for GNU Make.
|
||||
Copyright (C) 2016-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2016-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
|
||||
@@ -15,33 +15,69 @@ You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://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)
|
||||
#else
|
||||
|
||||
/* Determine the state of stdin/stdout/stderr. */
|
||||
unsigned int check_io_state ();
|
||||
|
||||
/* 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);
|
||||
#endif
|
||||
|
||||
/* Return a file descriptor for a new anonymous temp file, or -1. */
|
||||
#if defined(WINDOWS32)
|
||||
int os_anontmp ();
|
||||
#else
|
||||
# define os_anontmp() (-1)
|
||||
#endif
|
||||
|
||||
/* This section provides OS-specific functions to support the jobserver. */
|
||||
|
||||
#ifdef MAKE_JOBSERVER
|
||||
|
||||
/* Returns 1 if the jobserver is enabled, else 0. */
|
||||
unsigned int jobserver_enabled (void);
|
||||
unsigned int jobserver_enabled ();
|
||||
|
||||
/* Called in the master instance to set up the jobserver initially. */
|
||||
unsigned int jobserver_setup (int job_slots);
|
||||
/* Called in the parent make to set up the jobserver initially. */
|
||||
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);
|
||||
|
||||
/* Returns an allocated buffer used to pass to child instances. */
|
||||
char *jobserver_get_auth (void);
|
||||
char *jobserver_get_auth ();
|
||||
|
||||
/* 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 ();
|
||||
|
||||
/* Clear this instance's jobserver configuration. */
|
||||
void jobserver_clear (void);
|
||||
void jobserver_clear ();
|
||||
|
||||
/* Recover all the jobserver tokens and return the number we got. */
|
||||
unsigned int jobserver_acquire_all (void);
|
||||
unsigned int jobserver_acquire_all ();
|
||||
|
||||
/* Release a jobserver token. If it fails and is_fatal is 1, fatal. */
|
||||
void jobserver_release (int is_fatal);
|
||||
|
||||
/* Notify the jobserver that a child exited. */
|
||||
void jobserver_signal (void);
|
||||
void jobserver_signal ();
|
||||
|
||||
/* Get ready to start a non-recursive child. */
|
||||
void jobserver_pre_child (int);
|
||||
@@ -50,7 +86,7 @@ void jobserver_pre_child (int);
|
||||
void jobserver_post_child (int);
|
||||
|
||||
/* Set up to acquire a new token. */
|
||||
void jobserver_pre_acquire (void);
|
||||
void jobserver_pre_acquire ();
|
||||
|
||||
/* Wait until we can acquire a jobserver token.
|
||||
TIMEOUT is 1 if we have other jobs waiting for the load to go down;
|
||||
@@ -61,33 +97,63 @@ unsigned int jobserver_acquire (int timeout);
|
||||
|
||||
#else
|
||||
|
||||
#define jobserver_enabled() (0)
|
||||
#define jobserver_setup(_slots) (0)
|
||||
#define jobserver_parse_auth(_auth) (0)
|
||||
#define jobserver_get_auth() (NULL)
|
||||
#define jobserver_clear() (void)(0)
|
||||
#define jobserver_release(_fatal) (void)(0)
|
||||
#define jobserver_acquire_all() (0)
|
||||
#define jobserver_signal() (void)(0)
|
||||
#define jobserver_pre_child(_r) (void)(0)
|
||||
#define jobserver_post_child(_r) (void)(0)
|
||||
#define jobserver_pre_acquire() (void)(0)
|
||||
#define jobserver_acquire(_tmout) (0)
|
||||
#define jobserver_enabled() (0)
|
||||
#define jobserver_setup(_slots, _style) (0)
|
||||
#define jobserver_parse_auth(_auth) (0)
|
||||
#define jobserver_get_auth() (NULL)
|
||||
#define jobserver_get_invalid_auth() (NULL)
|
||||
#define jobserver_clear() (void)(0)
|
||||
#define jobserver_release(_fatal) (void)(0)
|
||||
#define jobserver_acquire_all() (0)
|
||||
#define jobserver_signal() (void)(0)
|
||||
#define jobserver_pre_child(_r) (void)(0)
|
||||
#define jobserver_post_child(_r) (void)(0)
|
||||
#define jobserver_pre_acquire() (void)(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 ();
|
||||
|
||||
/* Called in the parent make to set up output sync initially. */
|
||||
void osync_setup ();
|
||||
|
||||
/* Returns an allocated buffer containing output sync info to pass to child
|
||||
instances, or NULL if not needed. */
|
||||
char *osync_get_mutex ();
|
||||
|
||||
/* 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. */
|
||||
void osync_clear ();
|
||||
|
||||
/* Acquire the output sync lock. This will wait until available.
|
||||
Returns 0 if there was an error getting the semaphore. */
|
||||
unsigned int osync_acquire ();
|
||||
|
||||
/* Release the output sync lock. */
|
||||
void osync_release ();
|
||||
|
||||
#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. */
|
||||
#if defined(VMS) || defined(WINDOWS32) || defined(_AMIGA) || defined(__MSDOS__)
|
||||
# define get_bad_stdin() (-1)
|
||||
#else
|
||||
int get_bad_stdin (void);
|
||||
#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);
|
||||
int get_bad_stdin ();
|
||||
#endif
|
||||
|
||||
228
src/output.c
228
src/output.c
@@ -1,5 +1,5 @@
|
||||
/* Output to stdout / stderr for GNU make
|
||||
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2013-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
|
||||
@@ -47,12 +47,6 @@ unsigned int stdio_traced = 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. */
|
||||
static void
|
||||
_outputs (struct output *out, int is_err, const char *msg)
|
||||
@@ -143,73 +137,10 @@ log_working_directory (int entering)
|
||||
|
||||
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
|
||||
|
||||
/* 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() */
|
||||
static void
|
||||
pump_from_tmp (int from, FILE *to)
|
||||
@@ -250,55 +181,13 @@ pump_from_tmp (int from, FILE *to)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Obtain the lock for writing output. */
|
||||
static void *
|
||||
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. */
|
||||
/* Returns a file descriptor to a temporary file, that will be automatically
|
||||
deleted on exit. */
|
||||
int
|
||||
output_tmpfd (void)
|
||||
{
|
||||
mode_t mask = umask (0077);
|
||||
int fd = -1;
|
||||
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);
|
||||
|
||||
int fd = get_tmpfd (NULL);
|
||||
fd_set_append (fd);
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -309,13 +198,16 @@ output_tmpfd (void)
|
||||
static void
|
||||
setup_tmpfile (struct output *out)
|
||||
{
|
||||
/* Is make's stdout going to the same place as stderr? */
|
||||
static int combined_output = -1;
|
||||
unsigned int io_state = check_io_state ();
|
||||
|
||||
if (combined_output < 0)
|
||||
combined_output = sync_init ();
|
||||
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 (STREAM_OK (stdout))
|
||||
if (ANY_SET (io_state, IO_STDOUT_OK))
|
||||
{
|
||||
int fd = output_tmpfd ();
|
||||
if (fd < 0)
|
||||
@@ -324,9 +216,9 @@ setup_tmpfile (struct output *out)
|
||||
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;
|
||||
else
|
||||
{
|
||||
@@ -344,6 +236,7 @@ setup_tmpfile (struct output *out)
|
||||
error:
|
||||
output_close (out);
|
||||
output_sync = OUTPUT_SYNC_NONE;
|
||||
osync_clear ();
|
||||
}
|
||||
|
||||
/* Synchronize the output of jobs in -j mode to keep the results of
|
||||
@@ -354,6 +247,8 @@ setup_tmpfile (struct output *out)
|
||||
void
|
||||
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 errfd_not_empty = FD_NOT_EMPTY (out->err);
|
||||
|
||||
@@ -364,10 +259,15 @@ output_dump (struct output *out)
|
||||
/* Try to acquire the semaphore. If it fails, dump the output
|
||||
unsynchronized; still better than silently discarding it.
|
||||
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. */
|
||||
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
|
||||
if (print_directory && output_sync != OUTPUT_SYNC_RECURSE)
|
||||
traced = log_working_directory (1);
|
||||
|
||||
if (outfd_not_empty)
|
||||
@@ -379,8 +279,7 @@ output_dump (struct output *out)
|
||||
log_working_directory (0);
|
||||
|
||||
/* Exit the critical section. */
|
||||
if (sem)
|
||||
release_semaphore (sem);
|
||||
osync_release ();
|
||||
|
||||
/* Truncate and reset the output, in case we use it again. */
|
||||
if (out->out != OUTPUT_NONE)
|
||||
@@ -400,53 +299,6 @@ output_dump (struct output *out)
|
||||
#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
|
||||
output_init (struct output *out)
|
||||
{
|
||||
@@ -457,28 +309,10 @@ output_init (struct output *out)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Configure this instance of make. Be sure stdout is line-buffered. */
|
||||
|
||||
#ifdef HAVE_SETVBUF
|
||||
# ifdef SETVBUF_REVERSED
|
||||
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
|
||||
/* Force stdout/stderr into append mode (if they are files) to ensure
|
||||
parallel jobs won't lose output due to overlapping writes. */
|
||||
fd_set_append (fileno (stdout));
|
||||
fd_set_append (fileno (stderr));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -517,7 +351,7 @@ output_start (void)
|
||||
/* If we're not syncing this output per-line or per-target, make sure we emit
|
||||
the "Entering..." message where appropriate. */
|
||||
if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
|
||||
if (! stdio_traced && print_directory_flag)
|
||||
if (! stdio_traced && print_directory)
|
||||
stdio_traced = log_working_directory (1);
|
||||
}
|
||||
|
||||
|
||||
56
src/output.h
56
src/output.h
@@ -1,5 +1,5 @@
|
||||
/* Output to stdout / stderr for GNU make
|
||||
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2013-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
|
||||
@@ -50,57 +50,9 @@ void output_start (void);
|
||||
/* Show a message on stdout or stderr. Will start the output if needed. */
|
||||
void outputs (int is_err, const char *msg);
|
||||
|
||||
#if defined(HAVE_FCNTL_H)
|
||||
# include <fcntl.h>
|
||||
#elif defined(HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#ifdef NO_OUTPUT_SYNC
|
||||
# define RECORD_SYNC_MUTEX(m) \
|
||||
O (error, NILF, \
|
||||
_("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build."));
|
||||
#if defined(NO_OUTPUT_SYNC)
|
||||
# define output_dump(_o) (void)(0)
|
||||
#else
|
||||
int output_tmpfd (void);
|
||||
/* Dump any child output content to stdout, and reset it. */
|
||||
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 /* !NO_OUTPUT_SYNC */
|
||||
#endif
|
||||
|
||||
385
src/posixos.c
385
src/posixos.c
@@ -1,5 +1,5 @@
|
||||
/* POSIX-based operating system interface for GNU Make.
|
||||
Copyright (C) 2016-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 2016-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
|
||||
@@ -20,10 +20,15 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#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 !defined(FD_OK)
|
||||
# define FD_OK(_f) 1
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PSELECT) && defined(HAVE_SYS_SELECT_H)
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
@@ -32,7 +37,41 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#include "job.h"
|
||||
#include "os.h"
|
||||
|
||||
#ifdef MAKE_JOBSERVER
|
||||
#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. */
|
||||
|
||||
@@ -47,8 +86,21 @@ static int job_rfd = -1;
|
||||
/* Token written to the pipe (could be any character...) */
|
||||
static char token = '+';
|
||||
|
||||
/* 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 (void)
|
||||
make_job_rfd ()
|
||||
{
|
||||
#ifdef HAVE_PSELECT
|
||||
/* Pretend we succeeded. */
|
||||
@@ -81,13 +133,57 @@ set_blocking (int fd, int blocking)
|
||||
}
|
||||
|
||||
unsigned int
|
||||
jobserver_setup (int slots)
|
||||
jobserver_setup (int slots, const char *style)
|
||||
{
|
||||
int r;
|
||||
|
||||
EINTRLOOP (r, pipe (job_fds));
|
||||
if (r < 0)
|
||||
pfatal_with_name (_("creating jobs pipe"));
|
||||
#if HAVE_MKFIFO
|
||||
if (style == NULL || strcmp (style, "fifo") == 0)
|
||||
{
|
||||
fifo_name = get_tmppath ();
|
||||
|
||||
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));
|
||||
|
||||
DB (DB_JOBS, (_("Jobserver setup (fifo %s)\n"), fifo_name));
|
||||
|
||||
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));
|
||||
if (r < 0)
|
||||
pfatal_with_name (_("creating jobs pipe"));
|
||||
|
||||
DB (DB_JOBS, (_("Jobserver setup (fds %d,%d)\n"),
|
||||
job_fds[0], job_fds[1]));
|
||||
|
||||
js_type = js_pipe;
|
||||
}
|
||||
|
||||
/* By default we don't send the job pipe FDs to our children.
|
||||
See jobserver_pre_child() and jobserver_post_child(). */
|
||||
@@ -113,31 +209,62 @@ jobserver_setup (int slots)
|
||||
unsigned int
|
||||
jobserver_parse_auth (const char *auth)
|
||||
{
|
||||
int rfd, wfd;
|
||||
|
||||
/* 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
|
||||
# define FD_OK(_f) (fcntl ((_f), F_GETFD) != -1)
|
||||
#else
|
||||
# define FD_OK(_f) 1
|
||||
#endif
|
||||
EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY));
|
||||
if (job_fds[0] < 0)
|
||||
OSS (fatal, NILF,
|
||||
_("Cannot open jobserver %s: %s"), fifo_name, strerror (errno));
|
||||
|
||||
/* Make sure our pipeline is valid, and (possibly) create a duplicate pipe,
|
||||
that will be closed in the SIGCHLD handler. If this fails with EBADF,
|
||||
the parent has closed the pipe on us because it didn't think we were a
|
||||
submake. If so, warn and default to -j1. */
|
||||
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));
|
||||
|
||||
if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0)
|
||||
js_type = js_fifo;
|
||||
}
|
||||
/* If not, it must be a simple pipe. */
|
||||
else if (sscanf (auth, "%d,%d", &rfd, &wfd) == 2)
|
||||
{
|
||||
DB (DB_JOBS, (_("Jobserver client (fds %d,%d)\n"), rfd, wfd));
|
||||
|
||||
/* The parent overrode our FDs because we aren't a recursive make. */
|
||||
if (rfd == -2 || wfd == -2)
|
||||
return 0;
|
||||
|
||||
/* Make sure our pipeline is valid. */
|
||||
if (!FD_OK (rfd) || !FD_OK (wfd))
|
||||
return 0;
|
||||
|
||||
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 pipeline"));
|
||||
pfatal_with_name ("jobserver readfd");
|
||||
|
||||
job_fds[0] = job_fds[1] = -1;
|
||||
jobserver_clear ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -145,25 +272,51 @@ jobserver_parse_auth (const char *auth)
|
||||
/* When using pselect() we want the read to be non-blocking. */
|
||||
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;
|
||||
}
|
||||
|
||||
char *
|
||||
jobserver_get_auth (void)
|
||||
jobserver_get_auth ()
|
||||
{
|
||||
char *auth = xmalloc ((INTSTR_LENGTH * 2) + 2);
|
||||
sprintf (auth, "%d,%d", job_fds[0], job_fds[1]);
|
||||
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]);
|
||||
}
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
jobserver_enabled (void)
|
||||
const char *
|
||||
jobserver_get_invalid_auth ()
|
||||
{
|
||||
return job_fds[0] >= 0;
|
||||
/* If we're using a named pipe we don't need to invalidate the jobserver. */
|
||||
if (js_type == js_fifo) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* It's not really great that we are assuming the command line option
|
||||
here but other alternatives are also gross. */
|
||||
return " --" JOBSERVER_AUTH_OPT "=-2,-2";
|
||||
}
|
||||
|
||||
unsigned int
|
||||
jobserver_enabled ()
|
||||
{
|
||||
return js_type != js_none;
|
||||
}
|
||||
|
||||
void
|
||||
jobserver_clear (void)
|
||||
jobserver_clear ()
|
||||
{
|
||||
if (job_fds[0] >= 0)
|
||||
close (job_fds[0]);
|
||||
@@ -173,6 +326,11 @@ jobserver_clear (void)
|
||||
close (job_rfd);
|
||||
|
||||
job_fds[0] = job_fds[1] = job_rfd = -1;
|
||||
|
||||
free (fifo_name);
|
||||
fifo_name = NULL;
|
||||
|
||||
js_type = js_none;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -189,8 +347,9 @@ jobserver_release (int is_fatal)
|
||||
}
|
||||
|
||||
unsigned int
|
||||
jobserver_acquire_all (void)
|
||||
jobserver_acquire_all ()
|
||||
{
|
||||
int r;
|
||||
unsigned int tokens = 0;
|
||||
|
||||
/* Use blocking reads to wait for all outstanding jobs. */
|
||||
@@ -203,19 +362,25 @@ jobserver_acquire_all (void)
|
||||
while (1)
|
||||
{
|
||||
char intake;
|
||||
int r;
|
||||
EINTRLOOP (r, read (job_fds[0], &intake, 1));
|
||||
if (r != 1)
|
||||
return tokens;
|
||||
break;
|
||||
++tokens;
|
||||
}
|
||||
|
||||
if (fifo_name)
|
||||
EINTRLOOP (r, unlink (fifo_name));
|
||||
|
||||
DB (DB_JOBS, ("Acquired all %u jobserver tokens.\n", tokens));
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/* Prepare the jobserver to start a child process. */
|
||||
void
|
||||
jobserver_pre_child (int recursive)
|
||||
{
|
||||
if (recursive && job_fds[0] >= 0)
|
||||
if (recursive && js_type == js_pipe)
|
||||
{
|
||||
fd_inherit (job_fds[0]);
|
||||
fd_inherit (job_fds[1]);
|
||||
@@ -226,7 +391,7 @@ jobserver_pre_child (int recursive)
|
||||
void
|
||||
jobserver_post_child (int recursive)
|
||||
{
|
||||
if (recursive && job_fds[0] >= 0)
|
||||
if (recursive && js_type == js_pipe)
|
||||
{
|
||||
fd_noinherit (job_fds[0]);
|
||||
fd_noinherit (job_fds[1]);
|
||||
@@ -234,7 +399,7 @@ jobserver_post_child (int recursive)
|
||||
}
|
||||
|
||||
void
|
||||
jobserver_signal (void)
|
||||
jobserver_signal ()
|
||||
{
|
||||
if (job_rfd >= 0)
|
||||
{
|
||||
@@ -244,7 +409,7 @@ jobserver_signal (void)
|
||||
}
|
||||
|
||||
void
|
||||
jobserver_pre_acquire (void)
|
||||
jobserver_pre_acquire ()
|
||||
{
|
||||
/* Make sure we have a dup'd FD. */
|
||||
if (job_rfd < 0 && job_fds[0] >= 0 && make_job_rfd () < 0)
|
||||
@@ -319,7 +484,7 @@ jobserver_acquire (int timeout)
|
||||
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...?? */
|
||||
return r > 0;
|
||||
}
|
||||
@@ -351,7 +516,7 @@ jobserver_acquire (int timeout)
|
||||
during the section mentioned above, the read(2) will be invoked with an
|
||||
invalid FD and will return immediately with EBADF. */
|
||||
|
||||
static RETSIGTYPE
|
||||
static void
|
||||
job_noop (int sig UNUSED)
|
||||
{
|
||||
}
|
||||
@@ -442,9 +607,122 @@ jobserver_acquire (int timeout)
|
||||
|
||||
#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_parent = 0;
|
||||
|
||||
unsigned int
|
||||
osync_enabled ()
|
||||
{
|
||||
return osync_handle >= 0;
|
||||
}
|
||||
|
||||
void
|
||||
osync_setup ()
|
||||
{
|
||||
osync_handle = get_tmpfd (&osync_tmpfile);
|
||||
if (osync_handle >= 0)
|
||||
sync_parent = 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;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
osync_clear ()
|
||||
{
|
||||
if (osync_handle)
|
||||
{
|
||||
close (osync_handle);
|
||||
osync_handle = -1;
|
||||
}
|
||||
|
||||
if (sync_parent && osync_tmpfile)
|
||||
{
|
||||
unlink (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;
|
||||
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;
|
||||
if (fcntl (osync_handle, F_SETLKW, &fl) == -1)
|
||||
perror ("fcntl()");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */
|
||||
int
|
||||
get_bad_stdin (void)
|
||||
get_bad_stdin ()
|
||||
{
|
||||
static int bad_stdin = -1;
|
||||
|
||||
@@ -501,12 +779,33 @@ void
|
||||
fd_noinherit (int fd)
|
||||
{
|
||||
int flags;
|
||||
EINTRLOOP(flags, fcntl(fd, F_GETFD));
|
||||
EINTRLOOP (flags, fcntl(fd, F_GETFD));
|
||||
if (flags >= 0)
|
||||
{
|
||||
int r;
|
||||
flags |= FD_CLOEXEC;
|
||||
EINTRLOOP(r, fcntl(fd, F_SETFD, flags));
|
||||
EINTRLOOP (r, fcntl(fd, F_SETFD, flags));
|
||||
}
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
608
src/read.c
608
src/read.c
@@ -1,5 +1,5 @@
|
||||
/* Reading and parsing of makefiles for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -63,9 +63,9 @@ struct vmodifiers
|
||||
unsigned int assign_v:1;
|
||||
unsigned int define_v:1;
|
||||
unsigned int undefine_v:1;
|
||||
unsigned int export_v:1;
|
||||
unsigned int override_v:1;
|
||||
unsigned int private_v:1;
|
||||
enum variable_export export_v ENUM_BITFIELD (2);
|
||||
};
|
||||
|
||||
/* Types of "words" that can be read in a makefile. */
|
||||
@@ -107,7 +107,9 @@ static const char *default_include_directories[] =
|
||||
This is defined as a placeholder. */
|
||||
# define INCLUDEDIR "."
|
||||
#endif
|
||||
#if defined(INCLUDEDIR)
|
||||
INCLUDEDIR,
|
||||
#endif
|
||||
#ifndef _AMIGA
|
||||
"/usr/gnu/include",
|
||||
"/usr/local/include",
|
||||
@@ -142,6 +144,8 @@ static void do_undefine (char *name, enum variable_origin origin,
|
||||
static struct variable *do_define (char *name, enum variable_origin origin,
|
||||
struct ebuffer *ebuf);
|
||||
static int conditional_line (char *line, size_t len, const floc *flocp);
|
||||
static void check_specials (struct nameseq *filep, int set_default);
|
||||
static void check_special_file (struct file *filep, const floc *flocp);
|
||||
static void record_files (struct nameseq *filenames, int are_also_makes,
|
||||
const char *pattern,
|
||||
const char *pattern_percent, char *depstr,
|
||||
@@ -161,9 +165,8 @@ static char *unescape_char (char *string, int c);
|
||||
|
||||
|
||||
/* Compare a word, both length and contents.
|
||||
P must point to the word to be tested, and WLEN must be the length.
|
||||
*/
|
||||
#define word1eq(s) (wlen == CSTRLEN (s) && strneq (s, p, CSTRLEN (s)))
|
||||
P must point to the word to be tested, and WLEN must be the length. */
|
||||
#define word1eq(s) (wlen == CSTRLEN (s) && memcmp (s, p, CSTRLEN (s)) == 0)
|
||||
|
||||
|
||||
/* Read in all the makefiles and return a chain of targets to rebuild. */
|
||||
@@ -263,10 +266,6 @@ read_all_makefiles (const char **makefiles)
|
||||
{
|
||||
/* No default makefile was found. Add the default makefiles to the
|
||||
'read_files' chain so they will be updated if possible. */
|
||||
struct goaldep *tail = read_files;
|
||||
/* Add them to the tail, after any MAKEFILES variable makefiles. */
|
||||
while (tail != 0 && tail->next != 0)
|
||||
tail = tail->next;
|
||||
for (p = default_makefiles; *p != 0; ++p)
|
||||
{
|
||||
struct goaldep *d = alloc_goaldep ();
|
||||
@@ -274,14 +273,9 @@ read_all_makefiles (const char **makefiles)
|
||||
/* Tell update_goal_chain to bail out as soon as this file is
|
||||
made, and main not to die if we can't make this file. */
|
||||
d->flags = RM_DONTCARE;
|
||||
if (tail == 0)
|
||||
read_files = d;
|
||||
else
|
||||
tail->next = d;
|
||||
tail = d;
|
||||
d->next = read_files;
|
||||
read_files = d;
|
||||
}
|
||||
if (tail != 0)
|
||||
tail->next = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,24 +370,28 @@ eval_makefile (const char *filename, unsigned short flags)
|
||||
}
|
||||
}
|
||||
|
||||
/* If the makefile wasn't found and it's either a makefile from
|
||||
the 'MAKEFILES' variable or an included makefile,
|
||||
search the included makefile search path for this makefile. */
|
||||
if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/')
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; include_directories[i] != 0; ++i)
|
||||
{
|
||||
const char *included = concat (3, include_directories[i],
|
||||
"/", filename);
|
||||
ebuf.fp = fopen (included, "r");
|
||||
if (ebuf.fp)
|
||||
{
|
||||
filename = included;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If the makefile wasn't found and it's either a makefile from the
|
||||
'MAKEFILES' variable or an included makefile, search the included
|
||||
makefile search path for this makefile. */
|
||||
if (ebuf.fp == NULL && deps->error == ENOENT && (flags & RM_INCLUDED)
|
||||
&& *filename != '/' && include_directories)
|
||||
for (const char **dir = include_directories; *dir != NULL; ++dir)
|
||||
{
|
||||
const char *included = concat (3, *dir, "/", filename);
|
||||
|
||||
ENULLLOOP(ebuf.fp, fopen (included, "r"));
|
||||
if (ebuf.fp)
|
||||
{
|
||||
filename = included;
|
||||
break;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
filename = included;
|
||||
deps->error = errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter the final name for this makefile as a goaldep. */
|
||||
filename = strcache_add (filename);
|
||||
@@ -418,6 +416,11 @@ eval_makefile (const char *filename, unsigned short flags)
|
||||
/* Success; clear errno. */
|
||||
deps->error = 0;
|
||||
|
||||
/* If we tried and failed to read the included file before but this
|
||||
time we succeeded, reset the last mtime. */
|
||||
if (deps->file->last_mtime == NONEXISTENT_MTIME)
|
||||
deps->file->last_mtime = 0;
|
||||
|
||||
/* Avoid leaking the makefile to children. */
|
||||
fd_noinherit (fileno (ebuf.fp));
|
||||
|
||||
@@ -440,7 +443,7 @@ eval_makefile (const char *filename, unsigned short flags)
|
||||
fclose (ebuf.fp);
|
||||
|
||||
free (ebuf.bufstart);
|
||||
alloca (0);
|
||||
free_alloca ();
|
||||
|
||||
errno = 0;
|
||||
return deps;
|
||||
@@ -482,7 +485,7 @@ eval_buffer (char *buffer, const floc *flocp)
|
||||
|
||||
reading_file = curfile;
|
||||
|
||||
alloca (0);
|
||||
free_alloca ();
|
||||
}
|
||||
|
||||
/* Check LINE to see if it's a variable assignment or undefine.
|
||||
@@ -497,7 +500,7 @@ eval_buffer (char *buffer, const floc *flocp)
|
||||
based on the modifiers found if any, plus V_ASSIGN is 1.
|
||||
*/
|
||||
static char *
|
||||
parse_var_assignment (const char *line, struct vmodifiers *vmod)
|
||||
parse_var_assignment (const char *line, int targvar, struct vmodifiers *vmod)
|
||||
{
|
||||
const char *p;
|
||||
memset (vmod, '\0', sizeof (*vmod));
|
||||
@@ -525,19 +528,21 @@ parse_var_assignment (const char *line, struct vmodifiers *vmod)
|
||||
wlen = p2 - p;
|
||||
|
||||
if (word1eq ("export"))
|
||||
vmod->export_v = 1;
|
||||
vmod->export_v = v_export;
|
||||
else if (word1eq ("unexport"))
|
||||
vmod->export_v = v_noexport;
|
||||
else if (word1eq ("override"))
|
||||
vmod->override_v = 1;
|
||||
else if (word1eq ("private"))
|
||||
vmod->private_v = 1;
|
||||
else if (word1eq ("define"))
|
||||
else if (!targvar && word1eq ("define"))
|
||||
{
|
||||
/* We can't have modifiers after 'define' */
|
||||
vmod->define_v = 1;
|
||||
p = next_token (p2);
|
||||
break;
|
||||
}
|
||||
else if (word1eq ("undefine"))
|
||||
else if (!targvar && word1eq ("undefine"))
|
||||
{
|
||||
/* We can't have modifiers after 'undefine' */
|
||||
vmod->undefine_v = 1;
|
||||
@@ -722,7 +727,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
|
||||
/* See if this is a variable assignment. We need to do this early, to
|
||||
allow variables with names like 'ifdef', 'export', 'private', etc. */
|
||||
p = parse_var_assignment (p, &vmod);
|
||||
p = parse_var_assignment (p, 0, &vmod);
|
||||
if (vmod.assign_v)
|
||||
{
|
||||
struct variable *v;
|
||||
@@ -751,8 +756,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
|
||||
assert (v != NULL);
|
||||
|
||||
if (vmod.export_v)
|
||||
v->export = v_export;
|
||||
if (vmod.export_v != v_default)
|
||||
v->export = vmod.export_v;
|
||||
if (vmod.private_v)
|
||||
v->private_var = 1;
|
||||
|
||||
@@ -906,9 +911,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
| (set_default ? 0 : RM_NO_DEFAULT_GOAL));
|
||||
|
||||
struct goaldep *d = eval_makefile (files->name, flags);
|
||||
|
||||
if (errno)
|
||||
d->floc = *fstart;
|
||||
d->floc = *fstart;
|
||||
|
||||
free_ns (files);
|
||||
files = next;
|
||||
@@ -952,28 +955,37 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
struct nameseq *next = files->next;
|
||||
const char *name = files->name;
|
||||
struct goaldep *deps;
|
||||
struct file *f;
|
||||
int r;
|
||||
|
||||
/* Load the file. 0 means failure. */
|
||||
r = load_file (&ebuf->floc, &name, noerror);
|
||||
if (! r && ! noerror)
|
||||
OS (fatal, &ebuf->floc, _("%s: failed to load"), name);
|
||||
{
|
||||
struct file file = {0};
|
||||
file.name = name;
|
||||
/* Load the file. 0 means failure. */
|
||||
r = load_file (&ebuf->floc, &file, noerror);
|
||||
if (! r && ! noerror)
|
||||
OS (fatal, &ebuf->floc, _("%s: failed to load"), name);
|
||||
name = file.name;
|
||||
}
|
||||
|
||||
f = lookup_file (name);
|
||||
if (!f)
|
||||
f = enter_file (name);
|
||||
f->loaded = 1;
|
||||
f->unloaded = 0;
|
||||
|
||||
free_ns (files);
|
||||
files = next;
|
||||
|
||||
/* Return of -1 means a special load: don't rebuild it. */
|
||||
/* Return of -1 means don't ever try to rebuild. */
|
||||
if (r == -1)
|
||||
continue;
|
||||
|
||||
/* It succeeded, so add it to the list "to be rebuilt". */
|
||||
/* Otherwise add it to the list to be rebuilt. */
|
||||
deps = alloc_goaldep ();
|
||||
deps->next = read_files;
|
||||
read_files = deps;
|
||||
deps->file = lookup_file (name);
|
||||
if (deps->file == 0)
|
||||
deps->file = enter_file (name);
|
||||
deps->file->loaded = 1;
|
||||
deps->file = f;
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -997,7 +1009,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
|
||||
{
|
||||
enum make_word_type wtype;
|
||||
char *cmdleft, *semip, *lb_next;
|
||||
char *cmdleft, *semip = 0, *lb_next;
|
||||
size_t plen = 0;
|
||||
char *colonp;
|
||||
const char *end, *beg; /* Helpers for whitespace stripping. */
|
||||
@@ -1017,9 +1029,11 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
cmdleft = 0;
|
||||
}
|
||||
else if (cmdleft != 0)
|
||||
/* Found one. Cut the line short there before expanding it. */
|
||||
*(cmdleft++) = '\0';
|
||||
semip = cmdleft;
|
||||
{
|
||||
/* Found one. Cut the line short there before expanding it. */
|
||||
semip = cmdleft++;
|
||||
*semip = '\0';
|
||||
}
|
||||
|
||||
collapse_continuations (line);
|
||||
|
||||
@@ -1182,7 +1196,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
p2 = variable_buffer + l;
|
||||
}
|
||||
|
||||
p2 = parse_var_assignment (p2, &vmod);
|
||||
p2 = parse_var_assignment (p2, 1, &vmod);
|
||||
if (vmod.assign_v)
|
||||
{
|
||||
/* If there was a semicolon found, add it back, plus anything
|
||||
@@ -1190,7 +1204,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
if (semip)
|
||||
{
|
||||
size_t l = p2 - variable_buffer;
|
||||
*(--semip) = ';';
|
||||
*semip = ';';
|
||||
collapse_continuations (semip);
|
||||
variable_buffer_output (p2 + strlen (p2),
|
||||
semip, strlen (semip)+1);
|
||||
@@ -1322,79 +1336,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
||||
commands[commands_idx++] = '\n';
|
||||
}
|
||||
|
||||
/* Determine if this target should be made default. We used to do
|
||||
this in record_files() but because of the delayed target recording
|
||||
and because preprocessor directives are legal in target's commands
|
||||
it is too late. Consider this fragment for example:
|
||||
|
||||
foo:
|
||||
|
||||
ifeq ($(.DEFAULT_GOAL),foo)
|
||||
...
|
||||
endif
|
||||
|
||||
Because the target is not recorded until after ifeq directive is
|
||||
evaluated the .DEFAULT_GOAL does not contain foo yet as one
|
||||
would expect. Because of this we have to move the logic here. */
|
||||
|
||||
if (set_default && default_goal_var->value[0] == '\0')
|
||||
{
|
||||
struct dep *d;
|
||||
struct nameseq *t = filenames;
|
||||
|
||||
for (; t != 0; t = t->next)
|
||||
{
|
||||
int reject = 0;
|
||||
const char *name = t->name;
|
||||
|
||||
/* We have nothing to do if this is an implicit rule. */
|
||||
if (strchr (name, '%') != 0)
|
||||
break;
|
||||
|
||||
/* See if this target's name does not start with a '.',
|
||||
unless it contains a slash. */
|
||||
if (*name == '.' && strchr (name, '/') == 0
|
||||
#ifdef HAVE_DOS_PATHS
|
||||
&& strchr (name, '\\') == 0
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
|
||||
/* If this file is a suffix, don't let it be
|
||||
the default goal file. */
|
||||
for (d = suffix_file->deps; d != 0; d = d->next)
|
||||
{
|
||||
struct dep *d2;
|
||||
if (*dep_name (d) != '.' && streq (name, dep_name (d)))
|
||||
{
|
||||
reject = 1;
|
||||
break;
|
||||
}
|
||||
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
|
||||
{
|
||||
size_t l = strlen (dep_name (d2));
|
||||
if (!strneq (name, dep_name (d2), l))
|
||||
continue;
|
||||
if (streq (name + l, dep_name (d)))
|
||||
{
|
||||
reject = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reject)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reject)
|
||||
{
|
||||
define_variable_global (".DEFAULT_GOAL", 13, t->name,
|
||||
o_file, 0, NILF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
check_specials (filenames, set_default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1912,7 +1854,8 @@ record_target_var (struct nameseq *filenames, char *defn,
|
||||
/* Set up the variable to be *-specific. */
|
||||
v->per_target = 1;
|
||||
v->private_var = vmod->private_v;
|
||||
v->export = vmod->export_v ? v_export : v_default;
|
||||
if (vmod->export_v != v_default)
|
||||
v->export = vmod->export_v;
|
||||
|
||||
/* If it's not an override, check to see if there was a command-line
|
||||
setting. If so, reset the value. */
|
||||
@@ -1935,6 +1878,131 @@ record_target_var (struct nameseq *filenames, char *defn,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check for special targets. We used to do this in record_files() but that's
|
||||
too late: by the time we get there we'll have already parsed the next line
|
||||
and it have been mis-parsed because these special targets haven't been
|
||||
considered yet. */
|
||||
|
||||
static void
|
||||
check_specials (struct nameseq *files, int set_default)
|
||||
{
|
||||
struct nameseq *t;
|
||||
|
||||
for (t = files; t != NULL; t = t->next)
|
||||
{
|
||||
const char* nm = t->name;
|
||||
|
||||
if (!posix_pedantic && streq (nm, ".POSIX"))
|
||||
{
|
||||
posix_pedantic = 1;
|
||||
define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
|
||||
/* These default values are based on IEEE Std 1003.1-2008.
|
||||
It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow
|
||||
space between -O and the number so omit it here. */
|
||||
define_variable_cname ("CC", "c99", o_default, 0);
|
||||
define_variable_cname ("CFLAGS", "-O1", o_default, 0);
|
||||
define_variable_cname ("FC", "fort77", o_default, 0);
|
||||
define_variable_cname ("FFLAGS", "-O1", o_default, 0);
|
||||
define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
|
||||
define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!second_expansion && streq (nm, ".SECONDEXPANSION"))
|
||||
{
|
||||
second_expansion = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if !defined (__MSDOS__) && !defined (__EMX__)
|
||||
if (!one_shell && streq (nm, ".ONESHELL"))
|
||||
{
|
||||
one_shell = 1;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine if this target should be made default. */
|
||||
|
||||
if (set_default && default_goal_var->value[0] == '\0')
|
||||
{
|
||||
struct dep *d;
|
||||
int reject = 0;
|
||||
|
||||
/* We have nothing to do if this is an implicit rule. */
|
||||
if (strchr (nm, '%') != 0)
|
||||
break;
|
||||
|
||||
/* See if this target's name does not start with a '.',
|
||||
unless it contains a slash. */
|
||||
if (*nm == '.' && strchr (nm, '/') == 0
|
||||
#ifdef HAVE_DOS_PATHS
|
||||
&& strchr (nm, '\\') == 0
|
||||
#endif
|
||||
)
|
||||
continue;
|
||||
|
||||
/* If this file is a suffix, it can't be the default goal file. */
|
||||
for (d = suffix_file->deps; d != 0; d = d->next)
|
||||
{
|
||||
struct dep *d2;
|
||||
if (*dep_name (d) != '.' && streq (nm, dep_name (d)))
|
||||
{
|
||||
reject = 1;
|
||||
break;
|
||||
}
|
||||
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
|
||||
{
|
||||
size_t l = strlen (dep_name (d2));
|
||||
if (!strneq (nm, dep_name (d2), l))
|
||||
continue;
|
||||
if (streq (nm + l, dep_name (d)))
|
||||
{
|
||||
reject = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reject)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!reject)
|
||||
define_variable_global (".DEFAULT_GOAL", 13, t->name,
|
||||
o_file, 0, NILF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for special targets. We used to do this in record_files() but that's
|
||||
too late: by the time we get there we'll have already parsed the next line
|
||||
and it have been mis-parsed because these special targets haven't been
|
||||
considered yet. */
|
||||
|
||||
static void
|
||||
check_special_file (struct file *file, const floc *flocp)
|
||||
{
|
||||
if (streq (file->name, ".WAIT"))
|
||||
{
|
||||
static unsigned int wpre = 0, wcmd = 0;
|
||||
|
||||
if (!wpre && file->deps)
|
||||
{
|
||||
O (error, flocp, _(".WAIT should not have prerequisites"));
|
||||
wpre = 1;
|
||||
}
|
||||
|
||||
if (!wcmd && file->cmds)
|
||||
{
|
||||
O (error, flocp, _(".WAIT should not have commands"));
|
||||
wcmd = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record a description line for files FILENAMES,
|
||||
with dependencies DEPS, commands to execute described
|
||||
by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED.
|
||||
@@ -2076,29 +2144,6 @@ record_files (struct nameseq *filenames, int are_also_makes,
|
||||
|
||||
free_ns (filenames);
|
||||
|
||||
/* Check for special targets. Do it here instead of, say, snap_deps()
|
||||
so that we can immediately use the value. */
|
||||
if (!posix_pedantic && streq (name, ".POSIX"))
|
||||
{
|
||||
posix_pedantic = 1;
|
||||
define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
|
||||
/* These default values are based on IEEE Std 1003.1-2008.
|
||||
It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow space
|
||||
between -O and the number so omit it here. */
|
||||
define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
|
||||
define_variable_cname ("CC", "c99", o_default, 0);
|
||||
define_variable_cname ("CFLAGS", "-O1", o_default, 0);
|
||||
define_variable_cname ("FC", "fort77", o_default, 0);
|
||||
define_variable_cname ("FFLAGS", "-O1", o_default, 0);
|
||||
define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
|
||||
}
|
||||
else if (!second_expansion && streq (name, ".SECONDEXPANSION"))
|
||||
second_expansion = 1;
|
||||
#if !defined (__MSDOS__) && !defined (__EMX__)
|
||||
else if (!one_shell && streq (name, ".ONESHELL"))
|
||||
one_shell = 1;
|
||||
#endif
|
||||
|
||||
/* If this is a static pattern rule:
|
||||
'targets: target%pattern: prereq%pattern; recipe',
|
||||
make sure the pattern matches this target name. */
|
||||
@@ -2155,6 +2200,11 @@ record_files (struct nameseq *filenames, int are_also_makes,
|
||||
free_dep_chain (f->deps);
|
||||
f->deps = 0;
|
||||
}
|
||||
/* This file is explicitly mentioned as a target. There is no need
|
||||
to set is_explicit in the case of double colon below, because an
|
||||
implicit double colon rule only applies when the prerequisite
|
||||
exists. A prerequisite which exists is not intermediate anyway. */
|
||||
f->is_explicit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2197,10 +2247,9 @@ record_files (struct nameseq *filenames, int are_also_makes,
|
||||
if (pattern)
|
||||
{
|
||||
static const char *percent = "%";
|
||||
char *buffer = variable_expand ("");
|
||||
char *o = patsubst_expand_pat (buffer, name, pattern, percent,
|
||||
pattern_percent+1, percent+1);
|
||||
f->stem = strcache_add_len (buffer, o - buffer);
|
||||
char *o = patsubst_expand_pat (variable_buffer, name, pattern,
|
||||
percent, pattern_percent+1, percent+1);
|
||||
f->stem = strcache_add_len (variable_buffer, o - variable_buffer);
|
||||
if (this)
|
||||
{
|
||||
if (! this->need_2nd_expansion)
|
||||
@@ -2241,6 +2290,8 @@ record_files (struct nameseq *filenames, int are_also_makes,
|
||||
|
||||
name = f->name;
|
||||
|
||||
check_special_file (f, flocp);
|
||||
|
||||
/* All done! Set up for the next one. */
|
||||
if (nextf == 0)
|
||||
break;
|
||||
@@ -2351,8 +2402,12 @@ find_map_unquote (char *string, int stopmap)
|
||||
string_len = strlen (string);
|
||||
/* The number of backslashes is now -I.
|
||||
Copy P over itself to swallow half of them. */
|
||||
memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1);
|
||||
p += i/2;
|
||||
{
|
||||
/* Avoid arithmetic conversion of negative values to unsigned. */
|
||||
int hi = -(i/2);
|
||||
memmove (&p[i], &p[i/2], (string_len - (p - string)) + hi + 1);
|
||||
p += i/2;
|
||||
}
|
||||
if (i % 2 == 0)
|
||||
/* All the backslashes quoted each other; the STOPCHAR was
|
||||
unquoted. */
|
||||
@@ -2394,8 +2449,12 @@ find_char_unquote (char *string, int stop)
|
||||
string_len = strlen (string);
|
||||
/* The number of backslashes is now -I.
|
||||
Copy P over itself to swallow half of them. */
|
||||
memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1);
|
||||
p += i/2;
|
||||
{
|
||||
/* Avoid arithmetic conversion of negative values to unsigned. */
|
||||
int hi = -(i/2);
|
||||
memmove (&p[i], &p[i/2], (string_len - (p - string)) + hi + 1);
|
||||
p += i/2;
|
||||
}
|
||||
if (i % 2 == 0)
|
||||
/* All the backslashes quoted each other; the STOPCHAR was
|
||||
unquoted. */
|
||||
@@ -2465,80 +2524,65 @@ find_percent (char *pattern)
|
||||
return find_char_unquote (pattern, '%');
|
||||
}
|
||||
|
||||
/* Search STRING for an unquoted % and handle quoting. Returns a pointer to
|
||||
the % or NULL if no % was found.
|
||||
/* Return a pointer to the first unescaped %, or NULL if there isn't one.
|
||||
Compress any escape chars up to the first unescaped %, but not afterward.
|
||||
This version is used with strings in the string cache: if there's a need to
|
||||
modify the string a new version will be added to the string cache and
|
||||
*STRING will be set to that. */
|
||||
modify the string to handle escape chars a new version will be added to the
|
||||
string cache and *STRING will be set to that. */
|
||||
|
||||
const char *
|
||||
find_percent_cached (const char **string)
|
||||
{
|
||||
const char *p = *string;
|
||||
char *new = 0;
|
||||
size_t slen = 0;
|
||||
const char *p = strchr (*string, '%');
|
||||
char *new, *np;
|
||||
size_t slen;
|
||||
|
||||
/* If the first char is a % return now. This lets us avoid extra tests
|
||||
inside the loop. */
|
||||
if (*p == '%')
|
||||
/* If there is no % or there is but it's not escaped, reuse this string. */
|
||||
if (!p || p == *string || p[-1] != '\\')
|
||||
return p;
|
||||
|
||||
while (1)
|
||||
/* We must create a new cached string with backslashes compressed. */
|
||||
slen = strlen (*string);
|
||||
new = alloca (slen + 1);
|
||||
memcpy (new, *string, slen + 1);
|
||||
np = new + (p - *string);
|
||||
|
||||
do
|
||||
{
|
||||
p = strchr(p, '%');
|
||||
/* Remember where the percent is. */
|
||||
char *pp = np;
|
||||
int i = -2;
|
||||
|
||||
if (!p)
|
||||
break;
|
||||
|
||||
/* See if this % is escaped with a backslash; if not we're done. */
|
||||
if (p[-1] != '\\')
|
||||
break;
|
||||
/* This % is preceded by a backslash; search for more backslashes. */
|
||||
while (&np[i] >= new && np[i] == '\\')
|
||||
--i;
|
||||
++i;
|
||||
|
||||
/* The number of backslashes is -I. Copy the string over itself to
|
||||
swallow half of them. */
|
||||
{
|
||||
/* Search for more backslashes. */
|
||||
char *pv;
|
||||
int i = -2;
|
||||
|
||||
while (&p[i] >= *string && p[i] == '\\')
|
||||
--i;
|
||||
++i;
|
||||
|
||||
/* At this point we know we'll need to allocate a new string.
|
||||
Make a copy if we haven't yet done so. */
|
||||
if (! new)
|
||||
{
|
||||
slen = strlen (*string);
|
||||
new = alloca (slen + 1);
|
||||
memcpy (new, *string, slen + 1);
|
||||
p = new + (p - *string);
|
||||
*string = new;
|
||||
}
|
||||
|
||||
/* At this point *string, p, and new all point into the same string.
|
||||
Get a non-const version of p so we can modify new. */
|
||||
pv = new + (p - *string);
|
||||
|
||||
/* The number of backslashes is now -I.
|
||||
Copy P over itself to swallow half of them. */
|
||||
memmove (&pv[i], &pv[i/2], (slen - (pv - new)) - (i/2) + 1);
|
||||
p += i/2;
|
||||
|
||||
/* If the backslashes quoted each other; the % was unquoted. */
|
||||
if (i % 2 == 0)
|
||||
break;
|
||||
/* Avoid arithmetic conversion of negative values to unsigned. */
|
||||
int hi = -(i/2);
|
||||
memmove (&pp[i], &pp[i/2], (slen - (pp - new)) + hi + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we had to change STRING, add it to the strcache. */
|
||||
if (new)
|
||||
{
|
||||
*string = strcache_add (*string);
|
||||
if (p)
|
||||
p = *string + (p - new);
|
||||
/* Update SLEN and set NP to point after the %. */
|
||||
slen += i/2 + i%2;
|
||||
np += i/2;
|
||||
|
||||
/* If all backslashes quoted each other then % was unquoted. */
|
||||
if (i % 2 == 0)
|
||||
break;
|
||||
|
||||
np = strchr (np, '%');
|
||||
}
|
||||
while (np && np[-1] == '\\');
|
||||
|
||||
/* Add the new string to the strcache. */
|
||||
*string = strcache_add (new);
|
||||
|
||||
/* If we didn't find a %, return NULL. Otherwise return a ptr to it. */
|
||||
return p;
|
||||
return np ? *string + (np - new) : NULL;
|
||||
}
|
||||
|
||||
/* Find the next line of text in an eval buffer, combining continuation lines
|
||||
@@ -2730,7 +2774,7 @@ get_next_mword (char *buffer, char **startp, size_t *length)
|
||||
char c;
|
||||
|
||||
/* Skip any leading whitespace. */
|
||||
while (ISBLANK (*p))
|
||||
while (ISSPACE (*p))
|
||||
++p;
|
||||
|
||||
beg = p;
|
||||
@@ -2816,11 +2860,11 @@ get_next_mword (char *buffer, char **startp, size_t *length)
|
||||
char closeparen;
|
||||
int count;
|
||||
|
||||
if (END_OF_TOKEN (c))
|
||||
goto done_word;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '=':
|
||||
goto done_word;
|
||||
|
||||
@@ -2920,6 +2964,7 @@ construct_include_path (const char **arg_dirs)
|
||||
const char **dirs;
|
||||
const char **cpp;
|
||||
size_t idx;
|
||||
int disable = 0;
|
||||
|
||||
/* Compute the number of pointers we need in the table. */
|
||||
idx = sizeof (default_include_directories) / sizeof (const char *);
|
||||
@@ -2938,7 +2983,8 @@ construct_include_path (const char **arg_dirs)
|
||||
max_incl_len = 0;
|
||||
|
||||
/* First consider any dirs specified with -I switches.
|
||||
Ignore any that don't exist. Remember the maximum string length. */
|
||||
Ignore any that don't exist. Restart if we find "-".
|
||||
Remember the maximum string length. */
|
||||
|
||||
if (arg_dirs)
|
||||
while (*arg_dirs != 0)
|
||||
@@ -2947,6 +2993,14 @@ construct_include_path (const char **arg_dirs)
|
||||
char *expanded = 0;
|
||||
int e;
|
||||
|
||||
if (dir[0] == '-' && dir[1] == '\0')
|
||||
{
|
||||
disable = 1;
|
||||
idx = 0;
|
||||
max_incl_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dir[0] == '~')
|
||||
{
|
||||
expanded = tilde_expand (dir);
|
||||
@@ -2970,41 +3024,40 @@ construct_include_path (const char **arg_dirs)
|
||||
}
|
||||
|
||||
/* Now add the standard default dirs at the end. */
|
||||
|
||||
#ifdef __MSDOS__
|
||||
{
|
||||
/* The environment variable $DJDIR holds the root of the DJGPP directory
|
||||
tree; add ${DJDIR}/include. */
|
||||
struct variable *djdir = lookup_variable ("DJDIR", 5);
|
||||
|
||||
if (djdir)
|
||||
{
|
||||
size_t len = strlen (djdir->value) + 8;
|
||||
char *defdir = alloca (len + 1);
|
||||
|
||||
strcat (strcpy (defdir, djdir->value), "/include");
|
||||
dirs[idx++] = strcache_add (defdir);
|
||||
|
||||
if (len > max_incl_len)
|
||||
max_incl_len = len;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (cpp = default_include_directories; *cpp != 0; ++cpp)
|
||||
if (!disable)
|
||||
{
|
||||
int e;
|
||||
#ifdef __MSDOS__
|
||||
/* The environment variable $DJDIR holds the root of the DJGPP directory
|
||||
tree; add ${DJDIR}/include. */
|
||||
struct variable *djdir = lookup_variable ("DJDIR", 5);
|
||||
|
||||
EINTRLOOP (e, stat (*cpp, &stbuf));
|
||||
if (e == 0 && S_ISDIR (stbuf.st_mode))
|
||||
if (djdir)
|
||||
{
|
||||
size_t len = strlen (*cpp);
|
||||
/* If dir name is written with trailing slashes, discard them. */
|
||||
while (len > 1 && (*cpp)[len - 1] == '/')
|
||||
--len;
|
||||
size_t len = strlen (djdir->value) + 8;
|
||||
char *defdir = alloca (len + 1);
|
||||
|
||||
strcat (strcpy (defdir, djdir->value), "/include");
|
||||
dirs[idx++] = strcache_add (defdir);
|
||||
|
||||
if (len > max_incl_len)
|
||||
max_incl_len = len;
|
||||
dirs[idx++] = strcache_add_len (*cpp, len);
|
||||
}
|
||||
#endif
|
||||
for (cpp = default_include_directories; *cpp != 0; ++cpp)
|
||||
{
|
||||
int e;
|
||||
|
||||
EINTRLOOP (e, stat (*cpp, &stbuf));
|
||||
if (e == 0 && S_ISDIR (stbuf.st_mode))
|
||||
{
|
||||
size_t len = strlen (*cpp);
|
||||
/* If dir name is written with trailing slashes, discard them. */
|
||||
while (len > 1 && (*cpp)[len - 1] == '/')
|
||||
--len;
|
||||
if (len > max_incl_len)
|
||||
max_incl_len = len;
|
||||
dirs[idx++] = strcache_add_len (*cpp, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3012,10 +3065,12 @@ construct_include_path (const char **arg_dirs)
|
||||
|
||||
/* Now add each dir to the .INCLUDE_DIRS variable. */
|
||||
|
||||
do_variable_definition (NILF, ".INCLUDE_DIRS", "", o_default, f_simple, 0);
|
||||
for (cpp = dirs; *cpp != 0; ++cpp)
|
||||
do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp,
|
||||
o_default, f_append, 0);
|
||||
|
||||
free (include_directories);
|
||||
include_directories = dirs;
|
||||
}
|
||||
|
||||
@@ -3025,7 +3080,7 @@ construct_include_path (const char **arg_dirs)
|
||||
char *
|
||||
tilde_expand (const char *name)
|
||||
{
|
||||
#ifndef VMS
|
||||
#if !defined(VMS)
|
||||
if (name[1] == '/' || name[1] == '\0')
|
||||
{
|
||||
char *home_dir;
|
||||
@@ -3080,8 +3135,9 @@ tilde_expand (const char *name)
|
||||
{
|
||||
if (userend == 0)
|
||||
return xstrdup (pwent->pw_dir);
|
||||
else
|
||||
return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1));
|
||||
|
||||
*userend = '/';
|
||||
return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1));
|
||||
}
|
||||
else if (userend != 0)
|
||||
*userend = '/';
|
||||
@@ -3114,6 +3170,8 @@ tilde_expand (const char *name)
|
||||
PARSEFS_EXISTS - Only return globbed files that actually exist
|
||||
(cannot also set NOGLOB)
|
||||
PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees)
|
||||
PARSEFS_ONEWORD - Don't break the sequence on whitespace
|
||||
PARSEFS_WAIT - Assume struct dep and handle .WAIT
|
||||
*/
|
||||
|
||||
void *
|
||||
@@ -3129,16 +3187,22 @@ parse_file_seq (char **stringp, size_t size, int stopmap,
|
||||
struct nameseq *new = 0;
|
||||
struct nameseq **newp = &new;
|
||||
#define NEWELT(_n) do { \
|
||||
const char *__n = (_n); \
|
||||
*newp = xcalloc (size); \
|
||||
(*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \
|
||||
newp = &(*newp)->next; \
|
||||
struct nameseq *_ns = xcalloc (size); \
|
||||
const char *__n = (_n); \
|
||||
_ns->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \
|
||||
if (found_wait) { \
|
||||
((struct dep*)_ns)->wait_here = 1; \
|
||||
found_wait = 0; \
|
||||
} \
|
||||
*newp = _ns; \
|
||||
newp = &_ns->next; \
|
||||
} while(0)
|
||||
|
||||
char *p;
|
||||
glob_t gl;
|
||||
char *tp;
|
||||
int findmap = stopmap|MAP_VMSCOMMA|MAP_NUL;
|
||||
int found_wait = 0;
|
||||
|
||||
if (NONE_SET (flags, PARSEFS_ONEWORD))
|
||||
findmap |= MAP_BLANK;
|
||||
@@ -3212,13 +3276,21 @@ parse_file_seq (char **stringp, size_t size, int stopmap,
|
||||
if (!p)
|
||||
p = s + strlen (s);
|
||||
|
||||
if (ANY_SET (flags, PARSEFS_WAIT) && p - s == CSTRLEN (".WAIT")
|
||||
&& memcmp (s, ".WAIT", CSTRLEN (".WAIT")) == 0)
|
||||
{
|
||||
/* Note that we found a .WAIT for the next dep but skip it. */
|
||||
found_wait = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Strip leading "this directory" references. */
|
||||
if (NONE_SET (flags, PARSEFS_NOSTRIP))
|
||||
#ifdef VMS
|
||||
/* Skip leading '[]'s. should only be one set or bug somwhere else */
|
||||
/* Skip leading '[]'s. should only be one set or bug somewhere else */
|
||||
if (p - s > 2 && s[0] == '[' && s[1] == ']')
|
||||
s += 2;
|
||||
/* Skip leading '<>'s. should only be one set or bug somwhere else */
|
||||
/* Skip leading '<>'s. should only be one set or bug somewhere else */
|
||||
if (p - s > 2 && s[0] == '<' && s[1] == '>')
|
||||
s += 2;
|
||||
#endif
|
||||
|
||||
239
src/remake.c
239
src/remake.c
@@ -1,5 +1,5 @@
|
||||
/* Basic dependency engine for GNU Make.
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -35,6 +35,13 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
#endif
|
||||
#ifdef WINDOWS32
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
/* VC7 or later supprots _stat64 to access 64-bit file size. */
|
||||
#define STAT _stat64
|
||||
#else
|
||||
#define STAT stat
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -71,8 +78,8 @@ static FILE_TIMESTAMP name_mtime (const char *name);
|
||||
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
|
||||
was done, 0 if all goals were updated successfully, or 1 if a goal failed.
|
||||
/* 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,
|
||||
and -n should be disabled for them unless they were also command-line
|
||||
@@ -86,8 +93,8 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
enum update_status status = us_none;
|
||||
|
||||
/* Duplicate the chain so we can remove things from it. */
|
||||
|
||||
struct dep *goals = copy_dep_chain ((struct dep *)goaldeps);
|
||||
struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
|
||||
struct dep *goals = goals_orig;
|
||||
|
||||
goal_list = rebuilding_makefiles ? goaldeps : NULL;
|
||||
|
||||
@@ -101,7 +108,7 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
|
||||
while (goals != 0)
|
||||
{
|
||||
struct dep *g, *lastgoal;
|
||||
struct dep *gu, *g, *lastgoal;
|
||||
|
||||
/* Start jobs that are waiting for the load to go down. */
|
||||
|
||||
@@ -112,13 +119,15 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
reap_children (1, 0);
|
||||
|
||||
lastgoal = 0;
|
||||
g = goals;
|
||||
while (g != 0)
|
||||
gu = goals;
|
||||
while (gu != 0)
|
||||
{
|
||||
/* Iterate over all double-colon entries for this file. */
|
||||
struct file *file;
|
||||
int stop = 0, any_not_updated = 0;
|
||||
|
||||
g = gu->shuf ? gu->shuf : gu;
|
||||
|
||||
goal_dep = g;
|
||||
|
||||
for (file = g->file->double_colon ? g->file->double_colon : g->file;
|
||||
@@ -178,8 +187,7 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
FILE_TIMESTAMP mtime = MTIME (file);
|
||||
check_renamed (file);
|
||||
|
||||
if (file->updated && g->changed &&
|
||||
mtime != file->mtime_before_update)
|
||||
if (file->updated && mtime != file->mtime_before_update)
|
||||
{
|
||||
/* Updating was done. If this is a makefile and
|
||||
just_print_flag or question_flag is set (meaning
|
||||
@@ -229,31 +237,30 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
|
||||
/* This goal is finished. Remove it from the chain. */
|
||||
if (lastgoal == 0)
|
||||
goals = g->next;
|
||||
goals = gu->next;
|
||||
else
|
||||
lastgoal->next = g->next;
|
||||
lastgoal->next = gu->next;
|
||||
|
||||
/* Free the storage. */
|
||||
free (g);
|
||||
|
||||
g = lastgoal == 0 ? goals : lastgoal->next;
|
||||
gu = lastgoal == 0 ? goals : lastgoal->next;
|
||||
|
||||
if (stop)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastgoal = g;
|
||||
g = g->next;
|
||||
lastgoal = gu;
|
||||
gu = gu->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we reached the end of the dependency graph update CONSIDERED
|
||||
for the next pass. */
|
||||
if (g == 0)
|
||||
if (gu == 0)
|
||||
++considered;
|
||||
}
|
||||
|
||||
free_dep_chain (goals_orig);
|
||||
|
||||
if (rebuilding_makefiles)
|
||||
{
|
||||
touch_flag = t;
|
||||
@@ -281,7 +288,7 @@ show_goal_error (void)
|
||||
if (goal->error)
|
||||
{
|
||||
OSS (error, &goal->floc, "%s: %s",
|
||||
goal->file->name, strerror ((int)goal->error));
|
||||
goal->file->name, strerror (goal->error));
|
||||
goal->error = 0;
|
||||
}
|
||||
return;
|
||||
@@ -337,7 +344,7 @@ update_file (struct file *file, unsigned int depth)
|
||||
check_renamed (f);
|
||||
|
||||
/* Clean up any alloca() used during the update. */
|
||||
alloca (0);
|
||||
free_alloca ();
|
||||
|
||||
/* If we got an error, don't bother with double_colon etc. */
|
||||
if (new && !keep_going_flag)
|
||||
@@ -418,7 +425,7 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
FILE_TIMESTAMP this_mtime;
|
||||
int noexist, must_make, deps_changed;
|
||||
struct file *ofile;
|
||||
struct dep *d, *ad;
|
||||
struct dep *du, *d, *ad;
|
||||
struct dep amake;
|
||||
int running = 0;
|
||||
|
||||
@@ -496,17 +503,12 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
|
||||
}
|
||||
|
||||
must_make = noexist;
|
||||
|
||||
/* If file was specified as a target with no commands,
|
||||
come up with some default commands. */
|
||||
/* If file was specified as a target with no commands, come up with some
|
||||
default commands. This may also add more also_make files. */
|
||||
|
||||
if (!file->phony && file->cmds == 0 && !file->tried_implicit)
|
||||
{
|
||||
if (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"));
|
||||
try_implicit_rule (file, depth);
|
||||
file->tried_implicit = 1;
|
||||
}
|
||||
if (file->cmds == 0 && !file->is_target
|
||||
@@ -516,6 +518,26 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
file->cmds = default_file->cmds;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
check_renamed (adfile);
|
||||
noexist = fmtime == NONEXISTENT_MTIME;
|
||||
if (noexist)
|
||||
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;
|
||||
|
||||
/* Update all non-intermediate files we depend on, if necessary, and see
|
||||
whether any of them is more recent than this file. We need to walk our
|
||||
deps, AND the deps of any also_make targets to ensure everything happens
|
||||
@@ -528,17 +550,28 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
{
|
||||
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 */
|
||||
d = ad->file->deps;
|
||||
du = ad->file->deps;
|
||||
ad = ad->next;
|
||||
|
||||
while (d)
|
||||
while (du)
|
||||
{
|
||||
enum update_status new;
|
||||
FILE_TIMESTAMP mtime;
|
||||
int maybe_make;
|
||||
int dontcare = 0;
|
||||
|
||||
d = du->shuf ? du->shuf : du;
|
||||
|
||||
if (d->wait_here && running)
|
||||
break;
|
||||
|
||||
check_renamed (d->file);
|
||||
|
||||
mtime = file_mtime (d->file);
|
||||
@@ -548,14 +581,16 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
{
|
||||
OSS (error, NILF, _("Circular %s <- %s dependency dropped."),
|
||||
file->name, d->file->name);
|
||||
|
||||
/* We cannot free D here because our the caller will still have
|
||||
a reference to it when we were called recursively via
|
||||
check_dep below. */
|
||||
if (lastd == 0)
|
||||
file->deps = d->next;
|
||||
file->deps = du->next;
|
||||
else
|
||||
lastd->next = d->next;
|
||||
d = d->next;
|
||||
lastd->next = du->next;
|
||||
|
||||
du = du->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -604,8 +639,8 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
d->changed = ((file_mtime (d->file) != mtime)
|
||||
|| (mtime == NONEXISTENT_MTIME));
|
||||
|
||||
lastd = d;
|
||||
d = d->next;
|
||||
lastd = du;
|
||||
du = du->next;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,58 +649,65 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
|
||||
if (must_make || always_make_flag)
|
||||
{
|
||||
for (d = file->deps; d != 0; d = d->next)
|
||||
if (d->file->intermediate)
|
||||
{
|
||||
enum update_status new;
|
||||
int dontcare = 0;
|
||||
for (du = file->deps; du != 0; du = du->next)
|
||||
{
|
||||
d = du->shuf ? du->shuf : du;
|
||||
|
||||
FILE_TIMESTAMP mtime = file_mtime (d->file);
|
||||
check_renamed (d->file);
|
||||
d->file->parent = file;
|
||||
if (d->wait_here && running)
|
||||
break;
|
||||
|
||||
if (d->file->intermediate)
|
||||
{
|
||||
enum update_status new;
|
||||
int dontcare = 0;
|
||||
|
||||
FILE_TIMESTAMP mtime = file_mtime (d->file);
|
||||
check_renamed (d->file);
|
||||
d->file->parent = file;
|
||||
|
||||
/* Inherit dontcare flag from our parent. */
|
||||
if (rebuilding_makefiles)
|
||||
{
|
||||
dontcare = d->file->dontcare;
|
||||
d->file->dontcare = file->dontcare;
|
||||
}
|
||||
|
||||
/* We may have already considered this file, when we didn't know
|
||||
we'd need to update it. Force update_file() to consider it and
|
||||
not prune it. */
|
||||
d->file->considered = 0;
|
||||
|
||||
new = update_file (d->file, depth);
|
||||
if (new > dep_status)
|
||||
dep_status = new;
|
||||
|
||||
/* Restore original dontcare flag. */
|
||||
if (rebuilding_makefiles)
|
||||
d->file->dontcare = dontcare;
|
||||
|
||||
check_renamed (d->file);
|
||||
|
||||
/* Inherit dontcare flag from our parent. */
|
||||
if (rebuilding_makefiles)
|
||||
{
|
||||
dontcare = d->file->dontcare;
|
||||
d->file->dontcare = file->dontcare;
|
||||
struct file *f = d->file;
|
||||
if (f->double_colon)
|
||||
f = f->double_colon;
|
||||
do
|
||||
{
|
||||
running |= (f->command_state == cs_running
|
||||
|| f->command_state == cs_deps_running);
|
||||
f = f->prev;
|
||||
}
|
||||
while (f != 0);
|
||||
}
|
||||
|
||||
/* We may have already considered this file, when we didn't know
|
||||
we'd need to update it. Force update_file() to consider it and
|
||||
not prune it. */
|
||||
d->file->considered = 0;
|
||||
if (dep_status && !keep_going_flag)
|
||||
break;
|
||||
|
||||
new = update_file (d->file, depth);
|
||||
if (new > dep_status)
|
||||
dep_status = new;
|
||||
|
||||
/* Restore original dontcare flag. */
|
||||
if (rebuilding_makefiles)
|
||||
d->file->dontcare = dontcare;
|
||||
|
||||
check_renamed (d->file);
|
||||
|
||||
{
|
||||
struct file *f = d->file;
|
||||
if (f->double_colon)
|
||||
f = f->double_colon;
|
||||
do
|
||||
{
|
||||
running |= (f->command_state == cs_running
|
||||
|| f->command_state == cs_deps_running);
|
||||
f = f->prev;
|
||||
}
|
||||
while (f != 0);
|
||||
if (!running)
|
||||
d->changed = ((file->phony && file->cmds != 0)
|
||||
|| file_mtime (d->file) != mtime);
|
||||
}
|
||||
|
||||
if (dep_status && !keep_going_flag)
|
||||
break;
|
||||
|
||||
if (!running)
|
||||
d->changed = ((file->phony && file->cmds != 0)
|
||||
|| file_mtime (d->file) != mtime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finish_updating (file);
|
||||
@@ -806,6 +848,10 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
/* Since make has not created this file, make should not remove it,
|
||||
even if the file is intermediate. */
|
||||
file->secondary = 1;
|
||||
|
||||
notice_finished_file (file);
|
||||
|
||||
/* Since we don't need to remake the file, convert it to use the
|
||||
@@ -1035,10 +1081,7 @@ check_dep (struct file *file, unsigned int depth,
|
||||
|
||||
if (!file->phony && file->cmds == 0 && !file->tried_implicit)
|
||||
{
|
||||
if (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"));
|
||||
try_implicit_rule (file, depth);
|
||||
file->tried_implicit = 1;
|
||||
}
|
||||
if (file->cmds == 0 && !file->is_target
|
||||
@@ -1077,6 +1120,12 @@ check_dep (struct file *file, unsigned int depth,
|
||||
}
|
||||
|
||||
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;
|
||||
while (d != 0)
|
||||
{
|
||||
@@ -1414,7 +1463,7 @@ f_mtime (struct file *file, int search)
|
||||
/ 1e9));
|
||||
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);
|
||||
else
|
||||
sprintf (from_now_string, "%.2g", from_now);
|
||||
@@ -1466,7 +1515,11 @@ static FILE_TIMESTAMP
|
||||
name_mtime (const char *name)
|
||||
{
|
||||
FILE_TIMESTAMP mtime;
|
||||
#if defined(WINDOWS32)
|
||||
struct STAT st;
|
||||
#else
|
||||
struct stat st;
|
||||
#endif
|
||||
int e;
|
||||
|
||||
#if defined(WINDOWS32)
|
||||
@@ -1498,7 +1551,11 @@ name_mtime (const char *name)
|
||||
tend = &tem[0];
|
||||
}
|
||||
|
||||
#if defined(WINDOWS32)
|
||||
e = STAT (tem, &st);
|
||||
#else
|
||||
e = stat (tem, &st);
|
||||
#endif
|
||||
if (e == 0 && !_S_ISDIR (st.st_mode) && tend < tem + (p - name - 1))
|
||||
{
|
||||
errno = ENOTDIR;
|
||||
@@ -1563,7 +1620,7 @@ name_mtime (const char *name)
|
||||
mtime = ltime;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* Eh? Just take what we have. */
|
||||
@@ -1646,7 +1703,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
|
||||
static size_t buflen = 0;
|
||||
static size_t libdir_maxlen = 0;
|
||||
static unsigned int std_dirs = 0;
|
||||
char *libbuf = variable_expand ("");
|
||||
char *libbuf;
|
||||
|
||||
/* Expand the pattern using LIB as a replacement. */
|
||||
{
|
||||
@@ -1663,10 +1720,12 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
|
||||
p[len] = c;
|
||||
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, p3+1, len - (p3-p));
|
||||
p[len] = c;
|
||||
|
||||
libbuf = variable_buffer;
|
||||
}
|
||||
|
||||
/* Look first for 'libNAME.a' in the current directory. */
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Please do not send bug reports or questions about it to
|
||||
the Make maintainers.
|
||||
|
||||
Copyright (C) 1988-2020 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-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
|
||||
@@ -19,12 +19,15 @@ You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "makeint.h"
|
||||
|
||||
#include "filedef.h"
|
||||
#include "commands.h"
|
||||
#include "job.h"
|
||||
#include "commands.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#if HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
#include <netdb.h>
|
||||
|
||||
#include "customs.h"
|
||||
@@ -74,19 +77,12 @@ start_remote_job_p (int first_p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For secure Customs, make is installed setuid root and
|
||||
Customs requires a privileged source port be used. */
|
||||
make_access ();
|
||||
|
||||
if (ISDB (DB_JOBS))
|
||||
Rpc_Debug (1);
|
||||
|
||||
/* Ping the daemon once to see if it is there. */
|
||||
inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1;
|
||||
|
||||
/* Return to normal user access. */
|
||||
user_access ();
|
||||
|
||||
if (starting_directory == 0)
|
||||
/* main couldn't figure it out. */
|
||||
inited = -1;
|
||||
@@ -172,7 +168,7 @@ start_remote_job (char **argv, char **envp, int stdin_fd,
|
||||
len = Customs_MakeWayBill (&permit, normalized_cwd, argv[0], argv,
|
||||
envp, retport, waybill);
|
||||
|
||||
/* Modify the waybill as if the remote child had done 'child_access ()'. */
|
||||
/* Modify the waybill for the child's uid/gid. */
|
||||
{
|
||||
WayBill *wb = (WayBill *) waybill;
|
||||
wb->ruid = wb->euid;
|
||||
@@ -232,7 +228,8 @@ start_remote_job (char **argv, char **envp, int stdin_fd,
|
||||
else if (pid == 0)
|
||||
{
|
||||
/* Child side. Run 'export' to handle the connection. */
|
||||
static char sock_buf[20], retsock_buf[20], id_buf[20];
|
||||
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 };
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user