mirror of
https://github.com/mirror/make.git
synced 2026-08-20 08:53:28 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed493f6c91 | ||
|
|
7c3260bbdd | ||
|
|
38b19976f5 | ||
|
|
1dd52ab472 | ||
|
|
92789aa2e7 | ||
|
|
4e18732a1d | ||
|
|
11f9da227e | ||
|
|
b92340a1ea | ||
|
|
8064aee4f9 | ||
|
|
cf78e65fda | ||
|
|
04f0d8427f | ||
|
|
f8401ad28b | ||
|
|
e4b3bf7f97 | ||
|
|
d18a87d0a4 | ||
|
|
41c35f2ffe | ||
|
|
deb4a42c3e | ||
|
|
252c26bd20 | ||
|
|
6f8da5f4b8 | ||
|
|
c46b5a9e0e | ||
|
|
b4157d2ff4 | ||
|
|
f364e0d8d6 | ||
|
|
bb0c05a7f0 | ||
|
|
f987d181c4 | ||
|
|
cad3ddd165 | ||
|
|
54214176b1 | ||
|
|
c2f92c980f | ||
|
|
5b1ca277ca |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -60,6 +60,10 @@ WinRel/
|
||||
GccDebug/
|
||||
GccRel/
|
||||
|
||||
# Test artifacts
|
||||
makeerror-*
|
||||
test-suite.log
|
||||
|
||||
# Distribution artifacts
|
||||
.dep_segment
|
||||
.check-git-HEAD
|
||||
|
||||
32
Makefile.am
32
Makefile.am
@@ -137,8 +137,8 @@ src/gmk-default.h: $(top_srcdir)/src/gmk-default.scm
|
||||
dist-hook:
|
||||
(cd $(top_srcdir); \
|
||||
sub=`find tests/scripts -follow \( -name .git -o -name .deps -o -name work -o -name .gitignore -o -name \*.orig -o -name \*.rej -o -name \*~ -o -name \*.out -o -name Makefile \) -prune -o -type f -print`; \
|
||||
tar chf - $$sub) \
|
||||
| (cd $(distdir); tar xfBp -)
|
||||
$(AMTAR) chf - $$sub) \
|
||||
| (cd $(distdir); $(AMTAR) xfBp -)
|
||||
|
||||
|
||||
# --------------- Local CHECK Section
|
||||
@@ -162,9 +162,24 @@ MAKETESTFLAGS =
|
||||
|
||||
.PHONY: check-regression
|
||||
|
||||
GMK_OUTDIR=..
|
||||
GMK_OUTDIR = ..
|
||||
|
||||
testlog = test-suite.log
|
||||
testresult = tests/.test-result
|
||||
errorpre = makeerror-$(PACKAGE_VERSION)-$(host_triplet)
|
||||
|
||||
testfiles = $(testlog) $(testresult) $(errorfile)
|
||||
MOSTLYCLEANFILES = $(testfiles)
|
||||
|
||||
errordetails = config.status config.log src/config.h $(testlog) tests/work
|
||||
|
||||
# Create a 4-letter random sequence
|
||||
rand_value = c = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
rand_char = substr(c,int(rand()*36),1)
|
||||
rand_string = $(AWK) 'BEGIN{srand(); $(rand_value); print $(rand_char) "" $(rand_char) "" $(rand_char) "" $(rand_char);}'
|
||||
|
||||
check-regression: tests/config-flags.pm
|
||||
@rm -f $(testfiles)
|
||||
@if test -f '$(top_srcdir)/tests/run_make_tests'; then \
|
||||
ulimit -n 128; \
|
||||
if $(PERL) -v >/dev/null 2>&1; then \
|
||||
@@ -177,7 +192,16 @@ check-regression: tests/config-flags.pm
|
||||
done; fi ;; \
|
||||
esac; \
|
||||
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); \
|
||||
(cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir '$(abs_top_srcdir)' -make '$(GMK_OUTDIR)/make$(EXEEXT)' $(MAKETESTFLAGS); echo $$? >.test-result) 2>&1 | tee $(testlog); \
|
||||
er=$$(cat $(testresult)); if test "$$er" -ne 0; then \
|
||||
dirnm="$(errorpre)-$$($(rand_string))"; fnm="$$dirnm.tar.gz"; \
|
||||
rm -rf "$$dirnm"; mkdir "$$dirnm"; \
|
||||
$(AMTAR) chf - $(errordetails) | (cd "$$dirnm"; $(AMTAR) xf -); \
|
||||
$(AMTAR) chf - "$$dirnm" | eval GZIP= gzip $(GZIP_ENV) -c >"$$fnm"; \
|
||||
echo "*** Testing FAILED! Details: $$fnm"; \
|
||||
echo '*** Please report to <$(PACKAGE_BUGREPORT)>'; echo; \
|
||||
exit $$er; \
|
||||
fi; \
|
||||
else \
|
||||
echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \
|
||||
fi; \
|
||||
|
||||
12
NEWS
12
NEWS
@@ -1,6 +1,6 @@
|
||||
GNU Make NEWS -*-indented-text-*-
|
||||
History of user-visible changes.
|
||||
18 October 2022
|
||||
31 October 2022
|
||||
|
||||
See the end of this file for copyrights and conditions.
|
||||
|
||||
@@ -9,7 +9,7 @@ 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.91 (18 Oct 2022)
|
||||
Version 4.4 (31 Oct 2022)
|
||||
|
||||
A complete list of bugs fixed in this version is available here:
|
||||
|
||||
@@ -100,7 +100,7 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
|
||||
each prerequisite).
|
||||
|
||||
* New feature: The .NOTINTERMEDIATE special target
|
||||
.NOTINTERMEDIATE Disables intermediate behavior for specific files, for all
|
||||
.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>
|
||||
|
||||
@@ -186,9 +186,9 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
|
||||
* 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.
|
||||
* When the pipe-based 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
|
||||
|
||||
179
README.git
179
README.git
@@ -48,8 +48,8 @@ your commit messages (sans the leading TAB of course).
|
||||
|
||||
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.
|
||||
Rule #3: Squash-merge or rebase + merge --ff-only, rather than merging from
|
||||
personal branches into master.
|
||||
|
||||
Typical simple workflow might be:
|
||||
|
||||
@@ -178,6 +178,9 @@ Note, neither of these methods are tested regularly by the GNU Make
|
||||
maintainers. Building for Windows from a distribution tarball IS tested
|
||||
regularly.
|
||||
|
||||
NOTE! "Maintainer mode" (see above) IS ENABLED when building from Git using
|
||||
the build_w32.bat file.
|
||||
|
||||
|
||||
Debugging and Testing
|
||||
---------------------
|
||||
@@ -203,7 +206,7 @@ work on non-GNU systems (Windows, MacOS, etc.)
|
||||
|
||||
make clean
|
||||
make -j8 CFLAGS='-ggdb3 -fsanitize=address' LDFLAGS='-ggdb3 -fsanitize=address'
|
||||
(cd tests && ./run_make_tests -make ../make)
|
||||
make check
|
||||
|
||||
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.
|
||||
@@ -250,34 +253,118 @@ consistent (that's why we don't finalize the Git tag, etc. until the end).
|
||||
"Fixed Release" ID number.
|
||||
* Run "make distcheck" to be sure it all works.
|
||||
* Run "make check-alt-config" to be sure alternative configurations work
|
||||
* Run "make update-makeweb" to get a copy of the GNU Make web pages
|
||||
* Run "make update-gnuweb" to get a copy of the GNU website boilerplate pages
|
||||
* Update the web page boilerplate if necessary:
|
||||
../gnu-www/www/server/standards/patch-from-parent ../make-web/make.html \
|
||||
../gnu-www/www/server/standards/boilerplate.html
|
||||
* Run "make gendocs" (requires gnulib) to generate the manual files for
|
||||
the GNU Make web pages.
|
||||
* Follow the directions from gendocs for the web page repository
|
||||
* run "make tag-release" to create a Git tag for the release
|
||||
* Push everything:
|
||||
git push --tags origin master
|
||||
|
||||
Manage the Savannah project for GNU Make:
|
||||
The safest thing is to create an entirely new repository and build the final
|
||||
package from there:
|
||||
|
||||
>>> This is only for real releases, not release candidate builds <<<
|
||||
git clone git://git.savannah.gnu.org/make.git make-release
|
||||
cd make-release
|
||||
|
||||
If you don't want to create a new repository then run "git clean -fdx".
|
||||
Then:
|
||||
|
||||
./bootstrap.sh
|
||||
./configure
|
||||
make distcheck
|
||||
|
||||
Perform test builds on whichever systems you have access to.
|
||||
|
||||
Use a previous announcement as a template to create an announcement in a text
|
||||
file then sign it with GPG:
|
||||
|
||||
gpg --clearsign <announcement.txt>
|
||||
|
||||
Or, use your mail client's PGP/GPG signing capabilities.
|
||||
|
||||
NOTE! In order to publish a package on the FSF FTP site you need to have my
|
||||
GPG private key, and my passphrase to unlock it.
|
||||
|
||||
Depending on your distribution (whether GnuPG is integrated with your
|
||||
keyring etc.) the upload operation will either pop up a window asking
|
||||
for the GPG key passphrase one time, or else it will use the CLI to ask
|
||||
for the GPG passphrase _THREE_ times. Sigh.
|
||||
|
||||
|
||||
Publishing a Release Candidate
|
||||
------------------------------
|
||||
|
||||
Usually I publish one or two release candidates for people to test before
|
||||
making an official release. Release candidates use a GNU numbering scheme,
|
||||
which add a ".9x" release number to the PREVIOUS major release. So the first
|
||||
release candidate for GNU Make 4.4 would be GNU Make 4.3.90, the second
|
||||
release candidate would be 4.3.91, etc.
|
||||
|
||||
Upload a release candidate using:
|
||||
|
||||
make upload-alpha
|
||||
|
||||
Announce a release candidate to these mailing lists:
|
||||
|
||||
To: bug-make@gnu.org
|
||||
BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org
|
||||
|
||||
You will have to approve the BCC's on the mailing list admin sites. Send
|
||||
separate copies to (don't use CC as replies will go to these lists):
|
||||
|
||||
* coordinator@translationproject.org
|
||||
* platform-testers@gnu.org
|
||||
|
||||
|
||||
Publishing a Release
|
||||
--------------------
|
||||
|
||||
When publishing a final release there are extra steps that need to be taken:
|
||||
|
||||
* Run "make update-makeweb" to get a copy of the GNU Make web pages
|
||||
* Run "make update-gnuweb" to get a copy of the GNU website boilerplate pages
|
||||
* Update the web page boilerplate if necessary:
|
||||
( cd ~/src/make/make-web \
|
||||
&& ~/src/gnu-www/www/server/standards/patch-from-parent \
|
||||
make.html \
|
||||
~/src/gnu-www/www/server/standards/boilerplate.html )
|
||||
* Run "make gendocs" (requires gnulib) to generate the manual files for
|
||||
the GNU Make web pages.
|
||||
* Follow the directions from gendocs for the web page repository
|
||||
|
||||
Manage the Savannah project for GNU Make:
|
||||
|
||||
* In Savannah modify the "Value", "Rank", and "Description" values for the
|
||||
current "SCM" entry in both "Component Version" and "Fix Release" fields
|
||||
to refer to the new release. The "Rank" field should be 10 less than the
|
||||
previous release so it orders properly.
|
||||
* In Savannah create a new entry for the "Component Version" and "Fix
|
||||
Release" fields:
|
||||
|
||||
* In Savannah create a new entry for the "Component Version" field:
|
||||
- Value: SCM
|
||||
- Rank: 20
|
||||
- Descr: Issues found in code retrieved from Source Code Management (Git), rather than a distributed version. Please include the SHA you are working with.
|
||||
|
||||
* In Savannah create a new entry for the "Fix Release" field:
|
||||
- Value: SCM
|
||||
- Rank: 20
|
||||
- Descr: Fixed in Source Code Management (Git). The fix will be included in the next release of GNU Make.
|
||||
|
||||
Upload a release using:
|
||||
|
||||
make upload-ftp
|
||||
|
||||
Announce a release to these mailing lists:
|
||||
|
||||
To: info-gnu@gnu.org, bug-make@gnu.org
|
||||
BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org
|
||||
|
||||
You will have to approve the BCC's on the mailing list admin sites. Send
|
||||
separate copies to (don't use CC as replies will go to these lists):
|
||||
|
||||
* coordinator@translationproject.org
|
||||
* platform-testers@gnu.org
|
||||
|
||||
Announce on Savannah:
|
||||
|
||||
* Add a news item to the Savannah project site.
|
||||
|
||||
Start the next release:
|
||||
|
||||
* Update configure.ac and add a ".90" to the release number.
|
||||
@@ -285,66 +372,6 @@ Start the next release:
|
||||
* Update the Savannah URL for the bugs fixed in the NEWS section.
|
||||
|
||||
|
||||
Publishing a Package
|
||||
--------------------
|
||||
|
||||
In order to publish a package on the FSF FTP site, either the release
|
||||
site ftp://ftp.gnu.org, or the prerelease site ftp://alpha.gnu.org, you
|
||||
first need to have my GPG private key and my passphrase to unlock it.
|
||||
And, you can't have them! So there! But, just so I remember here's
|
||||
what to do:
|
||||
|
||||
Make sure the "Steps to Release" are complete and committed and tagged.
|
||||
|
||||
git clone git://git.savannah.gnu.org/make.git make-release
|
||||
|
||||
cd make-release
|
||||
|
||||
<run the commands above to build the release>
|
||||
|
||||
make upload-alpha # for alpha.gnu.org (pre-releases)
|
||||
-OR-
|
||||
make upload-ftp # for ftp.gnu.org (official releases)
|
||||
|
||||
Depending on your distribution (whether GnuPG is integrated with your keyring
|
||||
etc.) it will either pop up a window asking for your GPG key passphrase one
|
||||
time, or else it will use the CLI to ask for the GPG passphrase _THREE_ times.
|
||||
Sigh.
|
||||
|
||||
|
||||
For both final releases and pre-releases, send an email with the URL of
|
||||
the package to the GNU translation robot to allow the translators to
|
||||
work on it:
|
||||
|
||||
<coordinator@translationproject.org>
|
||||
|
||||
|
||||
Where to Announce
|
||||
-----------------
|
||||
|
||||
Create the announcement in a text file, using 'git shortlog',
|
||||
then sign it with GPG:
|
||||
|
||||
gpg --clearsign <announcement.txt>
|
||||
|
||||
Or, use your mail client's PGP/GPG signing capabilities.
|
||||
|
||||
Announce the release:
|
||||
|
||||
* For release candidate builds:
|
||||
To: bug-make@gnu.org
|
||||
CC: coordinator@translationproject.org, platform-testers@gnu.org
|
||||
BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org
|
||||
|
||||
* For release builds
|
||||
To: info-gnu@gnu.org, bug-make@gnu.org
|
||||
CC: coordinator@translationproject.org
|
||||
BCC: help-make@gnu.org, make-w32@gnu.org, make-alpha@gnu.org
|
||||
|
||||
* Add a news item to the Savannah project site.
|
||||
* Add an update to freecode.com (nee freshmeat.net)
|
||||
|
||||
|
||||
Appendix A - For The Brave
|
||||
--------------------------
|
||||
|
||||
@@ -360,6 +387,6 @@ For a debugging version:
|
||||
|
||||
./bootstrap && ./configure CFLAGS=-g && make check
|
||||
|
||||
For a release version
|
||||
For an optimized version
|
||||
|
||||
./bootstrap && ./configure && make check
|
||||
|
||||
13
README.in
13
README.in
@@ -66,6 +66,19 @@ You can find most information concerning the development of GNU Make at
|
||||
this site.
|
||||
|
||||
|
||||
Regression Tests
|
||||
----------------
|
||||
|
||||
GNU Make contains a suite of regression tests. To run them use "make check"
|
||||
after building GNU Make. If they fail a tar package will be created
|
||||
containing useful information, which can be emailed (as an attachment) to
|
||||
the <bug-make@gnu.org> mailing list.
|
||||
|
||||
Please note that since these tests rely on known-good-output comparisons,
|
||||
they can show spurious failures on some systems (particularly non-POSIX systems
|
||||
such as Windows).
|
||||
|
||||
|
||||
Bug Reporting
|
||||
-------------
|
||||
|
||||
|
||||
43
build.sh
43
build.sh
@@ -20,6 +20,11 @@
|
||||
# Get configure-generated values
|
||||
. ./build.cfg
|
||||
|
||||
die () { echo "$*" 1>&2; exit 1; }
|
||||
usage () { echo "$0 [-k]"; exit $1; }
|
||||
|
||||
keep_going=false
|
||||
|
||||
: ${OUTDIR:=.}
|
||||
OUTLIB="$OUTDIR/lib"
|
||||
|
||||
@@ -55,6 +60,7 @@ get_mk_var ()
|
||||
# Compile source files. Object files are put into $objs.
|
||||
compile ()
|
||||
{
|
||||
success=true
|
||||
objs=
|
||||
for ofile in "$@"; do
|
||||
# We should try to use a Makefile variable like libgnu_a_SOURCES or
|
||||
@@ -65,10 +71,18 @@ compile ()
|
||||
esac
|
||||
echo "compiling $file..."
|
||||
of="$OUTDIR/$ofile"
|
||||
mkdir -p "${of%/*}"
|
||||
$CC $cflags $CPPFLAGS $CFLAGS -c -o "$of" "$top_srcdir/$file"
|
||||
mkdir -p "${of%/*}" || exit 1
|
||||
if $CC $cflags $CPPFLAGS $CFLAGS -c -o "$of" "$top_srcdir/$file"; then
|
||||
: worked
|
||||
else
|
||||
$keep_going || die "Compilation failed."
|
||||
success=false
|
||||
fi
|
||||
|
||||
objs="${objs:+$objs }$of"
|
||||
done
|
||||
|
||||
$success
|
||||
}
|
||||
|
||||
# Use config.status to convert a .in file. Output file is put into $out.
|
||||
@@ -130,28 +144,39 @@ done
|
||||
# Get object files from the Makefile
|
||||
OBJS=$(get_mk_var Makefile make_OBJECTS | sed "s=\$[\(\{]OBJEXT[\)\}]=$OBJEXT=g")
|
||||
|
||||
# Exit as soon as any command fails.
|
||||
set -e
|
||||
while test -n "$1"; do
|
||||
case $1 in
|
||||
(-k) keep_going=true; shift ;;
|
||||
(--) shift; break ;;
|
||||
(-[h?]) usage 0 ;;
|
||||
(-*) echo "Unknown option: $1"; usage 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$1" || die "Unknown argument: $*"
|
||||
|
||||
# Generate gnulib header files that would normally be created by make
|
||||
set -e
|
||||
for b in $(get_mk_var lib/Makefile BUILT_SOURCES); do
|
||||
convert $b
|
||||
done
|
||||
set +e
|
||||
|
||||
# Build the gnulib library
|
||||
cflags="$DEFS -I$OUTLIB -Ilib -I$top_srcdir/lib -I$OUTDIR/src -Isrc -I$top_srcdir/src"
|
||||
compile $LIBOBJS
|
||||
compile $LIBOBJS || die "Compilation failed."
|
||||
|
||||
echo "creating libgnu.a..."
|
||||
$AR $ARFLAGS "$OUTLIB"/libgnu.a $objs
|
||||
$AR $ARFLAGS "$OUTLIB"/libgnu.a $objs || die "Archive of libgnu failed."
|
||||
|
||||
# Compile the source files into those objects.
|
||||
cflags="$DEFS $defines -I$OUTDIR/src -Isrc -I$top_srcdir/src -I$OUTLIB -Ilib -I$top_srcdir/lib"
|
||||
compile $OBJS
|
||||
compile $OBJS || die "Compilation failed."
|
||||
|
||||
# Link all the objects together.
|
||||
echo "linking make..."
|
||||
$CC $CFLAGS $LDFLAGS -L"$OUTLIB" $objs -lgnu $LOADLIBES -o "$OUTDIR/makenew$EXEEXT"
|
||||
mv -f "$OUTDIR/makenew$EXEEXT" "$OUTDIR/make$EXEEXT"
|
||||
$CC $CFLAGS $LDFLAGS -L"$OUTLIB" -o "$OUTDIR/makenew$EXEEXT" $objs -lgnu $LOADLIBES || die "Link failed."
|
||||
|
||||
mv -f "$OUTDIR/makenew$EXEEXT" "$OUTDIR/make$EXEEXT" || exit 1
|
||||
|
||||
echo done.
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU Make],[4.3.91],[bug-make@gnu.org])
|
||||
AC_INIT([GNU Make],[4.4],[bug-make@gnu.org])
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
@@ -175,15 +175,35 @@ AS_IF([test "x$with_guile" != xno],
|
||||
AC_MSG_RESULT([$guile_version])
|
||||
AS_IF([test "$have_guile" = yes],
|
||||
[ PKG_CHECK_MODULES(GUILE, [guile-$guile_version])
|
||||
# Unfortunately Guile requires a C99 compiler but GNU make doesn't, so
|
||||
# verify we can actually compile the header.
|
||||
# Unfortunately pkg doesn't help in multi-arch environments where the
|
||||
# package is installed for some architectures but not others; we need
|
||||
# to try to link.
|
||||
keep_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $pkg_cv_GUILE_CFLAGS"
|
||||
keep_LIBS="$LIBS"
|
||||
CPPFLAGS="$CPPFLAGS $GUILE_CFLAGS"
|
||||
LIBS="$LIBS $GUILE_LIBS"
|
||||
AC_CHECK_HEADER([libguile.h],
|
||||
[AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])],
|
||||
[have_guile=no],
|
||||
[/* Avoid configuration error warnings. */])
|
||||
AS_IF([test "$have_guile" = yes],
|
||||
[ AC_MSG_CHECKING([whether we can link GNU Guile])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <libguile.h>
|
||||
static void *
|
||||
guile_init (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
return 0;
|
||||
}
|
||||
]], [[
|
||||
scm_with_guile (guile_init, 0);
|
||||
]])],
|
||||
[have_guile=yes],
|
||||
[have_guile=no])
|
||||
AC_MSG_RESULT([$have_guile])])
|
||||
CPPFLAGS="$keep_CPPFLAGS"
|
||||
LIBS="$keep_LIBS"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@setfilename make.info
|
||||
|
||||
@include version.texi
|
||||
@set EDITION 0.75
|
||||
@set EDITION 0.76
|
||||
|
||||
@settitle GNU @code{make}
|
||||
@setchapternewpage odd
|
||||
|
||||
@@ -259,7 +259,8 @@ CFGCHECK_BUILDFLAGS =
|
||||
# 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+
|
||||
# We don't support C90 anymore, strictly, but this test still works (with lots
|
||||
# of warnings) and it helps us avoid egregious incompatibilities.
|
||||
checkcfg.strict-c90: CFGCHECK_CONFIGFLAGS = CFLAGS='-std=c90 -pedantic'
|
||||
checkcfg.strict-c90: CFGCHECK_MAKEFLAGS =
|
||||
|
||||
@@ -277,6 +278,7 @@ 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 \
|
||||
@@ -295,7 +297,7 @@ 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) \
|
||||
&& OUTDIR=_bld ../build.sh -k $(CFGCHECK_BUILD_FLAGS) \
|
||||
&& _bld/make GMK_OUTDIR=../_bld $(AM_MAKEFLAGS) check-local \
|
||||
&& _bld/make GMK_OUTDIR=../_bld $(AM_MAKEFLAGS) clean
|
||||
|
||||
|
||||
5
src/ar.c
5
src/ar.c
@@ -36,7 +36,7 @@ ar_name (const char *name)
|
||||
const char *p = strchr (name, '(');
|
||||
const char *end;
|
||||
|
||||
if (p == 0 || p == name)
|
||||
if (p == NULL || p == name)
|
||||
return 0;
|
||||
|
||||
end = p + strlen (p) - 1;
|
||||
@@ -61,6 +61,9 @@ ar_parse_name (const char *name, char **arname_p, char **memname_p)
|
||||
|
||||
*arname_p = xstrdup (name);
|
||||
p = strchr (*arname_p, '(');
|
||||
/* This is never called unless ar_name() is true so p cannot be NULL. */
|
||||
if (!p)
|
||||
OS (fatal, NILF, "Internal: ar_parse_name: bad name '%s'", *arname_p);
|
||||
*(p++) = '\0';
|
||||
p[strlen (p) - 1] = '\0';
|
||||
*memname_p = p;
|
||||
|
||||
10
src/dir.c
10
src/dir.c
@@ -521,7 +521,7 @@ find_directory (const char *name)
|
||||
/* See if the directory exists. */
|
||||
#if defined(WINDOWS32)
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
char tem[MAX_PATH+1], *tstart, *tend;
|
||||
size_t len = strlen (name);
|
||||
|
||||
/* Remove any trailing slashes. Windows32 stat fails even on
|
||||
@@ -601,7 +601,7 @@ find_directory (const char *name)
|
||||
/* Point the name-hashed entry for DIR at its contents data. */
|
||||
dir->contents = dc;
|
||||
|
||||
/* If the contents have changed, we need to reseet. */
|
||||
/* If the contents have changed, we need to reseed. */
|
||||
if (dc->counter != command_count)
|
||||
{
|
||||
if (dc->counter)
|
||||
@@ -1314,10 +1314,10 @@ local_stat (const char *path, struct stat *buf)
|
||||
foo/. => foo without checking first that foo is a directory. */
|
||||
if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2]))
|
||||
{
|
||||
char parent[MAXPATHLEN+1];
|
||||
char parent[MAX_PATH+1];
|
||||
|
||||
strncpy (parent, path, MAXPATHLEN);
|
||||
parent[MIN(plen - 2, MAXPATHLEN)] = '\0';
|
||||
strncpy (parent, path, MAX_PATH);
|
||||
parent[MIN(plen - 2, MAX_PATH)] = '\0';
|
||||
if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2811,7 +2811,8 @@ define_new_function (const floc *flocp, const char *name,
|
||||
ent->adds_command = 1;
|
||||
ent->fptr.alloc_func_ptr = func;
|
||||
|
||||
hash_insert (&function_table, ent);
|
||||
ent = hash_insert (&function_table, ent);
|
||||
free (ent);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
40
src/job.c
40
src/job.c
@@ -205,11 +205,10 @@ int getgid ();
|
||||
#endif
|
||||
|
||||
#if HAVE_SYS_LOADAVG_H
|
||||
# include <sys/time.h>
|
||||
# include <sys/loadavg.h>
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_GETLOADAVG
|
||||
#if HAVE_DECL_GETLOADAVG == 0
|
||||
int getloadavg (double loadavg[], int nelem);
|
||||
#endif
|
||||
|
||||
@@ -283,7 +282,7 @@ create_batch_file (char const *base, int unixy, int *fd)
|
||||
{
|
||||
const char *const ext = unixy ? "sh" : "bat";
|
||||
const char *error_string = NULL;
|
||||
char temp_path[MAXPATHLEN]; /* need to know its length */
|
||||
char temp_path[MAX_PATH+1]; /* need to know its length */
|
||||
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
|
||||
int path_is_dot = 0;
|
||||
/* The following variable is static so we won't try to reuse a name
|
||||
@@ -2092,6 +2091,7 @@ load_too_high (void)
|
||||
}
|
||||
|
||||
/* Find the real system load average. */
|
||||
errno = 0;
|
||||
if (getloadavg (&load, 1) != 1)
|
||||
{
|
||||
static int lossage = -1;
|
||||
@@ -2271,7 +2271,7 @@ child_execute_job (struct childbase *child, int good_stdin, char **argv)
|
||||
const int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
|
||||
int fdout = FD_STDOUT;
|
||||
int fderr = FD_STDERR;
|
||||
pid_t pid;
|
||||
pid_t pid = -1;
|
||||
int r;
|
||||
#if defined(USE_POSIX_SPAWN)
|
||||
char *cmd;
|
||||
@@ -3364,30 +3364,44 @@ construct_command_argv_internal (char *line, char **restp, const char *shell,
|
||||
#endif /* WINDOWS32 */
|
||||
/* Create an argv list for the shell command line. */
|
||||
{
|
||||
int n = 0;
|
||||
int n = 1;
|
||||
char *nextp;
|
||||
|
||||
new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *));
|
||||
new_argv[n++] = xstrdup (shell);
|
||||
|
||||
nextp = new_argv[0] = xmalloc (shell_len + sflags_len + line_len + 3);
|
||||
nextp = mempcpy (nextp, shell, shell_len + 1);
|
||||
|
||||
/* Chop up the shellflags (if any) and assign them. */
|
||||
if (! shellflags)
|
||||
new_argv[n++] = xstrdup ("");
|
||||
{
|
||||
new_argv[n++] = nextp;
|
||||
*(nextp++) = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parse shellflags using construct_command_argv_internal to
|
||||
handle quotes. */
|
||||
char **argv;
|
||||
char *f;
|
||||
f = alloca (sflags_len + 1); // +1 for null terminator.
|
||||
char *f = alloca (sflags_len + 1);
|
||||
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);
|
||||
if (argv)
|
||||
{
|
||||
char **a;
|
||||
for (a = argv; *a; ++a)
|
||||
{
|
||||
new_argv[n++] = nextp;
|
||||
nextp = stpcpy (nextp, *a) + 1;
|
||||
}
|
||||
free (argv[0]);
|
||||
free (argv);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the command to invoke. */
|
||||
new_argv[n++] = line;
|
||||
new_argv[n++] = nextp;
|
||||
memcpy(nextp, line, line_len + 1);
|
||||
new_argv[n++] = NULL;
|
||||
}
|
||||
return new_argv;
|
||||
|
||||
@@ -1182,6 +1182,11 @@ main (int argc, char **argv, char **envp)
|
||||
/* Useful for attaching debuggers, etc. */
|
||||
SPIN ("main-entry");
|
||||
|
||||
/* Don't die if our stdout sends us SIGPIPE. */
|
||||
#ifdef SIGPIPE
|
||||
bsd_signal (SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
if (ANY_SET (check_io_state (), IO_STDOUT_OK))
|
||||
atexit (close_stdout);
|
||||
@@ -1385,6 +1390,10 @@ main (int argc, char **argv, char **envp)
|
||||
|
||||
initialize_global_hash_tables ();
|
||||
|
||||
/* Ensure the temp directory is set up: we don't want the first time we use
|
||||
it to be in a forked process. */
|
||||
get_tmpdir ();
|
||||
|
||||
/* Figure out where we are. */
|
||||
|
||||
#ifdef WINDOWS32
|
||||
|
||||
@@ -152,13 +152,14 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# ifndef POSIX
|
||||
# ifdef MAXPATHLEN
|
||||
# define PATH_MAX MAXPATHLEN
|
||||
# else
|
||||
/* Some systems (HURD) have fully dynamic pathnames with no maximum.
|
||||
Ideally we'd support this but it will take some work. */
|
||||
# define PATH_MAX 4096
|
||||
# endif
|
||||
#endif
|
||||
#ifndef MAXPATHLEN
|
||||
# define MAXPATHLEN 1024
|
||||
#endif
|
||||
|
||||
#ifdef PATH_MAX
|
||||
# define GET_PATH_MAX PATH_MAX
|
||||
@@ -494,6 +495,8 @@ extern struct rlimit stack_limit;
|
||||
|
||||
/* Number of characters in a string constant. Does NOT include the \0 byte. */
|
||||
#define CSTRLEN(_s) (sizeof (_s)-1)
|
||||
|
||||
/* Only usable when NOT calling a macro: only use it for local functions. */
|
||||
#define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s)
|
||||
|
||||
/* The number of bytes needed to represent the largest signed and unsigned
|
||||
@@ -657,8 +660,12 @@ int unload_file (const char *name);
|
||||
#ifdef MAKE_MAINTAINER_MODE
|
||||
# define SPIN(_s) spin (_s)
|
||||
void spin (const char* suffix);
|
||||
# define DBG(_f) dbg _f
|
||||
void dbg (const char *fmt, ...);
|
||||
#else
|
||||
# define SPIN(_s)
|
||||
/* Never put this code into Git or a release. */
|
||||
# define DBG(_f) compile-error
|
||||
#endif
|
||||
|
||||
/* We omit these declarations on non-POSIX systems which define _POSIX_VERSION,
|
||||
|
||||
63
src/misc.c
63
src/misc.c
@@ -530,6 +530,22 @@ spin (const char* type)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dbg (const char *fmt, ...)
|
||||
{
|
||||
FILE *fp = fopen ("/tmp/gmkdebug.log", "a+");
|
||||
va_list args;
|
||||
char buf[4096];
|
||||
|
||||
va_start (args, fmt);
|
||||
vsprintf (buf, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf(fp, "%u: %s\n", (unsigned) make_pid (), buf);
|
||||
fflush (fp);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -552,7 +568,6 @@ umask (mode_t mask)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAKE_TMPDIR "MAKE_TMPDIR"
|
||||
#ifdef VMS
|
||||
# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
|
||||
#else
|
||||
@@ -566,13 +581,36 @@ get_tmpdir ()
|
||||
|
||||
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')
|
||||
# define TMP_EXTRAS "TMP", "TEMP",
|
||||
#else
|
||||
# define TMP_EXTRAS
|
||||
#endif
|
||||
&& ((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
|
||||
tmpdir = DEFAULT_TMPDIR;
|
||||
const char *tlist[] = { "MAKE_TMPDIR", "TMPDIR", TMP_EXTRAS NULL };
|
||||
const char **tp;
|
||||
unsigned int found = 0;
|
||||
|
||||
for (tp = tlist; *tp; ++tp)
|
||||
if ((tmpdir = getenv (*tp)) && *tmpdir != '\0')
|
||||
{
|
||||
struct stat st;
|
||||
int r;
|
||||
found = 1;
|
||||
EINTRLOOP(r, stat (tmpdir, &st));
|
||||
if (r < 0)
|
||||
OSSS (error, NILF,
|
||||
_("%s value %s: %s"), *tp, tmpdir, strerror (errno));
|
||||
else if (! S_ISDIR (st.st_mode))
|
||||
OSS (error, NILF,
|
||||
_("%s value %s: not a directory"), *tp, tmpdir);
|
||||
else
|
||||
return tmpdir;
|
||||
}
|
||||
|
||||
tmpdir = DEFAULT_TMPDIR;
|
||||
|
||||
if (found)
|
||||
OS (error, NILF, _("using default temporary directory '%s'"), tmpdir);
|
||||
}
|
||||
|
||||
return tmpdir;
|
||||
@@ -630,6 +668,7 @@ 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)
|
||||
@@ -639,6 +678,10 @@ get_tmpfd (char **name)
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Preserve the current umask, and set a restrictive one for temp files.
|
||||
Only really needed for mkstemp() but won't hurt for the open method. */
|
||||
mask = umask (0077);
|
||||
|
||||
#if defined(HAVE_MKSTEMP)
|
||||
tmpnm = get_tmptemplate ();
|
||||
|
||||
@@ -666,6 +709,8 @@ get_tmpfd (char **name)
|
||||
free (tmpnm);
|
||||
}
|
||||
|
||||
umask (mask);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -769,11 +814,11 @@ get_path_max (void)
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
long int x = pathconf ("/", _PC_PATH_MAX);
|
||||
long x = pathconf ("/", _PC_PATH_MAX);
|
||||
if (x > 0)
|
||||
value = x;
|
||||
value = (unsigned int) x;
|
||||
else
|
||||
return MAXPATHLEN;
|
||||
value = PATH_MAX;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
60
src/output.c
60
src/output.c
@@ -51,20 +51,24 @@ unsigned int stdio_traced = 0;
|
||||
static void
|
||||
_outputs (struct output *out, int is_err, const char *msg)
|
||||
{
|
||||
if (! out || ! out->syncout)
|
||||
{
|
||||
FILE *f = is_err ? stderr : stdout;
|
||||
fputs (msg, f);
|
||||
fflush (f);
|
||||
}
|
||||
else
|
||||
FILE *f;
|
||||
|
||||
if (out && out->syncout)
|
||||
{
|
||||
int fd = is_err ? out->err : out->out;
|
||||
size_t len = strlen (msg);
|
||||
int r;
|
||||
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
|
||||
writebuf (fd, msg, len);
|
||||
if (fd != OUTPUT_NONE)
|
||||
{
|
||||
size_t len = strlen (msg);
|
||||
int r;
|
||||
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
|
||||
writebuf (fd, msg, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
f = is_err ? stderr : stdout;
|
||||
fputs (msg, f);
|
||||
fflush (f);
|
||||
}
|
||||
|
||||
/* Write a message indicating that we've just entered or
|
||||
@@ -198,7 +202,16 @@ output_tmpfd (void)
|
||||
static void
|
||||
setup_tmpfile (struct output *out)
|
||||
{
|
||||
unsigned int io_state = check_io_state ();
|
||||
static unsigned int in_setup = 0;
|
||||
unsigned int io_state;
|
||||
|
||||
/* If something fails during setup we might recurse back into this function
|
||||
while writing errors. Make sure we don't do so infinitely. */
|
||||
if (in_setup)
|
||||
return;
|
||||
in_setup = 1;
|
||||
|
||||
io_state = check_io_state ();
|
||||
|
||||
if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK))
|
||||
{
|
||||
@@ -230,6 +243,7 @@ setup_tmpfile (struct output *out)
|
||||
}
|
||||
}
|
||||
|
||||
in_setup = 0;
|
||||
return;
|
||||
|
||||
/* If we failed to create a temp file, disable output sync going forward. */
|
||||
@@ -237,6 +251,7 @@ setup_tmpfile (struct output *out)
|
||||
output_close (out);
|
||||
output_sync = OUTPUT_SYNC_NONE;
|
||||
osync_clear ();
|
||||
in_setup = 0;
|
||||
}
|
||||
|
||||
/* Synchronize the output of jobs in -j mode to keep the results of
|
||||
@@ -394,10 +409,11 @@ void
|
||||
message (int prefix, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *start;
|
||||
char *p;
|
||||
|
||||
len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
|
||||
p = get_buffer (len);
|
||||
start = p = get_buffer (len);
|
||||
|
||||
if (prefix)
|
||||
{
|
||||
@@ -414,8 +430,8 @@ message (int prefix, size_t len, const char *fmt, ...)
|
||||
|
||||
strcat (p, "\n");
|
||||
|
||||
assert (fmtbuf.buffer[len-1] == '\0');
|
||||
outputs (0, fmtbuf.buffer);
|
||||
assert (start[len-1] == '\0');
|
||||
outputs (0, start);
|
||||
}
|
||||
|
||||
/* Print an error message. */
|
||||
@@ -424,12 +440,13 @@ void
|
||||
error (const floc *flocp, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *start;
|
||||
char *p;
|
||||
|
||||
len += (strlen (fmt) + strlen (program)
|
||||
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
|
||||
+ INTSTR_LENGTH + 4 + 1 + 1);
|
||||
p = get_buffer (len);
|
||||
start = p = get_buffer (len);
|
||||
|
||||
if (flocp && flocp->filenm)
|
||||
sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
|
||||
@@ -445,8 +462,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...)
|
||||
|
||||
strcat (p, "\n");
|
||||
|
||||
assert (fmtbuf.buffer[len-1] == '\0');
|
||||
outputs (1, fmtbuf.buffer);
|
||||
assert (start[len-1] == '\0');
|
||||
outputs (1, start);
|
||||
}
|
||||
|
||||
/* Print an error message and exit. */
|
||||
@@ -456,12 +473,13 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char *stop = _(". Stop.\n");
|
||||
char *start;
|
||||
char *p;
|
||||
|
||||
len += (strlen (fmt) + strlen (program)
|
||||
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
|
||||
+ INTSTR_LENGTH + 8 + strlen (stop) + 1);
|
||||
p = get_buffer (len);
|
||||
start = p = get_buffer (len);
|
||||
|
||||
if (flocp && flocp->filenm)
|
||||
sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
|
||||
@@ -477,8 +495,8 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
|
||||
|
||||
strcat (p, stop);
|
||||
|
||||
assert (fmtbuf.buffer[len-1] == '\0');
|
||||
outputs (1, fmtbuf.buffer);
|
||||
assert (start[len-1] == '\0');
|
||||
outputs (1, start);
|
||||
|
||||
die (MAKE_FAILURE);
|
||||
}
|
||||
|
||||
@@ -673,6 +673,7 @@ osync_parse_mutex (const char *mutex)
|
||||
return 0;
|
||||
}
|
||||
|
||||
free (osync_tmpfile);
|
||||
osync_tmpfile = xstrdup (mutex + CSTRLEN (MUTEX_PREFIX));
|
||||
|
||||
EINTRLOOP (osync_handle, open (osync_tmpfile, O_WRONLY));
|
||||
@@ -699,6 +700,7 @@ osync_clear ()
|
||||
int r;
|
||||
|
||||
EINTRLOOP (r, unlink (osync_tmpfile));
|
||||
free (osync_tmpfile);
|
||||
osync_tmpfile = NULL;
|
||||
}
|
||||
}
|
||||
@@ -838,17 +840,28 @@ fd_set_append (int fd)
|
||||
int
|
||||
os_anontmp ()
|
||||
{
|
||||
const char *tdir = get_tmpdir ();
|
||||
int fd = -1;
|
||||
|
||||
#ifdef O_TMPFILE
|
||||
EINTRLOOP (fd, open (get_tmpdir (), O_RDWR | O_TMPFILE | O_EXCL, 0600));
|
||||
if (fd < 0)
|
||||
pfatal_with_name ("open(O_TMPFILE)");
|
||||
#elif HAVE_DUP
|
||||
/* We don't have O_TMPFILE but we can dup: if we are creating temp files in
|
||||
the default location then try tmpfile() + dup() + fclose() to avoid ever
|
||||
having a name for a file. */
|
||||
if (streq (get_tmpdir (), DEFAULT_TMPDIR))
|
||||
static unsigned int tmpfile_works = 1;
|
||||
|
||||
if (tmpfile_works)
|
||||
{
|
||||
EINTRLOOP (fd, open (tdir, O_RDWR | O_TMPFILE | O_EXCL, 0600));
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
DB (DB_BASIC, (_("Cannot open '%s' with O_TMPFILE: %s.\n"),
|
||||
tdir, strerror (errno)));
|
||||
tmpfile_works = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_DUP
|
||||
/* If we can dup and we are creating temp files in the default location then
|
||||
try tmpfile() + dup() + fclose() to avoid ever having a named file. */
|
||||
if (streq (tdir, DEFAULT_TMPDIR))
|
||||
{
|
||||
mode_t mask = umask (0077);
|
||||
FILE *tfile;
|
||||
|
||||
35
src/read.c
35
src/read.c
@@ -375,23 +375,26 @@ eval_makefile (const char *filename, unsigned short flags)
|
||||
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);
|
||||
{
|
||||
const char **dir;
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
70
src/remake.c
70
src/remake.c
@@ -34,6 +34,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <starlet.h>
|
||||
#endif
|
||||
#ifdef WINDOWS32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
@@ -81,19 +82,20 @@ static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
|
||||
static void
|
||||
check_also_make (const struct file *file)
|
||||
{
|
||||
/* If the target was created by an implicit rule, and it exists and was
|
||||
updated, warn about any of its also_make targets that don't exist. */
|
||||
if (file->tried_implicit && is_ordinary_mtime (file->last_mtime)
|
||||
&& file->last_mtime > file->mtime_before_update)
|
||||
{
|
||||
struct dep *ad;
|
||||
struct dep *ad;
|
||||
FILE_TIMESTAMP mtime = file->last_mtime;
|
||||
|
||||
for (ad = file->also_make; ad; ad = ad->next)
|
||||
if (ad->file->last_mtime == NONEXISTENT_MTIME)
|
||||
OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
|
||||
_("warning: pattern recipe did not update peer target '%s'."),
|
||||
ad->file->name);
|
||||
}
|
||||
if (mtime == UNKNOWN_MTIME)
|
||||
mtime = name_mtime (file->name);
|
||||
|
||||
/* If we updated the file, check its also-make files. */
|
||||
|
||||
if (is_ordinary_mtime (mtime) && mtime > file->mtime_before_update)
|
||||
for (ad = file->also_make; ad; ad = ad->next)
|
||||
if (ad->file->last_mtime == NONEXISTENT_MTIME)
|
||||
OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
|
||||
_("warning: pattern recipe did not update peer target '%s'."),
|
||||
ad->file->name);
|
||||
}
|
||||
|
||||
/* Remake all the goals in the 'struct dep' chain GOALS. Return update_status
|
||||
@@ -205,8 +207,6 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
FILE_TIMESTAMP mtime = MTIME (file);
|
||||
check_renamed (file);
|
||||
|
||||
check_also_make (file);
|
||||
|
||||
if (file->updated && mtime != file->mtime_before_update)
|
||||
{
|
||||
/* Updating was done. If this is a makefile and
|
||||
@@ -1039,23 +1039,30 @@ notice_finished_file (struct file *file)
|
||||
}
|
||||
|
||||
if (ran && file->update_status != us_none)
|
||||
/* We actually tried to update FILE, which has
|
||||
updated its also_make's as well (if it worked).
|
||||
If it didn't work, it wouldn't work again for them.
|
||||
So mark them as updated with the same status. */
|
||||
for (d = file->also_make; d != 0; d = d->next)
|
||||
{
|
||||
d->file->command_state = cs_finished;
|
||||
d->file->updated = 1;
|
||||
d->file->update_status = file->update_status;
|
||||
{
|
||||
/* We actually tried to update FILE, which has
|
||||
updated its also_make's as well (if it worked).
|
||||
If it didn't work, it wouldn't work again for them.
|
||||
So mark them as updated with the same status. */
|
||||
for (d = file->also_make; d != 0; d = d->next)
|
||||
{
|
||||
d->file->command_state = cs_finished;
|
||||
d->file->updated = 1;
|
||||
d->file->update_status = file->update_status;
|
||||
|
||||
if (ran && !d->file->phony)
|
||||
/* Fetch the new modification time.
|
||||
We do this instead of just invalidating the cached time
|
||||
so that a vpath_search can happen. Otherwise, it would
|
||||
never be done because the target is already updated. */
|
||||
f_mtime (d->file, 0);
|
||||
}
|
||||
if (ran && !d->file->phony)
|
||||
/* Fetch the new modification time.
|
||||
We do this instead of just invalidating the cached time
|
||||
so that a vpath_search can happen. Otherwise, it would
|
||||
never be done because the target is already updated. */
|
||||
f_mtime (d->file, 0);
|
||||
}
|
||||
|
||||
/* If the target was created by an implicit rule, and it was updated,
|
||||
warn about any of its also_make targets that don't exist. */
|
||||
if (file->tried_implicit && file->also_make)
|
||||
check_also_make (file);
|
||||
}
|
||||
else if (file->update_status == us_none)
|
||||
/* Nothing was done for FILE, but it needed nothing done.
|
||||
So mark it now as "succeeded". */
|
||||
@@ -1094,7 +1101,6 @@ check_dep (struct file *file, unsigned int depth,
|
||||
check_renamed (file);
|
||||
if (mtime == NONEXISTENT_MTIME || mtime > this_mtime)
|
||||
*must_make_ptr = 1;
|
||||
check_also_make (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1546,7 +1552,7 @@ name_mtime (const char *name)
|
||||
|
||||
#if defined(WINDOWS32)
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
char tem[MAX_PATH+1], *tstart, *tend;
|
||||
const char *p = name + strlen (name);
|
||||
|
||||
/* Remove any trailing slashes and "."/"..". MS-Windows stat
|
||||
|
||||
@@ -94,7 +94,7 @@ get_rule_defn (struct rule *r)
|
||||
if (dep->ignore_mtime == 0)
|
||||
{
|
||||
if (dep->wait_here)
|
||||
p = mempcpy (p, STRING_SIZE_TUPLE (" .WAIT"));
|
||||
p = mempcpy (p, " .WAIT", CSTRLEN (" .WAIT"));
|
||||
p = mempcpy (mempcpy (p, " ", 1), dep_name (dep),
|
||||
strlen (dep_name (dep)));
|
||||
}
|
||||
@@ -107,7 +107,7 @@ get_rule_defn (struct rule *r)
|
||||
{
|
||||
p = mempcpy (p, sep, strlen (sep));
|
||||
if (ood->wait_here)
|
||||
p = mempcpy (p, STRING_SIZE_TUPLE (".WAIT "));
|
||||
p = mempcpy (p, ".WAIT ", CSTRLEN (".WAIT "));
|
||||
p = mempcpy (p, dep_name (ood), strlen (dep_name (ood)));
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
@@ -115,7 +115,7 @@ check_io_state ()
|
||||
int
|
||||
os_anontmp ()
|
||||
{
|
||||
char temp_path[MAXPATHLEN];
|
||||
char temp_path[MAX_PATH+1];
|
||||
unsigned path_size = GetTempPath (sizeof (temp_path), temp_path);
|
||||
int using_cwd = 0;
|
||||
|
||||
|
||||
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.test-result
|
||||
config-flags.pm
|
||||
work
|
||||
|
||||
54
tests/README
54
tests/README
@@ -23,10 +23,9 @@ distributed under the following terms:
|
||||
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
The test suite requires Perl. These days, you should have at least Perl
|
||||
5.004 (available from ftp.gnu.org, and portable to many machines). It
|
||||
used to work with Perl 4.036 but official support for Perl 4.x was
|
||||
abandoned a long time ago, due to lack of testbeds, as well as interest.
|
||||
The test suite requires Perl. These days, you should have at least Perl 5.6.
|
||||
Newer versions may be required: I don't test regularly with older versions
|
||||
than what is installed by default on my development systems.
|
||||
|
||||
The test suite assumes that the first "diff" it finds on your PATH is
|
||||
GNU diff, but that only matters if a test fails.
|
||||
@@ -54,14 +53,6 @@ with your network or file server, not GNU make (I believe). This
|
||||
shouldn't happen very often anymore: I've done a lot of work on the
|
||||
tests to reduce the impacts of this situation.
|
||||
|
||||
The options/dash-l test will not really test anything if the copy of
|
||||
make you are using can't obtain the system load. Some systems require
|
||||
make to be setgid sys or kmem for this; if you don't want to install
|
||||
make just to test it, make it setgid to kmem or whatever group /dev/kmem
|
||||
is (i.e., "chgrp kmem make;chmod g+s make" as root). In any case, the
|
||||
options/dash-l test should no longer *fail* because make can't read
|
||||
/dev/kmem.
|
||||
|
||||
A directory named "work" will be created when the tests are run which
|
||||
will contain any makefiles and "diff" files of tests that fail so that
|
||||
you may look at them afterward to see the output of make and the
|
||||
@@ -74,28 +65,35 @@ other possible options for the test suite.
|
||||
Open Issues
|
||||
-----------
|
||||
|
||||
The test suite has a number of problems which should be addressed. One
|
||||
VERY serious one is that there is no real documentation. You just have
|
||||
to see the existing tests. Use the newer tests: many of the tests
|
||||
haven't been updated to use the latest/greatest test methods. See the
|
||||
ChangeLog in the tests directory for pointers.
|
||||
The test suite has a number of problems which should be addressed. One VERY
|
||||
serious one is that there is no real documentation. You just have to see the
|
||||
existing tests. Use the newer tests: many of the tests haven't been updated
|
||||
to use the latest/greatest test methods. See the ChangeLogs for pointers.
|
||||
|
||||
The second serious problem is that it's not parallelizable: it scribbles
|
||||
all over its installation directory and so can only test one make at a
|
||||
time. The third serious problem is that it's not relocatable: the only
|
||||
way it works when you build out of the source tree is to create
|
||||
symlinks, which doesn't work on every system and is bogus to boot. The
|
||||
fourth serious problem is that it doesn't create its own sandbox when
|
||||
running tests, so that if a test forgets to clean up after itself that
|
||||
can impact future tests.
|
||||
The second serious problem is that it's not relocatable: when you build out of
|
||||
the source tree it creates symlinks, which doesn't work on every system and is
|
||||
just bogus to boot.
|
||||
|
||||
The third serious problem is that it's not parallelizable: it scribbles all
|
||||
over its installation directory and so can only test one make at a time.
|
||||
|
||||
The fourth serious problem is that since the tests scribble all over the same
|
||||
directory (a) they can interfere with each other and (b) we cannot preserve
|
||||
the full environment for every test, if it involves creating temporary files
|
||||
etc. as they must be deleted before the next test.
|
||||
|
||||
To solve these the suite should create a separate directory for EVERY test,
|
||||
local to the build directory, and all temporary files should exist in that
|
||||
directory. The directory can be preserved on error, or removed if the test
|
||||
succeeds (unless --keep is given).
|
||||
|
||||
|
||||
Bugs
|
||||
----
|
||||
|
||||
Any complaints/suggestions/bugs/etc. for the test suite itself (as
|
||||
opposed to problems in make that the suite finds) should be handled the
|
||||
same way as normal GNU make bugs/problems (see the README for GNU make).
|
||||
Any complaints/suggestions/bugs/etc. for the test suite itself should be
|
||||
handled the same way as normal GNU make bugs/problems (see the README for GNU
|
||||
make).
|
||||
|
||||
|
||||
Paul D. Smith
|
||||
|
||||
@@ -110,73 +110,6 @@ $ERR_nonexe_file = undef;
|
||||
$ERR_exe_dir = undef;
|
||||
$ERR_command_not_found = undef;
|
||||
|
||||
{
|
||||
use locale;
|
||||
|
||||
my $loc = undef;
|
||||
if ($has_POSIX) {
|
||||
POSIX->import(qw(locale_h));
|
||||
# Windows has POSIX locale, but only LC_ALL not LC_MESSAGES
|
||||
$loc = POSIX::setlocale(&POSIX::LC_ALL);
|
||||
POSIX::setlocale(&POSIX::LC_ALL, 'C');
|
||||
|
||||
# See set_defaults() as this doesn't work right on Windows :(
|
||||
$! = &POSIX::ERANGE;
|
||||
}
|
||||
|
||||
if (open(my $F, '<', 'file.none')) {
|
||||
print "Opened non-existent file! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_no_such_file = "$!";
|
||||
}
|
||||
|
||||
unlink('file.out');
|
||||
touch('file.out');
|
||||
|
||||
chmod(0444, 'file.out');
|
||||
if (open(my $F, '>', 'file.out')) {
|
||||
print "Opened read-only file! Skipping related tests.\n";
|
||||
close($F);
|
||||
} else {
|
||||
$ERR_read_only_file = "$!";
|
||||
}
|
||||
|
||||
$_ = `./file.out 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed non-executable file! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_nonexe_file = "$!";
|
||||
}
|
||||
|
||||
$_ = `./. 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed directory! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_exe_dir = "$!";
|
||||
}
|
||||
|
||||
chmod(0000, 'file.out');
|
||||
if (open(my $F, '<', 'file.out')) {
|
||||
print "Opened unreadable file! Skipping related tests.\n";
|
||||
close($F);
|
||||
} else {
|
||||
$ERR_unreadable_file = "$!";
|
||||
}
|
||||
|
||||
unlink('file.out') or die "Failed to delete file.out: $!\n";
|
||||
|
||||
$_ = `/bin/sh -c 'bad-command 2>&1'`;
|
||||
if ($? == 0) {
|
||||
print "Invoked invalid file! Skipping related tests.\n";
|
||||
} else {
|
||||
chomp($_);
|
||||
s/bad-command/#CMDNAME#/g;
|
||||
$ERR_command_not_found = $_;
|
||||
}
|
||||
|
||||
$loc and POSIX::setlocale(&POSIX::LC_ALL, $loc);
|
||||
}
|
||||
|
||||
#$SIG{INT} = sub { print STDERR "Caught a signal!\n"; die @_; };
|
||||
|
||||
sub valid_option
|
||||
@@ -472,6 +405,81 @@ sub set_defaults
|
||||
} else {
|
||||
$scriptsuffix = '.bat';
|
||||
}
|
||||
|
||||
$ENV{LC_ALL} = $makeENV{LC_ALL};
|
||||
$ENV{LANG} = $makeENV{LANG};
|
||||
$ENV{LANGUAGE} = $makeENV{LANGUAGE};
|
||||
|
||||
use locale;
|
||||
|
||||
my $loc = undef;
|
||||
if ($has_POSIX) {
|
||||
POSIX->import(qw(locale_h));
|
||||
# Windows has POSIX locale, but only LC_ALL not LC_MESSAGES
|
||||
$loc = POSIX::setlocale(&POSIX::LC_ALL);
|
||||
POSIX::setlocale(&POSIX::LC_ALL, 'C');
|
||||
}
|
||||
|
||||
if (open(my $F, '<', 'file.none')) {
|
||||
print "Opened non-existent file! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_no_such_file = "$!";
|
||||
}
|
||||
|
||||
unlink('file.out');
|
||||
touch('file.out');
|
||||
|
||||
chmod(0444, 'file.out');
|
||||
if (open(my $F, '>', 'file.out')) {
|
||||
print "Opened read-only file! Skipping related tests.\n";
|
||||
close($F);
|
||||
} else {
|
||||
$ERR_read_only_file = "$!";
|
||||
}
|
||||
|
||||
$_ = `./file.out 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed non-executable file! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_nonexe_file = "$!";
|
||||
}
|
||||
|
||||
if ($^O =~ /cygwin/i) {
|
||||
# For some reason the execute here gives a different answer than make's
|
||||
print "Skipping directory execution on $^O\n";
|
||||
} else {
|
||||
$_ = `./. 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed directory! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_exe_dir = "$!";
|
||||
}
|
||||
}
|
||||
|
||||
chmod(0000, 'file.out');
|
||||
if (open(my $F, '<', 'file.out')) {
|
||||
print "Opened unreadable file! Skipping related tests.\n";
|
||||
close($F);
|
||||
} else {
|
||||
$ERR_unreadable_file = "$!";
|
||||
}
|
||||
|
||||
unlink('file.out') or die "Failed to delete file.out: $!\n";
|
||||
|
||||
$_ = `/bin/sh -c 'bad-command 2>&1'`;
|
||||
if ($? == 0) {
|
||||
print "Invoked invalid file! Skipping related tests.\n";
|
||||
} else {
|
||||
chomp($_);
|
||||
s/bad-command/#CMDNAME#/g;
|
||||
$ERR_command_not_found = $_;
|
||||
}
|
||||
|
||||
$loc and POSIX::setlocale(&POSIX::LC_ALL, $loc);
|
||||
|
||||
$ENV{LC_ALL} = $origENV{LC_ALL};
|
||||
$ENV{LANG} = $origENV{LANG};
|
||||
$ENV{LANGUAGE} = $origENV{LANGUAGE};
|
||||
}
|
||||
|
||||
# This is no longer used: we import config-flags.pm instead
|
||||
|
||||
@@ -99,7 +99,7 @@ if ($ERR_nonexe_file) {
|
||||
# Try failing by "running" a directory
|
||||
|
||||
if ($ERR_exe_dir) {
|
||||
mkdir('sd', 0775);
|
||||
mkdir('sd', 0775) or print "mkdir: sd: $!\n";
|
||||
|
||||
run_make_test(q!
|
||||
PATH := .
|
||||
|
||||
@@ -13,12 +13,21 @@ my $details = "The various shells that this test uses are the default"
|
||||
|
||||
# Only bother with this on UNIX systems
|
||||
$port_type eq 'UNIX' or return -1;
|
||||
$^O =~ /cygwin/ and return -1;
|
||||
|
||||
my @shbangs = ('', '#!/bin/sh', "#!$perl_name");
|
||||
my @shells = ('', 'SHELL=/bin/sh');
|
||||
|
||||
# Try whatever shell the user has, as long as it's not a C shell.
|
||||
# The C shell is not usable with make, due to not correctly handling
|
||||
# file descriptors and possibly other issues.
|
||||
my $usersh = $origENV{SHELL};
|
||||
my $answer = 'hello, world';
|
||||
if ($usersh !~ /csh/) {
|
||||
push @shbangs, ("#!$usersh");
|
||||
push @shells, ("SHELL=$usersh");
|
||||
}
|
||||
|
||||
my @shbangs = ('', '#!/bin/sh', "#!$usersh", "#!$perl_name");
|
||||
my @shells = ('', 'SHELL=/bin/sh', "SHELL=$usersh");
|
||||
my $answer = 'hello, world';
|
||||
|
||||
# tests [0-11]
|
||||
# Have a makefile with various SHELL= exec a shell program with varios
|
||||
@@ -36,7 +45,7 @@ for my $shbang (@shbangs) {
|
||||
close(CMD);
|
||||
chmod 0700, $cmd;
|
||||
|
||||
run_make_test("# $shbang\n# $shell" . q!
|
||||
run_make_test("# shbang=$shbang\n# shell=$shell" . q!
|
||||
all:; @$(CMD)
|
||||
!, "$shell CMD=$cmd", "$answer\n");
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info hello.c)
|
||||
%$s:$r %.f; \$(info hello.f)
|
||||
hello.c:; false
|
||||
", '-r', "false\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
hello.c:; @#HELPER# fail 1
|
||||
", '-r', "fail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
|
||||
# Test that make finds the intended implicit rule based on existence of a
|
||||
# prerequisite in the filesystem, even when the prerequisite of another
|
||||
@@ -115,9 +115,9 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info \$<)
|
||||
%$s:$r %.f; \$(info \$<)
|
||||
.DEFAULT:; \$(info \$\@) false
|
||||
.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1
|
||||
unrelated: hello.c
|
||||
", '-r', "hello.c\nfalse\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
", '-r', "hello.c\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
|
||||
# hello.f is missing.
|
||||
# No rule is found, because hello.c is not mentioned explicitly.
|
||||
@@ -125,8 +125,8 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info \$<)
|
||||
%$s:$r %.f; \$(info \$<)
|
||||
.DEFAULT:; \@\$(info \$\@) false
|
||||
", '-r', "hello$s\n#MAKE#: *** [#MAKEFILE#:5: hello$s] Error 1\n", 512);
|
||||
.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1
|
||||
", '-r', "hello$s\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello$s] Error 1\n", 512);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,7 @@ for my $r (@rules) {
|
||||
|
||||
my $result = "#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n";
|
||||
if ($s or $r) {
|
||||
$result = "false\n#MAKE#: *** [#MAKEFILE#:6: hello.c] Error 1\n";
|
||||
$result = "fail 1\n#MAKE#: *** [#MAKEFILE#:6: hello.c] Error 1\n";
|
||||
}
|
||||
|
||||
run_make_test("
|
||||
@@ -210,7 +210,7 @@ all: hello.tsk
|
||||
%.tsk: %$s; \$(info hello.tsk)
|
||||
%$s:$r %.c; \$(info hello.c)
|
||||
%$s:$r %.f; \$(info hello.f)
|
||||
hello.c:; false
|
||||
hello.c:; @#HELPER# fail 1
|
||||
", '-r', $result, 512);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +190,10 @@ run_make_test("
|
||||
load testapi.so
|
||||
$extra_loads
|
||||
all:; \$(info \$(test-expand hello))
|
||||
testapi.so: force; false
|
||||
testapi.so: force; @#HELPER# fail 1
|
||||
force:;
|
||||
.PHONY: force
|
||||
", '', "testapi_gmk_setup\nfalse\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512);
|
||||
", '', "testapi_gmk_setup\nfail 1\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512);
|
||||
|
||||
# sv 63045.
|
||||
# Same as above, but testapi_gmk_setup returned -1.
|
||||
@@ -203,7 +203,7 @@ run_make_test("
|
||||
load testapi.so
|
||||
$extra_loads
|
||||
all:; \$(info \$(test-expand hello))
|
||||
testapi.so: force; false
|
||||
testapi.so: force; @#HELPER# fail 1
|
||||
force:;
|
||||
.PHONY: force
|
||||
", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n");
|
||||
|
||||
@@ -116,20 +116,24 @@ EOF
|
||||
close(MAKEFILE);
|
||||
|
||||
# Test per-make synchronization.
|
||||
# Note we have to sleep again here after starting the foo makefile before
|
||||
# starting the bar makefile, otherwise the "entering/leaving" messages for the
|
||||
# submakes might be ordered differently than we expect.
|
||||
|
||||
unlink(@syncfiles);
|
||||
run_make_test(qq!
|
||||
all: make-foo make-bar
|
||||
|
||||
make-foo: ; \$(MAKE) -C foo
|
||||
|
||||
make-bar: ; \$(MAKE) -C bar!,
|
||||
make-bar: ; #HELPER# -q sleep 1 ; \$(MAKE) -C bar!,
|
||||
'-j -Orecurse',
|
||||
"#MAKEPATH# -C foo
|
||||
#MAKE#[1]: Entering directory '#PWD#/foo'
|
||||
foo: start
|
||||
foo: end
|
||||
#MAKE#[1]: Leaving directory '#PWD#/foo'
|
||||
#MAKEPATH# -C bar
|
||||
#HELPER# -q sleep 1 ; #MAKEPATH# -C bar
|
||||
#MAKE#[1]: Entering directory '#PWD#/bar'
|
||||
bar: start
|
||||
bar: end
|
||||
@@ -352,10 +356,12 @@ use POSIX ();
|
||||
# Test that make removes temporary files, even when a signal is received.
|
||||
# The general test_driver postprocessing will ensure the temporary file used
|
||||
# to synchronize output and the jobserver fifo are both removed.
|
||||
# sleep is needed to let make write its "... Terminated" message to the log
|
||||
# file.
|
||||
run_make_test(q!
|
||||
pid:=$(shell echo $$PPID)
|
||||
all:; @kill -TERM $(pid)
|
||||
!, '-O -j2', "", POSIX::SIGTERM);
|
||||
all:; @kill -TERM $(pid) && sleep 16
|
||||
!, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM);
|
||||
}
|
||||
|
||||
unlink($fout);
|
||||
|
||||
@@ -75,7 +75,6 @@ rmfiles(qw(ONE.inc TWO.inc THREE.inc ONE TWO THREE 1.inc 2.inc));
|
||||
# function in an exported recursive variable. I added some code to check
|
||||
# for this situation and print a message if it occurred. This test used
|
||||
# to trigger this code when I added it but no longer does after the fix.
|
||||
# We have to increase the timeout from the default (5s) on this test.
|
||||
|
||||
run_make_test(q!
|
||||
export HI = $(shell $($@.CMD))
|
||||
@@ -86,7 +85,7 @@ second.CMD = #HELPER# sleep 4
|
||||
all: first second
|
||||
|
||||
first second: ; @#HELPER# out $@ sleep 1 out $@!,
|
||||
'-j2', "first\nsleep 1\nfirst\nsecond\nsleep 1\nsecond", 0, 7);
|
||||
'-j2', "first\nsleep 1\nfirst\nsecond\nsleep 1\nsecond", 0);
|
||||
|
||||
# Michael Matz <matz@suse.de> reported a bug where if make is running in
|
||||
# parallel without -k and two jobs die in a row, but not too close to each
|
||||
|
||||
@@ -196,7 +196,7 @@ all: foo.x foo-mt.x
|
||||
'', "one\ntwo");
|
||||
|
||||
# Test pattern rules building the same targets
|
||||
# See SV 54233. Rely on our standard test timeout to break the loop
|
||||
# See SV 54233.
|
||||
|
||||
touch('a.c');
|
||||
|
||||
@@ -478,6 +478,20 @@ run_make_test(q!
|
||||
'gta', "touch gta\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'gtb'.\n");
|
||||
unlink(qw(gta));
|
||||
|
||||
# We don't warn if we didn't update the file
|
||||
utouch(-10, qw(gta));
|
||||
run_make_test(q!
|
||||
%a %b : xyzzy ; $(OP)
|
||||
xyzzy: ;
|
||||
ifdef RUN
|
||||
OP = @echo no
|
||||
endif
|
||||
!,
|
||||
'-rR gta', "#MAKE#: 'gta' is up to date.\n");
|
||||
|
||||
run_make_test(undef, '-rR gta RUN=1', "no\n");
|
||||
unlink(qw(gta));
|
||||
|
||||
run_make_test(q!
|
||||
all:;
|
||||
include gta
|
||||
@@ -486,6 +500,14 @@ include gta
|
||||
'', "touch gta\n#MAKEFILE#:4: warning: pattern recipe did not update peer target 'gtb'.\n#MAKE#: 'all' is up to date.");
|
||||
unlink(qw(gta));
|
||||
|
||||
run_make_test(q!
|
||||
%.c %.h : %.y; touch $*.c
|
||||
%.o: %.c; touch $@
|
||||
foo.y: ; touch $@
|
||||
!,
|
||||
'foo.o', "touch foo.y\ntouch foo.c\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'foo.h'.\ntouch foo.o\nrm foo.c");
|
||||
unlink(qw(foo.y foo.c foo.o));
|
||||
|
||||
if (0) {
|
||||
# SV 12078: Missing grouped pattern peer causes remake regardless of which
|
||||
# target caused the rule to run.
|
||||
|
||||
@@ -62,6 +62,8 @@ use POSIX ();
|
||||
# include bye.mk and bye.mk: rule is needed to cause make to keep the temporary
|
||||
# file for re-exec. Without re-exec make will remove the file before the signal
|
||||
# arrives.
|
||||
# sleep is needed to let make write its "... Terminated" message to the log
|
||||
# file.
|
||||
&utouch(-600, 'bye.mk');
|
||||
close(STDIN);
|
||||
open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!";
|
||||
@@ -69,9 +71,9 @@ run_make_test(q!
|
||||
include bye.mk
|
||||
pid:=$(shell echo $$PPID)
|
||||
all:;
|
||||
bye.mk: force; @kill -TERM $(pid)
|
||||
bye.mk: force; @kill -TERM $(pid) && sleep 16
|
||||
force:
|
||||
!, '-f-', "", POSIX::SIGTERM);
|
||||
!, '-f-', '/#MAKE#: \*\*\* \[#MAKEFILE#:5: bye.mk] Terminated/', POSIX::SIGTERM);
|
||||
}
|
||||
unlink($fout);
|
||||
|
||||
@@ -82,7 +84,9 @@ unlink($fout);
|
||||
use File::Spec;
|
||||
use File::Copy;
|
||||
|
||||
my $makecopy = File::Spec->catfile($TEMPDIR, "make");
|
||||
my $tmakedir = File::Spec->catfile($cwdpath, 'tmakedir');
|
||||
mkdir($tmakedir, 0770);
|
||||
my $makecopy = File::Spec->catfile($tmakedir, 'make');
|
||||
copy("$mkpath", $makecopy);
|
||||
# Set file mode bits, because perl copy won't.
|
||||
chmod 0700, $makecopy;
|
||||
@@ -104,6 +108,7 @@ force:
|
||||
|
||||
@make_command = @make_orig;
|
||||
unlink($makecopy);
|
||||
rmdir($tmakedir);
|
||||
}
|
||||
|
||||
close(STDIN);
|
||||
|
||||
@@ -9,8 +9,7 @@ variable2 := Hello
|
||||
y = $(subst 1,2,$(x))
|
||||
z = y
|
||||
a := $($($(z)))
|
||||
all:
|
||||
@echo $(a)
|
||||
all: ; @echo $(a)
|
||||
',
|
||||
'', "Hello\n");
|
||||
|
||||
@@ -21,15 +20,8 @@ all:
|
||||
|
||||
run_make_test('
|
||||
VARIABLE = $(eval VARIABLE := echo hi)$(VARIABLE)
|
||||
wololo:
|
||||
@$(VARIABLE)
|
||||
wololo: ; @$(VARIABLE)
|
||||
',
|
||||
'', "hi\n");
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,11 +39,12 @@ all:;@echo 'a=,$a,' 'b=,$b,' 'x=,$x,' 'y=,$y,' 'z=,$z,'
|
||||
# We still expand the list and body.
|
||||
run_make_test('
|
||||
null =
|
||||
v = $(let ,$(info blankvar),abc)
|
||||
x = $(let $(null),$(info side-effect),abc)
|
||||
y = $(let y,,$ydef)
|
||||
|
||||
all: ; @echo $x$y',
|
||||
'', "side-effect\nabcdef\n");
|
||||
all: ; @echo $v/$x/$y',
|
||||
'', "blankvar\nside-effect\nabc/abc/def\n");
|
||||
|
||||
# The example macro from the manual.
|
||||
run_make_test('
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
$description = "Make sure make exits with an error if fopen fails.";
|
||||
|
||||
# For some reason on Cygwin, make exits with no error message after
|
||||
# it recurses for a while.
|
||||
$^O =~ /cygwin/ and return -1;
|
||||
|
||||
# Recurse infinitely until we run out of open files, and ensure we
|
||||
# fail with a non-zero exit code. Don't bother to test the output
|
||||
# since it's hard to know what it will be, exactly.
|
||||
|
||||
@@ -6,14 +6,7 @@ $details = "Verify that symlink handling with and without -L works properly.";
|
||||
|
||||
# Only run these tests if the system sypports symlinks
|
||||
|
||||
# Apparently the Windows port of Perl reports that it does support symlinks
|
||||
# (in that the symlink() function doesn't fail) but it really doesn't, so
|
||||
# check for it explicitly.
|
||||
|
||||
if ($port_type eq 'W32' || !( eval { symlink("",""); 1 })) {
|
||||
# This test is N/A
|
||||
return -1;
|
||||
}
|
||||
exists $FEATURES{'check-symlink'} or return -1;
|
||||
|
||||
use File::Spec;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ if ($port_type ne 'W32') {
|
||||
# Some shells (*shakes fist at Solaris*) cannot handle multiple flags in
|
||||
# separate arguments.
|
||||
my $t = `$sh_name -e -c true 2>/dev/null`;
|
||||
my $multi_ok = $? == 0;
|
||||
$multi_ok = $? == 0;
|
||||
}
|
||||
|
||||
# Simple
|
||||
|
||||
@@ -57,15 +57,11 @@ $pathsep = undef;
|
||||
$test_passed = 1;
|
||||
|
||||
# Timeout in seconds. If the test takes longer than this we'll fail it.
|
||||
$test_timeout = 5;
|
||||
$test_timeout = 10 if $^O eq 'VMS';
|
||||
# This is to prevent hung tests.
|
||||
$test_timeout = 60;
|
||||
|
||||
$diff_name = undef;
|
||||
|
||||
# Create a temporary directory that tests can use, outside the temp
|
||||
# directory that make is using.
|
||||
$TEMPDIR = File::Temp->newdir();
|
||||
|
||||
# Path to Perl
|
||||
$perl_name = $^X;
|
||||
if ($^O ne 'VMS') {
|
||||
@@ -201,7 +197,7 @@ sub toplevel
|
||||
'TZ', 'TMPDIR', 'HOME', 'USER', 'LOGNAME', 'PATH',
|
||||
'LD_LIBRARY_PATH',
|
||||
# *SAN things
|
||||
'ASAN_OPTIONS', 'UBSAN_OPTIONS',
|
||||
'ASAN_OPTIONS', 'UBSAN_OPTIONS', 'LSAN_OPTIONS',
|
||||
# Purify things
|
||||
'PURIFYOPTIONS',
|
||||
# Windows-specific things
|
||||
@@ -859,7 +855,8 @@ sub compare_output
|
||||
$slurp_mod =~ s,\r\n,\n,gs;
|
||||
|
||||
$answer_matched = ($slurp_mod eq $answer_mod);
|
||||
if ($^O eq 'VMS') {
|
||||
|
||||
if (!$answer_matched && $^O eq 'VMS') {
|
||||
|
||||
# VMS has extra blank lines in output sometimes.
|
||||
# Ticket #41760
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
$| = 1;
|
||||
|
||||
my $quiet = 0;
|
||||
my $timeout = 4;
|
||||
my $timeout = 10;
|
||||
|
||||
sub op {
|
||||
my ($op, $nm) = @_;
|
||||
|
||||
Reference in New Issue
Block a user