From 208d9858409f823d533d1e95396dde00be03d7d3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 28 May 2024 11:54:51 +0100 Subject: make: fixes to -t option The -t option (in general) causes targets to be touched instead of having build commands run to create them. There were two problems. The flag variable 'ssilent' in docmds was too small (uint8_t) to contain the value of 'dotouch' (uint32_t). Truncation of the value resulted in build commands being echoed when they shouldn't have been. The POSIX specification is unclear as to how build commands with a '+' prefix interact with touch. The rationale indicates that this feature was imported from GNU make, so the behaviour has been made to match what it does: if a '+' build command is run the target is not touched. The code has been rearranged to move the call to touch() up into docmds(). Adds 48 bytes. --- miscutils/make.c | 67 ++++++++++++++++++++++++++-------------------------- testsuite/make.tests | 26 ++++++++++++++++++++ 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/miscutils/make.c b/miscutils/make.c index 056cb2909..70fd30440 100644 --- a/miscutils/make.c +++ b/miscutils/make.c @@ -2294,6 +2294,31 @@ remove_target(void) } } +/* + * Update the modification time of a file to now. + */ +static void +touch(struct name *np) +{ + if (dryrun || !silent) + printf("touch %s\n", np->n_name); + + if (!dryrun) { + const struct timespec timebuf[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}}; + + if (utimensat(AT_FDCWD, np->n_name, timebuf, 0) < 0) { + if (errno == ENOENT) { + int fd = open(np->n_name, O_RDWR | O_CREAT, 0666); + if (fd >= 0) { + close(fd); + return; + } + } + warning("touch %s failed", np->n_name); + } + } +} + /* * Do commands to make a target */ @@ -2304,7 +2329,7 @@ docmds(struct name *np, struct cmd *cp) char *q, *command; for (; cp; cp = cp->c_next) { - uint8_t ssilent, signore, sdomake; + uint32_t ssilent, signore, sdomake; // Location of command in makefile (for use in error messages) makefile = cp->c_makefile; @@ -2380,44 +2405,24 @@ docmds(struct name *np, struct cmd *cp) } } } - if (sdomake || dryrun || dotouch) + if (sdomake || dryrun) estat = MAKE_DIDSOMETHING; free(command); } - makefile = NULL; - return estat; -} - -/* - * Update the modification time of a file to now. - */ -static void -touch(struct name *np) -{ - if (dryrun || !silent) - printf("touch %s\n", np->n_name); - if (!dryrun) { - const struct timespec timebuf[2] = {{0, UTIME_NOW}, {0, UTIME_NOW}}; - - if (utimensat(AT_FDCWD, np->n_name, timebuf, 0) < 0) { - if (errno == ENOENT) { - int fd = open(np->n_name, O_RDWR | O_CREAT, 0666); - if (fd >= 0) { - close(fd); - return; - } - } - warning("touch %s failed", np->n_name); - } + if (dotouch && !(np->n_flag & N_PHONY) && !(estat & MAKE_DIDSOMETHING)) { + touch(np); + estat = MAKE_DIDSOMETHING; } + + makefile = NULL; + return estat; } static int make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, char *dedup, struct name *implicit) { - int estat; char *name, *member = NULL, *base = NULL, *prereq = NULL; name = splitlib(np->n_name, &member); @@ -2457,11 +2462,7 @@ make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, setmacro("*", base, 0 | M_VALID); free(name); - estat = docmds(np, cp); - if (dotouch && !(np->n_flag & N_PHONY)) - touch(np); - - return estat; + return docmds(np, cp); } /* diff --git a/testsuite/make.tests b/testsuite/make.tests index 33e730602..c2b62532a 100755 --- a/testsuite/make.tests +++ b/testsuite/make.tests @@ -2,6 +2,7 @@ . ./testing.sh unset MAKEFLAGS +rm -rf make.tempdir # testing "test name" "command" "expected result" "file input" "stdin" @@ -116,6 +117,31 @@ baz: @: ' +# The -t option touches files that are out-of-date unless the target +# has no commands or they're already up-to-date. +mkdir make.tempdir && cd make.tempdir || exit 1 +touch baz +testing "make check -t option" \ + "make -t -f - 2>/dev/null" "touch bar\n" "" ' +all: foo bar baz +foo: +bar: + @echo bar +baz: + @echo baz +' +cd .. || exit 1; rm -rf make.tempdir 2>/dev/null + +# Build commands with a '+' prefix are executed even with the -t option. +mkdir make.tempdir && cd make.tempdir || exit 1 +testing "make execute build command with + prefix and -t" \ + "make -t -f - 2>/dev/null" "OK\n" "" ' +all: bar +bar: + @+echo OK +' +cd .. || exit 1; rm -rf make.tempdir 2>/dev/null + # A macro created using ::= remembers it's of type immediate-expansion. # Immediate expansion also occurs when += is used to append to such a macro. testing "make appending to immediate-expansion macro" \ -- cgit v1.2.3-55-g6feb